Factor out the bulk of client_serve_request, and add convenience converters in src/nbdtypes.c
This commit is contained in:
57
src/nbdtypes.c
Normal file
57
src/nbdtypes.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "nbdtypes.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
|
||||
|
||||
/**
|
||||
* We intentionally ignore the reserved 128 bytes at the end of the
|
||||
* request, since there's nothing we can do with them.
|
||||
*/
|
||||
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to )
|
||||
{
|
||||
memcpy( to->passwd, from->passwd, 8 );
|
||||
to->magic = be64toh( from->magic );
|
||||
to->size = be64toh( from->size );
|
||||
}
|
||||
|
||||
void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to)
|
||||
{
|
||||
memcpy( to->passwd, from->passwd, 8 );
|
||||
to->magic = htobe64( from->magic );
|
||||
to->size = htobe64( from->size );
|
||||
}
|
||||
|
||||
|
||||
void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to )
|
||||
{
|
||||
to->magic = htobe32( from->magic );
|
||||
to->type = htobe32( from->type );
|
||||
memcpy( to->handle, from->handle, 8 );
|
||||
to->from = htobe64( from->from );
|
||||
to->len = htobe32( from->len );
|
||||
}
|
||||
|
||||
void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to )
|
||||
{
|
||||
to->magic = be32toh( from->magic );
|
||||
to->type = be32toh( from->type );
|
||||
memcpy( to->handle, from->handle, 8 );
|
||||
to->from = be64toh( from->from );
|
||||
to->len = be32toh( from->len );
|
||||
}
|
||||
|
||||
|
||||
void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to )
|
||||
{
|
||||
to->magic = htobe32( from->magic );
|
||||
to->error = htobe32( from->error );
|
||||
memcpy( to->handle, from->handle, 8 );
|
||||
}
|
||||
|
||||
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to )
|
||||
{
|
||||
to->magic = be32toh( from->magic );
|
||||
to->error = be32toh( from->error );
|
||||
memcpy( to->handle, from->handle, 8 );
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
#ifndef __NBDTYPES_H
|
||||
#define __NBDTYPES_H
|
||||
|
||||
|
||||
/* http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-09/2332.html */
|
||||
#define INIT_PASSWD "NBDMAGIC"
|
||||
#define INIT_MAGIC 0x0000420281861253
|
||||
@@ -10,27 +11,70 @@
|
||||
#define REQUEST_WRITE 1
|
||||
#define REQUEST_DISCONNECT 2
|
||||
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include <linux/types.h>
|
||||
struct nbd_init {
|
||||
#include <inttypes.h>
|
||||
|
||||
/* The _raw types are the types as they appear on the wire. Non-_raw
|
||||
* types are in host-format.
|
||||
* Conversion functions are _r2h_ for converting raw to host, and _h2r_
|
||||
* for converting host to raw.
|
||||
*/
|
||||
struct nbd_init_raw {
|
||||
char passwd[8];
|
||||
__be64 magic;
|
||||
__be64 size;
|
||||
char reserved[128];
|
||||
};
|
||||
|
||||
struct nbd_request_raw {
|
||||
__be32 magic;
|
||||
__be32 type; /* == READ || == WRITE */
|
||||
char handle[8];
|
||||
__be64 from;
|
||||
__be32 len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nbd_reply_raw {
|
||||
__be32 magic;
|
||||
__be32 error; /* 0 = ok, else error */
|
||||
char handle[8]; /* handle you got from request */
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct nbd_init {
|
||||
char passwd[8];
|
||||
uint64_t magic;
|
||||
uint64_t size;
|
||||
char reserved[128];
|
||||
};
|
||||
|
||||
struct nbd_request {
|
||||
__be32 magic;
|
||||
__be32 type; /* == READ || == WRITE */
|
||||
char handle[8];
|
||||
__be64 from;
|
||||
__be32 len;
|
||||
uint32_t magic;
|
||||
uint32_t type; /* == READ || == WRITE */
|
||||
char handle[8];
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nbd_reply {
|
||||
__be32 magic;
|
||||
__be32 error; /* 0 = ok, else error */
|
||||
char handle[8]; /* handle you got from request */
|
||||
uint32_t magic;
|
||||
uint32_t error; /* 0 = ok, else error */
|
||||
char handle[8]; /* handle you got from request */
|
||||
};
|
||||
|
||||
|
||||
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to );
|
||||
void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to );
|
||||
void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to );
|
||||
|
||||
void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to);
|
||||
void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to );
|
||||
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to );
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -2,7 +2,10 @@
|
||||
#define __PARAMS_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "parse.h"
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include "nbdtypes.h"
|
||||
#include "ioutil.h"
|
||||
#include "util.h"
|
||||
#include "params.h"
|
||||
#include "params.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
212
src/serve.c
212
src/serve.c
@@ -132,12 +132,13 @@ void write_not_zeroes(struct client_params* client, off64_t from, int len)
|
||||
}
|
||||
}
|
||||
|
||||
int client_serve_request(struct client_params* client)
|
||||
|
||||
/* Returns 1 if *request was filled with a valid request which we should
|
||||
* try to honour. 0 otherwise. */
|
||||
int client_read_request( struct client_params * client , struct nbd_request *out_request )
|
||||
{
|
||||
off64_t offset;
|
||||
struct nbd_request request;
|
||||
struct nbd_reply reply;
|
||||
fd_set fds;
|
||||
struct nbd_request_raw request_raw;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(client->socket, &fds);
|
||||
@@ -146,53 +147,135 @@ int client_serve_request(struct client_params* client)
|
||||
"select() failed");
|
||||
|
||||
if (FD_ISSET(client->serve->close_signal[0], &fds))
|
||||
return 1;
|
||||
|
||||
if (readloop(client->socket, &request, sizeof(request)) == -1) {
|
||||
return 0;
|
||||
|
||||
if (readloop(client->socket, &request_raw, sizeof(request_raw)) == -1) {
|
||||
if (errno == 0) {
|
||||
debug("EOF reading request");
|
||||
return 1; /* neat point to close the socket */
|
||||
return 0; /* neat point to close the socket */
|
||||
}
|
||||
else {
|
||||
CLIENT_ERROR_ON_FAILURE(-1, "Error reading request");
|
||||
}
|
||||
}
|
||||
|
||||
nbd_r2h_request( &request_raw, out_request );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int client_write_reply( struct client_params * client, struct nbd_request *request, int error )
|
||||
{
|
||||
struct nbd_reply reply;
|
||||
struct nbd_reply_raw reply_raw;
|
||||
|
||||
reply.magic = REPLY_MAGIC;
|
||||
reply.error = error;
|
||||
memcpy( reply.handle, &request->handle, 8 );
|
||||
|
||||
nbd_h2r_reply( &reply, &reply_raw );
|
||||
|
||||
write( client->socket, &reply_raw, sizeof( reply_raw ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int client_request_needs_reply( struct client_params * client, struct nbd_request request, int *request_err )
|
||||
{
|
||||
debug("request type %d", request.type);
|
||||
|
||||
reply.magic = htobe32(REPLY_MAGIC);
|
||||
reply.error = htobe32(0);
|
||||
memcpy(reply.handle, request.handle, 8);
|
||||
|
||||
debug("request type %d", be32toh(request.type));
|
||||
|
||||
if (be32toh(request.magic) != REQUEST_MAGIC)
|
||||
CLIENT_ERROR("Bad magic %08x", be32toh(request.magic));
|
||||
if (request.magic != REQUEST_MAGIC)
|
||||
CLIENT_ERROR("Bad magic %08x", request.magic);
|
||||
|
||||
switch (be32toh(request.type))
|
||||
switch (request.type)
|
||||
{
|
||||
case REQUEST_READ:
|
||||
break;
|
||||
case REQUEST_WRITE:
|
||||
/* check it's not out of range */
|
||||
if (be64toh(request.from) < 0 ||
|
||||
be64toh(request.from)+be32toh(request.len) > client->serve->size) {
|
||||
if (request.from < 0 ||
|
||||
request.from+request.len > client->serve->size) {
|
||||
debug("request read %ld+%d out of range",
|
||||
be64toh(request.from),
|
||||
be32toh(request.len)
|
||||
request.from,
|
||||
request.len
|
||||
);
|
||||
reply.error = htobe32(1);
|
||||
write(client->socket, &reply, sizeof(reply));
|
||||
client_write_reply( client, &request, 1 );
|
||||
*request_err = 0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case REQUEST_DISCONNECT:
|
||||
debug("request disconnect");
|
||||
return 1;
|
||||
*request_err = 1;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
CLIENT_ERROR("Unknown request %08x", be32toh(request.type));
|
||||
CLIENT_ERROR("Unknown request %08x", request.type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void client_reply_to_read( struct client_params* client, struct nbd_request request )
|
||||
{
|
||||
off64_t offset;
|
||||
|
||||
debug("request read %ld+%d", request.from, request.len);
|
||||
client_write_reply( client, &request, 0);
|
||||
|
||||
offset = request.from;
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
sendfileloop(
|
||||
client->socket,
|
||||
client->fileno,
|
||||
&offset,
|
||||
request.len),
|
||||
"sendfile failed from=%ld, len=%d",
|
||||
offset,
|
||||
request.len);
|
||||
}
|
||||
|
||||
|
||||
void client_reply_to_write( struct client_params* client, struct nbd_request request )
|
||||
{
|
||||
debug("request write %ld+%d", request.from, request.len);
|
||||
if (client->serve->block_allocation_map) {
|
||||
write_not_zeroes( client, request.from, request.len );
|
||||
}
|
||||
else {
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
readloop(
|
||||
client->socket,
|
||||
client->mapped + request.from,
|
||||
request.len),
|
||||
"read failed from=%ld, len=%d",
|
||||
request.from,
|
||||
request.len );
|
||||
dirty(client->serve, request.from, request.len);
|
||||
}
|
||||
client_write_reply( client, &request, 0);
|
||||
}
|
||||
|
||||
|
||||
void client_reply( struct client_params* client, struct nbd_request request )
|
||||
{
|
||||
switch (request.type) {
|
||||
case REQUEST_READ:
|
||||
client_reply_to_read( client, request );
|
||||
break;
|
||||
|
||||
case REQUEST_WRITE:
|
||||
client_reply_to_write( client, request );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int client_lock_io( struct client_params * client )
|
||||
{
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
pthread_mutex_lock(&client->serve->l_io),
|
||||
"Problem with I/O lock"
|
||||
@@ -203,64 +286,43 @@ int client_serve_request(struct client_params* client)
|
||||
pthread_mutex_unlock(&client->serve->l_io),
|
||||
"Problem with I/O unlock"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (be32toh(request.type))
|
||||
{
|
||||
case REQUEST_READ:
|
||||
debug("request read %ld+%d", be64toh(request.from), be32toh(request.len));
|
||||
write(client->socket, &reply, sizeof(reply));
|
||||
|
||||
offset = be64toh(request.from);
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
sendfileloop(
|
||||
client->socket,
|
||||
client->fileno,
|
||||
&offset,
|
||||
be32toh(request.len)
|
||||
),
|
||||
"sendfile failed from=%ld, len=%d",
|
||||
offset,
|
||||
be32toh(request.len)
|
||||
);
|
||||
break;
|
||||
|
||||
case REQUEST_WRITE:
|
||||
debug("request write %ld+%d", be64toh(request.from), be32toh(request.len));
|
||||
if (client->serve->block_allocation_map) {
|
||||
write_not_zeroes(
|
||||
client,
|
||||
be64toh(request.from),
|
||||
be32toh(request.len)
|
||||
);
|
||||
}
|
||||
else {
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
readloop(
|
||||
client->socket,
|
||||
client->mapped + be64toh(request.from),
|
||||
be32toh(request.len)
|
||||
),
|
||||
"read failed from=%ld, len=%d",
|
||||
be64toh(request.from),
|
||||
be32toh(request.len)
|
||||
);
|
||||
dirty(client->serve, be64toh(request.from), be32toh(request.len));
|
||||
}
|
||||
write(client->socket, &reply, sizeof(reply));
|
||||
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void client_unlock_io( struct client_params * client )
|
||||
{
|
||||
CLIENT_ERROR_ON_FAILURE(
|
||||
pthread_mutex_unlock(&client->serve->l_io),
|
||||
"Problem with I/O unlock"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
int client_serve_request(struct client_params* client)
|
||||
{
|
||||
struct nbd_request request;
|
||||
int request_err;
|
||||
|
||||
if ( !client_read_request( client, &request ) ) { return 1; }
|
||||
if ( !client_request_needs_reply( client, request, &request_err ) ) {
|
||||
return request_err;
|
||||
}
|
||||
|
||||
if ( client_lock_io( client ) ){
|
||||
client_reply( client, request );
|
||||
client_unlock_io( client );
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void client_send_hello(struct client_params* client)
|
||||
{
|
||||
struct nbd_init init;
|
||||
|
Reference in New Issue
Block a user