From ee62ca14800eb27e51038a78a0dab4f71b6be31f Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 24 Apr 2015 17:13:31 +0200 Subject: [FUSE] Integrate into cmake build process --- CMakeLists.txt | 41 ++++-- cmake/FindFuse.cmake | 30 ++++ src/fuse/helper.c | 96 ++++++++++++ src/fuse/helper.h | 29 ++++ src/fuse/imageFuse.c | 384 ------------------------------------------------ src/fuse/imageHelper.c | 84 ----------- src/fuse/imageHelper.h | 28 ---- src/fuse/main.c | 348 +++++++++++++++++++++++++++++++++++++++++++ src/fuse/serialize.c | 5 + src/protocol.h | 138 +++++++++++++++++ src/serialize.h | 1 + src/server/altservers.c | 2 +- src/server/image.c | 2 +- src/server/protocol.h | 136 ----------------- src/server/uplink.c | 2 +- 15 files changed, 682 insertions(+), 644 deletions(-) create mode 100644 cmake/FindFuse.cmake create mode 100644 src/fuse/helper.c create mode 100644 src/fuse/helper.h delete mode 100755 src/fuse/imageFuse.c delete mode 100755 src/fuse/imageHelper.c delete mode 100755 src/fuse/imageHelper.h create mode 100644 src/fuse/main.c create mode 100644 src/fuse/serialize.c create mode 100644 src/protocol.h delete mode 100644 src/server/protocol.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e265f7..bb00189 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,17 +24,27 @@ endif() #SET(CMAKE_CXX_FLAGS_DEBUG "-std=c99 -O0 -g -Wall -Wno-unused-result -D_GNU_SOURCE -D_DEBUG") #SET(CMAKE_CXX_FLAGS_RELEASE "-std=c99 -O2 -Wno-unused-result -D_GNU_SOURCE -DNDEBUG" ) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") + ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) ADD_DEFINITIONS(-DWITH_IPV6) -FIND_PACKAGE(Threads REQUIRED) +FIND_PACKAGE(Threads) +FIND_PACKAGE(Fuse) FIND_PACKAGE(PkgConfig REQUIRED) #FIND_PACKAGE(LibXml2 REQUIRED) -FIND_PACKAGE(ZLIB REQUIRED) +FIND_PACKAGE(ZLIB) + +if(NOT FUSE_FOUND) + message( " *** No fuse dev libs found, won't build dnbd3-fuse" ) +endif() +if(NOT THREADS_FOUND OR NOT ZLIB_FOUND) + message( " *** No threads or no zlib found, won't build dnbd3-server" ) +endif() #PKG_CHECK_MODULES(GLIB glib-2.0 REQUIRED) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${ZLIB_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${ZLIB_INCLUDE_DIR} ${FUSE_INCLUDE_DIR}) ################################################################################ # VERSION HEADER # @@ -71,15 +81,28 @@ ADD_DEPENDENCIES(dnbd3-client version) # SERVER # ################################################################################ -FILE(GLOB_RECURSE SERVER_SRCS src/server/*.c) -ADD_EXECUTABLE(dnbd3-server ${SERVER_SRCS}) -TARGET_LINK_LIBRARIES(dnbd3-server ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) -if(UNIX AND NOT APPLE) - target_link_libraries(dnbd3-server rt) +if(THREADS_FOUND AND ZLIB_FOUND) + FILE(GLOB_RECURSE SERVER_SRCS src/server/*.c) + ADD_EXECUTABLE(dnbd3-server ${SERVER_SRCS}) + TARGET_LINK_LIBRARIES(dnbd3-server ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) + if(UNIX AND NOT APPLE) + target_link_libraries(dnbd3-server rt) + endif() + ADD_DEPENDENCIES(dnbd3-server version) endif() -ADD_DEPENDENCIES(dnbd3-server version) +################################################################################ +# FUSE # +################################################################################ + +if(FUSE_FOUND) + FILE(GLOB_RECURSE FUSE_SRCS src/fuse/*.c) + ADD_EXECUTABLE(dnbd3-fuse ${FUSE_SRCS}) + TARGET_LINK_LIBRARIES(dnbd3-fuse ${FUSE_LIBRARIES}) + ADD_DEPENDENCIES(dnbd3-fuse version) +endif() + ################################################################################ # MODULE # diff --git a/cmake/FindFuse.cmake b/cmake/FindFuse.cmake new file mode 100644 index 0000000..b9c6f91 --- /dev/null +++ b/cmake/FindFuse.cmake @@ -0,0 +1,30 @@ +# - Find fuse +# Find the native fuse includes and library +# +# FUSE_INCLUDE_DIR - where to find fuse/fuse.h. +# FUSE_LIBRARIES - List of libraries when using fuse. +# FUSE_FOUND - True if fuse found. + + +IF (FUSE_INCLUDE_DIR) + # Already in cache, be silent + SET(FUSE_FIND_QUIETLY TRUE) +ENDIF (FUSE_INCLUDE_DIR) + +FIND_PATH(FUSE_INCLUDE_DIR fuse/fuse.h) + +SET(FUSE_NAMES fuse) +FIND_LIBRARY(FUSE_LIBRARY NAMES ${FUSE_NAMES} ) + +# handle the QUIETLY and REQUIRED arguments and set FUSE_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FUSE REQUIRED FUSE_LIBRARY FUSE_INCLUDE_DIR) + +IF(FUSE_FOUND) + SET( FUSE_LIBRARIES ${FUSE_LIBRARY} ) +ELSE(FUSE_FOUND) + SET( FUSE_LIBRARIES ) +ENDIF(FUSE_FOUND) + +MARK_AS_ADVANCED( FUSE_LIBRARY FUSE_INCLUDE_DIR ) diff --git a/src/fuse/helper.c b/src/fuse/helper.c new file mode 100644 index 0000000..7b1101d --- /dev/null +++ b/src/fuse/helper.c @@ -0,0 +1,96 @@ +/* + * Helper functions for imageFuse + * by Stephan Schwaer, January 2014 + */ + +#include "helper.h" +void printLog( log_info *info ) +{ + FILE *logFile; + + // Create logfile + + logFile = fopen( "log.txt", "w" ); + if ( logFile == NULL ) { + printf( "Error creating/opening log.txt\n" ); + return; + } + + //rewind(file); + fprintf( logFile, "ImageSize: %"PRIu64" MiB\n", ( uint64_t )( info->imageSize/ ( 1024ll*1024ll ) ) ); + fprintf( logFile, "ReceivedMiB: %"PRIu64" MiB\n", ( uint64_t )( info->receivedBytes/ ( 1024ll*1024ll ) ) ); + fprintf( logFile, "imageBlockCount: %"PRIu64"\n", info->imageBlockCount ); + fprintf( logFile, "Blocksize: 4KiB\n\n" ); + fprintf( logFile, "Block access count:\n" ); + + uint64_t i = 0; + for ( ; i < info->imageBlockCount; i++ ) { + if ( i % 50 == 0 ) { + fprintf( logFile, "\n" ); + } + fprintf( logFile, "%i ", ( int ) info->blockRequestCount[i] ); + } + fprintf( logFile, "\n" ); + fclose( logFile ); +} + +bool sock_printable( struct sockaddr *addr, socklen_t addrLen, char *output, int len ) +{ + char host[100], port[10]; + int ret = getnameinfo( addr, addrLen, host, 100, port, 10, NI_NUMERICHOST | NI_NUMERICSERV ); + if ( ret == 0 ) { + snprintf( output, len, "[%s]:%s", host, port ); + } + return ret == 0; +} + +// TODO: Pretty much same as in server/* +int connect_to_server( char *server_address, int port ) +{ + const int on = 1; + int sock = -1; + struct addrinfo hints, *res, *ptr; + char portStr[6]; + + // Set hints for local addresses. + memset( &hints, 0, sizeof( hints ) ); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + snprintf( portStr, sizeof portStr, "%d", port ); + if ( getaddrinfo( server_address, portStr, &hints, &res ) != 0 || res == NULL ) { + return false; + } + // Attempt to bind to all of the addresses as long as there's room in the poll list + for ( ptr = res; ptr != NULL; ptr = ptr->ai_next ) { + char bla[100]; + if ( !sock_printable( ( struct sockaddr * ) ptr->ai_addr, ptr->ai_addrlen, bla, 100 ) ) { + snprintf( bla, 100, "[invalid]" ); + } + printf( "Trying to connect to %s ", bla ); + sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); + if ( sock < 0 ) { + printf( "...cannot create socket, errno=%d\n", errno ); + sock = -1; + continue; + } + setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof( on ) ); + if ( ptr->ai_family == PF_INET6 ) { + setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof( on ) ); + } + if ( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) < 0 ) { + // if ( bind( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) { + printf( "...socket Error, errno=%d\n", errno ); + close( sock ); + sock = -1; + continue; + } else { + printf( "... connecting successful!\n" ); + break; + } + } + + freeaddrinfo( res ); + return sock; +} + diff --git a/src/fuse/helper.h b/src/fuse/helper.h new file mode 100644 index 0000000..1c972e4 --- /dev/null +++ b/src/fuse/helper.h @@ -0,0 +1,29 @@ +#ifndef IMAGEHELPER_H +#define IMAGEHELPER_H + +#include "../protocol.h" +#include +#include +#include +#include +#include +#include +#include + + +typedef struct log_info { + uint64_t imageSize; + uint64_t receivedBytes; + uint64_t imageBlockCount; + uint8_t *blockRequestCount; +} log_info; + + + +void printLog(log_info *info); + +bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len); + +int connect_to_server(char *server_adress, int port); + +#endif diff --git a/src/fuse/imageFuse.c b/src/fuse/imageFuse.c deleted file mode 100755 index 2874b79..0000000 --- a/src/fuse/imageFuse.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * This program can be distributed under the terms of the GNU GPL. - * See the file COPYING. - * - * Changed by Stephan Schwaer - * */ - -#define FUSE_USE_VERSION 30 -#include -#include -#include -#include -#include -#include -#include -/* for socket */ -#include -#include -#include -#include -#include "protocol.h" -#include "serialize.h" -/* for printing uint */ -#define __STDC_FORMAT_MACROS -#include -#include "imageHelper.h" - -/* variables for socket */ -int sock = -1; -int n; - -char* server_adress = NULL; -int portno = -1; -char* image_Name = NULL; -char* imagePathName = NULL; -uint16_t rid; -uint8_t flags8; -char buffer[1000]; -static uint64_t imageSize; -/* Debug/Benchmark variables */ -bool useDebug = false; -bool useLog = false; -log_info logInfo; -uint8_t printCount = 0; - -void error(const char *msg) -{ - perror(msg); - exit(0); -} - -static int image_getattr(const char *path, struct stat *stbuf) -{ - int res = 0; - memset(stbuf, 0, sizeof(struct stat)); - if (strcmp(path, "/") == 0) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - } else if (strcmp(path, imagePathName) == 0) { - stbuf->st_mode = S_IFREG | 0755; - stbuf->st_nlink = 1; - stbuf->st_size = imageSize; - } else - res = -ENOENT; - return res; -} - -static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) -{ - (void) offset; - (void) fi; - if (strcmp(path, "/") != 0) - return -ENOENT; - filler(buf, ".", NULL, 0); - filler(buf, "..", NULL, 0); - filler(buf, imagePathName + 1, NULL, 0); - return 0; -} - -static int image_open(const char *path, struct fuse_file_info *fi) -{ - if (strcmp(path, imagePathName) != 0) - return -ENOENT; - if ((fi->flags & 3) != O_RDONLY) - return -EACCES; - return 0; -} - -static int image_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) -{ - size_t len; - /* buffer for throwing away unwanted messages. */ - char tBuf[100]; - - (void) fi; - if(strcmp(path, imagePathName) != 0) - return -ENOENT; - len = imageSize; - if (offset < len) { - if (offset + size > len) - size = len - offset; - -get_block: - /* seek inside the image */ - if(!dnbd3_get_block(sock, offset, size, offset)){ - printf("[ERROR] Get block error!\n");} - else { - printf("Get block success!\n"); - } - - /* count the requested blocks */ - uint64_t startBlock = offset / (4096); - uint64_t endBlock = (offset + size - 1) / (4096); - - printf("StartBlockRequest: %"PRIu64"\n", startBlock); - printf("EndBlockRequest: %"PRIu64"\n", endBlock); - - if(useDebug) { - for (; startBlock <= endBlock; startBlock++){ - logInfo.blockRequestCount[startBlock] += 1; - } - } - - dnbd3_reply_t reply; - - /*see if the received package is a requested block, throw away if not */ - while(true){ - if(!dnbd3_get_reply(sock, &reply)){ - printf("[ERROR] Reply error\n"); - - /* Try to reconnect after reply error */ - printf("Reconnecting!\n"); - sock = connect_to_server(&server_adress, &portno); - - if (sock == -1){ - printf("[ERROR] Connection Error!"); - exit(1); - } - - printf("Selecting image "); - - bzero(buffer,256); - rid = 0; - flags8 = 0; - serialized_buffer_t sbuffer; - uint16_t protocol_version; - char *name; - uint16_t rrid; - - if(dnbd3_select_image(sock, image_Name, rid, flags8) != 1){ - printf("- Error\n"); - } else {printf("- Success\n"); - } - - if(!dnbd3_select_image_reply(&sbuffer, sock, &protocol_version, &name, &rrid, &imageSize)) { - printf("Error reading reply\n"); - exit(1); - } else {printf("Reply successful\n"); - } - - printf("Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n",(int) protocol_version, name, (int) rrid,(int) (imageSize/(1024*1024))); - goto get_block; - - } else { - printf("Reply success\n"); - } - if(reply.cmd == CMD_ERROR) { - printf("Got a CMD_ERROR!\n"); - exit(1); - } - if(reply.cmd != CMD_GET_BLOCK) { - printf("Received block isn't a wanted block, throwing it away...\n"); - int tDone = 0; - int todo; - while(tDone < reply.size){ - todo = reply.size - tDone > 100 ? 100: reply.size - tDone; - - n = read(sock, tBuf, todo); - if (n <= 0) { - if(n < 0 && (errno == EAGAIN || errno == EINTR)) continue; - printf("[ERROR] Errno %i and %i\n",errno, n); - exit(1); - } - tDone += n ; - } - continue; - } - break; - } - - printf("Payloadsize: %i\n",(int) reply.size); - printf("Offset: %"PRIu64"\n", reply.handle); - - if(size != reply.size){ - printf("Size: %i, reply.size: %i!\n",(int) size,(int) reply.size); - exit(1); - } - /* read the data block data from received package */ - int done = 0; - while (done < size ){ - n = read(sock, buf + done, size - done); - if (n <= 0) { - if(n < 0 && (errno == EAGAIN || errno == EINTR)) continue; - printf("[ERROR] Error: %i and %i\n",errno, n); - exit(1); - } - done += n; - /* for benchmarking */ - logInfo.receivedBytes += n; - } - } else - size = 0; - printf("Received bytes: %i MiB\n",(int) (logInfo.receivedBytes/(1024*1024))); - - /* logfile stuff */ - if( useLog ){ - if (printCount == 0){ - printLog(&logInfo); - } - printCount = printCount + 1 % 100; - } - return size; -} - -/* close the connection */ -void image_destroy(void* private_data){ - if ( useLog ){ - printLog(&logInfo); - } - if (close(sock) != 0) { - printf("error closing file.\n"); - exit(-1); - } - free(imagePathName); - return; -} - -/* map the implemented fuse operations */ -static struct fuse_operations image_oper = { - .getattr = image_getattr, - .readdir = image_readdir, - .open = image_open, - .read = image_read, - .destroy = image_destroy, -}; - -int main (int argc, char *argv[]) -{ - char* mountPoint = NULL; - int opt; - bool testOpt = false; - - if(argc == 1 ||strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "--usage") == 0 ){ -exit_usage: - printf("Usage: %s [-l] [-d] [-t] -m -s -p -i \n", argv[0]); - printf(" -l: creates a logfile log.txt at program path\n"); - printf(" -d: fuse debug mode\n"); - printf(" -t: use hardcoded server, port and image for testing\n"); - exit(EXIT_FAILURE); - } - - while((opt = getopt(argc,argv,"m:s:p:i:tdl")) != -1){ - switch(opt) { - case 'm': - mountPoint = optarg; - break; - case 's': - server_adress = optarg; - break; - case 'p': - portno = atoi(optarg); - break; - case 'i': - image_Name = optarg; - break; - case 't': - testOpt = true; - break; - case 'd': - useDebug = true; - break; - case 'l': - useLog = true; - useDebug = true; - break; - default: - goto exit_usage; - } - } - - if(testOpt){ - /* values for testing. */ - server_adress = "132.230.4.1"; - portno = 5003; - image_Name = "windows7-umwelt.vmdk"; - useLog = true; - } - - if(server_adress == NULL || portno == -1 || image_Name == NULL || mountPoint == NULL){ - goto exit_usage; - } - - int arg_count = 5; - if (useDebug){ - arg_count++; - } - char * args[6] = {"foo", "-o", "ro,allow_other", "-s", mountPoint, "-d"}; - - sock = connect_to_server(&server_adress, &portno); - - if (sock == -1){ - printf("[ERROR] Connection Error!"); - exit(1); - } - - printf("Selecting image "); - - bzero(buffer,256); - rid = 0; - flags8 = 0; - - serialized_buffer_t sbuffer; - uint16_t protocol_version; - char *name; - uint16_t rrid; - - if(dnbd3_select_image(sock, image_Name, rid, flags8) != 1){ - printf("- Error\n"); - } else {printf("- Success\n"); - } - - if(!dnbd3_select_image_reply(&sbuffer, sock, &protocol_version, &name, &rrid, &imageSize)) { - printf("Error reading reply\n"); - exit(1); - } else {printf("Reply successful\n"); - } - - printf("Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n",(int) protocol_version, name, (int) rrid,(int) (imageSize/(1024*1024))); - - /* fix name of image if it contains '/' */ - int len = strlen(image_Name) - 1; - bool fixName = false; - for(; len >= 0; len--){ - if(image_Name[len] == '/'){ - fixName = true; - break; - } - } - if( fixName) { - memmove(image_Name, image_Name + len + 1, strlen(image_Name) - len); - printf("image_Name: %s\n", image_Name); - } - - - char * str1 = "/"; - char * tmpStr = (char *) malloc(1 + strlen(str1) + strlen(image_Name)); - strcpy(tmpStr, str1); - strcat(tmpStr, image_Name); - imagePathName = tmpStr; - - /* initialize benchmark variables */ - logInfo.receivedBytes = 0; - logInfo.imageSize = imageSize; - logInfo.imageBlockCount = imageSize % 4096 == 0 ? imageSize/(4096) : imageSize/(4096) + 1; - - uint8_t tmpShrt[logInfo.imageBlockCount]; - uint64_t i = 0; - if ( useLog ){ - for(; i < logInfo.imageBlockCount; i++){ - tmpShrt[i] = 0; - } - } - - logInfo.blockRequestCount = tmpShrt; - - printf("ImagePathName: %s\n",imagePathName); - return fuse_main(arg_count, args, &image_oper, NULL); -} - - diff --git a/src/fuse/imageHelper.c b/src/fuse/imageHelper.c deleted file mode 100755 index b5bc9bd..0000000 --- a/src/fuse/imageHelper.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Helper functions for imageFuse - * by Stephan Schwaer, January 2014 - */ - -#include "imageHelper.h" -void printLog(log_info *info){ - FILE *logFile; - - // Create logfile - - logFile = fopen("log.txt", "w+"); - if ( logFile == NULL) { - printf("Error creating/opening log.txt\n"); - return; - } - - //rewind(file); - fprintf(logFile, "ImageSize: %"PRIu64" MiB\n", (uint64_t)(info->imageSize/(1024ll*1024ll))); - fprintf(logFile, "ReceivedMiB: %"PRIu64" MiB\n", (uint64_t)(info->receivedBytes/(1024ll*1024ll))); - fprintf(logFile, "imageBlockCount: %"PRIu64"\n", info->imageBlockCount); - fprintf(logFile, "Blocksize: 4KiB\n\n"); - fprintf(logFile, "Block access count:\n"); - - uint64_t i = 0; - for (; i < info->imageBlockCount; i++){ - if( i % 50 == 0 ) fprintf(logFile, "\n"); - fprintf(logFile, "%i ",(int) info->blockRequestCount[i]); - } - fprintf(logFile, "\n"); - fclose(logFile); -} - -bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len) -{ - char host[100], port[10]; - int ret = getnameinfo( addr, addrLen, host, 100, port, 10, NI_NUMERICHOST | NI_NUMERICSERV ); - if ( ret == 0 ) snprintf( output, len, "[%s]:%s", host, port ); - return ret == 0; -} - - -int connect_to_server(char ** server_adress, int * port){ - const int on = 1; - int sock = -1; - struct addrinfo hints, *res, *ptr; - char portStr[6]; - - // Set hints for local addresses. - memset( &hints, 0, sizeof(hints) ); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - snprintf( portStr, sizeof portStr, "%d", *port ); - if ( getaddrinfo( *server_adress, portStr, &hints, &res ) != 0 || res == NULL ) return false; - // Attempt to bind to all of the addresses as long as there's room in the poll list - for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) { - char bla[100]; - if ( !sock_printable( (struct sockaddr*)ptr->ai_addr, ptr->ai_addrlen, bla, 100 ) ) snprintf( bla, 100, "[invalid]" ); - printf( "Trying to connect to %s ", bla ); - sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); - if ( sock < 0 ) { - printf( "...cannot create socket, errno=%d\n", errno ); - sock = -1; - continue; - } - setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); - if ( ptr->ai_family == PF_INET6 ) setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on) ); - if (connect(sock, ptr->ai_addr, ptr->ai_addrlen) < 0) { - // if ( bind( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) { - printf( "...socket Error, errno=%d\n", errno ); - close( sock ); - sock = -1; - continue; - } else { - printf( "... connecting successful!\n"); - break; - } - } - - freeaddrinfo( res ); - return sock; -} - diff --git a/src/fuse/imageHelper.h b/src/fuse/imageHelper.h deleted file mode 100755 index 60805cd..0000000 --- a/src/fuse/imageHelper.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef IMAGEHELPER_H -#define IMAGEHELPER_H - -#include -#include "protocol.h" -#include -#include -#include -#include -#include -#include - - -typedef struct log_info { - uint64_t imageSize; - uint64_t receivedBytes; - uint64_t imageBlockCount; - uint8_t * blockRequestCount; -} log_info; - - - -void printLog(log_info *info); - -bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len); - -int connect_to_server(char ** server_adress, int * port); -#endif diff --git a/src/fuse/main.c b/src/fuse/main.c new file mode 100644 index 0000000..79f17e8 --- /dev/null +++ b/src/fuse/main.c @@ -0,0 +1,348 @@ +/* + * FUSE: Filesystem in Userspace + * Copyright (C) 2001-2007 Miklos Szeredi + * This program can be distributed under the terms of the GNU GPL. + * See the file COPYING. + * + * Changed by Stephan Schwaer + * */ + +#include "../protocol.h" +#include "../serialize.h" +#include "helper.h" + +#define FUSE_USE_VERSION 30 +#include +#include +#include +#include +#include +#include +#include +/* for socket */ +#include +#include +#include +#include +/* for printing uint */ +#define __STDC_FORMAT_MACROS +#include + +/* variables for socket */ +int sock = -1; +int n; + +char *server_address = NULL; +int portno = -1; +char *image_Name = NULL; +const char *imagePathName = "/image"; +uint16_t rid; +static uint64_t imageSize; +/* Debug/Benchmark variables */ +bool useDebug = false; +bool useLog = false; +log_info logInfo; +uint8_t printCount = 0; + +void error(const char *msg) +{ + perror( msg ); + exit( 0 ); +} + +static void dnbd3_connect() +{ + while ( true ) { + if ( sock != -1 ) { + close( sock ); + } + sock = connect_to_server( server_address, portno ); + + if ( sock == -1 ) { + printf( "[ERROR] Connection Error!\n" ); + goto fail; + } + + printf( "Selecting image " ); + + serialized_buffer_t sbuffer; + uint16_t protocol_version; + char *name; + uint16_t rrid; + + if ( dnbd3_select_image( sock, image_Name, rid, 0 ) != 1 ) { + printf( "- Error\n" ); + goto fail; + } + printf( "- Success\n" ); + + if ( !dnbd3_select_image_reply( &sbuffer, sock, &protocol_version, &name, &rrid, &imageSize ) ) { + printf( "Error reading reply\n" ); + goto fail; + } + printf( "Reply successful\n" ); + + if ( rid != 0 && rid != rrid ) { + printf( "Got unexpected rid %d, wanted %d\n", (int)rrid, (int)rid ); + sleep( 10 ); + goto fail; + } + rid = rrid; + + printf( "Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n", (int)protocol_version, name, (int) rrid, (int)( imageSize/ ( 1024*1024 ) ) ); + return; + +fail: ; + sleep( 2 ); + } +} + +static int image_getattr(const char *path, struct stat *stbuf) +{ + int res = 0; + memset( stbuf, 0, sizeof( struct stat ) ); + if ( strcmp( path, "/" ) == 0 ) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if ( strcmp( path, imagePathName ) == 0 ) { + stbuf->st_mode = S_IFREG | 0755; + stbuf->st_nlink = 1; + stbuf->st_size = imageSize; + } else { + res = -ENOENT; + } + return res; +} + +static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset UNUSED, struct fuse_file_info *fi UNUSED) +{ + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + filler( buf, ".", NULL, 0 ); + filler( buf, "..", NULL, 0 ); + filler( buf, imagePathName + 1, NULL, 0 ); + return 0; +} + +static int image_open(const char *path, struct fuse_file_info *fi) +{ + if ( strcmp( path, imagePathName ) != 0 ) { + return -ENOENT; + } + if ( ( fi->flags & 3 ) != O_RDONLY ) { + return -EACCES; + } + return 0; +} + +static int image_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi UNUSED) +{ + /* buffer for throwing away unwanted messages. */ + char tBuf[100]; + + if ( strcmp( path, imagePathName ) != 0 ) { + return -ENOENT; + } + if ( offset >= imageSize ) { + return 0; + } + if ( offset + size > imageSize ) { + size = imageSize - offset; + } + + if ( sock == -1 ) { +retry: ; + dnbd3_connect(); + } + + /* seek inside the image */ + if ( !dnbd3_get_block( sock, offset, size, offset ) ) { + printf( "[ERROR] Get block error!\n" ); + goto retry; + } + + /* count the requested blocks */ + uint64_t startBlock = offset / ( 4096 ); + uint64_t endBlock = ( offset + size - 1 ) / ( 4096 ); + + printf( "StartBlockRequest: %"PRIu64"\n", startBlock ); + printf( "EndBlockRequest: %"PRIu64"\n", endBlock ); + + if ( useDebug ) { + for ( ; startBlock <= endBlock; startBlock++ ) { + logInfo.blockRequestCount[startBlock] += 1; + } + } + + dnbd3_reply_t reply; + + /*see if the received package is a requested block, throw away if not */ + while ( true ) { + if ( !dnbd3_get_reply( sock, &reply ) ) { + printf( "[ERROR] Reply error\n" ); + goto retry; + } + printf( "Reply success\n" ); + + if ( reply.cmd == CMD_ERROR ) { + printf( "Got a CMD_ERROR!\n" ); + goto retry; + } + if ( reply.cmd != CMD_GET_BLOCK ) { + printf( "Received block isn't a wanted block, throwing it away...\n" ); + int tDone = 0; + int todo; + while ( tDone < reply.size ) { + todo = reply.size - tDone > 100 ? 100: reply.size - tDone; + + n = read( sock, tBuf, todo ); + if ( n <= 0 ) { + if ( n < 0 && ( errno == EAGAIN || errno == EINTR ) ) { + continue; + } + printf( "[ERROR] Errno %i and %i\n",errno, n ); + goto retry; + } + tDone += n; + } + continue; + } + break; + } + + printf( "Payloadsize: %i\n", ( int ) reply.size ); + printf( "Offset: %"PRIu64"\n", reply.handle ); + + if ( size != reply.size || offset != reply.handle ) { + printf( "Size: %i, reply.size: %i!\n", ( int ) size, ( int ) reply.size ); + printf( "Handle: %" PRIu64 ", reply.handle: %" PRIu64 "!\n", offset, reply.handle ); + goto retry; + } + /* read the data block data from received package */ + int done = 0; + while ( done < size ) { + n = read( sock, buf + done, size - done ); + if ( n <= 0 ) { + if ( n < 0 && ( errno == EAGAIN || errno == EINTR ) ) { + continue; + } + printf( "[ERROR] Error: %i and %i\n",errno, n ); + goto retry; + } + done += n; + /* for benchmarking */ + logInfo.receivedBytes += n; + } + printf( "Received bytes: %i MiB\n", ( int )( logInfo.receivedBytes/ ( 1024*1024 ) ) ); + + /* logfile stuff */ + if ( useLog ) { + if ( printCount == 0 ) { + printLog( &logInfo ); + } + printCount++; + } + return size; +} + +/* close the connection */ +void image_destroy(void *private_data) +{ + if ( useLog ) { + printLog( &logInfo ); + } + if ( sock != -1 ) { + close( sock ); + sock = -1; + } + return; +} + +/* map the implemented fuse operations */ +static struct fuse_operations image_oper = { + .getattr = image_getattr, + .readdir = image_readdir, + .open = image_open, + .read = image_read, + .destroy = image_destroy, +}; + +int main(int argc, char *argv[]) +{ + char *mountPoint = NULL; + int opt; + bool testOpt = false; + + if ( argc == 1 || strcmp( argv[1], "--help" ) == 0 || strcmp( argv[1], "--usage" ) == 0 ) { +exit_usage: + printf( "Usage: %s [-l] [-d] [-t] -m -s -p -i \n", argv[0] ); + printf( " -l: creates a logfile log.txt at program path\n" ); + printf( " -d: fuse debug mode\n" ); + printf( " -t: use hardcoded server, port and image for testing\n" ); + exit( EXIT_FAILURE ); + } + + while ( ( opt = getopt( argc,argv,"m:s:p:i:tdl" ) ) != -1 ) { + switch ( opt ) { + case 'm': + mountPoint = optarg; + break; + case 's': + server_address = optarg; + break; + case 'p': + portno = atoi( optarg ); + break; + case 'i': + image_Name = optarg; + break; + case 't': + testOpt = true; + break; + case 'd': + useDebug = true; + break; + case 'l': + useLog = true; + useDebug = true; + break; + default: + goto exit_usage; + } + } + + if ( testOpt ) { + /* values for testing. */ + server_address = "132.230.4.1"; + portno = 5003; + image_Name = "windows7-umwelt.vmdk"; + useLog = true; + } + + if ( server_address == NULL || portno == -1 || image_Name == NULL || mountPoint == NULL ) { + goto exit_usage; + } + + int arg_count = 5; + if ( useDebug ) { + arg_count++; + } + char *args[6] = {"foo", "-o", "ro,allow_other", "-s", mountPoint, "-d"}; + + dnbd3_connect(); + + /* initialize benchmark variables */ + logInfo.receivedBytes = 0; + logInfo.imageSize = imageSize; + logInfo.imageBlockCount = ( imageSize + 4095 ) / 4096; + + uint8_t tmpShrt[logInfo.imageBlockCount]; + memset( tmpShrt, 0, sizeof tmpShrt ); + + logInfo.blockRequestCount = tmpShrt; + + printf( "ImagePathName: %s\n",imagePathName ); + return fuse_main( arg_count, args, &image_oper, NULL ); +} + diff --git a/src/fuse/serialize.c b/src/fuse/serialize.c new file mode 100644 index 0000000..4934132 --- /dev/null +++ b/src/fuse/serialize.c @@ -0,0 +1,5 @@ +#include +#include +#include + +#include "../serialize.c" diff --git a/src/protocol.h b/src/protocol.h new file mode 100644 index 0000000..d119dc5 --- /dev/null +++ b/src/protocol.h @@ -0,0 +1,138 @@ +#ifndef _PROTOCOL_H_ +#define _PROTOCOL_H_ + +#include +#include +#include +#include "types.h" +#include "serialize.h" + +#define FLAGS8_SERVER (1) + +#define REPLY_OK (0) +#define REPLY_ERRNO (-1) +#define REPLY_AGAIN (-2) +#define REPLY_INTR (-3) +#define REPLY_CLOSED (-4) +#define REPLY_INCOMPLETE (-5) +#define REPLY_WRONGMAGIC (-6) + +static inline int dnbd3_read_reply(int sock, dnbd3_reply_t *reply, bool wait) +{ + int ret = recv( sock, reply, sizeof(*reply), (wait ? MSG_WAITALL : MSG_DONTWAIT) | MSG_NOSIGNAL ); + if ( ret == 0 ) return REPLY_CLOSED; + if ( ret < 0 ) { + if ( errno == EAGAIN || errno == EWOULDBLOCK ) return REPLY_AGAIN; + if ( errno == EINTR ) return REPLY_INTR; + return REPLY_ERRNO; + } + if ( !wait && ret != sizeof(*reply) ) ret += recv( sock, ((char*)reply) + ret, sizeof(*reply) - ret, MSG_WAITALL | MSG_NOSIGNAL ); + if ( ret != sizeof(*reply) ) return REPLY_INCOMPLETE; + fixup_reply( *reply ); + if ( reply->magic != dnbd3_packet_magic ) return REPLY_WRONGMAGIC; + return REPLY_OK; +} + +static inline bool dnbd3_get_reply(int sock, dnbd3_reply_t *reply) +{ + return dnbd3_read_reply( sock, reply, true ) == REPLY_OK; +} + +static inline bool dnbd3_select_image(int sock, char *lower_name, uint16_t rid, uint8_t flags8) +{ + serialized_buffer_t serialized; + dnbd3_request_t request; + struct iovec iov[2]; + serializer_reset_write( &serialized ); + serializer_put_uint16( &serialized, PROTOCOL_VERSION ); + serializer_put_string( &serialized, lower_name ); + serializer_put_uint16( &serialized, rid ); + serializer_put_uint8( &serialized, flags8 ); + const ssize_t len = serializer_get_written_length( &serialized ); + request.magic = dnbd3_packet_magic; + request.cmd = CMD_SELECT_IMAGE; + request.size = len; +#ifdef _DEBUG + request.handle = 0; + request.offset = 0; +#endif + fixup_request( request ); + iov[0].iov_base = &request; + iov[0].iov_len = sizeof(request); + iov[1].iov_base = &serialized; + iov[1].iov_len = len; + return writev( sock, iov, 2 ) == len + (ssize_t)sizeof(request); +} + +static inline bool dnbd3_get_block(int sock, uint64_t offset, uint32_t size, uint64_t handle) +{ + dnbd3_request_t request; + request.magic = dnbd3_packet_magic; + request.handle = handle; + request.cmd = CMD_GET_BLOCK; + request.offset = offset; + request.size = size; + fixup_request( request ); + return send( sock, &request, sizeof(request), MSG_NOSIGNAL ) == sizeof(request); +} + +static inline bool dnbd3_get_crc32(int sock, uint32_t *master, void *buffer, size_t *bufferLen) +{ + dnbd3_request_t request; + dnbd3_reply_t reply; + request.magic = dnbd3_packet_magic; + request.handle = 0; + request.cmd = CMD_GET_CRC32; + request.offset = 0; + request.size = 0; + fixup_request( request ); + if ( send( sock, &request, sizeof(request), 0 ) != sizeof(request) ) return false; + if ( !dnbd3_get_reply( sock, &reply ) ) return false; + if ( reply.size == 0 ) { + *bufferLen = 0; + return true; + } + if ( reply.size < 4 ) return false; + reply.size -= 4; + if ( reply.cmd != CMD_GET_CRC32 || reply.size > *bufferLen ) return false; + *bufferLen = reply.size; + if ( recv( sock, master, sizeof(uint32_t), MSG_WAITALL | MSG_NOSIGNAL ) != sizeof(uint32_t) ) return false; + uint32_t done = 0; + while ( done < reply.size ) { + const ssize_t ret = recv( sock, (char*)buffer + done, reply.size - done, 0 ); + if ( ret <= 0 ) return false; + done += ret; + } + return true; +} + +/** + * Pass a full serialized_buffer_t and a socket fd. Parsed data will be returned in further arguments. + * Note that all strings will point into the passed buffer, so there's no need to free them. + * This function will also read the header for you, as this message can only occur during connection, + * where no unrequested messages could arrive inbetween. + */ +static inline bool dnbd3_select_image_reply(serialized_buffer_t *buffer, int sock, uint16_t *protocol_version, char **name, uint16_t *rid, + uint64_t *imageSize) +{ + dnbd3_reply_t reply; + if ( !dnbd3_get_reply( sock, &reply ) ) { + return false; + } + if ( reply.cmd != CMD_SELECT_IMAGE || reply.size < 3 || reply.size > MAX_PAYLOAD ) { + return false; + } +// receive reply payload + if ( recv( sock, buffer, reply.size, MSG_WAITALL | MSG_NOSIGNAL ) != reply.size ) { + return false; + } +// handle/check reply payload + serializer_reset_read( buffer, reply.size ); + *protocol_version = serializer_get_uint16( buffer ); + *name = serializer_get_string( buffer ); + *rid = serializer_get_uint16( buffer ); + *imageSize = serializer_get_uint64( buffer ); + return true; +} + +#endif diff --git a/src/serialize.h b/src/serialize.h index b6ce145..14d3d13 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,6 +1,7 @@ #ifndef SERIALIZER_H_ #define SERIALIZER_H_ +// Careful with includes - this is used in kernel module too #include "config.h" typedef struct diff --git a/src/server/altservers.c b/src/server/altservers.c index c7e2297..99cbdec 100644 --- a/src/server/altservers.c +++ b/src/server/altservers.c @@ -8,6 +8,7 @@ #include "image.h" #include "signal.h" #include "log.h" +#include "../protocol.h" #include #include #include @@ -16,7 +17,6 @@ #include #include #include -#include "protocol.h" static dnbd3_connection_t *pending[SERVER_MAX_PENDING_ALT_CHECKS]; static pthread_spinlock_t pendingLockProduce; // Lock for adding something to pending. (NULL -> nonNULL) diff --git a/src/server/image.c b/src/server/image.c index b86ecf3..f552843 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -5,7 +5,7 @@ #include "uplink.h" #include "locks.h" #include "integrity.h" -#include "protocol.h" +#include "../protocol.h" #include "sockhelper.h" #include "altservers.h" #include "server.h" diff --git a/src/server/protocol.h b/src/server/protocol.h deleted file mode 100644 index 41c6410..0000000 --- a/src/server/protocol.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef _PROTOCOL_H_ -#define _PROTOCOL_H_ - -#include "../types.h" -#include "../serialize.h" -#include - -#define FLAGS8_SERVER (1) - -#define REPLY_OK (0) -#define REPLY_ERRNO (-1) -#define REPLY_AGAIN (-2) -#define REPLY_INTR (-3) -#define REPLY_CLOSED (-4) -#define REPLY_INCOMPLETE (-5) -#define REPLY_WRONGMAGIC (-6) - -static inline int dnbd3_read_reply(int sock, dnbd3_reply_t *reply, bool wait) -{ - int ret = recv( sock, reply, sizeof(*reply), (wait ? MSG_WAITALL : MSG_DONTWAIT) | MSG_NOSIGNAL ); - if ( ret == 0 ) return REPLY_CLOSED; - if ( ret < 0 ) { - if ( errno == EAGAIN || errno == EWOULDBLOCK ) return REPLY_AGAIN; - if ( errno == EINTR ) return REPLY_INTR; - return REPLY_ERRNO; - } - if ( !wait && ret != sizeof(*reply) ) ret += recv( sock, ((char*)reply) + ret, sizeof(*reply) - ret, MSG_WAITALL | MSG_NOSIGNAL ); - if ( ret != sizeof(*reply) ) return REPLY_INCOMPLETE; - fixup_reply( *reply ); - if ( reply->magic != dnbd3_packet_magic ) return REPLY_WRONGMAGIC; - return REPLY_OK; -} - -static inline bool dnbd3_get_reply(int sock, dnbd3_reply_t *reply) -{ - return dnbd3_read_reply( sock, reply, true ) == REPLY_OK; -} - -static inline bool dnbd3_select_image(int sock, char *lower_name, uint16_t rid, uint8_t flags8) -{ - serialized_buffer_t serialized; - dnbd3_request_t request; - struct iovec iov[2]; - serializer_reset_write( &serialized ); - serializer_put_uint16( &serialized, PROTOCOL_VERSION ); - serializer_put_string( &serialized, lower_name ); - serializer_put_uint16( &serialized, rid ); - serializer_put_uint8( &serialized, flags8 ); - const ssize_t len = serializer_get_written_length( &serialized ); - request.magic = dnbd3_packet_magic; - request.cmd = CMD_SELECT_IMAGE; - request.size = len; -#ifdef _DEBUG - request.handle = 0; - request.offset = 0; -#endif - fixup_request( request ); - iov[0].iov_base = &request; - iov[0].iov_len = sizeof(request); - iov[1].iov_base = &serialized; - iov[1].iov_len = len; - return writev( sock, iov, 2 ) == len + (ssize_t)sizeof(request); -} - -static inline bool dnbd3_get_block(int sock, uint64_t offset, uint32_t size, uint64_t handle) -{ - dnbd3_request_t request; - request.magic = dnbd3_packet_magic; - request.handle = handle; - request.cmd = CMD_GET_BLOCK; - request.offset = offset; - request.size = size; - fixup_request( request ); - return send( sock, &request, sizeof(request), MSG_NOSIGNAL ) == sizeof(request); -} - -static inline bool dnbd3_get_crc32(int sock, uint32_t *master, void *buffer, size_t *bufferLen) -{ - dnbd3_request_t request; - dnbd3_reply_t reply; - request.magic = dnbd3_packet_magic; - request.handle = 0; - request.cmd = CMD_GET_CRC32; - request.offset = 0; - request.size = 0; - fixup_request( request ); - if ( send( sock, &request, sizeof(request), 0 ) != sizeof(request) ) return false; - if ( !dnbd3_get_reply( sock, &reply ) ) return false; - if ( reply.size == 0 ) { - *bufferLen = 0; - return true; - } - if ( reply.size < 4 ) return false; - reply.size -= 4; - if ( reply.cmd != CMD_GET_CRC32 || reply.size > *bufferLen ) return false; - *bufferLen = reply.size; - if ( recv( sock, master, sizeof(uint32_t), MSG_WAITALL | MSG_NOSIGNAL ) != sizeof(uint32_t) ) return false; - uint32_t done = 0; - while ( done < reply.size ) { - const ssize_t ret = recv( sock, (char*)buffer + done, reply.size - done, 0 ); - if ( ret <= 0 ) return false; - done += ret; - } - return true; -} - -/** - * Pass a full serialized_buffer_t and a socket fd. Parsed data will be returned in further arguments. - * Note that all strings will point into the passed buffer, so there's no need to free them. - * This function will also read the header for you, as this message can only occur during connection, - * where no unrequested messages could arrive inbetween. - */ -static inline bool dnbd3_select_image_reply(serialized_buffer_t *buffer, int sock, uint16_t *protocol_version, char **name, uint16_t *rid, - uint64_t *imageSize) -{ - dnbd3_reply_t reply; - if ( !dnbd3_get_reply( sock, &reply ) ) { - return false; - } - if ( reply.cmd != CMD_SELECT_IMAGE || reply.size < 3 || reply.size > MAX_PAYLOAD ) { - return false; - } -// receive reply payload - if ( recv( sock, buffer, reply.size, MSG_WAITALL | MSG_NOSIGNAL ) != reply.size ) { - return false; - } -// handle/check reply payload - serializer_reset_read( buffer, reply.size ); - *protocol_version = serializer_get_uint16( buffer ); - *name = serializer_get_string( buffer ); - *rid = serializer_get_uint16( buffer ); - *imageSize = serializer_get_uint64( buffer ); - return true; -} - -#endif diff --git a/src/server/uplink.c b/src/server/uplink.c index d71daa6..469ac4a 100644 --- a/src/server/uplink.c +++ b/src/server/uplink.c @@ -6,7 +6,7 @@ #include "helper.h" #include "altservers.h" #include "helper.h" -#include "protocol.h" +#include "../protocol.h" #include "signal.h" #include -- cgit v1.2.3-55-g7522