From 3a19a5657bc17fd84e5983669d28ea3ebaaf2b34 Mon Sep 17 00:00:00 2001 From: sr Date: Mon, 15 Jul 2013 19:13:59 +0200 Subject: Rewriiiiiiiiite --- src/server/net.c | 401 ++++++++++++++++++++++++------------------------------- 1 file changed, 177 insertions(+), 224 deletions(-) (limited to 'src/server/net.c') 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 ); } -- cgit v1.2.3-55-g7522