From f10e60d3c16252cd448cc394ee2eb324e8a45572 Mon Sep 17 00:00:00 2001 From: sr Date: Thu, 11 Jul 2013 19:43:24 +0200 Subject: Rewrite still in progres.... --- src/server/helper.h | 4 + src/server/image.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/server/image.h | 27 +++++- src/server/server.c | 248 +++++++++++++++++++++++--------------------------- src/server/server.h | 27 +----- 5 files changed, 394 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/server/helper.h b/src/server/helper.h index 1df86e8..f0285a2 100644 --- a/src/server/helper.h +++ b/src/server/helper.h @@ -100,4 +100,8 @@ static inline int strend(char *string, char *suffix) // but you actually need 2 bytes to have a complete cache map #define IMGSIZE_TO_MAPBYTES(bytes) ((int)(((bytes) + (1 << 15) - 1) >> 15)) +// calculate number of hash blocks in file. One hash block is 16MiB +#define HASH_BLOCK_SIZE (1 << 24) +#define IMGSIZE_TO_HASHBLOCKS(bytes) ((int)(((bytes) + HASH_BLOCK_SIZE - 1) / HASH_BLOCK_SIZE)) + #endif diff --git a/src/server/image.c b/src/server/image.c index 7e28e95..871d3d4 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -1,4 +1,5 @@ #include "image.h" +#include "helper.h" #include #include @@ -8,11 +9,14 @@ #include #include #include +#include // ########################################## -static void image_load_all(char *path); +static void image_load_all(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); // ########################################## @@ -111,7 +115,7 @@ dnbd3_image_t* image_get(char *name, uint16_t revision) if ( candidate == NULL ) return NULL ; // Not found // Found, see if it works struct stat st; - if ( !candidate->working || candidate->delete_soft < time( NULL ) || stat( candidate->path, &st ) < 0 ) { + if ( !candidate->working || stat( candidate->path, &st ) < 0 ) { candidate->working = FALSE; pthread_spin_unlock( &candidate->lock ); return NULL ; // Not working (anymore) @@ -122,8 +126,10 @@ dnbd3_image_t* image_get(char *name, uint16_t revision) } /** - * Release given image. This will merely decrease the reference counter of the image. - * Locks on: _images[].lock + * Release given image. This will decrease the reference counter of the image. + * If the usage counter reaches 0 and the image is not in the images array + * anymore, the image will be freed + * Locks on: _images_lock, _images[].lock */ void image_release(dnbd3_image_t *image) { @@ -131,12 +137,51 @@ void image_release(dnbd3_image_t *image) pthread_spin_lock( &image->lock ); assert( image->users > 0 ); image->users--; + if ( image->users > 0 ) { // Still in use, do nothing + pthread_spin_unlock( &image->lock ); + return; + } + pthread_spin_unlock( &image->lock ); + pthread_spin_lock( &_images_lock ); + pthread_spin_lock( &image->lock ); + // Check active users again as we unlocked + if ( image->users == 0 ) { + // Not in use anymore, see if it's in the images array + for (int i = 0; i < _num_images; ++i) { + if ( _images[i] == image ) { // Found, do nothing + pthread_spin_unlock( &image->lock ); + pthread_spin_unlock( &_images_lock ); + return; + } + } + } + // Not found, free pthread_spin_unlock( &image->lock ); + pthread_spin_unlock( &_images_lock ); + image_free( image ); } -void image_load_all() +/** + * Remove image from images array. Only free it if it has + * no active users + */ +void image_remove(dnbd3_image_t *image) { + pthread_spin_lock( &_images_lock ); + pthread_spin_lock( &image->lock ); + for (int i = _num_images - 1; i >= 0; --i) { + if ( _images[i] != image ) continue; + _images[i] = NULL; + if ( i + 1 == _num_images ) _num_images--; + } + if ( image->users == 0 ) image_free( image ); + pthread_spin_unlock( &image->lock ); + pthread_spin_unlock( &_images_lock ); +} +void image_load_all() +{ + image_load_all( _basePath, _basePath ); } /** @@ -185,6 +230,12 @@ static int image_load_all(char *base, char *path) static int image_try_load(char *base, char *path) { int i, revision; + struct stat st; + uint8_t *cache_map = NULL; + uint32_t *crc32list = NULL; + dnbd3_image_t *existing = NULL; + int fdImage = -1; + int function_return = FALSE; assert( base != NULL ); assert( path != NULL ); assert( *path == '/' ); @@ -216,16 +267,203 @@ static int image_try_load(char *base, char *path) if ( fileName[i - 1] != '.' ) return FALSE; revision = atoi( fileName + i + 1 ); src = fileName; - while (src < fileName + i - 1) { + while ( src < fileName + i - 1 ) { *dst++ = *src++; } *dst = '\0'; } - if (revision <= 0) { - memlogf("[WARNING] Image '%s' has invalid revision ID %d", path, revision); - return FALSE; + if ( revision <= 0 ) { + memlogf( "[WARNING] Image '%s' has invalid revision ID %d", path, revision ); + goto load_error; + } + strtolower( imgName ); + // Get pointer to already existing image if possible + existing = image_get( imgName, revision ); + // ### Now load the actual image related data ### + fdImage = open( path, O_RDONLY ); + if ( fdImage < 0 ) { + memlogf( "[ERROR] Could not open '%s' for reading...", path ); + goto load_error; + } + int64_t fileSize = lseek( fdImage, 0, SEEK_END ); + if ( fileSize < 0 ) { + memlogf( "[ERROR] Could not seek to end of file '%s'", path ); + goto load_error; + } + if ( fileSize == 0 ) { + 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 ); + if ( fdMap >= 0 ) { + size_t map_size = IMGSIZE_TO_MAPBYTES( fileSize ); + cache_map = calloc( 1, map_size ); + int rd = read( fdMap, cache_map, map_size ); + if ( map_size != rd ) { + memlogf( "[WARNING] Could only read %d of expected %d bytes of cache map of '%s'", (int)rd, (int)map_size, path ); + } + close( fdMap ); + } + // TODO: Maybe try sha-256 or 512 first if you're paranoid + 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 + // 2. Load CRC-32 list of image + sprintf( hashFile, "%s.crc", path ); + int fdHash = open( hashFile, O_RDONLY ); + if ( fdHash >= 0 ) { + off_t fs = lseek( fdHash, 0, SEEK_END ); + if ( fs < (hashBlocks + 1) * 4 ) { + memlogf( "[WARNING] Ignoring crc32 list for '%s' as it is too short", path ); + } else { + if ( 0 != lseek( fdHash, 0, SEEK_SET ) ) { + memlogf( "[WARNING] Could not seek back to beginning of '%s'", hashFile ); + } else { + uint32_t crcCrc; + if ( read( fdHash, &crc32, sizeof(crc32) ) != 4 ) { + memlogf( "[WARNING] Error reading first crc32 of '%s'", path ); + } else { + crc32list = calloc( hashBlocks, sizeof(uint32_t) ); + if ( read( fdHash, crc32list, hashBlocks * sizeof(uint32_t) ) != hashBlocks * sizeof(uint32_t) ) { + free( crc32list ); + crc32list = NULL; + 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) ); + if ( lists_crc != crcCrc ) { + free( crc32list ); + crc32list = NULL; + memlogf( "[WARNING] CRC-32 of CRC-32 list mismatch. CRC-32 list of '%s' might be corrupted.", path ); + } + } + } + } + } + close( fdHash ); + } + // Check CRC32 + if ( crc32list != NULL ) { + int blocks[] = { 0, rand() % hashBlocks, rand() % hashBlocks, -1 }; + if ( !image_check_blocks_crc32( fdImage, crc32list, blocks ) ) { + memlogf( "[ERROR] Quick integrity check for '%s' failed.", path ); + goto load_error; + } + } + // Compare to existing image + if ( existing != NULL ) { + if ( existing->filesize != fileSize ) { + memlogf( "[WARNING] Size of image '%s' has changed.", path ); + } else if ( existing->crc32 != NULL && crc32list != NULL + && memcmp( existing->crc32, crc32list, sizeof(uint32_t) * hashBlocks ) != 0 ) { + memlogf( "[WARNING] CRC32 list of image '%s' has changed.", path ); + } else { + function_return = TRUE; + goto load_error; + } + // Remove image from images array + image_release( existing ); + image_remove( existing ); + existing = NULL; + } + // Load fresh image + dnbd3_image_t *image = calloc( 1, sizeof(dnbd3_image_t) ); + image->path = strdup( path ); + image->lower_name = strdup( imgName ); + image->cache_map = cache_map; + image->crc32 = crc32list; + image->uplink = NULL; + image->filesize = fileSize; + image->rid = revision; + image->users = 0; + if ( stat( image, &st ) == 0 ) { + image->atime = st.st_mtime; + } else { + image->atime = time( NULL ); + } + image->working = (image->cache_map == NULL ); + pthread_spin_init( &image->lock ); + // Get rid of cache map if image is complete + if ( image->cache_map != NULL && image_is_complete( image ) ) { + remove( mapFile ); + free( image->cache_map ); + image->cache_map = NULL; + image->working = TRUE; + } + // Prevent freeing in cleanup + cache_map = NULL; + crc32list = NULL; + // Add to images array + pthread_spin_lock( &_images_lock ); + for (i = 0; i < _num_images; ++i) { + if ( _images[i] != NULL ) continue; + _images[i] = image; + break; + } + if ( i >= _num_images ) { + 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 ); + goto load_error; + } + _images[_num_images++] = image; } - // TODO: LOAD IMAGE DATA ETC. + pthread_spin_unlock( &_images_lock ); + function_return = TRUE; + // Clean exit: + load_error: ; + if ( existing != NULL ) image_release( existing ); + if ( crc32list != NULL ) free( crc32list ); + if ( cache_map != NULL ) free( cache_map ); + if ( fdImage != -1 ) close( fdImage ); + return function_return; +} + +/** + * Check the CRC-32 of the given blocks. The array blocks is of variable length. + * !! pass -1 as the last block so the function knows when to stop !! + */ +static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks) +{ + char buffer[32768]; + while ( *blocks != -1 ) { + if ( lseek( fd, *blocks * HASH_BLOCK_SIZE, SEEK_SET ) != *blocks * HASH_BLOCK_SIZE) { + memlogf( "Seek error" ); + return FALSE; + } + uint32_t crc = crc32( 0L, Z_NULL, 0 ); + int bytes = 0; + while ( bytes < HASH_BLOCK_SIZE) { + const int n = MIN(sizeof(buffer), HASH_BLOCK_SIZE - bytes); + const int r = read( fd, buffer, n ); + if ( r <= 0 ) { + memlogf( "Read error" ); + return FALSE; + } + crc = crc32( crc, buffer, r ); + bytes += r; + } + if ( crc != crc32list[*blocks] ) return FALSE; + blocks++; + } + return TRUE; +} + +static void 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 ); + memset( image, 0, sizeof(dnbd3_image_t) ); + free( image ); } /* diff --git a/src/server/image.h b/src/server/image.h index 6eb2b15..a27125b 100644 --- a/src/server/image.h +++ b/src/server/image.h @@ -1,7 +1,32 @@ #ifndef _IMAGE_H_ #define _IMAGE_H_ -#include "server.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; int image_is_complete(dnbd3_image_t *image); diff --git a/src/server/server.c b/src/server/server.c index 87b7c08..e4e2dd8 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -33,6 +33,7 @@ #include "sockhelper.h" #include "server.h" +#include "image.h" #include "net.h" #include "memlog.h" @@ -63,79 +64,75 @@ static void dnbd3_handle_sigterm(int signum); void dnbd3_print_help(char *argv_0) { - printf("Usage: %s [OPTIONS]...\n", argv_0); - printf("Start the DNBD3 server\n"); - printf("-f or --file Configuration file (default /etc/dnbd3-server.conf)\n"); + printf( "Usage: %s [OPTIONS]...\n", argv_0 ); + printf( "Start the DNBD3 server\n" ); + printf( "-f or --file Configuration file (default /etc/dnbd3-server.conf)\n" ); #ifdef _DEBUG printf("-d or --delay Add a fake network delay of X µs\n"); #endif - printf("-n or --nodaemon Start server in foreground\n"); - printf("-r or --reload Reload configuration file\n"); - printf("-s or --stop Stop running dnbd3-server\n"); - printf("-i or --info Print connected clients and used images\n"); - printf("-H or --help Show this help text and quit\n"); - printf("-V or --version Show version and quit\n"); - exit(0); + printf( "-n or --nodaemon Start server in foreground\n" ); + printf( "-r or --reload Reload configuration file\n" ); + printf( "-s or --stop Stop running dnbd3-server\n" ); + printf( "-i or --info Print connected clients and used images\n" ); + printf( "-H or --help Show this help text and quit\n" ); + printf( "-V or --version Show version and quit\n" ); + exit( 0 ); } void dnbd3_print_version() { - printf("Version: %s\n", VERSION_STRING); - exit(0); + printf( "Version: %s\n", VERSION_STRING ); + exit( 0 ); } void dnbd3_cleanup() { int fd, i; - memlogf("INFO: Cleanup...\n"); + memlogf( "INFO: Cleanup...\n" ); - for (int i = 0; i < socket_count; ++i) - { - if (sockets[i] == -1) - continue; - close(sockets[i]); + for (int i = 0; i < socket_count; ++i) { + if ( sockets[i] == -1 ) continue; + close( sockets[i] ); sockets[i] = -1; } socket_count = 0; // Clean up clients - pthread_spin_lock(&_clients_lock); - for (i = 0; i < _num_clients; ++i) - { + pthread_spin_lock( &_clients_lock ); + for (i = 0; i < _num_clients; ++i) { dnbd3_client_t * const client = _clients[i]; - pthread_spin_lock(&client->lock); - if (client->sock >= 0) shutdown(client->sock, SHUT_RDWR); - if (client->thread != 0) pthread_join(client->thread, NULL); + pthread_spin_lock( &client->lock ); + if ( client->sock >= 0 ) shutdown( client->sock, SHUT_RDWR ); + if ( client->thread != 0 ) pthread_join( client->thread, NULL ); _clients[i] = NULL; - pthread_spin_unlock(&client->lock); - free(client); + pthread_spin_unlock( &client->lock ); + free( client ); } _num_clients = 0; - pthread_spin_unlock(&_clients_lock); + pthread_spin_unlock( &_clients_lock ); // Clean up images - pthread_spin_lock(&_images_lock); - for (i = 0; i < _num_images; ++i) - { + pthread_spin_lock( &_images_lock ); + for (i = 0; i < _num_images; ++i) { dnbd3_image_t *image = _images[i]; - pthread_spin_lock(&image->lock); + pthread_spin_lock( &image->lock ); // save cache maps to files - image_save_cache_map(image); + image_save_cache_map( image ); // free uplink connection - uplink_free(image->uplink); + uplink_free( image->uplink ); // free other stuff - free(image->cache_map); - free(image->path); - free(image->lower_name); + free( image->cache_map ); + free( image->path ); + free( image->lower_name ); _images[i] = NULL; - pthread_spin_unlock(&image->lock); - free(image); + pthread_spin_unlock( &image->lock ); + free( image ); } _num_images = 0; - pthread_spin_unlock(&_images_lock); + pthread_spin_unlock( &_images_lock ); - exit(EXIT_SUCCESS); + exit( EXIT_SUCCESS ); } int main(int argc, char *argv[]) @@ -145,92 +142,82 @@ int main(int argc, char *argv[]) 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", no_argument, NULL, 'i' }, - { "help", no_argument, NULL, 'H' }, - { "version", no_argument, NULL, 'V' } - }; - - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - - while (opt != -1) - { - switch (opt) - { + 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", + no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' } }; + + opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); + + while ( opt != -1 ) { + switch ( opt ) { case 'f': - _config_file_name = strdup(optarg); + _config_file_name = strdup( optarg ); break; case 'd': #ifdef _DEBUG _fake_delay = atoi(optarg); break; #else - printf("This option is only available in debug builds.\n\n"); + printf( "This option is only available in debug builds.\n\n" ); return EXIT_FAILURE; #endif case 'n': demonize = 0; break; case 'r': - printf("INFO: Reloading configuration file...\n\n"); + printf( "INFO: Reloading configuration file...\n\n" ); //dnbd3_rpc_send(RPC_RELOAD); return EXIT_SUCCESS; case 's': - printf("INFO: Stopping running server...\n\n"); + printf( "INFO: Stopping running server...\n\n" ); //dnbd3_rpc_send(RPC_EXIT); return EXIT_SUCCESS; case 'i': - printf("INFO: Requesting information...\n\n"); + printf( "INFO: Requesting information...\n\n" ); //dnbd3_rpc_send(RPC_IMG_LIST); return EXIT_SUCCESS; case 'H': - dnbd3_print_help(argv[0]); + dnbd3_print_help( argv[0] ); break; case 'V': dnbd3_print_version(); break; case '?': - dnbd3_print_help(argv[0]); + dnbd3_print_help( argv[0] ); break; } - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); } - if (demonize) - daemon(1, 0); + if ( demonize ) daemon( 1, 0 ); - pthread_spin_init(&_clients_lock, PTHREAD_PROCESS_PRIVATE); - pthread_spin_init(&_images_lock, PTHREAD_PROCESS_PRIVATE); - pthread_spin_init(&_alts_lock, PTHREAD_PROCESS_PRIVATE); + pthread_spin_init( &_clients_lock, PTHREAD_PROCESS_PRIVATE ); + pthread_spin_init( &_images_lock, PTHREAD_PROCESS_PRIVATE ); + pthread_spin_init( &_alts_lock, PTHREAD_PROCESS_PRIVATE ); initmemlog(); - memlogf("DNBD3 server starting.... Machine type: " ENDIAN_MODE); + memlogf( "DNBD3 server starting.... Machine type: " ENDIAN_MODE ); // load config file dnbd3_load_config(); // setup signal handler - signal(SIGPIPE, dnbd3_handle_sigpipe); - signal(SIGTERM, dnbd3_handle_sigterm); - signal(SIGINT, dnbd3_handle_sigterm); + signal( SIGPIPE, dnbd3_handle_sigpipe ); + signal( SIGTERM, dnbd3_handle_sigterm ); + signal( SIGINT, dnbd3_handle_sigterm ); + + // Load all images in base path + images_load_all(); // setup network - sockets[socket_count] = sock_listen_any(PF_INET, PORT); - if (sockets[socket_count] != -1) - ++socket_count; + sockets[socket_count] = sock_listen_any( PF_INET, PORT ); + if ( sockets[socket_count] != -1 ) ++socket_count; #ifdef WITH_IPV6 sockets[socket_count] = sock_listen_any(PF_INET6, PORT); if (sockets[socket_count] != -1) - ++socket_count; + ++socket_count; #endif - if (socket_count == 0) - exit(EXIT_FAILURE); + if ( socket_count == 0 ) exit( EXIT_FAILURE ); struct sockaddr_storage client; socklen_t len; int fd; @@ -243,44 +230,40 @@ int main(int argc, char *argv[]) //pthread_t thread_job; //pthread_create(&(thread_job), NULL, &dnbd3_job_thread, NULL); - memlogf("[INFO] Server is ready..."); + memlogf( "[INFO] Server is ready..." ); // main loop - while (1) - { + while ( 1 ) { len = sizeof(client); - fd = accept_any(sockets, socket_count, &client, &len); - if (fd < 0) - { - memlogf("[ERROR] Client accept failure"); - usleep(10000); // 10ms + fd = accept_any( sockets, socket_count, &client, &len ); + if ( fd < 0 ) { + memlogf( "[ERROR] Client accept failure" ); + usleep( 10000 ); // 10ms continue; } //memlogf("INFO: Client %s connected\n", inet_ntoa(client.sin_addr)); - sock_set_timeout(fd, SOCKET_TIMEOUT_SERVER_MS); + sock_set_timeout( fd, SOCKET_TIMEOUT_SERVER_MS ); - dnbd3_client_t *dnbd3_client = dnbd3_init_client(&client, fd); - if (dnbd3_client == NULL) - { - close(fd); + dnbd3_client_t *dnbd3_client = dnbd3_init_client( &client, fd ); + if ( dnbd3_client == NULL ) { + close( fd ); continue; } // This has to be done before creating the thread, otherwise a race condition might occur when the new thread dies faster than this thread adds the client to the list after creating the thread - if (!dnbd3_add_client(dnbd3_client)) { - dnbd3_free_client(dnbd3_client); + if ( !dnbd3_add_client( dnbd3_client ) ) { + dnbd3_free_client( dnbd3_client ); continue; } - if (0 != pthread_create(&(dnbd3_client->thread), NULL, net_client_handler, (void *) (uintptr_t) dnbd3_client)) - { - memlogf("[ERROR] Could not start thread for new client."); - dnbd3_remove_client(dnbd3_client); - dnbd3_free_client(dnbd3_client); + if ( 0 != pthread_create( &(dnbd3_client->thread), NULL, net_client_handler, (void *)(uintptr_t)dnbd3_client ) ) { + memlogf( "[ERROR] Could not start thread for new client." ); + dnbd3_remove_client( dnbd3_client ); + dnbd3_free_client( dnbd3_client ); continue; } - pthread_detach(dnbd3_client->thread); + pthread_detach( dnbd3_client->thread ); } dnbd3_cleanup(); @@ -288,29 +271,29 @@ int main(int argc, char *argv[]) dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd) { - dnbd3_client_t *dnbd3_client = calloc(1, sizeof(dnbd3_client_t)); - if (dnbd3_client == NULL) { - memlogf("[ERROR] Could not alloc dnbd3_client_t for new client."); - return NULL; + dnbd3_client_t *dnbd3_client = calloc( 1, sizeof(dnbd3_client_t) ); + if ( dnbd3_client == NULL ) { + memlogf( "[ERROR] Could not alloc dnbd3_client_t for new client." ); + return NULL ; } - if (client.ss_family == AF_INET) { + 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); + memcpy( dnbd3_client->host.addr, &(v4->sin_addr), 4 ); dnbd3_client->host.port = v4->sin_port; - } else if (client.ss_family == AF_INET6) { + } 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); + 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); - free(dnbd3_client); - return NULL; + memlogf( "[ERROR] New client has unknown address family %d, disconnecting...", (int)client.ss_family ); + free( dnbd3_client ); + return NULL ; } dnbd3_client->sock = fd; - pthread_spin_init(&dnbd3_client->lock, PTHREAD_PROCESS_PRIVATE); + pthread_spin_init( &dnbd3_client->lock, PTHREAD_PROCESS_PRIVATE ); return dnbd3_client; } @@ -320,54 +303,53 @@ dnbd3_client_t* dnbd3_init_client(struct sockaddr_storage *client, int fd) void dnbd3_free_client(dnbd3_client_t *client) { GSList *it; // Doesn't lock, so call this function after removing the client from _dnbd3_clients - for (it = client->sendqueue; it; it = it->next) - { - free(it->data); + for (it = client->sendqueue; it; it = it->next) { + free( it->data ); } - g_slist_free(client->sendqueue); - if (client->sock >= 0) close(client->sock); - g_free(client); + g_slist_free( client->sendqueue ); + if ( client->sock >= 0 ) close( client->sock ); + g_free( client ); } int dnbd3_add_client(dnbd3_client_t *client) { int i; - pthread_spin_lock(&_clients_lock); + pthread_spin_lock( &_clients_lock ); for (i = 0; i < _num_clients; ++i) { - if (_clients[i] != NULL) continue; + if ( _clients[i] != NULL ) continue; _clients[i] = client; - pthread_spin_unlock(&_clients_lock); + pthread_spin_unlock( &_clients_lock ); return TRUE; } - if (_num_clients >= SERVER_MAX_CLIENTS) { - pthread_spin_unlock(&_clients_lock); - memlogf("[ERROR] Maximum number of clients reached!"); + if ( _num_clients >= SERVER_MAX_CLIENTS ) { + pthread_spin_unlock( &_clients_lock ); + memlogf( "[ERROR] Maximum number of clients reached!" ); return FALSE; } _clients[_num_clients++] = client; - pthread_spin_unlock(&_clients_lock); + pthread_spin_unlock( &_clients_lock ); return TRUE; } void dnbd3_remove_client(dnbd3_client_t *client) { int i; - pthread_spin_lock(&_clients_lock); + pthread_spin_lock( &_clients_lock ); for (i = _num_clients - 1; i >= 0; --i) { - if (_clients[i] != client) continue; + if ( _clients[i] != client ) continue; _clients[i] = NULL; - if (i + 1 == _num_clients) --_num_clients; + if ( i + 1 == _num_clients ) --_num_clients; } - pthread_spin_unlock(&_clients_lock); + pthread_spin_unlock( &_clients_lock ); } static void dnbd3_handle_sigpipe(int signum) { - memlogf("INFO: SIGPIPE received (%s)", strsignal(signum)); + memlogf( "INFO: SIGPIPE received (%s)", strsignal( signum ) ); } static void dnbd3_handle_sigterm(int signum) { - memlogf("INFO: SIGTERM or SIGINT received (%s)", strsignal(signum)); + memlogf( "INFO: SIGTERM or SIGINT received (%s)", strsignal( signum ) ); dnbd3_cleanup(); } diff --git a/src/server/server.h b/src/server/server.h index 410cc60..b512737 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -28,32 +28,7 @@ #include "../config.h" #include "../types.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 - dnbd3_connection_t *uplink; // NULL = local image / completely cached, pointer to a server connection otherwise - 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 - time_t delete_soft; // unixtime telling when this image should be deleted. if there are still clients using this image it weill be kept, but new clients requesting the image will be rejected. 0 = never - time_t delete_hard; // unixtime telling when this image should be deleted, no matter if there are still clients connected. 0 = never - pthread_spinlock_t lock; -} dnbd3_image_t; +struct dnbd3_image_t; typedef struct { -- cgit v1.2.3-55-g7522