From 2c9731d63810c839c8040d9d7131326ad48d515b Mon Sep 17 00:00:00 2001 From: sr Date: Mon, 15 Jul 2013 20:46:42 +0200 Subject: "It's compiling!" --- src/server/globals.h | 72 +++++++++++++++++++++++++++++++++++ src/server/image.c | 51 ++++++++++++++++--------- src/server/image.h | 29 +-------------- src/server/net.c | 15 +++----- src/server/server.c | 99 +++++++++++++++++++++++++++++++++++-------------- src/server/server.h | 41 +------------------- src/server/sockhelper.h | 1 + src/server/uplink.c | 18 ++++++--- src/server/uplink.h | 3 ++ src/types.h | 1 + 10 files changed, 204 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/server/globals.h b/src/server/globals.h index ccdaa01..e8203ea 100644 --- a/src/server/globals.h +++ b/src/server/globals.h @@ -1,6 +1,78 @@ #ifndef _GLOBALS_H_ #define _GLOBALS_H_ +#include "../types.h" +#include +#include +#include +#include + +// ######### All structs/types used by the server ######## + +typedef struct +{ + int fd; +} dnbd3_connection_t; + +typedef struct +{ + uint16_t len; + uint8_t data[65535]; +} dnbd3_binstring_t; +// Do not always allocate as much memory as required to hold the entire binstring struct, +// but only as much as is required to hold the actual data +#define NEW_BINSTRING(_name, _len) \ + dnbd3_binstring_t *_name = malloc(sizeof(uint16_t) + _len); \ + _name->len = _len + +typedef struct +{ + char comment[COMMENT_LENGTH]; + time_t last_told; + dnbd3_host_t host; +} dnbd3_alt_server_t; + +typedef struct +{ + char comment[COMMENT_LENGTH]; + dnbd3_host_t host; + dnbd3_host_t mask; +} dnbd3_acess_rules_t; + +/** + * Image struct. An image path could be something like + * /mnt/images/rz/zfs/Windows7 ZfS.vmdk.1 + * and the lower_name would then be + * rz/zfs/windows7 zfs.vmdk + */ +typedef struct +{ + char *path; // absolute path of the image + char *lower_name; // relative path, all lowercase, minus revision ID + uint8_t *cache_map; // cache map telling which parts are locally cached, NULL if complete + uint32_t *crc32; // list of crc32 checksums for each 16MiB block in image + dnbd3_connection_t *uplink; // pointer to a server connection + uint64_t filesize; // size of image + int rid; // revision of image + int users; // clients currently using this image + time_t atime; // last access time + char working; // TRUE if image exists and completeness is == 100% or a working upstream proxy is connected + pthread_spinlock_t lock; +} dnbd3_image_t; + +typedef struct +{ + int sock; + dnbd3_host_t host; + uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client + pthread_t thread; + dnbd3_image_t *image; + pthread_spinlock_t lock; + GSList *sendqueue; // list of dnbd3_binstring_t* +} dnbd3_client_t; + +// ####################################################### + /** * Base directory where all images are stored in. Will always have a trailing slash */ diff --git a/src/server/image.c b/src/server/image.c index 4e69eb2..78b528a 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -1,11 +1,14 @@ #include "image.h" #include "helper.h" +#include "memlog.h" +#include "uplink.h" #include #include #include #include #include +#include #include #include #include @@ -19,10 +22,10 @@ pthread_spinlock_t _images_lock; // ########################################## -static void image_load_all(char *base, char *path); +static int image_load_all_internal(char *base, char *path); static int image_try_load(char *base, char *path); static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks); -static void image_free(dnbd3_image_t *image); +static dnbd3_image_t* image_free(dnbd3_image_t *image); // ########################################## @@ -180,20 +183,28 @@ void image_remove(dnbd3_image_t *image) _images[i] = NULL; if ( i + 1 == _num_images ) _num_images--; } - if ( image->users == 0 ) image_free( image ); pthread_spin_unlock( &image->lock ); + if ( image->users <= 0 ) image = image_free( image ); pthread_spin_unlock( &_images_lock ); } -void image_load_all() +/** + * Load all images in given path recursively. + * Pass NULL to use path from config. + */ +int image_load_all(char *path) { - image_load_all( _basePath, _basePath ); + if ( path == NULL ) { + return image_load_all_internal( _basePath, _basePath ); + } + return image_load_all_internal( path, path ); } /** - * Load all images in the given path + * Load all images in the given path recursively, + * consider bash the base path that is to be cut off */ -static int image_load_all(char *base, char *path) +static int image_load_all_internal(char *base, char *path) { #define SUBDIR_LEN 120 assert( path != NULL ); @@ -223,7 +234,7 @@ static int image_load_all(char *base, char *path) continue; } if ( S_ISDIR( st.st_mode )) { - image_load_all( base, subpath ); // Recurse + image_load_all_internal( base, subpath ); // Recurse } else { image_try_load( base, subpath ); // Load image if possible } @@ -278,6 +289,8 @@ static int image_try_load(char *base, char *path) } *dst = '\0'; } + char mapFile[strlen( path ) + 10 + 1]; + char hashFile[strlen( path ) + 10 + 1]; if ( revision <= 0 ) { memlogf( "[WARNING] Image '%s' has invalid revision ID %d", path, revision ); goto load_error; @@ -300,8 +313,6 @@ static int image_try_load(char *base, char *path) memlogf( "[WARNING] Empty image file '%s'", path ); goto load_error; } - char mapFile[strlen( path ) + 10 + 1]; - char hashFile[strlen( path ) + 10 + 1]; // 1. Allocate memory for the cache map if the image is incomplete sprintf( mapFile, "%s.map", path ); int fdMap = open( path, O_RDONLY ); @@ -314,7 +325,7 @@ static int image_try_load(char *base, char *path) } close( fdMap ); } - // TODO: Maybe try sha-256 or 512 first if you're paranoid + // TODO: Maybe try sha-256 or 512 first if you're paranoid (to be implemented) const int hashBlocks = IMGSIZE_TO_HASHBLOCKS( fileSize ); // Currently this should only prevent accidental corruption (esp. regarding transparent proxy mode) // but maybe later on you want better security @@ -330,7 +341,7 @@ static int image_try_load(char *base, char *path) memlogf( "[WARNING] Could not seek back to beginning of '%s'", hashFile ); } else { uint32_t crcCrc; - if ( read( fdHash, &crc32, sizeof(crc32) ) != 4 ) { + if ( read( fdHash, &crcCrc, sizeof(crcCrc) ) != 4 ) { memlogf( "[WARNING] Error reading first crc32 of '%s'", path ); } else { crc32list = calloc( hashBlocks, sizeof(uint32_t) ); @@ -340,7 +351,7 @@ static int image_try_load(char *base, char *path) memlogf( "[WARNING] Could not read crc32 list of '%s'", path ); } else { uint32_t lists_crc = crc32( 0L, Z_NULL, 0 ); - lists_crc = crc32( lists_crc, crc32list, hashBlocks * sizeof(uint32_t) ); + lists_crc = crc32( lists_crc, (Bytef*)crc32list, hashBlocks * sizeof(uint32_t) ); if ( lists_crc != crcCrc ) { free( crc32list ); crc32list = NULL; @@ -386,13 +397,13 @@ static int image_try_load(char *base, char *path) image->filesize = fileSize; image->rid = revision; image->users = 0; - if ( stat( image, &st ) == 0 ) { + if ( stat( path, &st ) == 0 ) { image->atime = st.st_mtime; } else { image->atime = time( NULL ); } image->working = (image->cache_map == NULL ); - pthread_spin_init( &image->lock ); + pthread_spin_init( &image->lock, PTHREAD_PROCESS_PRIVATE ); // Get rid of cache map if image is complete if ( image->cache_map != NULL && image_is_complete( image ) ) { remove( mapFile ); @@ -414,7 +425,7 @@ static int image_try_load(char *base, char *path) if ( _num_images >= SERVER_MAX_IMAGES ) { memlogf( "[ERROR] Cannot load image '%s': maximum number of images reached.", path ); pthread_spin_unlock( &_images_lock ); - image_free( image ); + image = image_free( image ); goto load_error; } _images[_num_images++] = image; @@ -451,7 +462,7 @@ static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks) memlogf( "Read error" ); return FALSE; } - crc = crc32( crc, buffer, r ); + crc = crc32( crc, (Bytef*)buffer, r ); bytes += r; } if ( crc != crc32list[*blocks] ) return FALSE; @@ -460,16 +471,20 @@ static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks) return TRUE; } -static void image_free(dnbd3_image_t *image) +static dnbd3_image_t* image_free(dnbd3_image_t *image) { assert( image != NULL ); + // free( image->cache_map ); free( image->crc32 ); free( image->path ); free( image->lower_name ); uplink_shutdown( image->uplink ); + pthread_spin_destroy( &image->lock ); + // memset( image, 0, sizeof(dnbd3_image_t) ); free( image ); + return NULL ; } /* diff --git a/src/server/image.h b/src/server/image.h index 1a64b60..c776361 100644 --- a/src/server/image.h +++ b/src/server/image.h @@ -2,32 +2,7 @@ #define _IMAGE_H_ #include "../config.h" - -typedef struct -{ - int fd; -} dnbd3_connection_t; - -/** - * Image struct. An image path could be something like - * /mnt/images/rz/zfs/Windows7 ZfS.vmdk.1 - * and the lower_name would then be - * rz/zfs/windows7 zfs.vmdk - */ -typedef struct -{ - char *path; // absolute path of the image - char *lower_name; // relative path, all lowercase, minus revision ID - uint8_t *cache_map; // cache map telling which parts are locally cached, NULL if complete - uint32_t *crc32; // list of crc32 checksums for each 16MiB block in image - dnbd3_connection_t *uplink; // pointer to a server connection - uint64_t filesize; // size of image - int rid; // revision of image - int users; // clients currently using this image - time_t atime; // last access time - char working; // TRUE if image exists and completeness is == 100% or a working upstream proxy is connected - pthread_spinlock_t lock; -} dnbd3_image_t; +#include "globals.h" extern dnbd3_image_t *_images[SERVER_MAX_IMAGES]; extern int _num_images; @@ -41,7 +16,7 @@ dnbd3_image_t* image_get(char *name, uint16_t revision); void image_release(dnbd3_image_t *image); -void image_load_all(); +int image_load_all(char *path); diff --git a/src/server/net.c b/src/server/net.c index 5a75a9b..6aa5d5b 100644 --- a/src/server/net.c +++ b/src/server/net.c @@ -115,24 +115,24 @@ void *net_client_handler(void *dnbd3_client) dnbd3_image_t *image = NULL; int image_file = -1; - int i, num; + int num; int bOk = FALSE; - uint64_t map_y; - char map_x, bit_mask; serialized_buffer_t payload; char *image_name; uint16_t rid, client_version; + /* + char map_x, bit_mask; + uint64_t map_y; uint64_t todo_size = 0; uint64_t todo_offset = 0; uint64_t cur_offset = 0; uint64_t last_offset = 0; + */ dnbd3_server_entry_t server_list[NUMBER_SERVERS]; - int dirty = 0; - reply.magic = dnbd3_packet_magic; // Receive first packet. This must be CMD_SELECT_IMAGE by protocol specification @@ -153,7 +153,6 @@ void *net_client_handler(void *dnbd3_client) } } 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 ) { @@ -357,8 +356,6 @@ void *net_client_handler(void *dnbd3_client) } 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 ); + dnbd3_remove_client( client ); pthread_exit( (void *)0 ); } diff --git a/src/server/server.c b/src/server/server.c index 7c24358..97bf00a 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "../types.h" #include "../version.h" @@ -52,9 +53,15 @@ char *_config_file_name = DEFAULT_SERVER_CONFIG_FILE; char *_rpc_password = NULL; char *_cache_dir = NULL; +static int dnbd3_add_client(dnbd3_client_t *client); +static dnbd3_client_t* dnbd3_free_client(dnbd3_client_t *client); +static void dnbd3_load_config(); static void dnbd3_handle_sigpipe(int signum); static void dnbd3_handle_sigterm(int signum); +/** + * Print help text for usage instructions + */ void dnbd3_print_help(char *argv_0) { printf( "Usage: %s [OPTIONS]...\n", argv_0 ); @@ -72,15 +79,21 @@ void dnbd3_print_help(char *argv_0) exit( 0 ); } +/** + * Print version information + */ void dnbd3_print_version() { printf( "Version: %s\n", VERSION_STRING ); exit( 0 ); } +/** + * Clean up structs, connections, write out data, then exit + */ void dnbd3_cleanup() { - int fd, i; + int i; memlogf( "INFO: Cleanup...\n" ); @@ -113,7 +126,7 @@ void dnbd3_cleanup() // save cache maps to files image_save_cache_map( image ); // free uplink connection - uplink_free( image->uplink ); + uplink_shutdown( image->uplink ); // free other stuff free( image->cache_map ); free( image->path ); @@ -128,12 +141,14 @@ void dnbd3_cleanup() exit( EXIT_SUCCESS ); } +/** + * Program entry point + */ int main(int argc, char *argv[]) { int demonize = 1; int opt = 0; int longIndex = 0; - int i; static const char *optString = "f:d:nrsiHV?"; static const struct option longOpts[] = { { "file", required_argument, NULL, 'f' }, { "delay", required_argument, NULL, 'd' }, { "nodaemon", no_argument, NULL, 'n' }, { "reload", no_argument, NULL, 'r' }, { "stop", no_argument, NULL, 's' }, { "info", @@ -200,7 +215,10 @@ int main(int argc, char *argv[]) signal( SIGINT, dnbd3_handle_sigterm ); // Load all images in base path - images_load_all(); + if (!image_load_all(NULL)) { + printf("[ERROR] Could not load images.\n"); + return EXIT_FAILURE; + } // setup network sockets[socket_count] = sock_listen_any( PF_INET, PORT ); @@ -262,6 +280,10 @@ int main(int argc, char *argv[]) dnbd3_cleanup(); } +/** + * Initialize and populate the client struct - called when an incoming + * connection is accepted + */ dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd) { dnbd3_client_t *dnbd3_client = calloc( 1, sizeof(dnbd3_client_t) ); @@ -270,18 +292,18 @@ dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd) return NULL ; } - if ( client.ss_family == AF_INET ) { - struct sockaddr_in *v4 = (struct sockaddr_in *)&client; + if ( client->ss_family == AF_INET ) { + struct sockaddr_in *v4 = (struct sockaddr_in *)client; dnbd3_client->host.type = AF_INET; memcpy( dnbd3_client->host.addr, &(v4->sin_addr), 4 ); dnbd3_client->host.port = v4->sin_port; - } else if ( client.ss_family == AF_INET6 ) { - struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&client; + } else if ( client->ss_family == AF_INET6 ) { + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)client; dnbd3_client->host.type = AF_INET6; memcpy( dnbd3_client->host.addr, &(v6->sin6_addr), 16 ); dnbd3_client->host.port = v6->sin6_port; } else { - memlogf( "[ERROR] New client has unknown address family %d, disconnecting...", (int)client.ss_family ); + memlogf( "[ERROR] New client has unknown address family %d, disconnecting...", (int)client->ss_family ); free( dnbd3_client ); return NULL ; } @@ -291,21 +313,28 @@ dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd) } /** - * Free the client struct recursively. - * Doesn't lock, so call this function after removing the client from _dnbd3_clients + * Remove a client from the clients array + * Locks on: _clients_lock */ -void dnbd3_free_client(dnbd3_client_t *client) +void dnbd3_remove_client(dnbd3_client_t *client) { - GSList *it; - for (it = client->sendqueue; it; it = it->next) { - free( it->data ); + int i; + pthread_spin_lock( &_clients_lock ); + for (i = _num_clients - 1; i >= 0; --i) { + if ( _clients[i] != client ) continue; + _clients[i] = NULL; + if ( i + 1 == _num_clients ) --_num_clients; } - g_slist_free( client->sendqueue ); - if ( client->sock >= 0 ) close( client->sock ); - g_free( client ); + pthread_spin_unlock( &_clients_lock ); } -int dnbd3_add_client(dnbd3_client_t *client) +//###// + +/** + * Add client to the clients array. + * Locks on: _clients_lock + */ +static int dnbd3_add_client(dnbd3_client_t *client) { int i; pthread_spin_lock( &_clients_lock ); @@ -325,16 +354,32 @@ int dnbd3_add_client(dnbd3_client_t *client) return TRUE; } -void dnbd3_remove_client(dnbd3_client_t *client) +/** + * Free the client struct recursively. + * !! Make sure to call this function after removing the client from _dnbd3_clients !! + * Locks on: _clients[].lock + */ +static dnbd3_client_t* dnbd3_free_client(dnbd3_client_t *client) { - int i; - pthread_spin_lock( &_clients_lock ); - for (i = _num_clients - 1; i >= 0; --i) { - if ( _clients[i] != client ) continue; - _clients[i] = NULL; - if ( i + 1 == _num_clients ) --_num_clients; + GSList *it; + pthread_spin_lock(&client->lock); + for (it = client->sendqueue; it; it = it->next) { + free( it->data ); } - pthread_spin_unlock( &_clients_lock ); + g_slist_free( client->sendqueue ); + if ( client->sock >= 0 ) close( client->sock ); + client->sock = -1; + if ( client->image != NULL ) image_release( client->image ); + client->image = NULL; + pthread_spin_unlock(&client->lock); + pthread_spin_destroy(&client->lock); + free( client ); + return NULL; +} + +static void dnbd3_load_config() +{ + // Load configuration } static void dnbd3_handle_sigpipe(int signum) diff --git a/src/server/server.h b/src/server/server.h index 46cd86f..413b2d4 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -27,44 +27,9 @@ #include "../config.h" #include "../types.h" +#include "globals.h" -struct dnbd3_image_t; - -typedef struct -{ - uint16_t len; - uint8_t data[65535]; -} dnbd3_binstring_t; -// Do not always allocate as much memory as required to hold the entire binstring struct, -// but only as much as is required to hold the actual data -#define NEW_BINSTRING(_name, _len) \ - dnbd3_binstring_t *_name = malloc(sizeof(uint16_t) + _len); \ - _name->len = _len - -typedef struct -{ - int sock; - dnbd3_host_t host; - uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client - pthread_t thread; - dnbd3_image_t *image; - pthread_spinlock_t lock; - GSList *sendqueue; // list of dnbd3_binstring_t* -} dnbd3_client_t; - -typedef struct -{ - time_t last_told; - dnbd3_host_t host; - char comment[COMMENT_LENGTH]; -} dnbd3_alt_server_t; - -typedef struct -{ - char comment[COMMENT_LENGTH]; - dnbd3_host_t host; - dnbd3_host_t mask; -} dnbd3_acess_rules_t; +struct sockaddr_storage; extern dnbd3_client_t *_clients[SERVER_MAX_CLIENTS]; extern int _num_clients; @@ -77,10 +42,8 @@ extern int _fake_delay; #endif void dnbd3_cleanup(); -void dnbd3_add_client(dnbd3_client_t *client); void dnbd3_remove_client(dnbd3_client_t *client); dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd); -void dnbd3_free_client(dnbd3_client_t *client); #if !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64 #error Please set _FILE_OFFSET_BITS to 64 in your makefile/configuration diff --git a/src/server/sockhelper.h b/src/server/sockhelper.h index 421b8b5..c20cf8f 100644 --- a/src/server/sockhelper.h +++ b/src/server/sockhelper.h @@ -6,6 +6,7 @@ #include #include #include +#include int sock_connect4(struct sockaddr_in *addr, const int connect_ms, const int rw_ms); diff --git a/src/server/uplink.c b/src/server/uplink.c index 27e92b3..7675a76 100644 --- a/src/server/uplink.c +++ b/src/server/uplink.c @@ -1,6 +1,7 @@ #include "uplink.h" #include -#include +#include +#include dnbd3_alt_server_t *_alt_servers[SERVER_MAX_ALTS]; int _num_alts = 0; @@ -21,9 +22,9 @@ int uplink_get_matching_alt_servers(dnbd3_host_t *host, dnbd3_server_entry_t *ou if ( host->type != _alt_servers[i]->host.type ) continue; // Wrong address family if ( count == 0 ) { // Trivial - this is the first entry - memcpy( &output[0]->host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) ); - output[0]->failures = 0; - distance[0] = uplink_net_closeness( host, &output[0]->host ); + memcpy( &output[0].host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) ); + output[0].failures = 0; + distance[0] = uplink_net_closeness( host, &output[0].host ); count++; } else { // Other entries already exist, insert in proper position @@ -40,8 +41,8 @@ int uplink_get_matching_alt_servers(dnbd3_host_t *host, dnbd3_server_entry_t *ou } else { count++; } - memcpy( &output[j]->host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) ); - output[j]->failures = 0; + memcpy( &output[j].host, &_alt_servers[i]->host, sizeof(dnbd3_host_t) ); + output[j].failures = 0; distance[j] = dist; break; } @@ -69,3 +70,8 @@ int uplink_net_closeness(dnbd3_host_t *host1, dnbd3_host_t *host2) } return retval; } + +void uplink_shutdown( dnbd3_connection_t *uplink) +{ + return; +} diff --git a/src/server/uplink.h b/src/server/uplink.h index 77a6ca5..2a876ec 100644 --- a/src/server/uplink.h +++ b/src/server/uplink.h @@ -2,6 +2,7 @@ #define _UPLINK_H_ #include "../types.h" +#include "globals.h" extern dnbd3_alt_server_t *_alt_servers[SERVER_MAX_ALTS]; extern int _num_alts; @@ -11,4 +12,6 @@ int uplink_get_matching_alt_servers(dnbd3_host_t *host, dnbd3_server_entry_t *ou int uplink_net_closeness(dnbd3_host_t *host1, dnbd3_host_t *host2); +void uplink_shutdown( dnbd3_connection_t *uplink); + #endif /* UPLINK_H_ */ diff --git a/src/types.h b/src/types.h index f6eb5f4..6b074b7 100644 --- a/src/types.h +++ b/src/types.h @@ -22,6 +22,7 @@ #define TYPES_H_ #include "config.h" +#include // ioctl #define DNBD3_MAGIC 'd' -- cgit v1.2.3-55-g7522