From e72fabcee3d78ee8c9f1117a4bb622a27b2d7369 Mon Sep 17 00:00:00 2001 From: yoe Date: Wed, 11 Feb 2004 10:22:50 +0000 Subject: [PATCH] r49: Doxygenified the source, and started modularizing it. Lots of work still to do, but we'll eventually arrive somewhere. --- nbd-client.c | 11 + nbd-server.c | 719 +++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 469 insertions(+), 261 deletions(-) diff --git a/nbd-client.c b/nbd-client.c index 379a3bd..094b775 100644 --- a/nbd-client.c +++ b/nbd-client.c @@ -34,6 +34,12 @@ #include #include "cliserv.h" +/** + * Open a connection to a given host on a given port. + * @param name The host to connect to + * @param port The port to connect to + * @return A connected socket to the given host on the given port + **/ int opennet(char *name, int port) { int sock; @@ -58,6 +64,11 @@ int opennet(char *name, int port) return sock; } +/** + * Do everything + * @todo cut this thing into little tiny manageable pieces, preferably with a + * chainsaw. + **/ int main(int argc, char *argv[]) { int port, sock, nbd, one = 1; diff --git a/nbd-server.c b/nbd-server.c index be5f3fd..7ae3415 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -3,6 +3,7 @@ * * Copyright 1996-1998 Pavel Machek, distribute under GPL * + * Copyright 2001-2004 Wouter Verhelst * Copyright 2002 Anton Altaparmakov * * Version 1.0 - hopefully 64-bit-clean @@ -43,11 +44,13 @@ * 10/10/2003 - Size of the data "size_host" was wrong and so was not * correctly put in network endianness. Many types were corrected * (size_t and off_t instead of int). + * Version 2.6 - Some code cleanup. + * Version 2.7 - Better build system (not released (yet?)). + * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a + * lot more work, but this is a start. Wouter Verhelst + * */ -#define VERSION PACKAGE_VERSION -#define GIGA (1*1024*1024*1024) - #include #include #include @@ -67,17 +70,18 @@ #include #include #include +#include -/* used in cliserv.h, so must be first */ +/* used in cliserv.h, so must come first */ #define MY_NAME "nbd_server" #include "cliserv.h" -/* how much space for child PIDs we have by default. Dynamically +/** how much space for child PIDs we have by default. Dynamically allocated, and will be realloc()ed if out of space, so this should probably be fair for most situations. */ #define DEFAULT_CHILD_ARRAY 256 -/* Debugging macros, now nothing goes to syslog unless you say ISSERVER */ +/** Logging macros, now nothing goes to syslog unless you say ISSERVER */ #ifdef ISSERVER #define msg2(a,b) syslog(a,b) #define msg3(a,b,c) syslog(a,b,c) @@ -88,6 +92,7 @@ #define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0) #endif +/* Debugging macros */ //#define DODBG #ifdef DODBG #define DEBUG( a ) printf( a ) @@ -98,30 +103,104 @@ #define DEBUG2( a,b ) #define DEBUG3( a,b,c ) #endif - +/** sending macro... not really required */ +#define SEND writeit( net, &reply, sizeof( reply )); +/** error macro... not sure whether we really need this */ +#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; } #ifndef PACKAGE_VERSION #define PACKAGE_VERSION "" #endif - +/** + * The highest value a variable of type off_t can reach. + **/ /* This is starting to get ugly. If someone knows a better way to find * the maximum value of a signed type *without* relying on overflow * (doing so breaks on 64bit architectures), that would be nice. */ #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127 - -void serveconnection(int net); -void set_peername(int net,char *clientname); - -#define LINELEN 256 -char difffilename[256]; -unsigned int timeout = 0; -int autoreadonly = 0; -char *auth_file="nbd_server.allow"; - +#define LINELEN 256 /**< Size of static buffer used to read the + authorization file (yuck) */ +#define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */ +#define GIGA (1*1024*1024*1024) /**< 1 Gigabyte. Used as hunksize when doing + the multiple file thingy */ +#define DIFFPAGESIZE 4096 /**< diff file uses those chunks */ +#define F_READONLY 1 /**< flag to tell us a file is readonly */ +#define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */ +#define F_COPYONWRITE 4 /**< flag to tell us a file is exported using copyonwrite */ +char difffilename[256]; /**< filename of the copy-on-write file. Doesn't belong here! */ +unsigned int timeout = 0; /**< disconnect timeout */ +int autoreadonly = 0; /**< 1 = switch to readonly if opening readwrite isn't + possible */ +char *auth_file="nbd_server.allow"; /**< authorization file */ +char exportname2[1024]; /**< File I'm exporting, with virtualhost resolved */ +off_t lastpoint = (off_t)-1; /**< keep track of where we are in the file, to + avoid an lseek if possible */ +char pagebuf[DIFFPAGESIZE]; /**< when doing copyonwrite, this is + used as a temporary buffer to store + the exported block in. @todo this is + a great example of namespace + pollution. Throw it out. */ +unsigned int port; /**< Port I'm listening at */ +char *exportname; /**< File I'm exporting */ +off_t exportsize = OFFT_MAX; /**< length of file I'm exporting */ +off_t hunksize = OFFT_MAX; /**< size of each exported file in case of -m */ +int flags = 0; /**< flags associated with this exported file */ +int export[1024];/**< array of filedescriptors of exported files; only first is + used unless -m option is activated */ +int difffile=-1; /**< filedescriptor for copyonwrite file */ +u32 difffilelen=0 ; /**< number of pages in difffile */ +u32 *difmap=NULL ; /**< Determine whether a block is in the original file + (difmap[block]==-1) or in the copyonwrite file (in which + case it contains the offset where it is to be found in the + copyonwrite file). @todo the kernel knows about sparse + files, we should use those instead. Should also be off_t + instead of u32; copyonwrite is probably broken wrt LFS */ +char clientname[256] ; +int child_arraysize=DEFAULT_CHILD_ARRAY; /**< number of available slots for + child array */ +pid_t *children; /**< child array */ +char pidfname[256]; /**< name of our PID file */ + +/** + * Variables associated with a copyonwrite server. Not yet used. + **/ +typedef struct __cow_opts { + char* difffilename; /**< filename of the copy-on-write file */ + int difffile; /**< filedescriptor of copyonwrite file. @todo + shouldn't this be an array too? (cfr + nbd_server_opts::export) Or make -m and -c + mutually exclusive */ + u32 difffilelen; /**< number of pages in difffile */ + u32 *difmap; /**< see comment on the global difmap for this one */ +} cow_opts; + +/** + * Variables associated with a server. Not yet used. + **/ +typedef struct __nbd_server_opts { + char* exportname; /**< filename of the file we're exporting */ + unsigned int port; /**< port we're exporting this file at */ + char* authname; /**< filename of the authorization file */ + off_t exportsize; /**< size of the file we're exporting */ + off_t hunksize; /**< size of a hunk of an exported file */ + int flags; /**< flags associated with this exported file */ + char* clientname; /**< peer */ + unsigned int timeout;/**< how long a connection may be idle + (0=forever) */ + int export[1024]; /**< array of filedescriptors of exported files; + only the first is actually used unless we're + doing the multiple file option */ + cow_opts* cow; /**< only used if (flags | F_COPYONWRITE) */ +} nbd_server_opts; + +/** + * Check whether a client is allowed to connect. Works with an + * authorization file which contains one line per machine, no + * wildcards. + * @param name IP address of client trying to connect (in human-readable form) + * @return 0 - authorization refused, 1 - OK + **/ int authorized_client(char *name) -/* 0 - authorization refused, 1 - OK - authorization file contains one line per machine, no wildcards -*/ { FILE *f ; @@ -143,6 +222,13 @@ int authorized_client(char *name) return 0 ; } +/** + * Read data from a file descriptor into a buffer + * + * @param f a file descriptor + * @param buf a buffer + * @param len the number of bytes to be read + **/ inline void readit(int f, void *buf, size_t len) { ssize_t res; @@ -155,38 +241,34 @@ inline void readit(int f, void *buf, size_t len) } } +/** + * Write data from a buffer into a filedescriptor + * + * @param f a file descriptor + * @param buf a buffer containing data + * @param len the number of bytes to be written + **/ inline void writeit(int f, void *buf, size_t len) { ssize_t res; while (len > 0) { DEBUG("+"); - if ((res = send(f, buf, len, 0)) <= 0) + if ((res = write(f, buf, len)) <= 0) err("Send failed: %m"); len -= res; buf += res; } } -unsigned int port; /* Port I'm listening at */ -char *exportname; /* File I'm exporting */ -off_t exportsize = OFFT_MAX; /* ...and its length */ -off_t hunksize = OFFT_MAX; -int flags = 0; -int export[1024]; -int difffile=-1 ; -u32 difffilelen=0 ; /* number of pages in difffile */ -u32 *difmap=NULL ; -char clientname[256] ; -int child_arraysize=DEFAULT_CHILD_ARRAY; -pid_t *children; -char pidfname[256]; - -#define DIFFPAGESIZE 4096 /* diff file uses those chunks */ - -#define F_READONLY 1 -#define F_MULTIFILE 2 -#define F_COPYONWRITE 4 - +/** + * Parse the command line. + * + * @todo getopt() is a great thing, and easy to use. Also, we want to + * create a configuration file which nbd-server will read. + * + * @param argc the argc argument to main() + * @param argv the argv argument to main() + **/ void cmdline(int argc, char *argv[]) { int i; @@ -256,6 +338,11 @@ void cmdline(int argc, char *argv[]) exportname = argv[2]; } +/** + * Signal handler for SIGCHLD + * @param s the signal we're handling (must be SIGCHLD, or something + * is severely wrong) + **/ void sigchld_handler(int s) { int* status=NULL; @@ -276,7 +363,11 @@ void sigchld_handler(int s) } } -/* If we are terminated, make sure our children are, too. */ +/** + * Handle SIGTERM and dispatch it to our children + * @param s the signal we're handling (must be SIGTERM, or something + * is severely wrong). + **/ void sigterm_handler(int s) { int i; int parent=0; @@ -295,142 +386,108 @@ void sigterm_handler(int s) { exit(0); } -void connectme(unsigned int port) +/** + * Detect the size of a file. + * + * @param export An open filedescriptor + * @return the size of the file, or OFFT_MAX if detection was + * impossible. + **/ +off_t size_autodetect(int export) { - struct sockaddr_in addrin; - struct sigaction sa; - int addrinlen = sizeof(addrin); - int net, sock, newpid, i; -#ifndef sun - int yes=1; -#else - char yes='1'; -#endif /* sun */ -#ifndef NODAEMON -#ifndef NOFORK - FILE*pidf; - - if(port) { - if(daemon(0,0)<0) { - err("daemon"); - } - snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port); - pidf=fopen(pidfname, "w"); - if(pidf) { - fprintf(pidf,"%d", (int)getpid()); - fclose(pidf); - } else { - perror("fopen"); - fprintf(stderr, "Not fatal; continuing"); - } + off_t es; + u32 es32; + struct stat stat_buf; + int error; + + DEBUG("looking for export size with lseek SEEK_END\n"); + es = lseek(export, (off_t)0, SEEK_END); + if (es > ((off_t)0)) { + return es; + } else { + DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4))); + } + + DEBUG("looking for export size with fstat\n"); + stat_buf.st_size = 0; + error = fstat(export, &stat_buf); + if (!error && stat_buf.st_size > 0) { + return (off_t)stat_buf.st_size; + } else { + err("fstat failed: %m"); + } + +#ifdef BLKGETSIZE + DEBUG("looking for export size with ioctl BLKGETSIZE\n"); + if (!ioctl(export, BLKGETSIZE, &es32) && es32) { + es = (off_t)es32 * (off_t)512; + return es; } -#endif /* NOFORK */ -#endif /* NODAEMON */ - - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - err("socket: %m"); +#endif + err("Could not find size of exported block device: %m"); + return OFFT_MAX; +} - /* lose the pesky "Address already in use" error message */ - if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { - err("setsockopt SO_REUSEADDR"); +/** + * Seek to a position in a file, unless we're already there. + * @param handle a filedescriptor + * @param a position to seek to + **/ +void maybeseek(int handle, off_t a) { + if (a < 0 || a > exportsize) { + err("Can not happen\n"); } - if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) { - err("setsockopt SO_KEEPALIVE"); - } - - DEBUG("Waiting for connections... bind, "); - addrin.sin_family = AF_INET; - addrin.sin_port = htons(port); - addrin.sin_addr.s_addr = 0; - if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0) - err("bind: %m"); - DEBUG("listen, "); - if (listen(sock, 1) < 0) - err("listen: %m"); - DEBUG("accept, "); - sa.sa_handler = sigchld_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if(sigaction(SIGCHLD, &sa, NULL) == -1) - err("sigaction: %m"); - sa.sa_handler = sigterm_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if(sigaction(SIGTERM, &sa, NULL) == -1) - err("sigaction: %m"); - children=malloc(sizeof(pid_t)*child_arraysize); - memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY); - for(;;) { /* infinite loop */ - if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0) - err("accept: %m"); - - set_peername(net,clientname) ; - if (!authorized_client(clientname)) { - msg2(LOG_INFO,"Unauthorized client") ; - close(net) ; - continue ; + if (lastpoint != a) { + if (lseek(handle, a, SEEK_SET) < 0) { + err("Can not seek locally!\n"); } - msg2(LOG_INFO,"Authorized client") ; - for(i=0;children[i]&&i=child_arraysize) { - pid_t*ptr; - - ptr=realloc(children, sizeof(pid_t)*child_arraysize); - if(ptr) { - children=ptr; - memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY); - i=child_arraysize+1; - child_arraysize+=DEFAULT_CHILD_ARRAY; - } else { - msg2(LOG_INFO,"Not enough memory to store child PID"); - close(net); - continue; - } - } -#ifndef NOFORK - if ((children[i]=fork())<0) { - msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ; - close(net) ; - continue ; - } - if (children[i]>0) { /* parent */ - close(net) ; continue ; } - /* child */ - realloc(children,0); - child_arraysize=0; - close(sock) ; -#endif // NOFORK - msg2(LOG_INFO,"Starting to serve") ; - serveconnection(net) ; + lastpoint = a; + } else { + DEBUG("S"); } } -#define SEND writeit( net, &reply, sizeof( reply )); -#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; } - -off_t lastpoint = (off_t)-1; - -void maybeseek(int handle, off_t a) +/** + * Write an amount of bytes at a given offset to the right file. This + * abstracts the write-side of the multiple file option. + * + * @param a The offset where the write should start + * @param buf The buffer to write from + * @param len The length of buf + * @return The number of bytes actually written, or -1 in case of an error + **/ +int rawexpwrite(off_t a, char *buf, size_t len) { -if (a < 0 || a > exportsize) - err("Can not happen\n"); -if (lastpoint != a) { - if (lseek(handle, a, SEEK_SET) < 0) - err("Can not seek locally!\n"); - lastpoint = a; -} else { - DEBUG("@"); -} + ssize_t res; + + maybeseek(export[a/hunksize], a%hunksize); + res = write(export[a/hunksize], buf, len); + return (res < 0 || (size_t)res != len); } -void myseek(int handle,off_t a) -{ - if (lseek(handle, a, SEEK_SET) < 0) +/** + * seek to a position in a file, no matter what. Used when using maybeseek is a + * bad idea (for instance, because we're reading the copyonwrite file instead + * of the exported file) + * @param handle a filedescriptor + * @param a position to seek to + **/ +void myseek(int handle,off_t a) { + if (lseek(handle, a, SEEK_SET) < 0) { err("Can not seek locally!\n"); + } } -char pagebuf[DIFFPAGESIZE]; - +/** + * Read an amount of bytes at a given offset from the right file. This + * abstracts the read-side of the multiple files option. + * + * @param a The offset where the read should start + * @param buf A buffer to read into + * @param len The size of buf + * @return The number of bytes actually read, or -1 in case of an + * error. + **/ int rawexpread(off_t a, char *buf, size_t len) { ssize_t res; @@ -440,6 +497,15 @@ int rawexpread(off_t a, char *buf, size_t len) return (res < 0 || (size_t)res != len); } +/** + * Read an amount of bytes at a given offset from the right file. This + * abstracts the read-side of the copyonwrite stuff, and calls + * rawexpread() with the right parameters to do the actual work. + * @param a The offset where the read should start + * @param buf A buffer to read into + * @param len The size of buf + * @return The number of bytes actually read, or -1 in case of an error + **/ int expread(off_t a, char *buf, size_t len) { off_t rdlen, offset; @@ -471,16 +537,16 @@ int expread(off_t a, char *buf, size_t len) return 0; } -int rawexpwrite(off_t a, char *buf, size_t len) -{ - ssize_t res; - - maybeseek(export[a/hunksize], a%hunksize); - res = write(export[a/hunksize], buf, len); - return (res < 0 || (size_t)res != len); -} - - +/** + * Write an amount of bytes at a given offset to the right file. This + * abstracts the write-side of the copyonwrite option, and calls + * rawexpwrite() with the right parameters to do the actual work. + * + * @param a The offset where the write should start + * @param buf The buffer to write from + * @param len The length of buf + * @return The number of bytes actually written, or -1 in case of an error + **/ int expwrite(off_t a, char *buf, size_t len) { off_t mapcnt,mapl,maph ; @@ -523,12 +589,13 @@ int expwrite(off_t a, char *buf, size_t len) return 0; } -int mainloop(int net) -{ - struct nbd_request request; - struct nbd_reply reply; +/** + * Do the initial negotiation. + * + * @param net A socket to do the negotiation over + **/ +void negotiate(int net) { char zeros[300]; - int i = 0; u64 size_host; memset(zeros, 0, 290); @@ -542,26 +609,42 @@ int mainloop(int net) err("Negotiation failed: %m"); if (write(net, zeros, 128) < 0) err("Negotiation failed: %m"); +} +/** + * Serve a file to a single client. + * + * @todo This beast needs to be split up in many tiny little manageable + * pieces. Preferably with a chainsaw. + * + * @param net A network socket, connected to an nbd client + * @return never + **/ +int mainloop(int net) +{ + struct nbd_request request; + struct nbd_reply reply; +#ifdef DODBG + int i = 0; +#endif + negotiate(net); DEBUG("Entering request loop!\n"); reply.magic = htonl(NBD_REPLY_MAGIC); reply.error = 0; while (1) { -#define BUFSIZE (1024*1024) char buf[BUFSIZE]; size_t len; #ifdef DODBG i++; printf("%d: ", i); #endif - if (timeout) alarm(timeout); readit(net, &request, sizeof(request)); request.from = ntohll(request.from); request.type = ntohl(request.type); - if (request.type==2) { /* Disconnect request */ + if (request.type==NBD_CMD_DISC) { /* Disconnect request */ if (difmap) free(difmap) ; if (difffile>=0) { close(difffile) ; unlink(difffilename) ; } @@ -585,12 +668,14 @@ int mainloop(int net) ERROR; continue; } - if (((size_t)((off_t)request.from + len) > exportsize) || + + if (((ssize_t)((off_t)request.from + len) > exportsize) || ((flags & F_READONLY) && request.type)) { DEBUG("[RANGE!]"); ERROR; continue; } + if (request.type==1) { /* WRITE */ DEBUG("wr: net->buf, "); readit(net, buf, len); @@ -623,8 +708,74 @@ int mainloop(int net) } } -char exportname2[1024]; +/** + * Split a single exportfile into multiple ones, if that was asked. + * @return 0 on success, -1 on failure + **/ +int splitexport(void) { + off_t i ; + + for (i=0; i OFFT_MAX) { + err("Size of exported file is too big\n"); + } + else + msg3(LOG_INFO, "size of exported file/device is %Lu", + (unsigned long long)exportsize); + setmysockopt(net); + + mainloop(net); +} + +/** + * Find the name of the file we have to serve. This will use sprintf() + * to put the IP address of the client inside a filename containing + * "%s". That name is then written to exportname2 + * + * @param net A socket connected to an nbd client + * @param clientname a buffer which must be at least 255+1 bytes long; + * the IP address (in human-readable format) will be copied in there. + **/ void set_peername(int net,char *clientname) { struct sockaddr_in addrin; @@ -636,45 +787,135 @@ void set_peername(int net,char *clientname) peername = inet_ntoa(addrin.sin_addr); sprintf(exportname2, exportname, peername); - msg4(LOG_INFO, "connect from %s, assigned file is %s", peername, exportname2); + msg4(LOG_INFO, "connect from %s, assigned file is %s", + peername, exportname2); strncpy(clientname,peername,255) ; } -off_t size_autodetect(int export) +/** + * Connect the socket, and start to serve. This function will fork() + * if a connection from an authorized client is received, and will + * start mainloop(). + * + * @todo modularize this giant beast. Preferably with a chainsaw. Also, + * it has no business starting mainloop(); it should connect, and be + * done with it. + * + * @param port the port where we will listen + **/ +void connectme(unsigned int port) { - off_t es; - u32 es32; - struct stat stat_buf; - int error; - - DEBUG("looking for export size with lseek SEEK_END\n"); - es = lseek(export, (off_t)0, SEEK_END); - if (es > ((off_t)0)) { - return es; - } else { - DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4))); - } - - DEBUG("looking for export size with fstat\n"); - stat_buf.st_size = 0; - error = fstat(export, &stat_buf); - if (!error && stat_buf.st_size > 0) { - return (off_t)stat_buf.st_size; - } else { - err("fstat failed: %m"); - } - -#ifdef BLKGETSIZE - DEBUG("looking for export size with ioctl BLKGETSIZE\n"); - if (!ioctl(export, BLKGETSIZE, &es32) && es32) { - es = (off_t)es32 * (off_t)512; - return es; + struct sockaddr_in addrin; + struct sigaction sa; + int addrinlen = sizeof(addrin); + int net, sock, newpid, i; +#ifndef sun + int yes=1; +#else + char yes='1'; +#endif /* sun */ +#ifndef NODAEMON +#ifndef NOFORK + FILE*pidf; + + if(port) { + if(daemon(0,0)<0) { + err("daemon"); + } + snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port); + pidf=fopen(pidfname, "w"); + if(pidf) { + fprintf(pidf,"%d", (int)getpid()); + fclose(pidf); + } else { + perror("fopen"); + fprintf(stderr, "Not fatal; continuing"); + } + } +#endif /* NOFORK */ +#endif /* NODAEMON */ + + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + err("socket: %m"); + + /* lose the pesky "Address already in use" error message */ + if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { + err("setsockopt SO_REUSEADDR"); + } + if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) { + err("setsockopt SO_KEEPALIVE"); + } + + DEBUG("Waiting for connections... bind, "); + addrin.sin_family = AF_INET; + addrin.sin_port = htons(port); + addrin.sin_addr.s_addr = 0; + if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0) + err("bind: %m"); + DEBUG("listen, "); + if (listen(sock, 1) < 0) + err("listen: %m"); + DEBUG("accept, "); + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGCHLD, &sa, NULL) == -1) + err("sigaction: %m"); + sa.sa_handler = sigterm_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGTERM, &sa, NULL) == -1) + err("sigaction: %m"); + children=malloc(sizeof(pid_t)*child_arraysize); + memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY); + for(;;) { /* infinite loop */ + if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0) + err("accept: %m"); + + set_peername(net,clientname); + if (!authorized_client(clientname)) { + msg2(LOG_INFO,"Unauthorized client") ; + close(net) ; + continue ; + } + msg2(LOG_INFO,"Authorized client") ; + for(i=0;children[i]&&i=child_arraysize) { + pid_t*ptr; + + ptr=realloc(children, sizeof(pid_t)*child_arraysize); + if(ptr) { + children=ptr; + memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY); + i=child_arraysize+1; + child_arraysize+=DEFAULT_CHILD_ARRAY; + } else { + msg2(LOG_INFO,"Not enough memory to store child PID"); + close(net); + continue; + } + } +#ifndef NOFORK + if ((children[i]=fork())<0) { + msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ; + close(net) ; + continue ; + } + if (children[i]>0) { /* parent */ + close(net) ; continue ; } + /* child */ + realloc(children,0); + child_arraysize=0; + close(sock) ; +#endif // NOFORK + msg2(LOG_INFO,"Starting to serve") ; + serveconnection(net) ; } -#endif - err("Could not find size of exported block device: %m"); - return OFFT_MAX; } +/** + * Main entry point... + **/ int main(int argc, char *argv[]) { if (sizeof( struct nbd_request )!=28) { @@ -689,47 +930,3 @@ int main(int argc, char *argv[]) return 0 ; } - -void serveconnection(int net) -{ - off_t i ; - - for (i=0; i OFFT_MAX) { - err("Size of exported file is too big\n"); - } - else - msg3(LOG_INFO, "size of exported file/device is %Lu", - (unsigned long long)exportsize); - - if (flags & F_COPYONWRITE) { - sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname, - (int)getpid()) ; - msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ; - difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ; - if (difffile<0) err("Could not create diff file (%m)") ; - if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL) - err("Could not allocate memory") ; - for (i=0;i