summaryrefslogtreecommitdiffstats
path: root/src/server/net.c
diff options
context:
space:
mode:
authorsr2013-07-15 19:13:59 +0200
committersr2013-07-15 19:13:59 +0200
commit3a19a5657bc17fd84e5983669d28ea3ebaaf2b34 (patch)
treefff67175d97752464ec4ac14f1a14f71d5e3be5d /src/server/net.c
parentRewriting..... (diff)
downloaddnbd3-3a19a5657bc17fd84e5983669d28ea3ebaaf2b34.tar.gz
dnbd3-3a19a5657bc17fd84e5983669d28ea3ebaaf2b34.tar.xz
dnbd3-3a19a5657bc17fd84e5983669d28ea3ebaaf2b34.zip
Rewriiiiiiiiite
Diffstat (limited to 'src/server/net.c')
-rw-r--r--src/server/net.c401
1 files changed, 177 insertions, 224 deletions
diff --git a/src/server/net.c b/src/server/net.c
index 8dcce3c..5a75a9b 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -31,32 +31,31 @@
#include "sockhelper.h"
#include "helper.h"
#include "server.h"
+#include "image.h"
+#include "uplink.h"
#include "memlog.h"
#include "../serialize.h"
#include "../config.h"
-
static inline char recv_request_header(int sock, dnbd3_request_t *request)
{
int ret;
// Read request header from socket
- if ((ret = recv(sock, request, sizeof(*request), MSG_WAITALL)) != sizeof(*request))
- {
- if (ret == 0) return 0;
- printf("[DEBUG] Error receiving request: Could not read message header (%d/%d)\n", ret, (int)sizeof(*request));
+ if ( (ret = recv( sock, request, sizeof(*request), MSG_WAITALL )) != sizeof(*request) ) {
+ if ( ret == 0 ) return 0;
+ printf( "[DEBUG] Error receiving request: Could not read message header (%d/%d)\n", ret, (int)sizeof(*request) );
return 0;
}
// Make sure all bytes are in the right order (endianness)
- fixup_request(*request);
- if (request->magic != dnbd3_packet_magic)
- {
- printf("[DEBUG] Magic in client request incorrect (cmd: %d, len: %d)\n", (int)request->cmd, (int)request->size);
+ fixup_request( *request );
+ if ( request->magic != dnbd3_packet_magic ) {
+ printf( "[DEBUG] Magic in client request incorrect (cmd: %d, len: %d)\n", (int)request->cmd, (int)request->size );
return 0;
}
// Payload sanity check
- if (request->cmd != CMD_GET_BLOCK && request->size > MAX_PAYLOAD)
- {
- memlogf("[WARNING] Client tries to send a packet of type %d with %d bytes payload. Dropping client.", (int)request->cmd, (int)request->size);
+ if ( request->cmd != CMD_GET_BLOCK && request->size > MAX_PAYLOAD ) {
+ memlogf( "[WARNING] Client tries to send a packet of type %d with %d bytes payload. Dropping client.", (int)request->cmd,
+ (int)request->size );
return 0;
}
#ifdef _DEBUG
@@ -67,48 +66,40 @@ static inline char recv_request_header(int sock, dnbd3_request_t *request)
static inline char recv_request_payload(int sock, uint32_t size, serialized_buffer_t *payload)
{
- if (size == 0)
- {
- memlogf("[BUG] Called recv_request_payload() to receive 0 bytes");
+ if ( size == 0 ) {
+ memlogf( "[BUG] Called recv_request_payload() to receive 0 bytes" );
return 0;
}
- if (size > MAX_PAYLOAD)
- {
- memlogf("[BUG] Called recv_request_payload() for more bytes than the passed buffer could hold!");
+ if ( size > MAX_PAYLOAD ) {
+ memlogf( "[BUG] Called recv_request_payload() for more bytes than the passed buffer could hold!" );
return 0;
}
- if (recv(sock, payload->buffer, size, MSG_WAITALL) != size)
- {
- printf("[ERROR] Could not receive request payload of length %d\n", (int)size);
+ if ( recv( sock, payload->buffer, size, MSG_WAITALL ) != size ) {
+ printf( "[ERROR] Could not receive request payload of length %d\n", (int)size );
return 0;
}
// Prepare payload buffer for reading
- serializer_reset_read(payload, size);
+ serializer_reset_read( payload, size );
return 1;
}
static inline char send_reply(int sock, dnbd3_reply_t *reply, void *payload)
{
const unsigned int size = reply->size;
- fixup_reply(*reply);
- if (!payload || size == 0)
- {
- if (send(sock, reply, sizeof(dnbd3_reply_t), MSG_WAITALL) != sizeof(dnbd3_reply_t))
- {
- printf("[DEBUG] Send failed (header-only)\n");
+ fixup_reply( *reply );
+ if ( !payload || size == 0 ) {
+ if ( send( sock, reply, sizeof(dnbd3_reply_t), MSG_WAITALL ) != sizeof(dnbd3_reply_t) ) {
+ printf( "[DEBUG] Send failed (header-only)\n" );
return 0;
}
- }
- else
- {
+ } else {
struct iovec iov[2];
iov[0].iov_base = reply;
iov[0].iov_len = sizeof(dnbd3_reply_t);
iov[1].iov_base = payload;
iov[1].iov_len = size;
- if (writev(sock, iov, 2) != sizeof(dnbd3_reply_t) + size)
- {
- printf("[DEBUG] Send failed (reply with payload of %u bytes)\n", size);
+ if ( writev( sock, iov, 2 ) != sizeof(dnbd3_reply_t) + size ) {
+ printf( "[DEBUG] Send failed (reply with payload of %u bytes)\n", size );
return 0;
}
}
@@ -117,7 +108,7 @@ static inline char send_reply(int sock, dnbd3_reply_t *reply, void *payload)
void *net_client_handler(void *dnbd3_client)
{
- dnbd3_client_t *client = (dnbd3_client_t *) (uintptr_t) dnbd3_client;
+ dnbd3_client_t *client = (dnbd3_client_t *)(uintptr_t)dnbd3_client;
dnbd3_request_t request;
dnbd3_reply_t reply;
@@ -145,60 +136,41 @@ void *net_client_handler(void *dnbd3_client)
reply.magic = dnbd3_packet_magic;
// Receive first packet. This must be CMD_SELECT_IMAGE by protocol specification
- if (recv_request_header(client->sock, &request))
- {
- if (request.cmd != CMD_SELECT_IMAGE)
- {
- printf("[DEBUG] Client sent invalid handshake (%d). Dropping Client\n", (int)request.cmd);
- }
- else
- {
- if (recv_request_payload(client->sock, request.size, &payload))
- {
- client_version = serializer_get_uint16(&payload);
- image_name = serializer_get_string(&payload);
- rid = serializer_get_uint16(&payload);
- client->is_server = serializer_get_uint8(&payload);
- if (request.size < 3 || !image_name || client_version < MIN_SUPPORTED_CLIENT)
- {
- if (client_version < MIN_SUPPORTED_CLIENT)
- {
- printf("[DEBUG] Client too old\n");
- }
- else
- {
- printf("[DEBUG] Incomplete handshake received\n");
- }
- }
- else
- {
- image = image_get(image_name, rid);
- const time_t now = time(NULL);
- if (image==NULL)
- {
- printf("[DEBUG] Client requested non-existent image '%s' (rid:%d), rejected\n", image_name, (int)rid);
- }
- else if (!image->working)
- {
- printf("[DEBUG] Client requested non-working image '%s' (rid:%d), rejected\n", image_name, (int)rid);
+ if ( recv_request_header( client->sock, &request ) ) {
+ if ( request.cmd != CMD_SELECT_IMAGE ) {
+ printf( "[DEBUG] Client sent invalid handshake (%d). Dropping Client\n", (int)request.cmd );
+ } else {
+ if ( recv_request_payload( client->sock, request.size, &payload ) ) {
+ client_version = serializer_get_uint16( &payload );
+ image_name = serializer_get_string( &payload );
+ rid = serializer_get_uint16( &payload );
+ client->is_server = serializer_get_uint8( &payload );
+ if ( request.size < 3 || !image_name || client_version < MIN_SUPPORTED_CLIENT ) {
+ if ( client_version < MIN_SUPPORTED_CLIENT ) {
+ printf( "[DEBUG] Client too old\n" );
+ } else {
+ printf( "[DEBUG] Incomplete handshake received\n" );
}
- else
- {
- image_file = open(image->path, O_RDONLY);
- if (image_file >= 0)
- {
- serializer_reset_write(&payload);
- serializer_put_uint16(&payload, PROTOCOL_VERSION);
- serializer_put_string(&payload, image->lower_name);
- serializer_put_uint16(&payload, image->rid);
- serializer_put_uint64(&payload, image->filesize);
+ } else {
+ image = image_get( image_name, rid );
+ const time_t now = time( NULL );
+ if ( image == NULL ) {
+ printf( "[DEBUG] Client requested non-existent image '%s' (rid:%d), rejected\n", image_name, (int)rid );
+ } else if ( !image->working ) {
+ printf( "[DEBUG] Client requested non-working image '%s' (rid:%d), rejected\n", image_name, (int)rid );
+ } else {
+ image_file = open( image->path, O_RDONLY );
+ if ( image_file >= 0 ) {
+ serializer_reset_write( &payload );
+ serializer_put_uint16( &payload, PROTOCOL_VERSION );
+ serializer_put_string( &payload, image->lower_name );
+ serializer_put_uint16( &payload, image->rid );
+ serializer_put_uint64( &payload, image->filesize );
reply.cmd = CMD_SELECT_IMAGE;
- reply.size = serializer_get_written_length(&payload);
- if (send_reply(client->sock, &reply, &payload))
- {
+ reply.size = serializer_get_written_length( &payload );
+ if ( send_reply( client->sock, &reply, &payload ) ) {
client->image = image;
- if (!client->is_server)
- image->atime = time(NULL); // TODO: check if mutex is needed
+ if ( !client->is_server ) image->atime = time( NULL );
bOk = TRUE;
}
@@ -210,38 +182,33 @@ void *net_client_handler(void *dnbd3_client)
}
// client handling mainloop
- if (bOk)
- {while (recv_request_header(client->sock, &request))
- {
- switch (request.cmd)
- {
+ if ( bOk ) {
+ while ( recv_request_header( client->sock, &request ) ) {
+ switch ( request.cmd ) {
case CMD_GET_BLOCK:
- if (request.offset >= image->filesize)
- {
+ if ( request.offset >= image->filesize ) {
// Sanity check
- memlogf("[WARNING] Client requested non-existent block");
+ memlogf( "[WARNING] Client requested non-existent block" );
reply.size = 0;
reply.cmd = CMD_ERROR;
- send_reply(client->sock, &reply, NULL);
+ send_reply( client->sock, &reply, NULL );
break;
}
- if (request.offset + request.size > image->filesize)
- {
+ if ( request.offset + request.size > image->filesize ) {
// Sanity check
- memlogf("[WARNING] Client requested data block that extends beyond image size");
+ memlogf( "[WARNING] Client requested data block that extends beyond image size" );
reply.size = 0;
reply.cmd = CMD_ERROR;
- send_reply(client->sock, &reply, NULL);
+ send_reply( client->sock, &reply, NULL );
break;
}
- if (request.size > image->filesize)
- {
+ if ( request.size > image->filesize ) {
// Sanity check
- memlogf("[WARNING] Client requested data block that is bigger than the image size");
+ memlogf( "[WARNING] Client requested data block that is bigger than the image size" );
reply.size = 0;
reply.cmd = CMD_ERROR;
- send_reply(client->sock, &reply, NULL);
+ send_reply( client->sock, &reply, NULL );
break;
}
@@ -249,129 +216,118 @@ void *net_client_handler(void *dnbd3_client)
reply.size = request.size;
reply.handle = request.handle;
- fixup_reply(reply);
- if (send(client->sock, &reply, sizeof(dnbd3_reply_t), MSG_MORE) != sizeof(dnbd3_reply_t))
- {
- printf("[DEBUG] Sending CMD_GET_BLOCK header failed\n");
- return 0;
+ fixup_reply( reply );
+ if ( send( client->sock, &reply, sizeof(dnbd3_reply_t), MSG_MORE ) != sizeof(dnbd3_reply_t) ) {
+ printf( "[DEBUG] Sending CMD_GET_BLOCK header failed\n" );
+ goto exit_client_cleanup;
}
- if (request.size == 0) // Request for 0 bytes, done after sending header
- break;
+ if ( request.size == 0 ) // Request for 0 bytes, done after sending header
+ break;
- // caching is off
- if (image_cache == -1)
- {
- const ssize_t ret = sendfile(client->sock, image_file, (off_t *)&request.offset, request.size);
- if (ret != request.size)
- {
- printf("[ERROR] sendfile failed (image to net %d/%d)\n", (int)ret, (int)request.size);
- close(client->sock);
- client->sock = -1;
+ // no cache map means image is complete
+ if ( image->cache_map == NULL ) {
+ const ssize_t ret = sendfile( client->sock, image_file, (off_t *)&request.offset, request.size );
+ if ( ret != request.size ) {
+ printf( "[ERROR] sendfile failed (image to net %d/%d)\n", (int)ret, (int)request.size );
+ goto exit_client_cleanup;
}
break;
}
- // caching is on
- dirty = 0;
- todo_size = 0;
- todo_offset = request.offset;
- cur_offset = request.offset;
- last_offset = request.offset + request.size;
-
- // first make sure the whole requested part is in the local cache file
- while(cur_offset < last_offset)
- {
- map_y = cur_offset >> 15; // div 32768
- map_x = (cur_offset >> 12) & 7; // (X div 4096) mod 8
- bit_mask = 0b00000001 << (map_x);
-
- cur_offset += 4096;
-
- if ((image->cache_map[map_y] & bit_mask) != 0) // cache hit
- {
- if (todo_size != 0) // fetch missing chunks
- {
- lseek(image_cache, todo_offset, SEEK_SET);
- if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size)
- {
- if (image->file == NULL)
- printf("[ERROR] Device was closed when local copy was incomplete.");
- printf("[ERROR] sendfile failed (copy to cache 1)\n");
- close(client->sock);
- client->sock = -1;
- // Reset these so we don't update the cache map with false information
- dirty = 0;
- todo_size = 0;
- break;
- }
- todo_size = 0;
- dirty = 1;
- }
- todo_offset = cur_offset;
- }
- else
- {
- todo_size += 4096;
- }
- }
-
- // whole request was missing
- if (todo_size != 0)
- {
- lseek(image_cache, todo_offset, SEEK_SET);
- if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size)
- {
- printf("[ERROR] sendfile failed (copy to cache 2)\n");
- close(client->sock);
- client->sock = -1;
- break;
- }
- dirty = 1;
- }
-
- if (dirty) // cache map needs to be updated as something was missing locally
- {
- // set 1 in cache map for whole request
- cur_offset = request.offset;
- while(cur_offset < last_offset)
- {
- map_y = cur_offset >> 15;
- map_x = (cur_offset >> 12) & 7; // mod 8
- bit_mask = 0b00000001 << (map_x);
- image->cache_map[map_y] |= bit_mask;
- cur_offset += 4096;
- }
- }
-
- // send data to client
- if (sendfile(client->sock, image_cache, (off_t *) &request.offset, request.size) != request.size)
- {
- memlogf("[ERROR] sendfile failed (cache to net)\n");
- close(client->sock);
- client->sock = -1;
- }
+ printf( "[DEBUG] Caching/Proxying not implemented yet!\n" );
+ goto exit_client_cleanup;
+
+ /*
+
+ // caching is on
+ dirty = 0;
+ todo_size = 0;
+ todo_offset = request.offset;
+ cur_offset = request.offset;
+ last_offset = request.offset + request.size;
+
+ // first make sure the whole requested part is in the local cache file
+ while(cur_offset < last_offset)
+ {
+ map_y = cur_offset >> 15; // div 32768
+ map_x = (cur_offset >> 12) & 7; // (X div 4096) mod 8
+ bit_mask = 0b00000001 << (map_x);
+
+ cur_offset += 4096;
+
+ if ((image->cache_map[map_y] & bit_mask) != 0) // cache hit
+ {
+ if (todo_size != 0) // fetch missing chunks
+ {
+ lseek(image_cache, todo_offset, SEEK_SET);
+ if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size)
+ {
+ if (image->file == NULL)
+ printf("[ERROR] Device was closed when local copy was incomplete.");
+ printf("[ERROR] sendfile failed (copy to cache 1)\n");
+ goto exit_client_cleanup;
+ }
+ todo_size = 0;
+ dirty = 1;
+ }
+ todo_offset = cur_offset;
+ }
+ else
+ {
+ todo_size += 4096;
+ }
+ }
+
+ // whole request was missing
+ if (todo_size != 0)
+ {
+ lseek(image_cache, todo_offset, SEEK_SET);
+ if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size)
+ {
+ printf("[ERROR] sendfile failed (copy to cache 2)\n");
+ goto exit_client_cleanup;
+ }
+ dirty = 1;
+ }
+
+ if (dirty) // cache map needs to be updated as something was missing locally
+ {
+ // set 1 in cache map for whole request
+ cur_offset = request.offset;
+ while(cur_offset < last_offset)
+ {
+ map_y = cur_offset >> 15;
+ map_x = (cur_offset >> 12) & 7; // mod 8
+ bit_mask = 0b00000001 << (map_x);
+ image->cache_map[map_y] |= bit_mask;
+ cur_offset += 4096;
+ }
+ }
+
+ // send data to client
+ if (sendfile(client->sock, image_cache, (off_t *) &request.offset, request.size) != request.size)
+ {
+ memlogf("[ERROR] sendfile failed (cache to net)\n");
+ close(client->sock);
+ client->sock = -1;
+ }
+ */
break;
-
case CMD_GET_SERVERS:
client->is_server = FALSE; // Only clients request list of servers
// Build list of known working alt servers
- num = 0;
- for (i = 0; i < NUMBER_SERVERS; i++)
- {
- if (image->servers[i].host.type == 0 || image->servers[i].failures > 200) continue;
- memcpy(server_list + num++, image->servers + i, sizeof(dnbd3_server_entry_t));
- }
+ num = uplink_get_matching_alt_servers( &client->host, server_list, NUMBER_SERVERS );
reply.cmd = CMD_GET_SERVERS;
reply.size = num * sizeof(dnbd3_server_entry_t);
- send_reply(client->sock, &reply, server_list);
+ send_reply( client->sock, &reply, server_list );
break;
case CMD_KEEPALIVE:
reply.cmd = CMD_KEEPALIVE;
reply.size = 0;
- send_reply(client->sock, &reply, NULL);
+ send_reply( client->sock, &reply, NULL );
break;
case CMD_SET_CLIENT_MODE:
@@ -379,33 +335,30 @@ void *net_client_handler(void *dnbd3_client)
break;
default:
- memlogf("[ERROR] Unknown command: %d", (int)request.cmd);
+ memlogf( "[ERROR] Unknown command: %d", (int)request.cmd );
break;
}
// Check for messages that have been queued from another thread
- while (client->sendqueue != NULL)
- {
+ while ( client->sendqueue != NULL ) {
dnbd3_binstring_t *message = NULL;
- pthread_spin_lock(&_spinlock);
- if (client->sendqueue != NULL)
- {
+ pthread_spin_lock( &client->lock );
+ if ( client->sendqueue != NULL ) {
message = client->sendqueue->data;
- client->sendqueue = g_slist_remove(client->sendqueue, message);
+ client->sendqueue = g_slist_remove( client->sendqueue, message );
}
- pthread_spin_unlock(&_spinlock);
- send_data(client->sock, message->data, message->len);
- free(message);
+ pthread_spin_unlock( &client->lock );
+ send_data( client->sock, message->data, message->len );
+ free( message );
}
}
-}
- if (client->sock != -1)
- close(client->sock);
- if (image_file != -1) close(image_file);
- image_release(image);
+ }
+ exit_client_cleanup: if ( client->sock != -1 ) close( client->sock );
+ if ( image_file != -1 ) close( image_file );
+ image_release( image );
client->image = image = NULL;
- dnbd3_free_client(client);
- pthread_exit((void *) 0);
+ dnbd3_free_client( client );
+ pthread_exit( (void *)0 );
}