diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f53854e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contribution guide + +The code is formatted using the K&R style of "indent". diff --git a/src/common/ioutil.c b/src/common/ioutil.c index dfa47df..761b6e9 100644 --- a/src/common/ioutil.c +++ b/src/common/ioutil.c @@ -13,228 +13,236 @@ #include "ioutil.h" -int build_allocation_map(struct bitset * allocation_map, int fd) +int build_allocation_map(struct bitset *allocation_map, int fd) { - /* break blocking ioctls down */ - const unsigned long max_length = 100*1024*1024; - const unsigned int max_extents = 1000; + /* break blocking ioctls down */ + const unsigned long max_length = 100 * 1024 * 1024; + const unsigned int max_extents = 1000; - unsigned long offset = 0; + unsigned long offset = 0; - struct { - struct fiemap fiemap; - struct fiemap_extent extents[max_extents]; - } fiemap_static; - struct fiemap* fiemap = (struct fiemap*) &fiemap_static; + struct { + struct fiemap fiemap; + struct fiemap_extent extents[max_extents]; + } fiemap_static; + struct fiemap *fiemap = (struct fiemap *) &fiemap_static; - memset(&fiemap_static, 0, sizeof(fiemap_static)); + memset(&fiemap_static, 0, sizeof(fiemap_static)); - for (offset = 0; offset < allocation_map->size; ) { + for (offset = 0; offset < allocation_map->size;) { - fiemap->fm_start = offset; + fiemap->fm_start = offset; - fiemap->fm_length = max_length; - if ( offset + max_length > allocation_map->size ) { - fiemap->fm_length = allocation_map->size-offset; - } - - fiemap->fm_flags = FIEMAP_FLAG_SYNC; - fiemap->fm_extent_count = max_extents; - fiemap->fm_mapped_extents = 0; - - if ( ioctl( fd, FS_IOC_FIEMAP, fiemap ) < 0 ) { - debug( "Couldn't get fiemap, returning no allocation_map" ); - return 0; /* it's up to the caller to free the map */ - } - else { - for ( unsigned int i = 0; i < fiemap->fm_mapped_extents; i++ ) { - bitset_set_range( allocation_map, - fiemap->fm_extents[i].fe_logical, - fiemap->fm_extents[i].fe_length ); - } - - - /* must move the offset on, but careful not to jump max_length - * if we've actually hit max_offsets. - */ - if (fiemap->fm_mapped_extents > 0) { - struct fiemap_extent *last = &fiemap->fm_extents[ - fiemap->fm_mapped_extents-1 - ]; - offset = last->fe_logical + last->fe_length; - } - else { - offset += fiemap->fm_length; - } - } + fiemap->fm_length = max_length; + if (offset + max_length > allocation_map->size) { + fiemap->fm_length = allocation_map->size - offset; } - info("Successfully built allocation map"); - return 1; + fiemap->fm_flags = FIEMAP_FLAG_SYNC; + fiemap->fm_extent_count = max_extents; + fiemap->fm_mapped_extents = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { + debug("Couldn't get fiemap, returning no allocation_map"); + return 0; /* it's up to the caller to free the map */ + } else { + for (unsigned int i = 0; i < fiemap->fm_mapped_extents; i++) { + bitset_set_range(allocation_map, + fiemap->fm_extents[i].fe_logical, + fiemap->fm_extents[i].fe_length); + } + + + /* must move the offset on, but careful not to jump max_length + * if we've actually hit max_offsets. + */ + if (fiemap->fm_mapped_extents > 0) { + struct fiemap_extent *last = + &fiemap->fm_extents[fiemap->fm_mapped_extents - 1]; + offset = last->fe_logical + last->fe_length; + } else { + offset += fiemap->fm_length; + } + } + } + + info("Successfully built allocation map"); + return 1; } -int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **out_map) +int open_and_mmap(const char *filename, int *out_fd, uint64_t * out_size, + void **out_map) { - /* - * size and out_size are intentionally of different types. - * lseek64() uses off64_t to signal errors in the sign bit. - * Since we check for these errors before trying to assign to - * *out_size, we know *out_size can never go negative. - */ - off64_t size; + /* + * size and out_size are intentionally of different types. + * lseek64() uses off64_t to signal errors in the sign bit. + * Since we check for these errors before trying to assign to + * *out_size, we know *out_size can never go negative. + */ + off64_t size; - /* O_DIRECT should not be used with mmap() */ - *out_fd = open(filename, O_RDWR | O_NOATIME ); + /* O_DIRECT should not be used with mmap() */ + *out_fd = open(filename, O_RDWR | O_NOATIME); - if (*out_fd < 1) { - warn("open(%s) failed: does it exist?", filename); - return *out_fd; + if (*out_fd < 1) { + warn("open(%s) failed: does it exist?", filename); + return *out_fd; + } + + size = lseek64(*out_fd, 0, SEEK_END); + if (size < 0) { + warn("lseek64() failed"); + return size; + } + + /* If discs are not in multiples of 512, then odd things happen, + * resulting in reads/writes past the ends of files. + */ + if (size != (size & (~0x1ff))) { + warn("file does not fit into 512-byte sectors; the end of the file will be ignored."); + size &= ~0x1ff; + } + + if (out_size) { + *out_size = size; + } + + if (out_map) { + *out_map = mmap64(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + *out_fd, 0); + if (((long) *out_map) == -1) { + warn("mmap64() failed"); + return -1; } + debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd, + *out_map); + } else { + debug("opened %s size %ld on fd %d", filename, size, *out_fd); + } - size = lseek64(*out_fd, 0, SEEK_END); - if (size < 0) { - warn("lseek64() failed"); - return size; - } - - /* If discs are not in multiples of 512, then odd things happen, - * resulting in reads/writes past the ends of files. - */ - if ( size != (size & (~0x1ff))) { - warn("file does not fit into 512-byte sectors; the end of the file will be ignored."); - size &= ~0x1ff; - } - - if (out_size) { - *out_size = size; - } - - if (out_map) { - *out_map = mmap64(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, - *out_fd, 0); - if (((long) *out_map) == -1) { - warn("mmap64() failed"); - return -1; - } - debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd, *out_map); - } - else { - debug("opened %s size %ld on fd %d", filename, size, *out_fd); - } - - return 0; + return 0; } int writeloop(int filedes, const void *buffer, size_t size) { - size_t written=0; - while (written < size) { - ssize_t result = write(filedes, buffer+written, size-written); - if (result == -1) { - if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) { - continue; // busy-wait - } - return -1; // failure - } - written += result; + size_t written = 0; + while (written < size) { + ssize_t result = write(filedes, buffer + written, size - written); + if (result == -1) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + continue; // busy-wait + } + return -1; // failure } - return 0; + written += result; + } + return 0; } int readloop(int filedes, void *buffer, size_t size) { - size_t readden=0; - while (readden < size) { - ssize_t result = read(filedes, buffer+readden, size-readden); + size_t readden = 0; + while (readden < size) { + ssize_t result = read(filedes, buffer + readden, size - readden); - if ( result == 0 /* EOF */ ) { - warn( "end-of-file detected while reading after %i bytes", readden ); - return -1; - } - - if ( result == -1 ) { - if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) { - continue; // busy-wait - } - return -1; // failure - } - readden += result; + if (result == 0 /* EOF */ ) { + warn("end-of-file detected while reading after %i bytes", + readden); + return -1; } - return 0; + + if (result == -1) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + continue; // busy-wait + } + return -1; // failure + } + readden += result; + } + return 0; } -int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count) +int sendfileloop(int out_fd, int in_fd, off64_t * offset, size_t count) { - size_t sent=0; - while (sent < count) { - ssize_t result = sendfile64(out_fd, in_fd, offset, count-sent); - debug("sendfile64(out_fd=%d, in_fd=%d, offset=%p, count-sent=%ld) = %ld", out_fd, in_fd, offset, count-sent, result); + size_t sent = 0; + while (sent < count) { + ssize_t result = sendfile64(out_fd, in_fd, offset, count - sent); + debug + ("sendfile64(out_fd=%d, in_fd=%d, offset=%p, count-sent=%ld) = %ld", + out_fd, in_fd, offset, count - sent, result); - if (result == -1) { - debug( "%s (%i) calling sendfile64()", strerror(errno), errno ); - return -1; - } - sent += result; - debug("sent=%ld, count=%ld", sent, count); + if (result == -1) { + debug("%s (%i) calling sendfile64()", strerror(errno), errno); + return -1; } - debug("exiting sendfileloop"); - return 0; + sent += result; + debug("sent=%ld, count=%ld", sent, count); + } + debug("exiting sendfileloop"); + return 0; } #include -ssize_t spliceloop(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags2) +ssize_t spliceloop(int fd_in, loff_t * off_in, int fd_out, + loff_t * off_out, size_t len, unsigned int flags2) { - const unsigned int flags = SPLICE_F_MORE|SPLICE_F_MOVE|flags2; - size_t spliced=0; + const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE | flags2; + size_t spliced = 0; - //debug("spliceloop(%d, %ld, %d, %ld, %ld)", fd_in, off_in ? *off_in : 0, fd_out, off_out ? *off_out : 0, len); + //debug("spliceloop(%d, %ld, %d, %ld, %ld)", fd_in, off_in ? *off_in : 0, fd_out, off_out ? *off_out : 0, len); - while (spliced < len) { - ssize_t result = splice(fd_in, off_in, fd_out, off_out, len, flags); - if (result < 0) { - //debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); - if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK) ) { - return spliced; - } - else { - return -1; - } - } else { - spliced += result; - //debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); - } + while (spliced < len) { + ssize_t result = + splice(fd_in, off_in, fd_out, off_out, len, flags); + if (result < 0) { + //debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); + if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK)) { + return spliced; + } else { + return -1; + } + } else { + spliced += result; + //debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); } + } - return spliced; + return spliced; } int splice_via_pipe_loop(int fd_in, int fd_out, size_t len) { - int pipefd[2]; /* read end, write end */ - size_t spliced=0; + int pipefd[2]; /* read end, write end */ + size_t spliced = 0; - if (pipe(pipefd) == -1) { - return -1; + if (pipe(pipefd) == -1) { + return -1; + } + + while (spliced < len) { + ssize_t run = len - spliced; + ssize_t s2, s1 = + spliceloop(fd_in, NULL, pipefd[1], NULL, run, + SPLICE_F_NONBLOCK); + /*if (run > 65535) + run = 65535; */ + if (s1 < 0) { + break; } - while (spliced < len) { - ssize_t run = len-spliced; - ssize_t s2, s1 = spliceloop(fd_in, NULL, pipefd[1], NULL, run, SPLICE_F_NONBLOCK); - /*if (run > 65535) - run = 65535;*/ - if (s1 < 0) { break; } - - s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0); - if (s2 < 0) { break; } - spliced += s2; + s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0); + if (s2 < 0) { + break; } - close(pipefd[0]); - close(pipefd[1]); + spliced += s2; + } + close(pipefd[0]); + close(pipefd[1]); - return spliced < len ? -1 : 0; + return spliced < len ? -1 : 0; } /* Reads single bytes from fd until either an EOF or a newline appears. @@ -244,117 +252,123 @@ int splice_via_pipe_loop(int fd_in, int fd_out, size_t len) * Returns the number of read bytes: the length of the line without the * newline, plus the trailing null. */ -int read_until_newline(int fd, char* buf, int bufsize) +int read_until_newline(int fd, char *buf, int bufsize) { - int cur; + int cur; - for (cur=0; cur < bufsize; cur++) { - int result = read(fd, buf+cur, 1); - if (result <= 0) { return -1; } - if (buf[cur] == 10) { - buf[cur] = '\0'; - break; - } + for (cur = 0; cur < bufsize; cur++) { + int result = read(fd, buf + cur, 1); + if (result <= 0) { + return -1; } + if (buf[cur] == 10) { + buf[cur] = '\0'; + break; + } + } - return cur+1; + return cur + 1; } int read_lines_until_blankline(int fd, int max_line_length, char ***lines) { - int lines_count = 0; - char line[max_line_length+1]; - *lines = NULL; + int lines_count = 0; + char line[max_line_length + 1]; + *lines = NULL; - memset(line, 0, max_line_length+1); + memset(line, 0, max_line_length + 1); - while (1) { - int readden = read_until_newline(fd, line, max_line_length); - /* readden will be: - * 1 for an empty line - * -1 for an eof - * -1 for a read error - */ - if (readden <= 1) { return lines_count; } - *lines = xrealloc(*lines, (lines_count+1) * sizeof(char*)); - (*lines)[lines_count] = strdup(line); - if ((*lines)[lines_count][0] == 0) { - return lines_count; - } - lines_count++; + while (1) { + int readden = read_until_newline(fd, line, max_line_length); + /* readden will be: + * 1 for an empty line + * -1 for an eof + * -1 for a read error + */ + if (readden <= 1) { + return lines_count; } + *lines = xrealloc(*lines, (lines_count + 1) * sizeof(char *)); + (*lines)[lines_count] = strdup(line); + if ((*lines)[lines_count][0] == 0) { + return lines_count; + } + lines_count++; + } } -int fd_is_closed( int fd_in ) +int fd_is_closed(int fd_in) { - int errno_old = errno; - int result = fcntl( fd_in, F_GETFL ) < 0; - errno = errno_old; - return result; + int errno_old = errno; + int result = fcntl(fd_in, F_GETFL) < 0; + errno = errno_old; + return result; } static inline int io_errno_permanent(void) { - return ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR ); + return (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR); } /* Returns -1 if the operation failed, or the number of bytes read if all is * well. Note that 0 bytes may be returned. Unlike read(), this is not an EOF! */ -ssize_t iobuf_read(int fd, struct iobuf *iobuf, size_t default_size ) +ssize_t iobuf_read(int fd, struct iobuf * iobuf, size_t default_size) { - size_t left; - ssize_t count; + size_t left; + ssize_t count; - if ( iobuf->needle == 0 ) { - iobuf->size = default_size; - } + if (iobuf->needle == 0) { + iobuf->size = default_size; + } - left = iobuf->size - iobuf->needle; - debug( "Reading %"PRIu32" of %"PRIu32" bytes from fd %i", left, iobuf->size, fd ); + left = iobuf->size - iobuf->needle; + debug("Reading %" PRIu32 " of %" PRIu32 " bytes from fd %i", left, + iobuf->size, fd); - count = read( fd, iobuf->buf + iobuf->needle, left ); + count = read(fd, iobuf->buf + iobuf->needle, left); - if ( count > 0 ) { - iobuf->needle += count; - debug( "read() returned %"PRIu32" bytes", count ); - } else if ( count == 0 ) { - warn( "read() returned EOF on fd %i", fd ); - errno = 0; - return -1; - } else if ( count == -1 ) { - if ( io_errno_permanent() ) { - warn( SHOW_ERRNO( "read() failed on fd %i", fd ) ); - } else { - debug( SHOW_ERRNO( "read() returned 0 bytes" ) ); - count = 0; - } - } - - return count; -} - -ssize_t iobuf_write( int fd, struct iobuf *iobuf ) -{ - size_t left = iobuf->size - iobuf->needle; - ssize_t count; - - debug( "Writing %"PRIu32" of %"PRIu32" bytes to fd %i", left, iobuf->size, fd ); - count = write( fd, iobuf->buf + iobuf->needle, left ); - - if ( count >= 0 ) { - iobuf->needle += count; - debug( "write() returned %"PRIu32" bytes", count ); + if (count > 0) { + iobuf->needle += count; + debug("read() returned %" PRIu32 " bytes", count); + } else if (count == 0) { + warn("read() returned EOF on fd %i", fd); + errno = 0; + return -1; + } else if (count == -1) { + if (io_errno_permanent()) { + warn(SHOW_ERRNO("read() failed on fd %i", fd)); } else { - if ( io_errno_permanent() ) { - warn( SHOW_ERRNO( "write() failed on fd %i", fd ) ); - } else { - debug( SHOW_ERRNO( "write() returned 0 bytes" ) ); - count = 0; - } + debug(SHOW_ERRNO("read() returned 0 bytes")); + count = 0; } + } - return count; + return count; +} + +ssize_t iobuf_write(int fd, struct iobuf * iobuf) +{ + size_t left = iobuf->size - iobuf->needle; + ssize_t count; + + debug("Writing %" PRIu32 " of %" PRIu32 " bytes to fd %i", left, + iobuf->size, fd); + count = write(fd, iobuf->buf + iobuf->needle, left); + + if (count >= 0) { + iobuf->needle += count; + debug("write() returned %" PRIu32 " bytes", count); + } else { + if (io_errno_permanent()) { + warn(SHOW_ERRNO("write() failed on fd %i", fd)); + } else { + debug(SHOW_ERRNO("write() returned 0 bytes")); + count = 0; + } + } + + return count; } diff --git a/src/common/ioutil.h b/src/common/ioutil.h index da69452..e018ec7 100644 --- a/src/common/ioutil.h +++ b/src/common/ioutil.h @@ -3,16 +3,16 @@ #include struct iobuf { - unsigned char *buf; - size_t size; - size_t needle; + unsigned char *buf; + size_t size; + size_t needle; }; -ssize_t iobuf_read( int fd, struct iobuf* iobuf, size_t default_size ); -ssize_t iobuf_write( int fd, struct iobuf* iobuf ); +ssize_t iobuf_read(int fd, struct iobuf *iobuf, size_t default_size); +ssize_t iobuf_write(int fd, struct iobuf *iobuf); #include "serve.h" -struct bitset; /* don't need whole of bitset.h here */ +struct bitset; /* don't need whole of bitset.h here */ /** Scan the file opened in ''fd'', set bits in ''allocation_map'' that * correspond to which blocks are physically allocated on disc (or part- @@ -20,7 +20,7 @@ struct bitset; /* don't need whole of bitset.h here */ * than you've asked for, any block or part block will count as "allocated" * with the corresponding bit set. Returns 1 if successful, 0 otherwise. */ -int build_allocation_map(struct bitset * allocation_map, int fd); +int build_allocation_map(struct bitset *allocation_map, int fd); /** Repeat a write() operation that succeeds partially until ''size'' bytes * are written, or an error is returned, when it returns -1 as usual. @@ -35,10 +35,11 @@ int readloop(int filedes, void *buffer, size_t size); /** Repeat a sendfile() operation that succeeds partially until ''size'' bytes * are written, or an error is returned, when it returns -1 as usual. */ -int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count); +int sendfileloop(int out_fd, int in_fd, off64_t * offset, size_t count); /** Repeat a splice() operation until we have 'len' bytes. */ -ssize_t spliceloop(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags2); +ssize_t spliceloop(int fd_in, loff_t * off_in, int fd_out, + loff_t * off_out, size_t len, unsigned int flags2); /** Copy ''len'' bytes from ''fd_in'' to ''fd_out'' by creating a temporary * pipe and using the Linux splice call repeatedly until it has transferred @@ -50,7 +51,7 @@ int splice_via_pipe_loop(int fd_in, int fd_out, size_t len); * until an LF character is received, which is written to the buffer at a zero * byte. Returns -1 on error, or the number of bytes written to the buffer. */ -int read_until_newline(int fd, char* buf, int bufsize); +int read_until_newline(int fd, char *buf, int bufsize); /** Read a number of lines using read_until_newline, until an empty line is * received (i.e. the sequence LF LF). The data is read from ''fd'' and @@ -65,12 +66,12 @@ int read_lines_until_blankline(int fd, int max_line_length, char ***lines); * ''out_size'' and the address of the mmap in ''out_map''. If anything goes * wrong, returns -1 setting errno, otherwise 0. */ -int open_and_mmap( const char* filename, int* out_fd, uint64_t* out_size, void **out_map); +int open_and_mmap(const char *filename, int *out_fd, uint64_t * out_size, + void **out_map); /** Check to see whether the given file descriptor is closed. */ -int fd_is_closed( int fd_in ); +int fd_is_closed(int fd_in); #endif - diff --git a/src/common/mode.h b/src/common/mode.h index f117e95..29313fe 100644 --- a/src/common/mode.h +++ b/src/common/mode.h @@ -2,7 +2,7 @@ #define MODE_H -void mode(char* mode, int argc, char **argv); +void mode(char *mode, int argc, char **argv); #include @@ -68,9 +68,9 @@ void mode(char* mode, int argc, char **argv); "\t--" OPT_VERBOSE ",-" SOPT_VERBOSE "\t\tOutput debug information.\n" #ifdef DEBUG -# define VERBOSE_LOG_LEVEL 0 +#define VERBOSE_LOG_LEVEL 0 #else -# define VERBOSE_LOG_LEVEL 1 +#define VERBOSE_LOG_LEVEL 1 #endif #define QUIET_LOG_LEVEL 4 @@ -91,7 +91,6 @@ void mode(char* mode, int argc, char **argv); #define MAX_SPEED_LINE \ "\t--" OPT_MAX_SPEED ",-m \tMaximum speed of the migration, in bytes/sec.\n" -char * help_help_text; +char *help_help_text; #endif - diff --git a/src/common/nbdtypes.c b/src/common/nbdtypes.c index 20020b4..59e58e9 100644 --- a/src/common/nbdtypes.c +++ b/src/common/nbdtypes.c @@ -8,55 +8,54 @@ * We intentionally ignore the reserved 128 bytes at the end of the * request, since there's nothing we can do with them. */ -void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to ) +void nbd_r2h_init(struct nbd_init_raw *from, struct nbd_init *to) { - memcpy( to->passwd, from->passwd, 8 ); - to->magic = be64toh( from->magic ); - to->size = be64toh( from->size ); - to->flags = be32toh( from->flags ); + memcpy(to->passwd, from->passwd, 8); + to->magic = be64toh(from->magic); + to->size = be64toh(from->size); + to->flags = be32toh(from->flags); } -void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to) +void nbd_h2r_init(struct nbd_init *from, struct nbd_init_raw *to) { - memcpy( to->passwd, from->passwd, 8 ); - to->magic = htobe64( from->magic ); - to->size = htobe64( from->size ); - to->flags = htobe32( from->flags ); + memcpy(to->passwd, from->passwd, 8); + to->magic = htobe64(from->magic); + to->size = htobe64(from->size); + to->flags = htobe32(from->flags); } -void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to ) +void nbd_r2h_request(struct nbd_request_raw *from, struct nbd_request *to) { - to->magic = be32toh( from->magic ); - to->flags = be16toh( from->flags ); - to->type = be16toh( from->type ); - to->handle.w = from->handle.w; - to->from = be64toh( from->from ); - to->len = be32toh( from->len ); + to->magic = be32toh(from->magic); + to->flags = be16toh(from->flags); + to->type = be16toh(from->type); + to->handle.w = from->handle.w; + to->from = be64toh(from->from); + to->len = be32toh(from->len); } -void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to ) +void nbd_h2r_request(struct nbd_request *from, struct nbd_request_raw *to) { - to->magic = htobe32( from->magic ); - to->flags = htobe16( from->flags ); - to->type = htobe16( from->type ); - to->handle.w = from->handle.w; - to->from = htobe64( from->from ); - to->len = htobe32( from->len ); + to->magic = htobe32(from->magic); + to->flags = htobe16(from->flags); + to->type = htobe16(from->type); + to->handle.w = from->handle.w; + to->from = htobe64(from->from); + to->len = htobe32(from->len); } -void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to ) +void nbd_r2h_reply(struct nbd_reply_raw *from, struct nbd_reply *to) { - to->magic = be32toh( from->magic ); - to->error = be32toh( from->error ); - to->handle.w = from->handle.w; + to->magic = be32toh(from->magic); + to->error = be32toh(from->error); + to->handle.w = from->handle.w; } -void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to ) +void nbd_h2r_reply(struct nbd_reply *from, struct nbd_reply_raw *to) { - to->magic = htobe32( from->magic ); - to->error = htobe32( from->error ); - to->handle.w = from->handle.w; + to->magic = htobe32(from->magic); + to->error = htobe32(from->error); + to->handle.w = from->handle.w; } - diff --git a/src/common/nbdtypes.h b/src/common/nbdtypes.h index 5d5b614..5504268 100644 --- a/src/common/nbdtypes.h +++ b/src/common/nbdtypes.h @@ -29,8 +29,8 @@ #define FLAG_READ_ONLY (1 << 1) /* Device is read-only */ #define FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ #define FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ -#define FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */ -#define FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */ +#define FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */ +#define FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */ #define CMD_FLAG_NO_HOLE (1 << 1) #endif @@ -48,8 +48,8 @@ #include typedef union nbd_handle_t { - uint8_t b[8]; - uint64_t w; + uint8_t b[8]; + uint64_t w; } nbd_handle_t; /* The _raw types are the types as they appear on the wire. Non-_raw @@ -58,58 +58,57 @@ typedef union nbd_handle_t { * for converting host to raw. */ struct nbd_init_raw { - char passwd[8]; - __be64 magic; - __be64 size; - __be32 flags; - char reserved[124]; + char passwd[8]; + __be64 magic; + __be64 size; + __be32 flags; + char reserved[124]; }; struct nbd_request_raw { - __be32 magic; - __be16 flags; - __be16 type; /* == READ || == WRITE || == FLUSH */ - nbd_handle_t handle; - __be64 from; - __be32 len; -} __attribute__((packed)); + __be32 magic; + __be16 flags; + __be16 type; /* == READ || == WRITE || == FLUSH */ + nbd_handle_t handle; + __be64 from; + __be32 len; +} __attribute__ ((packed)); struct nbd_reply_raw { - __be32 magic; - __be32 error; /* 0 = ok, else error */ - nbd_handle_t handle; /* handle you got from request */ + __be32 magic; + __be32 error; /* 0 = ok, else error */ + nbd_handle_t handle; /* handle you got from request */ }; struct nbd_init { - char passwd[8]; - uint64_t magic; - uint64_t size; - uint32_t flags; - char reserved[124]; + char passwd[8]; + uint64_t magic; + uint64_t size; + uint32_t flags; + char reserved[124]; }; struct nbd_request { - uint32_t magic; - uint16_t flags; - uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */ - nbd_handle_t handle; - uint64_t from; - uint32_t len; -} __attribute__((packed)); + uint32_t magic; + uint16_t flags; + uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */ + nbd_handle_t handle; + uint64_t from; + uint32_t len; +} __attribute__ ((packed)); struct nbd_reply { - uint32_t magic; - uint32_t error; /* 0 = ok, else error */ - nbd_handle_t handle; /* handle you got from request */ + uint32_t magic; + uint32_t error; /* 0 = ok, else error */ + nbd_handle_t handle; /* handle you got from request */ }; -void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to ); -void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to ); -void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to ); +void nbd_r2h_init(struct nbd_init_raw *from, struct nbd_init *to); +void nbd_r2h_request(struct nbd_request_raw *from, struct nbd_request *to); +void nbd_r2h_reply(struct nbd_reply_raw *from, struct nbd_reply *to); -void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to); -void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to ); -void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to ); +void nbd_h2r_init(struct nbd_init *from, struct nbd_init_raw *to); +void nbd_h2r_request(struct nbd_request *from, struct nbd_request_raw *to); +void nbd_h2r_reply(struct nbd_reply *from, struct nbd_reply_raw *to); #endif - diff --git a/src/common/parse.c b/src/common/parse.c index 5f8c006..f2ff52f 100644 --- a/src/common/parse.c +++ b/src/common/parse.c @@ -10,118 +10,116 @@ int atoi(const char *nptr); ) /* FIXME: should change this to return negative on error like everything else */ -int parse_ip_to_sockaddr(struct sockaddr* out, char* src) +int parse_ip_to_sockaddr(struct sockaddr *out, char *src) { - NULLCHECK( out ); - NULLCHECK( src ); + NULLCHECK(out); + NULLCHECK(src); - char temp[64]; - struct sockaddr_in *v4 = (struct sockaddr_in *) out; - struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out; + char temp[64]; + struct sockaddr_in *v4 = (struct sockaddr_in *) out; + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out; - /* allow user to start with [ and end with any other invalid char */ - { - int i=0, j=0; - if (src[i] == '[') { i++; } - for (; i<64 && IS_IP_VALID_CHAR(src[i]); i++) { - temp[j++] = src[i]; - } - temp[j] = 0; + /* allow user to start with [ and end with any other invalid char */ + { + int i = 0, j = 0; + if (src[i] == '[') { + i++; } - - if (temp[0] == '0' && temp[1] == '\0') { - v4->sin_family = AF_INET; - v4->sin_addr.s_addr = INADDR_ANY; - return 1; + for (; i < 64 && IS_IP_VALID_CHAR(src[i]); i++) { + temp[j++] = src[i]; } + temp[j] = 0; + } - if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) { - out->sa_family = AF_INET; - return 1; - } + if (temp[0] == '0' && temp[1] == '\0') { + v4->sin_family = AF_INET; + v4->sin_addr.s_addr = INADDR_ANY; + return 1; + } - if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) { - out->sa_family = AF_INET6; - return 1; - } + if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) { + out->sa_family = AF_INET; + return 1; + } - return 0; + if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) { + out->sa_family = AF_INET6; + return 1; + } + + return 0; } -int parse_to_sockaddr(struct sockaddr* out, char* address) +int parse_to_sockaddr(struct sockaddr *out, char *address) { - struct sockaddr_un* un = (struct sockaddr_un*) out; + struct sockaddr_un *un = (struct sockaddr_un *) out; - NULLCHECK( address ); + NULLCHECK(address); - if ( address[0] == '/' ) { - un->sun_family = AF_UNIX; - strncpy( un->sun_path, address, 108 ); /* FIXME: linux only */ - return 1; - } + if (address[0] == '/') { + un->sun_family = AF_UNIX; + strncpy(un->sun_path, address, 108); /* FIXME: linux only */ + return 1; + } - return parse_ip_to_sockaddr( out, address ); + return parse_ip_to_sockaddr(out, address); } int parse_acl(struct ip_and_mask (**out)[], int max, char **entries) { - struct ip_and_mask* list; - int i; + struct ip_and_mask *list; + int i; - if (max == 0) { - *out = NULL; - return 0; - } - else { - list = xmalloc(max * sizeof(struct ip_and_mask)); - *out = (struct ip_and_mask (*)[])list; - debug("acl alloc: %p", *out); - } + if (max == 0) { + *out = NULL; + return 0; + } else { + list = xmalloc(max * sizeof(struct ip_and_mask)); + *out = (struct ip_and_mask(*)[]) list; + debug("acl alloc: %p", *out); + } - for (i = 0; i < max; i++) { - int j; - struct ip_and_mask* outentry = &list[i]; + for (i = 0; i < max; i++) { + int j; + struct ip_and_mask *outentry = &list[i]; # define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128) - if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) { - return i; - } + if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) { + return i; + } - for (j=0; entries[i][j] && entries[i][j] != '/'; j++) - ; // increment j! + for (j = 0; entries[i][j] && entries[i][j] != '/'; j++); // increment j! - if (entries[i][j] == '/') { - outentry->mask = atoi(entries[i]+j+1); - if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) { - return i; - } - } - else { - outentry->mask = MAX_MASK_BITS; - } + if (entries[i][j] == '/') { + outentry->mask = atoi(entries[i] + j + 1); + if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) { + return i; + } + } else { + outentry->mask = MAX_MASK_BITS; + } # undef MAX_MASK_BITS - debug("acl ptr[%d]: %p %d",i, outentry, outentry->mask); - } + debug("acl ptr[%d]: %p %d", i, outentry, outentry->mask); + } - for (i=0; i < max; i++) { - debug("acl entry %d @ %p has mask %d", i, list[i], list[i].mask); - } + for (i = 0; i < max; i++) { + debug("acl entry %d @ %p has mask %d", i, list[i], list[i].mask); + } - return max; + return max; } -void parse_port( char *s_port, struct sockaddr_in *out ) +void parse_port(char *s_port, struct sockaddr_in *out) { - NULLCHECK( s_port ); + NULLCHECK(s_port); - int raw_port; + int raw_port; - raw_port = atoi( s_port ); - if ( raw_port < 0 || raw_port > 65535 ) { - fatal( "Port number must be >= 0 and <= 65535" ); - } - out->sin_port = htobe16( raw_port ); + raw_port = atoi(s_port); + if (raw_port < 0 || raw_port > 65535) { + fatal("Port number must be >= 0 and <= 65535"); + } + out->sin_port = htobe16(raw_port); } - diff --git a/src/common/parse.h b/src/common/parse.h index afe08ea..686830c 100644 --- a/src/common/parse.h +++ b/src/common/parse.h @@ -8,22 +8,21 @@ #include union mysockaddr { - unsigned short family; - struct sockaddr generic; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - struct sockaddr_un un; + unsigned short family; + struct sockaddr generic; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + struct sockaddr_un un; }; struct ip_and_mask { - union mysockaddr ip; - int mask; + union mysockaddr ip; + int mask; }; -int parse_ip_to_sockaddr(struct sockaddr* out, char* src); -int parse_to_sockaddr(struct sockaddr* out, char* src); +int parse_ip_to_sockaddr(struct sockaddr *out, char *src); +int parse_to_sockaddr(struct sockaddr *out, char *src); int parse_acl(struct ip_and_mask (**out)[], int max, char **entries); -void parse_port( char *s_port, struct sockaddr_in *out ); +void parse_port(char *s_port, struct sockaddr_in *out); #endif - diff --git a/src/common/readwrite.c b/src/common/readwrite.c index 414c169..3734588 100644 --- a/src/common/readwrite.c +++ b/src/common/readwrite.c @@ -8,214 +8,217 @@ #include #include -int socket_connect(struct sockaddr* to, struct sockaddr* from) +int socket_connect(struct sockaddr *to, struct sockaddr *from) { - int fd = socket(to->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_STREAM, 0); - if( fd < 0 ){ - warn( "Couldn't create client socket"); - return -1; - } + int fd = + socket(to->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_STREAM, + 0); + if (fd < 0) { + warn("Couldn't create client socket"); + return -1; + } - if (NULL != from) { - if ( 0 > bind( fd, from, sizeof(struct sockaddr_in6 ) ) ){ - warn( SHOW_ERRNO( "bind() to source address failed" ) ); - if ( 0 > close( fd ) ) { /* Non-fatal leak */ - warn( SHOW_ERRNO( "Failed to close fd %i", fd ) ); - } - return -1; - } + if (NULL != from) { + if (0 > bind(fd, from, sizeof(struct sockaddr_in6))) { + warn(SHOW_ERRNO("bind() to source address failed")); + if (0 > close(fd)) { /* Non-fatal leak */ + warn(SHOW_ERRNO("Failed to close fd %i", fd)); + } + return -1; } + } - if ( 0 > sock_try_connect( fd, to, sizeof( struct sockaddr_in6 ), 15 ) ) { - warn( SHOW_ERRNO( "connect failed" ) ); - if ( 0 > close( fd ) ) { /* Non-fatal leak */ - warn( SHOW_ERRNO( "Failed to close fd %i", fd ) ); - } - return -1; + if (0 > sock_try_connect(fd, to, sizeof(struct sockaddr_in6), 15)) { + warn(SHOW_ERRNO("connect failed")); + if (0 > close(fd)) { /* Non-fatal leak */ + warn(SHOW_ERRNO("Failed to close fd %i", fd)); } + return -1; + } - if ( sock_set_tcp_nodelay( fd, 1 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) ); - } + if (sock_set_tcp_nodelay(fd, 1) == -1) { + warn(SHOW_ERRNO("Failed to set TCP_NODELAY")); + } - return fd; + return fd; } -int nbd_check_hello( struct nbd_init_raw* init_raw, uint64_t* out_size, uint32_t* out_flags ) +int nbd_check_hello(struct nbd_init_raw *init_raw, uint64_t * out_size, + uint32_t * out_flags) { - if ( strncmp( init_raw->passwd, INIT_PASSWD, 8 ) != 0 ) { - warn( "wrong passwd" ); - goto fail; - } - if ( be64toh( init_raw->magic ) != INIT_MAGIC ) { - warn( "wrong magic (%x)", be64toh( init_raw->magic ) ); - goto fail; - } + if (strncmp(init_raw->passwd, INIT_PASSWD, 8) != 0) { + warn("wrong passwd"); + goto fail; + } + if (be64toh(init_raw->magic) != INIT_MAGIC) { + warn("wrong magic (%x)", be64toh(init_raw->magic)); + goto fail; + } - if ( NULL != out_size ) { - *out_size = be64toh( init_raw->size ); - } + if (NULL != out_size) { + *out_size = be64toh(init_raw->size); + } - if ( NULL != out_flags ) { - *out_flags = be32toh( init_raw->flags ); - } + if (NULL != out_flags) { + *out_flags = be32toh(init_raw->flags); + } - return 1; -fail: + return 1; + fail: + return 0; + +} + +int socket_nbd_read_hello(int fd, uint64_t * out_size, + uint32_t * out_flags) +{ + struct nbd_init_raw init_raw; + + + if (0 > readloop(fd, &init_raw, sizeof(init_raw))) { + warn("Couldn't read init"); return 0; + } + return nbd_check_hello(&init_raw, out_size, out_flags); } -int socket_nbd_read_hello( int fd, uint64_t* out_size, uint32_t* out_flags ) +void nbd_hello_to_buf(struct nbd_init_raw *buf, off64_t out_size, + uint32_t out_flags) { - struct nbd_init_raw init_raw; + struct nbd_init init; + memcpy(&init.passwd, INIT_PASSWD, 8); + init.magic = INIT_MAGIC; + init.size = out_size; + init.flags = out_flags; - if ( 0 > readloop( fd, &init_raw, sizeof(init_raw) ) ) { - warn( "Couldn't read init" ); - return 0; - } + memset(buf, 0, sizeof(struct nbd_init_raw)); // ensure reserved is 0s + nbd_h2r_init(&init, buf); - return nbd_check_hello( &init_raw, out_size, out_flags ); + return; } -void nbd_hello_to_buf( struct nbd_init_raw *buf, off64_t out_size, uint32_t out_flags ) +int socket_nbd_write_hello(int fd, off64_t out_size, uint32_t out_flags) { - struct nbd_init init; + struct nbd_init_raw init_raw; + nbd_hello_to_buf(&init_raw, out_size, out_flags); - memcpy( &init.passwd, INIT_PASSWD, 8 ); - init.magic = INIT_MAGIC; - init.size = out_size; - init.flags = out_flags; - - memset( buf, 0, sizeof( struct nbd_init_raw ) ); // ensure reserved is 0s - nbd_h2r_init( &init, buf ); - - return; + if (0 > writeloop(fd, &init_raw, sizeof(init_raw))) { + warn(SHOW_ERRNO("failed to write hello to socket")); + return 0; + } + return 1; } -int socket_nbd_write_hello( int fd, off64_t out_size, uint32_t out_flags ) +void fill_request(struct nbd_request_raw *request_raw, uint16_t type, + uint16_t flags, uint64_t from, uint32_t len) { - struct nbd_init_raw init_raw; - nbd_hello_to_buf( &init_raw, out_size, out_flags ); - - if ( 0 > writeloop( fd, &init_raw, sizeof( init_raw ) ) ) { - warn( SHOW_ERRNO( "failed to write hello to socket" ) ); - return 0; - } - return 1; + request_raw->magic = htobe32(REQUEST_MAGIC); + request_raw->type = htobe16(type); + request_raw->flags = htobe16(flags); + request_raw->handle.w = + (((uint64_t) rand()) << 32) | ((uint64_t) rand()); + request_raw->from = htobe64(from); + request_raw->len = htobe32(len); } -void fill_request(struct nbd_request_raw *request_raw, uint16_t type, uint16_t flags, uint64_t from, uint32_t len) +void read_reply(int fd, uint64_t request_raw_handle, + struct nbd_reply *reply) { - request_raw->magic = htobe32(REQUEST_MAGIC); - request_raw->type = htobe16(type); - request_raw->flags = htobe16(flags); - request_raw->handle.w = (((uint64_t)rand()) << 32) | ((uint64_t)rand()); - request_raw->from = htobe64(from); - request_raw->len = htobe32(len); + struct nbd_reply_raw reply_raw; + + ERROR_IF_NEGATIVE(readloop + (fd, &reply_raw, sizeof(struct nbd_reply_raw)), + "Couldn't read reply"); + + nbd_r2h_reply(&reply_raw, reply); + + if (reply->magic != REPLY_MAGIC) { + error("Reply magic incorrect (%x)", reply->magic); + } + if (reply->error != 0) { + error("Server replied with error %d", reply->error); + } + if (request_raw_handle != reply_raw.handle.w) { + error("Did not reply with correct handle"); + } } -void read_reply(int fd, uint64_t request_raw_handle, struct nbd_reply *reply) +void wait_for_data(int fd, int timeout_secs) { - struct nbd_reply_raw reply_raw; + fd_set fds; + struct timeval tv = { timeout_secs, 0 }; + int selected; - ERROR_IF_NEGATIVE(readloop(fd, &reply_raw, sizeof(struct nbd_reply_raw)), - "Couldn't read reply"); + FD_ZERO(&fds); + FD_SET(fd, &fds); - nbd_r2h_reply( &reply_raw, reply ); + selected = + sock_try_select(FD_SETSIZE, &fds, NULL, NULL, + timeout_secs >= 0 ? &tv : NULL); - if (reply->magic != REPLY_MAGIC) { - error("Reply magic incorrect (%x)", reply->magic); - } - if (reply->error != 0) { - error("Server replied with error %d", reply->error); - } - if (request_raw_handle != reply_raw.handle.w) { - error("Did not reply with correct handle"); - } -} - -void wait_for_data( int fd, int timeout_secs ) -{ - fd_set fds; - struct timeval tv = { timeout_secs, 0 }; - int selected; - - FD_ZERO( &fds ); - FD_SET( fd, &fds ); - - selected = sock_try_select( - FD_SETSIZE, &fds, NULL, NULL, timeout_secs >=0 ? &tv : NULL - ); - - FATAL_IF( -1 == selected, "Select failed" ); - ERROR_IF( 0 == selected, "Timed out waiting for reply" ); + FATAL_IF(-1 == selected, "Select failed"); + ERROR_IF(0 == selected, "Timed out waiting for reply"); } -void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs) +void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, + void *out_buf, int timeout_secs) { - struct nbd_request_raw request_raw; - struct nbd_reply reply; + struct nbd_request_raw request_raw; + struct nbd_reply reply; - fill_request(&request_raw, REQUEST_READ, 0, from, len); - FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), - "Couldn't write request"); + fill_request(&request_raw, REQUEST_READ, 0, from, len); + FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), + "Couldn't write request"); - wait_for_data( fd, timeout_secs ); - read_reply(fd, request_raw.handle.w, &reply); + wait_for_data(fd, timeout_secs); + read_reply(fd, request_raw.handle.w, &reply); - if (out_buf) { - FATAL_IF_NEGATIVE(readloop(fd, out_buf, len), - "Read failed"); - } - else { - FATAL_IF_NEGATIVE( - splice_via_pipe_loop(fd, out_fd, len), - "Splice failed" - ); - } + if (out_buf) { + FATAL_IF_NEGATIVE(readloop(fd, out_buf, len), "Read failed"); + } else { + FATAL_IF_NEGATIVE(splice_via_pipe_loop(fd, out_fd, len), + "Splice failed"); + } } -void socket_nbd_write(int fd, uint64_t from, uint32_t len, int in_fd, void* in_buf, int timeout_secs) +void socket_nbd_write(int fd, uint64_t from, uint32_t len, int in_fd, + void *in_buf, int timeout_secs) { - struct nbd_request_raw request_raw; - struct nbd_reply reply; + struct nbd_request_raw request_raw; + struct nbd_reply reply; - fill_request(&request_raw, REQUEST_WRITE, 0, from, len); - ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), - "Couldn't write request"); + fill_request(&request_raw, REQUEST_WRITE, 0, from, len); + ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), + "Couldn't write request"); - if (in_buf) { - ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len), - "Write failed"); - } - else { - ERROR_IF_NEGATIVE( - splice_via_pipe_loop(in_fd, fd, len), - "Splice failed" - ); - } + if (in_buf) { + ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len), "Write failed"); + } else { + ERROR_IF_NEGATIVE(splice_via_pipe_loop(in_fd, fd, len), + "Splice failed"); + } - wait_for_data( fd, timeout_secs ); - read_reply(fd, request_raw.handle.w, &reply); + wait_for_data(fd, timeout_secs); + read_reply(fd, request_raw.handle.w, &reply); } -int socket_nbd_disconnect( int fd ) +int socket_nbd_disconnect(int fd) { - int success = 1; - struct nbd_request_raw request_raw; + int success = 1; + struct nbd_request_raw request_raw; - fill_request( &request_raw, REQUEST_DISCONNECT, 0, 0, 0 ); - /* FIXME: This shouldn't be a FATAL error. We should just drop - * the mirror without affecting the main server. - */ - FATAL_IF_NEGATIVE( writeloop( fd, &request_raw, sizeof( request_raw ) ), - "Failed to write the disconnect request." ); - return success; + fill_request(&request_raw, REQUEST_DISCONNECT, 0, 0, 0); + /* FIXME: This shouldn't be a FATAL error. We should just drop + * the mirror without affecting the main server. + */ + FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), + "Failed to write the disconnect request."); + return success; } #define CHECK_RANGE(error_type) { \ @@ -237,23 +240,26 @@ int socket_nbd_disconnect( int fd ) }\ } -void do_read(struct mode_readwrite_params* params) +void do_read(struct mode_readwrite_params *params) { - params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic); - FATAL_IF_NEGATIVE( params->client, "Couldn't connect." ); - CHECK_RANGE("read"); - socket_nbd_read(params->client, params->from, params->len, - params->data_fd, NULL, 10); - close(params->client); + params->client = + socket_connect(¶ms->connect_to.generic, + ¶ms->connect_from.generic); + FATAL_IF_NEGATIVE(params->client, "Couldn't connect."); + CHECK_RANGE("read"); + socket_nbd_read(params->client, params->from, params->len, + params->data_fd, NULL, 10); + close(params->client); } -void do_write(struct mode_readwrite_params* params) +void do_write(struct mode_readwrite_params *params) { - params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic); - FATAL_IF_NEGATIVE( params->client, "Couldn't connect." ); - CHECK_RANGE("write"); - socket_nbd_write(params->client, params->from, params->len, - params->data_fd, NULL, 10); - close(params->client); + params->client = + socket_connect(¶ms->connect_to.generic, + ¶ms->connect_from.generic); + FATAL_IF_NEGATIVE(params->client, "Couldn't connect."); + CHECK_RANGE("write"); + socket_nbd_write(params->client, params->from, params->len, + params->data_fd, NULL, 10); + close(params->client); } - diff --git a/src/common/readwrite.h b/src/common/readwrite.h index 8b7371b..a358646 100644 --- a/src/common/readwrite.h +++ b/src/common/readwrite.h @@ -6,18 +6,21 @@ #include #include "nbdtypes.h" -int socket_connect(struct sockaddr* to, struct sockaddr* from); -int socket_nbd_read_hello(int fd, uint64_t* size, uint32_t* flags); +int socket_connect(struct sockaddr *to, struct sockaddr *from); +int socket_nbd_read_hello(int fd, uint64_t * size, uint32_t * flags); int socket_nbd_write_hello(int fd, uint64_t size, uint32_t flags); -void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs); -void socket_nbd_write(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs); -int socket_nbd_disconnect( int fd ); +void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, + void *out_buf, int timeout_secs); +void socket_nbd_write(int fd, uint64_t from, uint32_t len, int out_fd, + void *out_buf, int timeout_secs); +int socket_nbd_disconnect(int fd); /* as you can see, we're slowly accumulating code that should really be in an * NBD library */ -void nbd_hello_to_buf( struct nbd_init_raw* buf, uint64_t out_size, uint32_t out_flags ); -int nbd_check_hello( struct nbd_init_raw* init_raw, uint64_t* out_size, uint32_t* out_flags ); +void nbd_hello_to_buf(struct nbd_init_raw *buf, uint64_t out_size, + uint32_t out_flags); +int nbd_check_hello(struct nbd_init_raw *init_raw, uint64_t * out_size, + uint32_t * out_flags); #endif - diff --git a/src/common/remote.c b/src/common/remote.c index 43830a5..f379940 100644 --- a/src/common/remote.c +++ b/src/common/remote.c @@ -4,64 +4,62 @@ #include #include -static const int max_response=1024; +static const int max_response = 1024; -void print_response( const char * response ) +void print_response(const char *response) { - char * response_text; - FILE * out; - int exit_status; + char *response_text; + FILE *out; + int exit_status; - NULLCHECK( response ); + NULLCHECK(response); - exit_status = atoi(response); - response_text = strchr( response, ':' ); + exit_status = atoi(response); + response_text = strchr(response, ':'); - FATAL_IF_NULL( response_text, - "Error parsing server response: '%s'", response ); + FATAL_IF_NULL(response_text, + "Error parsing server response: '%s'", response); - out = exit_status > 0 ? stderr : stdout; - fprintf(out, "%s\n", response_text + 2); + out = exit_status > 0 ? stderr : stdout; + fprintf(out, "%s\n", response_text + 2); } -void do_remote_command(char* command, char* socket_name, int argc, char** argv) +void do_remote_command(char *command, char *socket_name, int argc, + char **argv) { - char newline=10; - int i; - debug( "connecting to run remote command %s", command ); - int remote = socket(AF_UNIX, SOCK_STREAM, 0); - struct sockaddr_un address; - char response[max_response]; + char newline = 10; + int i; + debug("connecting to run remote command %s", command); + int remote = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un address; + char response[max_response]; - memset(&address, 0, sizeof(address)); + memset(&address, 0, sizeof(address)); - FATAL_IF_NEGATIVE(remote, "Couldn't create client socket"); + FATAL_IF_NEGATIVE(remote, "Couldn't create client socket"); - address.sun_family = AF_UNIX; - strncpy(address.sun_path, socket_name, sizeof(address.sun_path)); + address.sun_family = AF_UNIX; + strncpy(address.sun_path, socket_name, sizeof(address.sun_path)); - FATAL_IF_NEGATIVE( - connect(remote, (struct sockaddr*) &address, sizeof(address)), - "Couldn't connect to %s", socket_name - ); + FATAL_IF_NEGATIVE(connect + (remote, (struct sockaddr *) &address, + sizeof(address)), "Couldn't connect to %s", + socket_name); - write(remote, command, strlen(command)); - write(remote, &newline, 1); - for (i=0; iread_fd = fds[0]; - sig->write_fd = fds[1]; + return NULL; + } - return sig; + sig->read_fd = fds[0]; + sig->write_fd = fds[1]; + + return sig; } @@ -83,19 +86,19 @@ struct self_pipe * self_pipe_create(void) * Returns 1 on success. Can fail if weirdness happened to the write fd * of the pipe in the self_pipe struct. */ -int self_pipe_signal( struct self_pipe * sig ) +int self_pipe_signal(struct self_pipe *sig) { - NULLCHECK( sig ); - FATAL_IF( 1 == sig->write_fd, "Shouldn't be writing to stdout" ); - FATAL_IF( 2 == sig->write_fd, "Shouldn't be writing to stderr" ); + NULLCHECK(sig); + FATAL_IF(1 == sig->write_fd, "Shouldn't be writing to stdout"); + FATAL_IF(2 == sig->write_fd, "Shouldn't be writing to stderr"); - int written = write( sig->write_fd, "X", 1 ); - if ( written != 1 ) { - self_pipe_server_error( errno, ERR_MSG_WRITE ); - return 0; - } + int written = write(sig->write_fd, "X", 1); + if (written != 1) { + self_pipe_server_error(errno, ERR_MSG_WRITE); + return 0; + } - return 1; + return 1; } @@ -106,11 +109,11 @@ int self_pipe_signal( struct self_pipe * sig ) * Returns the number of bytes read, which will be 1 on success and 0 if * there was no signal. */ -int self_pipe_signal_clear( struct self_pipe *sig ) +int self_pipe_signal_clear(struct self_pipe *sig) { - char buf[1]; + char buf[1]; - return 1 == read( sig->read_fd, buf, 1 ); + return 1 == read(sig->read_fd, buf, 1); } @@ -118,30 +121,30 @@ int self_pipe_signal_clear( struct self_pipe *sig ) * Close the pipe and free the self_pipe. Do not try to use the * self_pipe struct after calling this, the innards are mush. */ -int self_pipe_destroy( struct self_pipe * sig ) +int self_pipe_destroy(struct self_pipe *sig) { - NULLCHECK(sig); + NULLCHECK(sig); - while( close( sig->read_fd ) == -1 && errno == EINTR ); - while( close( sig->write_fd ) == -1 && errno == EINTR ); + while (close(sig->read_fd) == -1 && errno == EINTR); + while (close(sig->write_fd) == -1 && errno == EINTR); - /* Just in case anyone *does* try to use this after free, - * we should set the memory locations to an error value - */ - sig->read_fd = -1; - sig->write_fd = -1; + /* Just in case anyone *does* try to use this after free, + * we should set the memory locations to an error value + */ + sig->read_fd = -1; + sig->write_fd = -1; - free( sig ); - return 1; + free(sig); + return 1; } -int self_pipe_fd_set( struct self_pipe * sig, fd_set * fds) +int self_pipe_fd_set(struct self_pipe *sig, fd_set * fds) { - FD_SET( sig->read_fd, fds ); - return 1; + FD_SET(sig->read_fd, fds); + return 1; } -int self_pipe_fd_isset( struct self_pipe * sig, fd_set * fds) +int self_pipe_fd_isset(struct self_pipe *sig, fd_set * fds) { - return FD_ISSET( sig->read_fd, fds ); + return FD_ISSET(sig->read_fd, fds); } diff --git a/src/common/self_pipe.h b/src/common/self_pipe.h index 76576df..561519f 100644 --- a/src/common/self_pipe.h +++ b/src/common/self_pipe.h @@ -4,16 +4,16 @@ #include struct self_pipe { - int read_fd; - int write_fd; + int read_fd; + int write_fd; }; -struct self_pipe * self_pipe_create(void); -int self_pipe_signal( struct self_pipe * sig ); -int self_pipe_signal_clear( struct self_pipe *sig ); -int self_pipe_destroy( struct self_pipe * sig ); -int self_pipe_fd_set( struct self_pipe * sig, fd_set * fds ); -int self_pipe_fd_isset( struct self_pipe *sig, fd_set *fds ); +struct self_pipe *self_pipe_create(void); +int self_pipe_signal(struct self_pipe *sig); +int self_pipe_signal_clear(struct self_pipe *sig); +int self_pipe_destroy(struct self_pipe *sig); +int self_pipe_fd_set(struct self_pipe *sig, fd_set * fds); +int self_pipe_fd_isset(struct self_pipe *sig, fd_set * fds); #endif diff --git a/src/common/sockutil.c b/src/common/sockutil.c index 56d728f..6dfe3ae 100644 --- a/src/common/sockutil.c +++ b/src/common/sockutil.c @@ -9,279 +9,287 @@ #include "sockutil.h" #include "util.h" -size_t sockaddr_size( const struct sockaddr* sa ) +size_t sockaddr_size(const struct sockaddr * sa) { - struct sockaddr_un* un = (struct sockaddr_un*) sa; - size_t ret = 0; + struct sockaddr_un *un = (struct sockaddr_un *) sa; + size_t ret = 0; - switch( sa->sa_family ) { - case AF_INET: - ret = sizeof( struct sockaddr_in ); - break; - case AF_INET6: - ret = sizeof( struct sockaddr_in6 ); - break; - case AF_UNIX: - ret = sizeof( un->sun_family ) + SUN_LEN( un ); - break; - } + switch (sa->sa_family) { + case AF_INET: + ret = sizeof(struct sockaddr_in); + break; + case AF_INET6: + ret = sizeof(struct sockaddr_in6); + break; + case AF_UNIX: + ret = sizeof(un->sun_family) + SUN_LEN(un); + break; + } - return ret; + return ret; } -const char* sockaddr_address_string( const struct sockaddr* sa, char* dest, size_t len ) +const char *sockaddr_address_string(const struct sockaddr *sa, char *dest, + size_t len) { - NULLCHECK( sa ); - NULLCHECK( dest ); + NULLCHECK(sa); + NULLCHECK(dest); - struct sockaddr_in* in = ( struct sockaddr_in* ) sa; - struct sockaddr_in6* in6 = ( struct sockaddr_in6* ) sa; - struct sockaddr_un* un = ( struct sockaddr_un* ) sa; + struct sockaddr_in *in = (struct sockaddr_in *) sa; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) sa; + struct sockaddr_un *un = (struct sockaddr_un *) sa; - unsigned short real_port = ntohs( in->sin_port ); // common to in and in6 - const char* ret = NULL; + unsigned short real_port = ntohs(in->sin_port); // common to in and in6 + const char *ret = NULL; - memset( dest, 0, len ); + memset(dest, 0, len); - if ( sa->sa_family == AF_INET ) { - ret = inet_ntop( AF_INET, &in->sin_addr, dest, len ); - } else if ( sa->sa_family == AF_INET6 ) { - ret = inet_ntop( AF_INET6, &in6->sin6_addr, dest, len ); - } else if ( sa->sa_family == AF_UNIX ) { - ret = strncpy( dest, un->sun_path, SUN_LEN( un ) ); - } + if (sa->sa_family == AF_INET) { + ret = inet_ntop(AF_INET, &in->sin_addr, dest, len); + } else if (sa->sa_family == AF_INET6) { + ret = inet_ntop(AF_INET6, &in6->sin6_addr, dest, len); + } else if (sa->sa_family == AF_UNIX) { + ret = strncpy(dest, un->sun_path, SUN_LEN(un)); + } - if ( ret == NULL ) { - strncpy( dest, "???", len ); - } + if (ret == NULL) { + strncpy(dest, "???", len); + } - if ( NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX ) { - size_t size = strlen( dest ); - snprintf( dest + size, len - size, " port %d", real_port ); - } + if (NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX) { + size_t size = strlen(dest); + snprintf(dest + size, len - size, " port %d", real_port); + } - return ret; + return ret; } -int sock_set_reuseaddr( int fd, int optval ) +int sock_set_reuseaddr(int fd, int optval) { - return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ); + return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); } -int sock_set_keepalive_params( int fd, int time, int intvl, int probes) +int sock_set_keepalive_params(int fd, int time, int intvl, int probes) { - if (sock_set_keepalive(fd, 1) || - sock_set_tcp_keepidle(fd, time) || - sock_set_tcp_keepintvl(fd, intvl) || - sock_set_tcp_keepcnt(fd, probes)) { - return -1; - } - return 0; + if (sock_set_keepalive(fd, 1) || + sock_set_tcp_keepidle(fd, time) || + sock_set_tcp_keepintvl(fd, intvl) || + sock_set_tcp_keepcnt(fd, probes)) { + return -1; + } + return 0; } -int sock_set_keepalive( int fd, int optval ) +int sock_set_keepalive(int fd, int optval) { - return setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) ); + return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, + sizeof(optval)); } -int sock_set_tcp_keepidle( int fd, int optval ) +int sock_set_tcp_keepidle(int fd, int optval) { - return setsockopt( fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval) ); + return setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, + sizeof(optval)); } -int sock_set_tcp_keepintvl( int fd, int optval ) +int sock_set_tcp_keepintvl(int fd, int optval) { - return setsockopt( fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval) ); + return setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, + sizeof(optval)); } -int sock_set_tcp_keepcnt( int fd, int optval ) +int sock_set_tcp_keepcnt(int fd, int optval) { - return setsockopt( fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval) ); + return setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, + sizeof(optval)); } /* Set the tcp_nodelay option */ -int sock_set_tcp_nodelay( int fd, int optval ) +int sock_set_tcp_nodelay(int fd, int optval) { - return setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval) ); + return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, + sizeof(optval)); } -int sock_set_tcp_cork( int fd, int optval ) +int sock_set_tcp_cork(int fd, int optval) { - return setsockopt( fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval) ); + return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval)); } -int sock_set_nonblock( int fd, int optval ) +int sock_set_nonblock(int fd, int optval) { - int flags = fcntl( fd, F_GETFL ); + int flags = fcntl(fd, F_GETFL); - if ( flags == -1 ) { - return -1; - } + if (flags == -1) { + return -1; + } - if ( optval ) { - flags = flags | O_NONBLOCK; + if (optval) { + flags = flags | O_NONBLOCK; + } else { + flags = flags & (~O_NONBLOCK); + } + + return fcntl(fd, F_SETFL, flags); +} + +int sock_try_bind(int fd, const struct sockaddr *sa) +{ + int bind_result; + char s_address[256]; + int retry = 10; + + sockaddr_address_string(sa, &s_address[0], 256); + + do { + bind_result = bind(fd, sa, sockaddr_size(sa)); + if (0 == bind_result) { + info("Bound to %s", s_address); + break; } else { - flags = flags & (~O_NONBLOCK); + warn(SHOW_ERRNO("Couldn't bind to %s", s_address)); + + switch (errno) { + /* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF, + * EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, + * ENOMEM, ENOTDIR, EROFS + * + * Any of these other than EADDRINUSE & EADDRNOTAVAIL signify + * that there's a logic error somewhere. + * + * EADDRINUSE is fatal: if there's something already where we + * want to be listening, we have no guarantees that any clients + * will cope with it. + */ + case EADDRNOTAVAIL: + retry--; + if (retry) { + debug("retrying"); + sleep(1); + } + continue; + case EADDRINUSE: + warn("%s in use, giving up.", s_address); + retry = 0; + break; + default: + warn("giving up"); + retry = 0; + } + } + } while (retry); + + return bind_result; +} + +int sock_try_select(int nfds, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval *timeout) +{ + int result; + + do { + result = select(nfds, readfds, writefds, exceptfds, timeout); + if (errno != EINTR) { + break; } - return fcntl( fd, F_SETFL, flags ); + } while (result == -1); + + return result; } -int sock_try_bind( int fd, const struct sockaddr* sa ) +int sock_try_connect(int fd, struct sockaddr *to, socklen_t addrlen, + int wait) { - int bind_result; - char s_address[256]; - int retry = 10; + fd_set fds; + struct timeval tv = { wait, 0 }; + int result = 0; - sockaddr_address_string( sa, &s_address[0], 256 ); + if (sock_set_nonblock(fd, 1) == -1) { + warn(SHOW_ERRNO + ("Failed to set socket non-blocking for connect()")); + return connect(fd, to, addrlen); + } - do { - bind_result = bind( fd, sa, sockaddr_size( sa ) ); - if ( 0 == bind_result ) { - info( "Bound to %s", s_address ); - break; - } - else { - warn( SHOW_ERRNO( "Couldn't bind to %s", s_address ) ); + FD_ZERO(&fds); + FD_SET(fd, &fds); - switch ( errno ) { - /* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF, - * EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, - * ENOMEM, ENOTDIR, EROFS - * - * Any of these other than EADDRINUSE & EADDRNOTAVAIL signify - * that there's a logic error somewhere. - * - * EADDRINUSE is fatal: if there's something already where we - * want to be listening, we have no guarantees that any clients - * will cope with it. - */ - case EADDRNOTAVAIL: - retry--; - if (retry) { - debug( "retrying" ); - sleep( 1 ); - } - continue; - case EADDRINUSE: - warn( "%s in use, giving up.", s_address ); - retry = 0; - break; - default: - warn( "giving up" ); - retry = 0; - } - } - } while ( retry ); + do { + result = connect(fd, to, addrlen); - return bind_result; -} - -int sock_try_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) -{ - int result; - - do { - result = select(nfds, readfds, writefds, exceptfds, timeout); - if ( errno != EINTR ) { - break; - } - - } while ( result == -1 ); - - return result; -} - -int sock_try_connect( int fd, struct sockaddr* to, socklen_t addrlen, int wait ) -{ - fd_set fds; - struct timeval tv = { wait, 0 }; - int result = 0; - - if ( sock_set_nonblock( fd, 1 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to set socket non-blocking for connect()" ) ); - return connect( fd, to, addrlen ); - } - - FD_ZERO( &fds ); - FD_SET( fd, &fds ); - - do { - result = connect( fd, to, addrlen ); - - if ( result == -1 ) { - switch( errno ) { - case EINPROGRESS: - result = 0; - break; /* success */ - case EAGAIN: - case EINTR: - /* Try connect() again. This only breaks out of the switch, - * not the do...while loop. since result == -1, we go again. - */ - break; - default: - warn( SHOW_ERRNO( "Failed to connect()" ) ); - goto out; - } - } - } while ( result == -1 ); - - if ( -1 == sock_try_select( FD_SETSIZE, NULL, &fds, NULL, &tv) ) { - warn( SHOW_ERRNO( "failed to select() on non-blocking connect" ) ); - result = -1; + if (result == -1) { + switch (errno) { + case EINPROGRESS: + result = 0; + break; /* success */ + case EAGAIN: + case EINTR: + /* Try connect() again. This only breaks out of the switch, + * not the do...while loop. since result == -1, we go again. + */ + break; + default: + warn(SHOW_ERRNO("Failed to connect()")); goto out; + } } + } while (result == -1); - if ( !FD_ISSET( fd, &fds ) ) { - result = -1; - errno = ETIMEDOUT; - goto out; - } + if (-1 == sock_try_select(FD_SETSIZE, NULL, &fds, NULL, &tv)) { + warn(SHOW_ERRNO("failed to select() on non-blocking connect")); + result = -1; + goto out; + } - int scratch; - socklen_t s_size = sizeof( scratch ); - if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size ) == -1 ) { - result = -1; - warn( SHOW_ERRNO( "getsockopt() failed" ) ); - goto out; - } + if (!FD_ISSET(fd, &fds)) { + result = -1; + errno = ETIMEDOUT; + goto out; + } - if ( scratch == EINPROGRESS ) { - scratch = ETIMEDOUT; - } + int scratch; + socklen_t s_size = sizeof(scratch); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size) == -1) { + result = -1; + warn(SHOW_ERRNO("getsockopt() failed")); + goto out; + } - result = scratch ? -1 : 0; - errno = scratch; + if (scratch == EINPROGRESS) { + scratch = ETIMEDOUT; + } -out: - if ( sock_set_nonblock( fd, 0 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to make socket blocking after connect()" ) ); - return -1; - } + result = scratch ? -1 : 0; + errno = scratch; - debug( "sock_try_connect: %i", result ); - return result; + out: + if (sock_set_nonblock(fd, 0) == -1) { + warn(SHOW_ERRNO("Failed to make socket blocking after connect()")); + return -1; + } + + debug("sock_try_connect: %i", result); + return result; } -int sock_try_close( int fd ) +int sock_try_close(int fd) { - int result; + int result; - do { - result = close( fd ); + do { + result = close(fd); - if ( result == -1 ) { - if ( EINTR == errno ) { - continue; /* retry EINTR */ - } else { - warn( SHOW_ERRNO( "Failed to close() fd %i", fd ) ); - break; /* Other errors get reported */ - } - } + if (result == -1) { + if (EINTR == errno) { + continue; /* retry EINTR */ + } else { + warn(SHOW_ERRNO("Failed to close() fd %i", fd)); + break; /* Other errors get reported */ + } + } - } while( 0 ); + } while (0); - return result; + return result; } - diff --git a/src/common/sockutil.h b/src/common/sockutil.h index 94dbf85..a68ae5c 100644 --- a/src/common/sockutil.h +++ b/src/common/sockutil.h @@ -7,15 +7,16 @@ #include /* Returns the size of the sockaddr, or 0 on error */ -size_t sockaddr_size(const struct sockaddr* sa); +size_t sockaddr_size(const struct sockaddr *sa); /* Convert a sockaddr into an address. Like inet_ntop, it returns dest if * successful, NULL otherwise. In the latter case, dest will contain "???" */ -const char* sockaddr_address_string(const struct sockaddr* sa, char* dest, size_t len); +const char *sockaddr_address_string(const struct sockaddr *sa, char *dest, + size_t len); /* Configure TCP keepalive on a socket */ -int sock_set_keepalive_params( int fd, int time, int intvl, int probes); +int sock_set_keepalive_params(int fd, int time, int intvl, int probes); /* Set the SOL_KEEPALIVE otion */ int sock_set_keepalive(int fd, int optval); @@ -41,16 +42,17 @@ int sock_set_tcp_cork(int fd, int optval); int sock_set_nonblock(int fd, int optval); /* Attempt to bind the fd to the sockaddr, retrying common transient failures */ -int sock_try_bind(int fd, const struct sockaddr* sa); +int sock_try_bind(int fd, const struct sockaddr *sa); /* Try to call select(), retrying EINTR */ -int sock_try_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +int sock_try_select(int nfds, fd_set * readfds, fd_set * writefds, + fd_set * exceptfds, struct timeval *timeout); /* Try to call connect(), timing out after wait seconds */ -int sock_try_connect( int fd, struct sockaddr* to, socklen_t addrlen, int wait ); +int sock_try_connect(int fd, struct sockaddr *to, socklen_t addrlen, + int wait); /* Try to call close(), retrying EINTR */ -int sock_try_close( int fd ); +int sock_try_close(int fd); #endif - diff --git a/src/common/util.c b/src/common/util.c index b6a279b..6cf66d6 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -17,72 +17,75 @@ char *log_context = ""; void error_init(void) { - pthread_key_create(&cleanup_handler_key, free); + pthread_key_create(&cleanup_handler_key, free); } void error_handler(int fatal) { - DECLARE_ERROR_CONTEXT(context); + DECLARE_ERROR_CONTEXT(context); - if (context) { - longjmp(context->jmp, fatal ? 1 : 2 ); - } - else { - if ( fatal ) { abort(); } - else { pthread_exit((void*) 1); } + if (context) { + longjmp(context->jmp, fatal ? 1 : 2); + } else { + if (fatal) { + abort(); + } else { + pthread_exit((void *) 1); } + } } -void exit_err( const char *msg ) +void exit_err(const char *msg) { - fprintf( stderr, "%s\n", msg ); - exit( 1 ); + fprintf(stderr, "%s\n", msg); + exit(1); } -void mylog(int line_level, const char* format, ...) +void mylog(int line_level, const char *format, ...) { - if (line_level < log_level) { return; } + if (line_level < log_level) { + return; + } - va_list argptr; + va_list argptr; - va_start(argptr, format); - vfprintf(stderr, format, argptr); - va_end(argptr); + va_start(argptr, format); + vfprintf(stderr, format, argptr); + va_end(argptr); } uint64_t monotonic_time_ms() { - struct timespec ts; - uint64_t seconds_ms, nanoseconds_ms; + struct timespec ts; + uint64_t seconds_ms, nanoseconds_ms; - FATAL_IF_NEGATIVE( - clock_gettime(CLOCK_MONOTONIC, &ts), - SHOW_ERRNO( "clock_gettime failed" ) + FATAL_IF_NEGATIVE(clock_gettime(CLOCK_MONOTONIC, &ts), + SHOW_ERRNO("clock_gettime failed") ); - seconds_ms = ts.tv_sec; - seconds_ms = seconds_ms * 1000; + seconds_ms = ts.tv_sec; + seconds_ms = seconds_ms * 1000; - nanoseconds_ms = ts.tv_nsec; - nanoseconds_ms = nanoseconds_ms / 1000000; + nanoseconds_ms = ts.tv_nsec; + nanoseconds_ms = nanoseconds_ms / 1000000; - return seconds_ms + nanoseconds_ms; + return seconds_ms + nanoseconds_ms; } -void* xrealloc(void* ptr, size_t size) +void *xrealloc(void *ptr, size_t size) { - void* p = realloc(ptr, size); - FATAL_IF_NULL(p, "couldn't xrealloc %d bytes", ptr ? "realloc" : "malloc", size); - return p; + void *p = realloc(ptr, size); + FATAL_IF_NULL(p, "couldn't xrealloc %d bytes", + ptr ? "realloc" : "malloc", size); + return p; } -void* xmalloc(size_t size) +void *xmalloc(size_t size) { - void* p = xrealloc(NULL, size); - memset(p, 0, size); - return p; + void *p = xrealloc(NULL, size); + memset(p, 0, size); + return p; } - diff --git a/src/common/util.h b/src/common/util.h index 3f05e78..c984e5f 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -10,10 +10,11 @@ #include #include -void* xrealloc(void* ptr, size_t size); -void* xmalloc(size_t size); +void *xrealloc(void *ptr, size_t size); +void *xmalloc(size_t size); -typedef void (cleanup_handler)(void* /* context */, int /* is fatal? */); +typedef void (cleanup_handler) (void * /* context */ , + int /* is fatal? */ ); /* set from 0 - 5 depending on what level of verbosity you want */ extern int log_level; @@ -25,15 +26,15 @@ void error_init(void); extern char *log_context; -void exit_err( const char * ); +void exit_err(const char *); /* error_set_handler must be a macro not a function due to setjmp stack rules */ #include struct error_handler_context { - jmp_buf jmp; - cleanup_handler* handler; - void* data; + jmp_buf jmp; + cleanup_handler *handler; + void *data; }; #define DECLARE_ERROR_CONTEXT(name) \ @@ -87,7 +88,7 @@ extern pthread_key_t cleanup_handler_key; void error_handler(int fatal); /* mylog a line at the given level (0 being most verbose) */ -void mylog(int line_level, const char* format, ...); +void mylog(int line_level, const char *format, ...); /* Returns the current time, in milliseconds, from CLOCK_MONOTONIC */ uint64_t monotonic_time_ms(void); @@ -98,9 +99,9 @@ uint64_t monotonic_time_ms(void); #define myloglev(level, msg, ...) mylog( level, "%"PRIu64":%c:%d %p %s %s:%d: "msg"\n", monotonic_time_ms(), levstr(level), getpid(),pthread_self(), log_context, __FILE__, __LINE__, ##__VA_ARGS__ ) #ifdef DEBUG -# define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__) +#define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__) #else -# define debug(msg, ...) /* no-op */ +#define debug(msg, ...) /* no-op */ #endif /* informational message, not expected to be compiled out */ @@ -162,4 +163,3 @@ uint64_t monotonic_time_ms(void); #define WARN_IF_NEGATIVE( value, msg, ... ) if ( value < 0 ) { warn( msg, ##__VA_ARGS__ ); } #endif - diff --git a/src/main.c b/src/main.c index aaf37dd..463057f 100644 --- a/src/main.c +++ b/src/main.c @@ -5,18 +5,17 @@ #include #include -int main(int argc, char** argv) +int main(int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ - error_init(); + signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ + error_init(); - srand(time(NULL)); + srand(time(NULL)); - if (argc < 2) { - exit_err( help_help_text ); - } - mode(argv[1], argc-1, argv+1); /* never returns */ + if (argc < 2) { + exit_err(help_help_text); + } + mode(argv[1], argc - 1, argv + 1); /* never returns */ - return 0; + return 0; } - diff --git a/src/proxy-main.c b/src/proxy-main.c index fae4d07..7e382b8 100644 --- a/src/proxy-main.c +++ b/src/proxy-main.c @@ -8,164 +8,158 @@ static struct option proxy_options[] = { - GETOPT_HELP, - GETOPT_ADDR, - GETOPT_PORT, - GETOPT_CONNECT_ADDR, - GETOPT_CONNECT_PORT, - GETOPT_BIND, - GETOPT_CACHE, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_ADDR, + GETOPT_PORT, + GETOPT_CONNECT_ADDR, + GETOPT_CONNECT_PORT, + GETOPT_BIND, + GETOPT_CACHE, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE; static char proxy_help_text[] = - "Usage: flexnbd-proxy \n\n" - "Resiliently proxy an NBD connection between client and server\n" - "We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n" - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address we will bind to as a proxy.\n" - "\t--" OPT_PORT ",-p \tThe port we will bind to as a proxy, if required.\n" - "\t--" OPT_CONNECT_ADDR ",-C \tAddress of the proxied server.\n" - "\t--" OPT_CONNECT_PORT ",-P \tPort of the proxied server.\n" - "\t--" OPT_BIND ",-b \tThe address we connect from, as a proxy.\n" - "\t--" OPT_CACHE ",-c[=]\tUse a RAM read cache of the given size.\n" - QUIET_LINE - VERBOSE_LINE; + "Usage: flexnbd-proxy \n\n" + "Resiliently proxy an NBD connection between client and server\n" + "We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n" + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address we will bind to as a proxy.\n" + "\t--" OPT_PORT + ",-p \tThe port we will bind to as a proxy, if required.\n" + "\t--" OPT_CONNECT_ADDR ",-C \tAddress of the proxied server.\n" + "\t--" OPT_CONNECT_PORT ",-P \tPort of the proxied server.\n" + "\t--" OPT_BIND + ",-b \tThe address we connect from, as a proxy.\n" "\t--" + OPT_CACHE + ",-c[=]\tUse a RAM read cache of the given size.\n" + QUIET_LINE VERBOSE_LINE; static char proxy_default_cache_size[] = "4096"; -void read_proxy_param( - int c, - char **downstream_addr, - char **downstream_port, - char **upstream_addr, - char **upstream_port, - char **bind_addr, - char **cache_bytes) +void read_proxy_param(int c, + char **downstream_addr, + char **downstream_port, + char **upstream_addr, + char **upstream_port, + char **bind_addr, char **cache_bytes) { - switch( c ) { - case 'h' : - fprintf( stdout, "%s\n", proxy_help_text ); - exit( 0 ); - case 'l': - *downstream_addr = optarg; - break; - case 'p': - *downstream_port = optarg; - break; - case 'C': - *upstream_addr = optarg; - break; - case 'P': - *upstream_port = optarg; - break; - case 'b': - *bind_addr = optarg; - break; - case 'c': - *cache_bytes = optarg ? optarg : proxy_default_cache_size; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( proxy_help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", proxy_help_text); + exit(0); + case 'l': + *downstream_addr = optarg; + break; + case 'p': + *downstream_port = optarg; + break; + case 'C': + *upstream_addr = optarg; + break; + case 'P': + *upstream_port = optarg; + break; + case 'b': + *bind_addr = optarg; + break; + case 'c': + *cache_bytes = optarg ? optarg : proxy_default_cache_size; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(proxy_help_text); + break; + } } -struct proxier * proxy = NULL; +struct proxier *proxy = NULL; void my_exit(int signum) { - info( "Exit signalled (%i)", signum ); - if ( NULL != proxy ) { - proxy_cleanup( proxy ); - }; - exit( 0 ); + info("Exit signalled (%i)", signum); + if (NULL != proxy) { + proxy_cleanup(proxy); + }; + exit(0); } -int main( int argc, char *argv[] ) +int main(int argc, char *argv[]) { - int c; - char *downstream_addr = NULL; - char *downstream_port = NULL; - char *upstream_addr = NULL; - char *upstream_port = NULL; - char *bind_addr = NULL; - char *cache_bytes = NULL; - int success; + int c; + char *downstream_addr = NULL; + char *downstream_port = NULL; + char *upstream_addr = NULL; + char *upstream_port = NULL; + char *bind_addr = NULL; + char *cache_bytes = NULL; + int success; - sigset_t mask; - struct sigaction exit_action; + sigset_t mask; + struct sigaction exit_action; - sigemptyset( &mask ); - sigaddset( &mask, SIGTERM ); - sigaddset( &mask, SIGQUIT ); - sigaddset( &mask, SIGINT ); + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGINT); - exit_action.sa_handler = my_exit; - exit_action.sa_mask = mask; - exit_action.sa_flags = 0; + exit_action.sa_handler = my_exit; + exit_action.sa_mask = mask; + exit_action.sa_flags = 0; - srand(time(NULL)); + srand(time(NULL)); - while (1) { - c = getopt_long( argc, argv, proxy_short_options, proxy_options, NULL ); - if ( -1 == c ) { break; } - read_proxy_param( c, - &downstream_addr, - &downstream_port, - &upstream_addr, - &upstream_port, - &bind_addr, - &cache_bytes - ); + while (1) { + c = getopt_long(argc, argv, proxy_short_options, proxy_options, + NULL); + if (-1 == c) { + break; } + read_proxy_param(c, + &downstream_addr, + &downstream_port, + &upstream_addr, + &upstream_port, &bind_addr, &cache_bytes); + } - if ( NULL == downstream_addr ){ - fprintf( stderr, "--addr is required.\n" ); - exit_err( proxy_help_text ); - } else if ( NULL == upstream_addr || NULL == upstream_port ){ - fprintf( stderr, "both --conn-addr and --conn-port are required.\n" ); - exit_err( proxy_help_text ); - } + if (NULL == downstream_addr) { + fprintf(stderr, "--addr is required.\n"); + exit_err(proxy_help_text); + } else if (NULL == upstream_addr || NULL == upstream_port) { + fprintf(stderr, + "both --conn-addr and --conn-port are required.\n"); + exit_err(proxy_help_text); + } - proxy = proxy_create( - downstream_addr, - downstream_port, - upstream_addr, - upstream_port, - bind_addr, - cache_bytes - ); + proxy = proxy_create(downstream_addr, + downstream_port, + upstream_addr, + upstream_port, bind_addr, cache_bytes); - /* Set these *after* proxy has been assigned to */ - sigaction(SIGTERM, &exit_action, NULL); - sigaction(SIGQUIT, &exit_action, NULL); - sigaction(SIGINT, &exit_action, NULL); - signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ + /* Set these *after* proxy has been assigned to */ + sigaction(SIGTERM, &exit_action, NULL); + sigaction(SIGQUIT, &exit_action, NULL); + sigaction(SIGINT, &exit_action, NULL); + signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ - if ( NULL != downstream_port ) { - info( - "Proxying between %s %s (downstream) and %s %s (upstream)", - downstream_addr, downstream_port, upstream_addr, upstream_port - ); - } else { - info( - "Proxying between %s (downstream) and %s %s (upstream)", - downstream_addr, upstream_addr, upstream_port - ); - } + if (NULL != downstream_port) { + info("Proxying between %s %s (downstream) and %s %s (upstream)", + downstream_addr, downstream_port, upstream_addr, + upstream_port); + } else { + info("Proxying between %s (downstream) and %s %s (upstream)", + downstream_addr, upstream_addr, upstream_port); + } - success = do_proxy( proxy ); - proxy_destroy( proxy ); + success = do_proxy(proxy); + proxy_destroy(proxy); - return success ? 0 : 1; + return success ? 0 : 1; } - diff --git a/src/proxy/prefetch.c b/src/proxy/prefetch.c index 4fa77b2..2ae435f 100644 --- a/src/proxy/prefetch.c +++ b/src/proxy/prefetch.c @@ -2,67 +2,77 @@ #include "util.h" -struct prefetch* prefetch_create( size_t size_bytes ){ +struct prefetch *prefetch_create(size_t size_bytes) +{ - struct prefetch* out = xmalloc( sizeof( struct prefetch ) ); - NULLCHECK( out ); - - out->buffer = xmalloc( size_bytes ); - NULLCHECK( out->buffer ); + struct prefetch *out = xmalloc(sizeof(struct prefetch)); + NULLCHECK(out); - out->size = size_bytes; - out->is_full = 0; - out->from = 0; - out->len = 0; + out->buffer = xmalloc(size_bytes); + NULLCHECK(out->buffer); - return out; + out->size = size_bytes; + out->is_full = 0; + out->from = 0; + out->len = 0; + + return out; } -void prefetch_destroy( struct prefetch *prefetch ) { - if( prefetch ) { - free( prefetch->buffer ); - free( prefetch ); - } +void prefetch_destroy(struct prefetch *prefetch) +{ + if (prefetch) { + free(prefetch->buffer); + free(prefetch); + } } -size_t prefetch_size( struct prefetch *prefetch){ - if ( prefetch ) { - return prefetch->size; - } else { - return 0; - } +size_t prefetch_size(struct prefetch *prefetch) +{ + if (prefetch) { + return prefetch->size; + } else { + return 0; + } } -void prefetch_set_is_empty( struct prefetch *prefetch ){ - prefetch_set_full( prefetch, 0 ); +void prefetch_set_is_empty(struct prefetch *prefetch) +{ + prefetch_set_full(prefetch, 0); } -void prefetch_set_is_full( struct prefetch *prefetch ){ - prefetch_set_full( prefetch, 1 ); +void prefetch_set_is_full(struct prefetch *prefetch) +{ + prefetch_set_full(prefetch, 1); } -void prefetch_set_full( struct prefetch *prefetch, int val ){ - if( prefetch ) { - prefetch->is_full = val; - } +void prefetch_set_full(struct prefetch *prefetch, int val) +{ + if (prefetch) { + prefetch->is_full = val; + } } -int prefetch_is_full( struct prefetch *prefetch ){ - if( prefetch ) { - return prefetch->is_full; - } else { - return 0; - } +int prefetch_is_full(struct prefetch *prefetch) +{ + if (prefetch) { + return prefetch->is_full; + } else { + return 0; + } } -int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len ){ - NULLCHECK( prefetch ); - return from >= prefetch->from && - from + len <= prefetch->from + prefetch->len; +int prefetch_contains(struct prefetch *prefetch, uint64_t from, + uint32_t len) +{ + NULLCHECK(prefetch); + return from >= prefetch->from && + from + len <= prefetch->from + prefetch->len; } -char *prefetch_offset( struct prefetch *prefetch, uint64_t from ){ - NULLCHECK( prefetch ); - return prefetch->buffer + (from - prefetch->from); +char *prefetch_offset(struct prefetch *prefetch, uint64_t from) +{ + NULLCHECK(prefetch); + return prefetch->buffer + (from - prefetch->from); } diff --git a/src/proxy/prefetch.h b/src/proxy/prefetch.h index 7c71885..6fde1ca 100644 --- a/src/proxy/prefetch.h +++ b/src/proxy/prefetch.h @@ -7,27 +7,28 @@ #define PREFETCH_BUFSIZE 4096 struct prefetch { - /* True if there is data in the buffer. */ - int is_full; - /* The start point of the current content of buffer */ - uint64_t from; - /* The length of the current content of buffer */ - uint32_t len; + /* True if there is data in the buffer. */ + int is_full; + /* The start point of the current content of buffer */ + uint64_t from; + /* The length of the current content of buffer */ + uint32_t len; - /* The total size of the buffer, in bytes. */ - size_t size; + /* The total size of the buffer, in bytes. */ + size_t size; - char *buffer; + char *buffer; }; -struct prefetch* prefetch_create( size_t size_bytes ); -void prefetch_destroy( struct prefetch *prefetch ); -size_t prefetch_size( struct prefetch *); -void prefetch_set_is_empty( struct prefetch *prefetch ); -void prefetch_set_is_full( struct prefetch *prefetch ); -void prefetch_set_full( struct prefetch *prefetch, int val ); -int prefetch_is_full( struct prefetch *prefetch ); -int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len ); -char *prefetch_offset( struct prefetch *prefetch, uint64_t from ); +struct prefetch *prefetch_create(size_t size_bytes); +void prefetch_destroy(struct prefetch *prefetch); +size_t prefetch_size(struct prefetch *); +void prefetch_set_is_empty(struct prefetch *prefetch); +void prefetch_set_is_full(struct prefetch *prefetch); +void prefetch_set_full(struct prefetch *prefetch, int val); +int prefetch_is_full(struct prefetch *prefetch); +int prefetch_contains(struct prefetch *prefetch, uint64_t from, + uint32_t len); +char *prefetch_offset(struct prefetch *prefetch, uint64_t from); #endif diff --git a/src/proxy/proxy.c b/src/proxy/proxy.c index 291acd6..8781308 100644 --- a/src/proxy/proxy.c +++ b/src/proxy/proxy.c @@ -13,674 +13,671 @@ #include #include -struct proxier* proxy_create( - char* s_downstream_address, - char* s_downstream_port, - char* s_upstream_address, - char* s_upstream_port, - char* s_upstream_bind, - char* s_cache_bytes ) +struct proxier *proxy_create(char *s_downstream_address, + char *s_downstream_port, + char *s_upstream_address, + char *s_upstream_port, + char *s_upstream_bind, char *s_cache_bytes) { - struct proxier* out; - out = xmalloc( sizeof( struct proxier ) ); + struct proxier *out; + out = xmalloc(sizeof(struct proxier)); - FATAL_IF_NULL(s_downstream_address, "Listen address not specified"); - NULLCHECK( s_downstream_address ); + FATAL_IF_NULL(s_downstream_address, "Listen address not specified"); + NULLCHECK(s_downstream_address); - FATAL_UNLESS( - parse_to_sockaddr( &out->listen_on.generic, s_downstream_address ), - "Couldn't parse downstream address %s" - ); + FATAL_UNLESS(parse_to_sockaddr + (&out->listen_on.generic, s_downstream_address), + "Couldn't parse downstream address %s"); - if ( out->listen_on.family != AF_UNIX ) { - FATAL_IF_NULL( s_downstream_port, "Downstream port not specified" ); - NULLCHECK( s_downstream_port ); - parse_port( s_downstream_port, &out->listen_on.v4 ); - } + if (out->listen_on.family != AF_UNIX) { + FATAL_IF_NULL(s_downstream_port, "Downstream port not specified"); + NULLCHECK(s_downstream_port); + parse_port(s_downstream_port, &out->listen_on.v4); + } - FATAL_IF_NULL(s_upstream_address, "Upstream address not specified"); - NULLCHECK( s_upstream_address ); + FATAL_IF_NULL(s_upstream_address, "Upstream address not specified"); + NULLCHECK(s_upstream_address); - FATAL_UNLESS( - parse_ip_to_sockaddr( &out->connect_to.generic, s_upstream_address ), - "Couldn't parse upstream address '%s'", - s_upstream_address - ); + FATAL_UNLESS(parse_ip_to_sockaddr + (&out->connect_to.generic, s_upstream_address), + "Couldn't parse upstream address '%s'", + s_upstream_address); - FATAL_IF_NULL( s_upstream_port, "Upstream port not specified" ); - NULLCHECK( s_upstream_port ); - parse_port( s_upstream_port, &out->connect_to.v4 ); + FATAL_IF_NULL(s_upstream_port, "Upstream port not specified"); + NULLCHECK(s_upstream_port); + parse_port(s_upstream_port, &out->connect_to.v4); - if ( s_upstream_bind ) { - FATAL_IF_ZERO( - parse_ip_to_sockaddr( &out->connect_from.generic, s_upstream_bind ), - "Couldn't parse bind address '%s'", - s_upstream_bind - ); - out->bind = 1; - } + if (s_upstream_bind) { + FATAL_IF_ZERO(parse_ip_to_sockaddr + (&out->connect_from.generic, s_upstream_bind), + "Couldn't parse bind address '%s'", s_upstream_bind); + out->bind = 1; + } - out->listen_fd = -1; - out->downstream_fd = -1; - out->upstream_fd = -1; + out->listen_fd = -1; + out->downstream_fd = -1; + out->upstream_fd = -1; - out->prefetch = NULL; - if ( s_cache_bytes ){ - int cache_bytes = atoi( s_cache_bytes ); - /* leaving this off or setting a cache size of zero or - * less results in no cache. - */ - if ( cache_bytes >= 0 ) { - out->prefetch = prefetch_create( cache_bytes ); - } - } - - out->init.buf = xmalloc( sizeof( struct nbd_init_raw ) ); - - /* Add on the request / reply size to our malloc to accommodate both - * the struct and the data + out->prefetch = NULL; + if (s_cache_bytes) { + int cache_bytes = atoi(s_cache_bytes); + /* leaving this off or setting a cache size of zero or + * less results in no cache. */ - out->req.buf = xmalloc( NBD_MAX_SIZE + NBD_REQUEST_SIZE ); - out->rsp.buf = xmalloc( NBD_MAX_SIZE + NBD_REPLY_SIZE ); + if (cache_bytes >= 0) { + out->prefetch = prefetch_create(cache_bytes); + } + } - log_context = xmalloc( strlen(s_upstream_address) + strlen(s_upstream_port) + 2 ); - sprintf(log_context, "%s:%s", s_upstream_address, s_upstream_port); + out->init.buf = xmalloc(sizeof(struct nbd_init_raw)); - return out; + /* Add on the request / reply size to our malloc to accommodate both + * the struct and the data + */ + out->req.buf = xmalloc(NBD_MAX_SIZE + NBD_REQUEST_SIZE); + out->rsp.buf = xmalloc(NBD_MAX_SIZE + NBD_REPLY_SIZE); + + log_context = + xmalloc(strlen(s_upstream_address) + strlen(s_upstream_port) + 2); + sprintf(log_context, "%s:%s", s_upstream_address, s_upstream_port); + + return out; } -int proxy_prefetches( struct proxier* proxy ) { - NULLCHECK( proxy ); - return proxy->prefetch != NULL; -} - -int proxy_prefetch_bufsize( struct proxier* proxy ){ - NULLCHECK( proxy ); - return prefetch_size( proxy->prefetch ); -} - -void proxy_destroy( struct proxier* proxy ) +int proxy_prefetches(struct proxier *proxy) { - free( proxy->init.buf ); - free( proxy->req.buf ); - free( proxy->rsp.buf ); - prefetch_destroy( proxy->prefetch ); + NULLCHECK(proxy); + return proxy->prefetch != NULL; +} - free( proxy ); +int proxy_prefetch_bufsize(struct proxier *proxy) +{ + NULLCHECK(proxy); + return prefetch_size(proxy->prefetch); +} + +void proxy_destroy(struct proxier *proxy) +{ + free(proxy->init.buf); + free(proxy->req.buf); + free(proxy->rsp.buf); + prefetch_destroy(proxy->prefetch); + + free(proxy); } /* Shared between our two different connect_to_upstream paths */ -void proxy_finish_connect_to_upstream( struct proxier *proxy, uint64_t size, uint32_t flags ); +void proxy_finish_connect_to_upstream(struct proxier *proxy, uint64_t size, + uint32_t flags); /* Try to establish a connection to our upstream server. Return 1 on success, * 0 on failure. this is a blocking call that returns a non-blocking socket. */ -int proxy_connect_to_upstream( struct proxier* proxy ) +int proxy_connect_to_upstream(struct proxier *proxy) { - struct sockaddr* connect_from = NULL; - if ( proxy->bind ) { - connect_from = &proxy->connect_from.generic; - } + struct sockaddr *connect_from = NULL; + if (proxy->bind) { + connect_from = &proxy->connect_from.generic; + } - int fd = socket_connect( &proxy->connect_to.generic, connect_from ); - uint64_t size = 0; - uint32_t flags = 0; + int fd = socket_connect(&proxy->connect_to.generic, connect_from); + uint64_t size = 0; + uint32_t flags = 0; - if ( -1 == fd ) { - return 0; - } + if (-1 == fd) { + return 0; + } - if( !socket_nbd_read_hello( fd, &size, &flags ) ) { - WARN_IF_NEGATIVE( - sock_try_close( fd ), - "Couldn't close() after failed read of NBD hello on fd %i", fd - ); - return 0; - } + if (!socket_nbd_read_hello(fd, &size, &flags)) { + WARN_IF_NEGATIVE(sock_try_close(fd), + "Couldn't close() after failed read of NBD hello on fd %i", + fd); + return 0; + } - proxy->upstream_fd = fd; - sock_set_nonblock( fd, 1 ); - proxy_finish_connect_to_upstream( proxy, size, flags ); + proxy->upstream_fd = fd; + sock_set_nonblock(fd, 1); + proxy_finish_connect_to_upstream(proxy, size, flags); - return 1; + return 1; } /* First half of non-blocking connection to upstream. Gets as far as calling * connect() on a non-blocking socket. */ -void proxy_start_connect_to_upstream( struct proxier* proxy ) +void proxy_start_connect_to_upstream(struct proxier *proxy) { - int fd, result; - struct sockaddr* from = NULL; - struct sockaddr* to = &proxy->connect_to.generic; + int fd, result; + struct sockaddr *from = NULL; + struct sockaddr *to = &proxy->connect_to.generic; - if ( proxy->bind ) { - from = &proxy->connect_from.generic; - } + if (proxy->bind) { + from = &proxy->connect_from.generic; + } - fd = socket( to->sa_family , SOCK_STREAM, 0 ); + fd = socket(to->sa_family, SOCK_STREAM, 0); - if( fd < 0 ) { - warn( SHOW_ERRNO( "Couldn't create socket to reconnect to upstream" ) ); - return; - } - - info( "Beginning non-blocking connection to upstream on fd %i", fd ); - - if ( NULL != from ) { - if ( 0 > bind( fd, from, sockaddr_size( from ) ) ) { - warn( SHOW_ERRNO( "bind() to source address failed" ) ); - } - } - - result = sock_set_nonblock( fd, 1 ); - if ( result == -1 ) { - warn( SHOW_ERRNO( "Failed to set upstream fd %i non-blocking", fd ) ); - goto error; - } - - result = connect( fd, to, sockaddr_size( to ) ); - if ( result == -1 && errno != EINPROGRESS ) { - warn( SHOW_ERRNO( "Failed to start connect()ing to upstream!" ) ); - goto error; - } - - proxy->upstream_fd = fd; + if (fd < 0) { + warn(SHOW_ERRNO + ("Couldn't create socket to reconnect to upstream")); return; + } -error: - if ( sock_try_close( fd ) == -1 ) { - /* Non-fatal leak, although still nasty */ - warn( SHOW_ERRNO( "Failed to close fd for upstream %i", fd ) ); + info("Beginning non-blocking connection to upstream on fd %i", fd); + + if (NULL != from) { + if (0 > bind(fd, from, sockaddr_size(from))) { + warn(SHOW_ERRNO("bind() to source address failed")); } - return; + } + + result = sock_set_nonblock(fd, 1); + if (result == -1) { + warn(SHOW_ERRNO("Failed to set upstream fd %i non-blocking", fd)); + goto error; + } + + result = connect(fd, to, sockaddr_size(to)); + if (result == -1 && errno != EINPROGRESS) { + warn(SHOW_ERRNO("Failed to start connect()ing to upstream!")); + goto error; + } + + proxy->upstream_fd = fd; + return; + + error: + if (sock_try_close(fd) == -1) { + /* Non-fatal leak, although still nasty */ + warn(SHOW_ERRNO("Failed to close fd for upstream %i", fd)); + } + return; } -void proxy_finish_connect_to_upstream( struct proxier *proxy, uint64_t size, uint32_t flags ) { +void proxy_finish_connect_to_upstream(struct proxier *proxy, uint64_t size, + uint32_t flags) +{ - if ( proxy->upstream_size == 0 ) { - info( "Size of upstream image is %"PRIu64" bytes", size ); - } else if ( proxy->upstream_size != size ) { - warn( - "Size changed from %"PRIu64" to %"PRIu64" bytes", - proxy->upstream_size, size - ); + if (proxy->upstream_size == 0) { + info("Size of upstream image is %" PRIu64 " bytes", size); + } else if (proxy->upstream_size != size) { + warn("Size changed from %" PRIu64 " to %" PRIu64 " bytes", + proxy->upstream_size, size); + } + + proxy->upstream_size = size; + + if (proxy->upstream_flags == 0) { + info("Upstream transmission flags set to %" PRIu32 "", flags); + } else if (proxy->upstream_flags != flags) { + warn("Upstream transmission flags changed from %" PRIu32 " to %" + PRIu32 "", proxy->upstream_flags, flags); + } + + proxy->upstream_flags = flags; + + if (AF_UNIX != proxy->connect_to.family) { + if (sock_set_tcp_nodelay(proxy->upstream_fd, 1) == -1) { + warn(SHOW_ERRNO("Failed to set TCP_NODELAY")); } + } - proxy->upstream_size = size; + info("Connected to upstream on fd %i", proxy->upstream_fd); - if ( proxy->upstream_flags == 0 ) { - info( "Upstream transmission flags set to %"PRIu32"", flags ); - } else if ( proxy->upstream_flags != flags ) { - warn( - "Upstream transmission flags changed from %"PRIu32" to %"PRIu32"", - proxy->upstream_flags, flags - ); - } - - proxy->upstream_flags = flags; - - if ( AF_UNIX != proxy->connect_to.family ) { - if ( sock_set_tcp_nodelay( proxy->upstream_fd, 1 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) ); - } - } - - info( "Connected to upstream on fd %i", proxy->upstream_fd ); - - return; + return; } -void proxy_disconnect_from_upstream( struct proxier* proxy ) +void proxy_disconnect_from_upstream(struct proxier *proxy) { - if ( -1 != proxy->upstream_fd ) { - info("Closing upstream connection on fd %i", proxy->upstream_fd ); + if (-1 != proxy->upstream_fd) { + info("Closing upstream connection on fd %i", proxy->upstream_fd); - /* TODO: An NBD disconnect would be pleasant here */ - WARN_IF_NEGATIVE( - sock_try_close( proxy->upstream_fd ), - "Failed to close() fd %i when disconnecting from upstream", - proxy->upstream_fd - ); - proxy->upstream_fd = -1; - } + /* TODO: An NBD disconnect would be pleasant here */ + WARN_IF_NEGATIVE(sock_try_close(proxy->upstream_fd), + "Failed to close() fd %i when disconnecting from upstream", + proxy->upstream_fd); + proxy->upstream_fd = -1; + } } /** Prepares a listening socket for the NBD server, binding etc. */ -void proxy_open_listen_socket(struct proxier* params) +void proxy_open_listen_socket(struct proxier *params) { - NULLCHECK( params ); + NULLCHECK(params); - params->listen_fd = socket(params->listen_on.family, SOCK_STREAM, 0); - FATAL_IF_NEGATIVE( - params->listen_fd, SHOW_ERRNO( "Couldn't create listen socket" ) + params->listen_fd = socket(params->listen_on.family, SOCK_STREAM, 0); + FATAL_IF_NEGATIVE(params->listen_fd, + SHOW_ERRNO("Couldn't create listen socket") ); - /* Allow us to restart quickly */ - FATAL_IF_NEGATIVE( - sock_set_reuseaddr(params->listen_fd, 1), - SHOW_ERRNO( "Couldn't set SO_REUSEADDR" ) + /* Allow us to restart quickly */ + FATAL_IF_NEGATIVE(sock_set_reuseaddr(params->listen_fd, 1), + SHOW_ERRNO("Couldn't set SO_REUSEADDR") ); - if( AF_UNIX != params->listen_on.family ) { - FATAL_IF_NEGATIVE( - sock_set_tcp_nodelay(params->listen_fd, 1), - SHOW_ERRNO( "Couldn't set TCP_NODELAY" ) - ); - } + if (AF_UNIX != params->listen_on.family) { + FATAL_IF_NEGATIVE(sock_set_tcp_nodelay(params->listen_fd, 1), + SHOW_ERRNO("Couldn't set TCP_NODELAY") + ); + } - FATAL_UNLESS_ZERO( - sock_try_bind( params->listen_fd, ¶ms->listen_on.generic ), - SHOW_ERRNO( "Failed to bind to listening socket" ) + FATAL_UNLESS_ZERO(sock_try_bind + (params->listen_fd, ¶ms->listen_on.generic), + SHOW_ERRNO("Failed to bind to listening socket") ); - /* We're only serving one client at a time, hence backlog of 1 */ - FATAL_IF_NEGATIVE( - listen(params->listen_fd, 1), - SHOW_ERRNO( "Failed to listen on listening socket" ) + /* We're only serving one client at a time, hence backlog of 1 */ + FATAL_IF_NEGATIVE(listen(params->listen_fd, 1), + SHOW_ERRNO("Failed to listen on listening socket") ); - info( "Now listening for incoming connections" ); + info("Now listening for incoming connections"); - return; + return; } typedef enum { - EXIT, - WRITE_TO_DOWNSTREAM, - READ_FROM_DOWNSTREAM, - CONNECT_TO_UPSTREAM, - READ_INIT_FROM_UPSTREAM, - WRITE_TO_UPSTREAM, - READ_FROM_UPSTREAM + EXIT, + WRITE_TO_DOWNSTREAM, + READ_FROM_DOWNSTREAM, + CONNECT_TO_UPSTREAM, + READ_INIT_FROM_UPSTREAM, + WRITE_TO_UPSTREAM, + READ_FROM_UPSTREAM } proxy_session_states; -static char* proxy_session_state_names[] = { - "EXIT", - "WRITE_TO_DOWNSTREAM", - "READ_FROM_DOWNSTREAM", - "CONNECT_TO_UPSTREAM", - "READ_INIT_FROM_UPSTREAM", - "WRITE_TO_UPSTREAM", - "READ_FROM_UPSTREAM" +static char *proxy_session_state_names[] = { + "EXIT", + "WRITE_TO_DOWNSTREAM", + "READ_FROM_DOWNSTREAM", + "CONNECT_TO_UPSTREAM", + "READ_INIT_FROM_UPSTREAM", + "WRITE_TO_UPSTREAM", + "READ_FROM_UPSTREAM" }; -static inline int proxy_state_upstream( int state ) +static inline int proxy_state_upstream(int state) { - return state == CONNECT_TO_UPSTREAM || state == READ_INIT_FROM_UPSTREAM || - state == WRITE_TO_UPSTREAM || state == READ_FROM_UPSTREAM; + return state == CONNECT_TO_UPSTREAM || state == READ_INIT_FROM_UPSTREAM + || state == WRITE_TO_UPSTREAM || state == READ_FROM_UPSTREAM; } -int proxy_prefetch_for_request( struct proxier* proxy, int state ) +int proxy_prefetch_for_request(struct proxier *proxy, int state) { - NULLCHECK( proxy ); - struct nbd_request* req = &proxy->req_hdr; - struct nbd_reply* rsp = &proxy->rsp_hdr; + NULLCHECK(proxy); + struct nbd_request *req = &proxy->req_hdr; + struct nbd_reply *rsp = &proxy->rsp_hdr; - struct nbd_request_raw* req_raw = (struct nbd_request_raw*) proxy->req.buf; - struct nbd_reply_raw *rsp_raw = (struct nbd_reply_raw*) proxy->rsp.buf; + struct nbd_request_raw *req_raw = + (struct nbd_request_raw *) proxy->req.buf; + struct nbd_reply_raw *rsp_raw = + (struct nbd_reply_raw *) proxy->rsp.buf; - int is_read = req->type == REQUEST_READ; + int is_read = req->type == REQUEST_READ; - if ( is_read ) { - /* See if we can respond with what's in our prefetch - * cache */ - if ( prefetch_is_full( proxy->prefetch ) && - prefetch_contains( proxy->prefetch, req->from, req->len ) ) { - /* HUZZAH! A match! */ - debug( "Prefetch hit!" ); + if (is_read) { + /* See if we can respond with what's in our prefetch + * cache */ + if (prefetch_is_full(proxy->prefetch) && + prefetch_contains(proxy->prefetch, req->from, req->len)) { + /* HUZZAH! A match! */ + debug("Prefetch hit!"); - /* First build a reply header */ - rsp->magic = REPLY_MAGIC; - rsp->error = 0; - memcpy( &rsp->handle, &req->handle, 8 ); + /* First build a reply header */ + rsp->magic = REPLY_MAGIC; + rsp->error = 0; + memcpy(&rsp->handle, &req->handle, 8); - /* now copy it into the response */ - nbd_h2r_reply( rsp, rsp_raw ); + /* now copy it into the response */ + nbd_h2r_reply(rsp, rsp_raw); - /* and the data */ - memcpy( - proxy->rsp.buf + NBD_REPLY_SIZE, - prefetch_offset( proxy->prefetch, req->from ), - req->len - ); + /* and the data */ + memcpy(proxy->rsp.buf + NBD_REPLY_SIZE, + prefetch_offset(proxy->prefetch, req->from), req->len); - proxy->rsp.size = NBD_REPLY_SIZE + req->len; - proxy->rsp.needle = 0; + proxy->rsp.size = NBD_REPLY_SIZE + req->len; + proxy->rsp.needle = 0; - /* return early, our work here is done */ - return WRITE_TO_DOWNSTREAM; - } + /* return early, our work here is done */ + return WRITE_TO_DOWNSTREAM; } - else { - /* Safety catch. If we're sending a write request, we - * blow away the cache. This is very pessimistic, but - * it's simpler (and therefore safer) than working out - * whether we can keep it or not. - */ - debug( "Blowing away prefetch cache on type %d request.", req->type ); - prefetch_set_is_empty( proxy->prefetch ); - } - - debug( "Prefetch cache MISS!"); - - uint64_t prefetch_start = req->from; - /* We prefetch what we expect to be the next request. */ - uint64_t prefetch_end = req->from + ( req->len * 2 ); - - /* We only want to consider prefetching if we know we're not - * getting too much data back, if it's a read request, and if - * the prefetch won't try to read past the end of the file. + } else { + /* Safety catch. If we're sending a write request, we + * blow away the cache. This is very pessimistic, but + * it's simpler (and therefore safer) than working out + * whether we can keep it or not. */ - int prefetching = - req->len <= prefetch_size( proxy->prefetch ) && - is_read && - prefetch_start < prefetch_end && - prefetch_end <= proxy->upstream_size; + debug("Blowing away prefetch cache on type %d request.", + req->type); + prefetch_set_is_empty(proxy->prefetch); + } - /* We pull the request out of the proxy struct, rewrite the - * request size, and write it back. + debug("Prefetch cache MISS!"); + + uint64_t prefetch_start = req->from; + /* We prefetch what we expect to be the next request. */ + uint64_t prefetch_end = req->from + (req->len * 2); + + /* We only want to consider prefetching if we know we're not + * getting too much data back, if it's a read request, and if + * the prefetch won't try to read past the end of the file. + */ + int prefetching = + req->len <= prefetch_size(proxy->prefetch) && + is_read && + prefetch_start < prefetch_end && + prefetch_end <= proxy->upstream_size; + + /* We pull the request out of the proxy struct, rewrite the + * request size, and write it back. + */ + if (prefetching) { + proxy->is_prefetch_req = 1; + proxy->prefetch_req_orig_len = req->len; + + req->len *= 2; + + debug("Prefetching additional %" PRIu32 " bytes", + req->len - proxy->prefetch_req_orig_len); + nbd_h2r_request(req, req_raw); + } + + return state; +} + +int proxy_prefetch_for_reply(struct proxier *proxy, int state) +{ + size_t prefetched_bytes; + + if (!proxy->is_prefetch_req) { + return state; + } + + prefetched_bytes = proxy->req_hdr.len - proxy->prefetch_req_orig_len; + + debug("Prefetched additional %d bytes", prefetched_bytes); + memcpy(proxy->prefetch->buffer, + proxy->rsp.buf + proxy->prefetch_req_orig_len + NBD_REPLY_SIZE, + prefetched_bytes); + + proxy->prefetch->from = + proxy->req_hdr.from + proxy->prefetch_req_orig_len; + proxy->prefetch->len = prefetched_bytes; + + /* We've finished with proxy->req by now, so don't need to alter it to make + * it look like the request was before prefetch */ + + /* Truncate the bytes we'll write downstream */ + proxy->req_hdr.len = proxy->prefetch_req_orig_len; + proxy->rsp.size -= prefetched_bytes; + + /* And we need to reset these */ + prefetch_set_is_full(proxy->prefetch); + proxy->is_prefetch_req = 0; + + return state; +} + + + +int proxy_read_from_downstream(struct proxier *proxy, int state) +{ + ssize_t count; + + struct nbd_request_raw *request_raw = + (struct nbd_request_raw *) proxy->req.buf; + struct nbd_request *request = &(proxy->req_hdr); + +// assert( state == READ_FROM_DOWNSTREAM ); + + count = + iobuf_read(proxy->downstream_fd, &proxy->req, NBD_REQUEST_SIZE); + + if (count == -1) { + warn(SHOW_ERRNO("Couldn't read request from downstream")); + return EXIT; + } + + if (proxy->req.needle == NBD_REQUEST_SIZE) { + nbd_r2h_request(request_raw, request); + + if (request->type == REQUEST_DISCONNECT) { + info("Received disconnect request from client"); + return EXIT; + } + + /* Simple validations -- the request / reply size have already + * been taken into account in the xmalloc, so no need to worry + * about them here */ - if ( prefetching ) { - proxy->is_prefetch_req = 1; - proxy->prefetch_req_orig_len = req->len; - - req->len *= 2; - - debug( "Prefetching additional %"PRIu32" bytes", - req->len - proxy->prefetch_req_orig_len ); - nbd_h2r_request( req, req_raw ); - } - - return state; -} - -int proxy_prefetch_for_reply( struct proxier* proxy, int state ) -{ - size_t prefetched_bytes; - - if ( !proxy->is_prefetch_req ) { - return state; - } - - prefetched_bytes = proxy->req_hdr.len - proxy->prefetch_req_orig_len; - - debug( "Prefetched additional %d bytes", prefetched_bytes ); - memcpy( - proxy->prefetch->buffer, - proxy->rsp.buf + proxy->prefetch_req_orig_len + NBD_REPLY_SIZE, - prefetched_bytes - ); - - proxy->prefetch->from = proxy->req_hdr.from + proxy->prefetch_req_orig_len; - proxy->prefetch->len = prefetched_bytes; - - /* We've finished with proxy->req by now, so don't need to alter it to make - * it look like the request was before prefetch */ - - /* Truncate the bytes we'll write downstream */ - proxy->req_hdr.len = proxy->prefetch_req_orig_len; - proxy->rsp.size -= prefetched_bytes; - - /* And we need to reset these */ - prefetch_set_is_full( proxy->prefetch ); - proxy->is_prefetch_req = 0; - - return state; -} - - - -int proxy_read_from_downstream( struct proxier *proxy, int state ) -{ - ssize_t count; - - struct nbd_request_raw* request_raw = (struct nbd_request_raw*) proxy->req.buf; - struct nbd_request* request = &(proxy->req_hdr); - -// assert( state == READ_FROM_DOWNSTREAM ); - - count = iobuf_read( proxy->downstream_fd, &proxy->req, NBD_REQUEST_SIZE ); - - if ( count == -1 ) { - warn( SHOW_ERRNO( "Couldn't read request from downstream" ) ); + if (request->type == REQUEST_READ) { + if (request->len > NBD_MAX_SIZE) { + warn("NBD read request size %" PRIu32 " too large", + request->len); return EXIT; + } } + if (request->type == REQUEST_WRITE) { + if (request->len > NBD_MAX_SIZE) { + warn("NBD write request size %" PRIu32 " too large", + request->len); + return EXIT; + } - if ( proxy->req.needle == NBD_REQUEST_SIZE ) { - nbd_r2h_request( request_raw, request ); - - if ( request->type == REQUEST_DISCONNECT ) { - info( "Received disconnect request from client" ); - return EXIT; - } - - /* Simple validations -- the request / reply size have already - * been taken into account in the xmalloc, so no need to worry - * about them here - */ - if ( request->type == REQUEST_READ ) { - if ( request->len > NBD_MAX_SIZE ) { - warn( "NBD read request size %"PRIu32" too large", request->len ); - return EXIT; - } - } - if ( request->type == REQUEST_WRITE ) { - if ( request->len > NBD_MAX_SIZE ) { - warn( "NBD write request size %"PRIu32" too large", request->len ); - return EXIT; - } - - proxy->req.size += request->len; - } + proxy->req.size += request->len; } + } - if ( proxy->req.needle == proxy->req.size ) { - debug( - "Received NBD request from downstream. type=%"PRIu16" flags=%"PRIu16" from=%"PRIu64" len=%"PRIu32, - request->type, request->flags, request->from, request->len - ); + if (proxy->req.needle == proxy->req.size) { + debug("Received NBD request from downstream. type=%" PRIu16 + " flags=%" PRIu16 " from=%" PRIu64 " len=%" PRIu32, + request->type, request->flags, request->from, request->len); - /* Finished reading, so advance state. Leave size untouched so the next - * state knows how many bytes to write */ - proxy->req.needle = 0; - return WRITE_TO_UPSTREAM; - } + /* Finished reading, so advance state. Leave size untouched so the next + * state knows how many bytes to write */ + proxy->req.needle = 0; + return WRITE_TO_UPSTREAM; + } - return state; + return state; } -int proxy_continue_connecting_to_upstream( struct proxier* proxy, int state ) +int proxy_continue_connecting_to_upstream(struct proxier *proxy, int state) { - int error, result; - socklen_t len = sizeof( error ); + int error, result; + socklen_t len = sizeof(error); -// assert( state == CONNECT_TO_UPSTREAM ); +// assert( state == CONNECT_TO_UPSTREAM ); - result = getsockopt( - proxy->upstream_fd, SOL_SOCKET, SO_ERROR, &error, &len - ); + result = + getsockopt(proxy->upstream_fd, SOL_SOCKET, SO_ERROR, &error, &len); - if ( result == -1 ) { - warn( SHOW_ERRNO( "Failed to tell if connected to upstream" ) ); - return state; - } + if (result == -1) { + warn(SHOW_ERRNO("Failed to tell if connected to upstream")); + return state; + } - if ( error != 0 ) { - errno = error; - warn( SHOW_ERRNO( "Failed to connect to upstream" ) ); - return state; - } + if (error != 0) { + errno = error; + warn(SHOW_ERRNO("Failed to connect to upstream")); + return state; + } - /* Data may have changed while we were disconnected */ - prefetch_set_is_empty( proxy->prefetch ); + /* Data may have changed while we were disconnected */ + prefetch_set_is_empty(proxy->prefetch); - info( "Connected to upstream on fd %i", proxy->upstream_fd ); - return READ_INIT_FROM_UPSTREAM; + info("Connected to upstream on fd %i", proxy->upstream_fd); + return READ_INIT_FROM_UPSTREAM; } -int proxy_read_init_from_upstream( struct proxier* proxy, int state ) +int proxy_read_init_from_upstream(struct proxier *proxy, int state) { - ssize_t count; + ssize_t count; -// assert( state == READ_INIT_FROM_UPSTREAM ); +// assert( state == READ_INIT_FROM_UPSTREAM ); - count = iobuf_read( proxy->upstream_fd, &proxy->init, sizeof( struct nbd_init_raw ) ); + count = + iobuf_read(proxy->upstream_fd, &proxy->init, + sizeof(struct nbd_init_raw)); - if ( count == -1 ) { - warn( SHOW_ERRNO( "Failed to read init from upstream" ) ); - goto disconnect; + if (count == -1) { + warn(SHOW_ERRNO("Failed to read init from upstream")); + goto disconnect; + } + + if (proxy->init.needle == proxy->init.size) { + uint64_t upstream_size; + uint32_t upstream_flags; + if (!nbd_check_hello + ((struct nbd_init_raw *) proxy->init.buf, &upstream_size, + &upstream_flags)) { + warn("Upstream sent invalid init"); + goto disconnect; } - if ( proxy->init.needle == proxy->init.size ) { - uint64_t upstream_size; - uint32_t upstream_flags; - if ( !nbd_check_hello( (struct nbd_init_raw*) proxy->init.buf, &upstream_size, &upstream_flags ) ) { - warn( "Upstream sent invalid init" ); - goto disconnect; - } + /* record the flags, and log the reconnection, set TCP_NODELAY */ + proxy_finish_connect_to_upstream(proxy, upstream_size, + upstream_flags); - /* record the flags, and log the reconnection, set TCP_NODELAY */ - proxy_finish_connect_to_upstream( proxy, upstream_size, upstream_flags ); - - /* Currently, we only get disconnected from upstream (so needing to come - * here) when we have an outstanding request. If that becomes false, - * we'll need to choose the right state to return to here */ - proxy->init.needle = 0; - return WRITE_TO_UPSTREAM; - } - - return state; - -disconnect: + /* Currently, we only get disconnected from upstream (so needing to come + * here) when we have an outstanding request. If that becomes false, + * we'll need to choose the right state to return to here */ proxy->init.needle = 0; - proxy->init.size = 0; + return WRITE_TO_UPSTREAM; + } + + return state; + + disconnect: + proxy->init.needle = 0; + proxy->init.size = 0; + return CONNECT_TO_UPSTREAM; +} + +int proxy_write_to_upstream(struct proxier *proxy, int state) +{ + ssize_t count; + +// assert( state == WRITE_TO_UPSTREAM ); + + /* FIXME: We may set cork=1 multiple times as a result of this idiom. + * Not a serious problem, but we could do better + */ + if (proxy->req.needle == 0 && AF_UNIX != proxy->connect_to.family) { + if (sock_set_tcp_cork(proxy->upstream_fd, 1) == -1) { + warn(SHOW_ERRNO("Failed to set TCP_CORK")); + } + } + + count = iobuf_write(proxy->upstream_fd, &proxy->req); + + if (count == -1) { + warn(SHOW_ERRNO("Failed to send request to upstream")); + proxy->req.needle = 0; + // We're throwing the socket away so no need to uncork return CONNECT_TO_UPSTREAM; + } + + if (proxy->req.needle == proxy->req.size) { + /* Request sent. Advance to reading the response from upstream. We might + * still need req.size if reading the reply fails - we disconnect + * and resend the reply in that case - so keep it around for now. */ + proxy->req.needle = 0; + + if (AF_UNIX != proxy->connect_to.family) { + if (sock_set_tcp_cork(proxy->upstream_fd, 0) == -1) { + warn(SHOW_ERRNO("Failed to unset TCP_CORK")); + // TODO: should we return to CONNECT_TO_UPSTREAM in this instance? + } + } + + return READ_FROM_UPSTREAM; + } + + return state; } -int proxy_write_to_upstream( struct proxier* proxy, int state ) +int proxy_read_from_upstream(struct proxier *proxy, int state) { - ssize_t count; + ssize_t count; -// assert( state == WRITE_TO_UPSTREAM ); + struct nbd_reply *reply = &(proxy->rsp_hdr); + struct nbd_reply_raw *reply_raw = + (struct nbd_reply_raw *) proxy->rsp.buf; - /* FIXME: We may set cork=1 multiple times as a result of this idiom. - * Not a serious problem, but we could do better - */ - if ( proxy->req.needle == 0 && AF_UNIX != proxy->connect_to.family ) { - if ( sock_set_tcp_cork( proxy->upstream_fd, 1 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to set TCP_CORK" ) ); - } + /* We can't assume the NBD_REPLY_SIZE + req->len is what we'll get back */ + count = iobuf_read(proxy->upstream_fd, &proxy->rsp, NBD_REPLY_SIZE); + + if (count == -1) { + warn(SHOW_ERRNO("Failed to get reply from upstream")); + goto disconnect; + } + + if (proxy->rsp.needle == NBD_REPLY_SIZE) { + nbd_r2h_reply(reply_raw, reply); + + if (reply->magic != REPLY_MAGIC) { + warn("Reply magic is incorrect"); + goto disconnect; } - count = iobuf_write( proxy->upstream_fd, &proxy->req ); - - if ( count == -1 ) { - warn( SHOW_ERRNO( "Failed to send request to upstream" ) ); - proxy->req.needle = 0; - // We're throwing the socket away so no need to uncork - return CONNECT_TO_UPSTREAM; + if (proxy->req_hdr.type == REQUEST_READ) { + /* Get the read reply data too. */ + proxy->rsp.size += proxy->req_hdr.len; } + } - if ( proxy->req.needle == proxy->req.size ) { - /* Request sent. Advance to reading the response from upstream. We might - * still need req.size if reading the reply fails - we disconnect - * and resend the reply in that case - so keep it around for now. */ - proxy->req.needle = 0; - - if ( AF_UNIX != proxy->connect_to.family ) { - if ( sock_set_tcp_cork( proxy->upstream_fd, 0 ) == -1 ) { - warn( SHOW_ERRNO( "Failed to unset TCP_CORK" ) ); - // TODO: should we return to CONNECT_TO_UPSTREAM in this instance? - } - } - - return READ_FROM_UPSTREAM; - } - - return state; -} - -int proxy_read_from_upstream( struct proxier* proxy, int state ) -{ - ssize_t count; - - struct nbd_reply* reply = &(proxy->rsp_hdr); - struct nbd_reply_raw* reply_raw = (struct nbd_reply_raw*) proxy->rsp.buf; - - /* We can't assume the NBD_REPLY_SIZE + req->len is what we'll get back */ - count = iobuf_read( proxy->upstream_fd, &proxy->rsp, NBD_REPLY_SIZE ); - - if ( count == -1 ) { - warn( SHOW_ERRNO( "Failed to get reply from upstream" ) ); - goto disconnect; - } - - if ( proxy->rsp.needle == NBD_REPLY_SIZE ) { - nbd_r2h_reply( reply_raw, reply ); - - if ( reply->magic != REPLY_MAGIC ) { - warn( "Reply magic is incorrect" ); - goto disconnect; - } - - if ( proxy->req_hdr.type == REQUEST_READ ) { - /* Get the read reply data too. */ - proxy->rsp.size += proxy->req_hdr.len; - } - } - - if ( proxy->rsp.size == proxy->rsp.needle ) { - debug( "NBD reply received from upstream." ); - proxy->rsp.needle = 0; - return WRITE_TO_DOWNSTREAM; - } - - return state; - -disconnect: + if (proxy->rsp.size == proxy->rsp.needle) { + debug("NBD reply received from upstream."); proxy->rsp.needle = 0; - proxy->rsp.size = 0; - return CONNECT_TO_UPSTREAM; + return WRITE_TO_DOWNSTREAM; + } + + return state; + + disconnect: + proxy->rsp.needle = 0; + proxy->rsp.size = 0; + return CONNECT_TO_UPSTREAM; } -int proxy_write_to_downstream( struct proxier* proxy, int state ) +int proxy_write_to_downstream(struct proxier *proxy, int state) { - ssize_t count; + ssize_t count; -// assert( state == WRITE_TO_DOWNSTREAM ); +// assert( state == WRITE_TO_DOWNSTREAM ); - if ( !proxy->hello_sent ) { - info( "Writing init to downstream" ); + if (!proxy->hello_sent) { + info("Writing init to downstream"); + } + + count = iobuf_write(proxy->downstream_fd, &proxy->rsp); + + if (count == -1) { + warn(SHOW_ERRNO("Failed to write to downstream")); + return EXIT; + } + + if (proxy->rsp.needle == proxy->rsp.size) { + if (!proxy->hello_sent) { + info("Hello message sent to client"); + proxy->hello_sent = 1; + } else { + debug("Reply sent"); + proxy->req_count++; } - count = iobuf_write( proxy->downstream_fd, &proxy->rsp ); + /* We're done with the request & response buffers now */ + proxy->req.size = 0; + proxy->req.needle = 0; + proxy->rsp.size = 0; + proxy->rsp.needle = 0; + return READ_FROM_DOWNSTREAM; + } - if ( count == -1 ) { - warn( SHOW_ERRNO( "Failed to write to downstream" ) ); - return EXIT; - } - - if ( proxy->rsp.needle == proxy->rsp.size ) { - if ( !proxy->hello_sent ) { - info( "Hello message sent to client" ); - proxy->hello_sent = 1; - } else { - debug( "Reply sent" ); - proxy->req_count++; - } - - /* We're done with the request & response buffers now */ - proxy->req.size = 0; - proxy->req.needle = 0; - proxy->rsp.size = 0; - proxy->rsp.needle = 0; - return READ_FROM_DOWNSTREAM; - } - - return state; + return state; } /* Non-blocking proxy session. Simple(ish) state machine. We read from d/s until @@ -692,305 +689,300 @@ int proxy_write_to_downstream( struct proxier* proxy, int state ) * This is the second-simplest NBD proxy I can think of. The first version was * non-blocking I/O, but it was getting impossible to manage exceptional stuff */ -void proxy_session( struct proxier* proxy ) +void proxy_session(struct proxier *proxy) { - uint64_t state_started = monotonic_time_ms(); - int old_state = EXIT; - int state; - int connect_to_upstream_cooldown = 0; + uint64_t state_started = monotonic_time_ms(); + int old_state = EXIT; + int state; + int connect_to_upstream_cooldown = 0; - /* First action: Write hello to downstream */ - nbd_hello_to_buf( (struct nbd_init_raw *) proxy->rsp.buf, proxy->upstream_size, proxy->upstream_flags ); - proxy->rsp.size = sizeof( struct nbd_init_raw ); - proxy->rsp.needle = 0; - state = WRITE_TO_DOWNSTREAM; + /* First action: Write hello to downstream */ + nbd_hello_to_buf((struct nbd_init_raw *) proxy->rsp.buf, + proxy->upstream_size, proxy->upstream_flags); + proxy->rsp.size = sizeof(struct nbd_init_raw); + proxy->rsp.needle = 0; + state = WRITE_TO_DOWNSTREAM; - info( "Beginning proxy session on fd %i", proxy->downstream_fd ); + info("Beginning proxy session on fd %i", proxy->downstream_fd); - while( state != EXIT ) { + while (state != EXIT) { - struct timeval select_timeout = { - .tv_sec = 0, - .tv_usec = 0 - }; + struct timeval select_timeout = { + .tv_sec = 0, + .tv_usec = 0 + }; - struct timeval *select_timeout_ptr = NULL; + struct timeval *select_timeout_ptr = NULL; - int result; /* used by select() */ + int result; /* used by select() */ - fd_set rfds; - fd_set wfds; + fd_set rfds; + fd_set wfds; - FD_ZERO( &rfds ); - FD_ZERO( &wfds ); + FD_ZERO(&rfds); + FD_ZERO(&wfds); - if ( state != old_state ) { - state_started = monotonic_time_ms(); + if (state != old_state) { + state_started = monotonic_time_ms(); - debug( - "State transition from %s to %s", - proxy_session_state_names[old_state], - proxy_session_state_names[state] - ); - } else { - debug( "Proxy is in state %s", proxy_session_state_names[state], state ); - } - - old_state = state; - - switch( state ) { - case READ_FROM_DOWNSTREAM: - FD_SET( proxy->downstream_fd, &rfds ); - break; - case WRITE_TO_DOWNSTREAM: - FD_SET( proxy->downstream_fd, &wfds ); - break; - case WRITE_TO_UPSTREAM: - select_timeout.tv_sec = 15; - FD_SET(proxy->upstream_fd, &wfds ); - break; - case CONNECT_TO_UPSTREAM: - /* upstream_fd is now -1 */ - proxy_disconnect_from_upstream( proxy ); - - if ( connect_to_upstream_cooldown ) { - connect_to_upstream_cooldown = 0; - select_timeout.tv_sec = 3; - } else { - proxy_start_connect_to_upstream( proxy ); - - if ( proxy->upstream_fd == -1 ) { - warn( SHOW_ERRNO( "Error acquiring socket to upstream" ) ); - continue; - } - FD_SET( proxy->upstream_fd, &wfds ); - select_timeout.tv_sec = 15; - } - break; - case READ_INIT_FROM_UPSTREAM: - case READ_FROM_UPSTREAM: - select_timeout.tv_sec = 15; - FD_SET( proxy->upstream_fd, &rfds ); - break; - }; - - if ( select_timeout.tv_sec > 0 ) { - select_timeout_ptr = &select_timeout; - } - - result = sock_try_select( FD_SETSIZE, &rfds, &wfds, NULL, select_timeout_ptr ); - - if ( result == -1 ) { - warn( SHOW_ERRNO( "select() failed: " ) ); - break; - } - - /* Happens after failed reconnect. Avoid SIGBUS on FD_ISSET() */ - if ( proxy->upstream_fd == -1 ) { - continue; - } - - switch( state ) { - case READ_FROM_DOWNSTREAM: - if ( FD_ISSET( proxy->downstream_fd, &rfds ) ) { - state = proxy_read_from_downstream( proxy, state ); - /* Check if we can fulfil the request from prefetch, or - * rewrite the request to fill the prefetch buffer if needed - */ - if ( proxy_prefetches( proxy ) && state == WRITE_TO_UPSTREAM ) { - state = proxy_prefetch_for_request( proxy, state ); - } - } - break; - case CONNECT_TO_UPSTREAM: - if ( FD_ISSET( proxy->upstream_fd, &wfds ) ) { - state = proxy_continue_connecting_to_upstream( proxy, state ); - } - /* Leaving state untouched will retry connecting to upstream - - * so introduce a bit of sleep */ - if ( state == CONNECT_TO_UPSTREAM ) { - connect_to_upstream_cooldown = 1; - } - - break; - case READ_INIT_FROM_UPSTREAM: - state = proxy_read_init_from_upstream( proxy, state ); - - if ( state == CONNECT_TO_UPSTREAM ) { - connect_to_upstream_cooldown = 1; - } - - break; - case WRITE_TO_UPSTREAM: - if ( FD_ISSET( proxy->upstream_fd, &wfds ) ) { - state = proxy_write_to_upstream( proxy, state ); - } - break; - case READ_FROM_UPSTREAM: - if ( FD_ISSET( proxy->upstream_fd, &rfds ) ) { - state = proxy_read_from_upstream( proxy, state ); - } - /* Fill the prefetch buffer and rewrite the reply, if needed */ - if ( proxy_prefetches( proxy ) && state == WRITE_TO_DOWNSTREAM ) { - state = proxy_prefetch_for_reply( proxy, state ); - } - break; - case WRITE_TO_DOWNSTREAM: - if ( FD_ISSET( proxy->downstream_fd, &wfds ) ) { - state = proxy_write_to_downstream( proxy, state ); - } - break; - } - - /* In these states, we're interested in restarting after a timeout. - */ - if ( old_state == state && proxy_state_upstream( state ) ) { - if ( ( monotonic_time_ms() ) - state_started > UPSTREAM_TIMEOUT ) { - warn( - "Timed out in state %s while communicating with upstream", - proxy_session_state_names[state] - ); - state = CONNECT_TO_UPSTREAM; - - /* Since we've timed out, we won't have gone through the timeout logic - * in the various state handlers that resets these appropriately... */ - proxy->init.size = 0; - proxy->init.needle = 0; - proxy->rsp.size = 0; - proxy->rsp.needle = 0; - } - } + debug("State transition from %s to %s", + proxy_session_state_names[old_state], + proxy_session_state_names[state] + ); + } else { + debug("Proxy is in state %s", proxy_session_state_names[state], + state); } - info( - "Finished proxy session on fd %i after %"PRIu64" successful request(s)", - proxy->downstream_fd, proxy->req_count - ); + old_state = state; - /* Reset these two for the next session */ - proxy->req_count = 0; - proxy->hello_sent = 0; + switch (state) { + case READ_FROM_DOWNSTREAM: + FD_SET(proxy->downstream_fd, &rfds); + break; + case WRITE_TO_DOWNSTREAM: + FD_SET(proxy->downstream_fd, &wfds); + break; + case WRITE_TO_UPSTREAM: + select_timeout.tv_sec = 15; + FD_SET(proxy->upstream_fd, &wfds); + break; + case CONNECT_TO_UPSTREAM: + /* upstream_fd is now -1 */ + proxy_disconnect_from_upstream(proxy); - return; + if (connect_to_upstream_cooldown) { + connect_to_upstream_cooldown = 0; + select_timeout.tv_sec = 3; + } else { + proxy_start_connect_to_upstream(proxy); + + if (proxy->upstream_fd == -1) { + warn(SHOW_ERRNO("Error acquiring socket to upstream")); + continue; + } + FD_SET(proxy->upstream_fd, &wfds); + select_timeout.tv_sec = 15; + } + break; + case READ_INIT_FROM_UPSTREAM: + case READ_FROM_UPSTREAM: + select_timeout.tv_sec = 15; + FD_SET(proxy->upstream_fd, &rfds); + break; + }; + + if (select_timeout.tv_sec > 0) { + select_timeout_ptr = &select_timeout; + } + + result = + sock_try_select(FD_SETSIZE, &rfds, &wfds, NULL, + select_timeout_ptr); + + if (result == -1) { + warn(SHOW_ERRNO("select() failed: ")); + break; + } + + /* Happens after failed reconnect. Avoid SIGBUS on FD_ISSET() */ + if (proxy->upstream_fd == -1) { + continue; + } + + switch (state) { + case READ_FROM_DOWNSTREAM: + if (FD_ISSET(proxy->downstream_fd, &rfds)) { + state = proxy_read_from_downstream(proxy, state); + /* Check if we can fulfil the request from prefetch, or + * rewrite the request to fill the prefetch buffer if needed + */ + if (proxy_prefetches(proxy) && state == WRITE_TO_UPSTREAM) { + state = proxy_prefetch_for_request(proxy, state); + } + } + break; + case CONNECT_TO_UPSTREAM: + if (FD_ISSET(proxy->upstream_fd, &wfds)) { + state = + proxy_continue_connecting_to_upstream(proxy, state); + } + /* Leaving state untouched will retry connecting to upstream - + * so introduce a bit of sleep */ + if (state == CONNECT_TO_UPSTREAM) { + connect_to_upstream_cooldown = 1; + } + + break; + case READ_INIT_FROM_UPSTREAM: + state = proxy_read_init_from_upstream(proxy, state); + + if (state == CONNECT_TO_UPSTREAM) { + connect_to_upstream_cooldown = 1; + } + + break; + case WRITE_TO_UPSTREAM: + if (FD_ISSET(proxy->upstream_fd, &wfds)) { + state = proxy_write_to_upstream(proxy, state); + } + break; + case READ_FROM_UPSTREAM: + if (FD_ISSET(proxy->upstream_fd, &rfds)) { + state = proxy_read_from_upstream(proxy, state); + } + /* Fill the prefetch buffer and rewrite the reply, if needed */ + if (proxy_prefetches(proxy) && state == WRITE_TO_DOWNSTREAM) { + state = proxy_prefetch_for_reply(proxy, state); + } + break; + case WRITE_TO_DOWNSTREAM: + if (FD_ISSET(proxy->downstream_fd, &wfds)) { + state = proxy_write_to_downstream(proxy, state); + } + break; + } + + /* In these states, we're interested in restarting after a timeout. + */ + if (old_state == state && proxy_state_upstream(state)) { + if ((monotonic_time_ms()) - state_started > UPSTREAM_TIMEOUT) { + warn("Timed out in state %s while communicating with upstream", proxy_session_state_names[state] + ); + state = CONNECT_TO_UPSTREAM; + + /* Since we've timed out, we won't have gone through the timeout logic + * in the various state handlers that resets these appropriately... */ + proxy->init.size = 0; + proxy->init.needle = 0; + proxy->rsp.size = 0; + proxy->rsp.needle = 0; + } + } + } + + info("Finished proxy session on fd %i after %" PRIu64 + " successful request(s)", proxy->downstream_fd, proxy->req_count); + + /* Reset these two for the next session */ + proxy->req_count = 0; + proxy->hello_sent = 0; + + return; } /** Accept an NBD socket connection, dispatch appropriately */ -int proxy_accept( struct proxier* params ) +int proxy_accept(struct proxier *params) { - NULLCHECK( params ); + NULLCHECK(params); - int client_fd; - fd_set fds; + int client_fd; + fd_set fds; - union mysockaddr client_address; - socklen_t socklen = sizeof( client_address ); + union mysockaddr client_address; + socklen_t socklen = sizeof(client_address); - info( "Waiting for client connection" ); + info("Waiting for client connection"); - FD_ZERO(&fds); - FD_SET(params->listen_fd, &fds); + FD_ZERO(&fds); + FD_SET(params->listen_fd, &fds); - FATAL_IF_NEGATIVE( - sock_try_select(FD_SETSIZE, &fds, NULL, NULL, NULL), - SHOW_ERRNO( "select() failed" ) + FATAL_IF_NEGATIVE(sock_try_select(FD_SETSIZE, &fds, NULL, NULL, NULL), + SHOW_ERRNO("select() failed") ); - if ( FD_ISSET( params->listen_fd, &fds ) ) { - client_fd = accept( params->listen_fd, &client_address.generic, &socklen ); + if (FD_ISSET(params->listen_fd, &fds)) { + client_fd = + accept(params->listen_fd, &client_address.generic, &socklen); - if ( client_address.family != AF_UNIX ) { - if ( sock_set_tcp_nodelay(client_fd, 1) == -1 ) { - warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) ); - } - } - - info( "Accepted nbd client socket fd %d", client_fd ); - sock_set_nonblock( client_fd, 1 ); - params->downstream_fd = client_fd; - proxy_session( params ); - - WARN_IF_NEGATIVE( - sock_try_close( params->downstream_fd ), - "Couldn't close() downstram fd %i after proxy session", - params->downstream_fd - ); - params->downstream_fd = -1; + if (client_address.family != AF_UNIX) { + if (sock_set_tcp_nodelay(client_fd, 1) == -1) { + warn(SHOW_ERRNO("Failed to set TCP_NODELAY")); + } } - return 1; /* We actually expect to be interrupted by signal handlers */ + info("Accepted nbd client socket fd %d", client_fd); + sock_set_nonblock(client_fd, 1); + params->downstream_fd = client_fd; + proxy_session(params); + + WARN_IF_NEGATIVE(sock_try_close(params->downstream_fd), + "Couldn't close() downstram fd %i after proxy session", + params->downstream_fd); + params->downstream_fd = -1; + } + + return 1; /* We actually expect to be interrupted by signal handlers */ } -void proxy_accept_loop( struct proxier* params ) +void proxy_accept_loop(struct proxier *params) { - NULLCHECK( params ); - while( proxy_accept( params ) ); + NULLCHECK(params); + while (proxy_accept(params)); } /** Closes sockets */ -void proxy_cleanup( struct proxier* proxy ) +void proxy_cleanup(struct proxier *proxy) { - NULLCHECK( proxy ); + NULLCHECK(proxy); - info( "Cleaning up" ); + info("Cleaning up"); - if ( -1 != proxy->listen_fd ) { + if (-1 != proxy->listen_fd) { - if ( AF_UNIX == proxy->listen_on.family ) { - if ( -1 == unlink( proxy->listen_on.un.sun_path ) ) { - warn( SHOW_ERRNO( "Failed to unlink %s", proxy->listen_on.un.sun_path ) ); - } - } - - WARN_IF_NEGATIVE( - sock_try_close( proxy->listen_fd ), - SHOW_ERRNO( "Failed to close() listen fd %i", proxy->listen_fd ) - ); - proxy->listen_fd = -1; + if (AF_UNIX == proxy->listen_on.family) { + if (-1 == unlink(proxy->listen_on.un.sun_path)) { + warn(SHOW_ERRNO + ("Failed to unlink %s", + proxy->listen_on.un.sun_path)); + } } - if ( -1 != proxy->downstream_fd ) { - WARN_IF_NEGATIVE( - sock_try_close( proxy->downstream_fd ), - SHOW_ERRNO( - "Failed to close() downstream fd %i", proxy->downstream_fd - ) - ); - proxy->downstream_fd = -1; - } + WARN_IF_NEGATIVE(sock_try_close(proxy->listen_fd), + SHOW_ERRNO("Failed to close() listen fd %i", + proxy->listen_fd) + ); + proxy->listen_fd = -1; + } - if ( -1 != proxy->upstream_fd ) { - WARN_IF_NEGATIVE( - sock_try_close( proxy->upstream_fd ), - SHOW_ERRNO( - "Failed to close() upstream fd %i", proxy->upstream_fd - ) - ); - proxy->upstream_fd = -1; - } + if (-1 != proxy->downstream_fd) { + WARN_IF_NEGATIVE(sock_try_close(proxy->downstream_fd), + SHOW_ERRNO("Failed to close() downstream fd %i", + proxy->downstream_fd) + ); + proxy->downstream_fd = -1; + } - info( "Cleanup done" ); + if (-1 != proxy->upstream_fd) { + WARN_IF_NEGATIVE(sock_try_close(proxy->upstream_fd), + SHOW_ERRNO("Failed to close() upstream fd %i", + proxy->upstream_fd) + ); + proxy->upstream_fd = -1; + } + + info("Cleanup done"); } /** Full lifecycle of the proxier */ -int do_proxy( struct proxier* params ) +int do_proxy(struct proxier *params) { - NULLCHECK( params ); + NULLCHECK(params); - info( "Ensuring upstream server is open" ); + info("Ensuring upstream server is open"); - if ( !proxy_connect_to_upstream( params ) ) { - warn( "Couldn't connect to upstream server during initialization, exiting" ); - proxy_cleanup( params ); - return 1; - }; + if (!proxy_connect_to_upstream(params)) { + warn("Couldn't connect to upstream server during initialization, exiting"); + proxy_cleanup(params); + return 1; + }; - proxy_open_listen_socket( params ); - proxy_accept_loop( params ); - proxy_cleanup( params ); + proxy_open_listen_socket(params); + proxy_accept_loop(params); + proxy_cleanup(params); - return 0; + return 0; } - diff --git a/src/proxy/proxy.h b/src/proxy/proxy.h index 4be93d5..3652350 100644 --- a/src/proxy/proxy.h +++ b/src/proxy/proxy.h @@ -10,7 +10,7 @@ #include "self_pipe.h" #ifdef PREFETCH - #include "prefetch.h" +#include "prefetch.h" #endif /** UPSTREAM_TIMEOUT @@ -21,80 +21,77 @@ struct proxier { /** address/port to bind to */ - union mysockaddr listen_on; + union mysockaddr listen_on; /** address/port to connect to */ - union mysockaddr connect_to; + union mysockaddr connect_to; /** address to bind to when making outgoing connections */ - union mysockaddr connect_from; - int bind; /* Set to true if we should use it */ + union mysockaddr connect_from; + int bind; /* Set to true if we should use it */ - /* The socket we listen() on and accept() against */ - int listen_fd; + /* The socket we listen() on and accept() against */ + int listen_fd; - /* The socket returned by accept() that we receive requests from and send - * responses to - */ - int downstream_fd; + /* The socket returned by accept() that we receive requests from and send + * responses to + */ + int downstream_fd; - /* The socket returned by connect() that we send requests to and receive - * responses from - */ - int upstream_fd; + /* The socket returned by connect() that we send requests to and receive + * responses from + */ + int upstream_fd; - /* This is the size we advertise to the downstream server */ - uint64_t upstream_size; + /* This is the size we advertise to the downstream server */ + uint64_t upstream_size; - /* These are the transmission flags sent as part of the handshake */ - uint32_t upstream_flags; + /* These are the transmission flags sent as part of the handshake */ + uint32_t upstream_flags; - /* We transform the raw request header into here */ - struct nbd_request req_hdr; + /* We transform the raw request header into here */ + struct nbd_request req_hdr; - /* We transform the raw reply header into here */ - struct nbd_reply rsp_hdr; + /* We transform the raw reply header into here */ + struct nbd_reply rsp_hdr; - /* Used for our non-blocking negotiation with upstream. TODO: maybe use - * for downstream as well ( we currently overload rsp ) */ - struct iobuf init; + /* Used for our non-blocking negotiation with upstream. TODO: maybe use + * for downstream as well ( we currently overload rsp ) */ + struct iobuf init; - /* The current NBD request from downstream */ - struct iobuf req; + /* The current NBD request from downstream */ + struct iobuf req; - /* The current NBD reply from upstream */ - struct iobuf rsp; + /* The current NBD reply from upstream */ + struct iobuf rsp; - /* It's starting to feel like we need an object for a single proxy session. - * These two track how many requests we've sent so far, and whether the - * NBD_INIT code has been sent to the client yet. - */ - uint64_t req_count; - int hello_sent; + /* It's starting to feel like we need an object for a single proxy session. + * These two track how many requests we've sent so far, and whether the + * NBD_INIT code has been sent to the client yet. + */ + uint64_t req_count; + int hello_sent; /** These are only used if we pass --cache on the command line */ - /* While the in-flight request has been munged by prefetch, these two are - * set to true, and the original length of the request, respectively */ - int is_prefetch_req; - uint32_t prefetch_req_orig_len; + /* While the in-flight request has been munged by prefetch, these two are + * set to true, and the original length of the request, respectively */ + int is_prefetch_req; + uint32_t prefetch_req_orig_len; - /* And here, we actually store the prefetched data once it's returned */ - struct prefetch *prefetch; + /* And here, we actually store the prefetched data once it's returned */ + struct prefetch *prefetch; /** */ }; -struct proxier* proxy_create( - char* s_downstream_address, - char* s_downstream_port, - char* s_upstream_address, - char* s_upstream_port, - char* s_upstream_bind, - char* s_cache_bytes); -int do_proxy( struct proxier* proxy ); -void proxy_cleanup( struct proxier* proxy ); -void proxy_destroy( struct proxier* proxy ); +struct proxier *proxy_create(char *s_downstream_address, + char *s_downstream_port, + char *s_upstream_address, + char *s_upstream_port, + char *s_upstream_bind, char *s_cache_bytes); +int do_proxy(struct proxier *proxy); +void proxy_cleanup(struct proxier *proxy); +void proxy_destroy(struct proxier *proxy); #endif - diff --git a/src/server/acl.c b/src/server/acl.c index eb605a9..67f76f2 100644 --- a/src/server/acl.c +++ b/src/server/acl.c @@ -6,103 +6,104 @@ #include "acl.h" -struct acl * acl_create( int len, char ** lines, int default_deny ) +struct acl *acl_create(int len, char **lines, int default_deny) { - struct acl * acl; + struct acl *acl; - acl = (struct acl *)xmalloc( sizeof( struct acl ) ); - acl->len = parse_acl( &acl->entries, len, lines ); - acl->default_deny = default_deny; - return acl; + acl = (struct acl *) xmalloc(sizeof(struct acl)); + acl->len = parse_acl(&acl->entries, len, lines); + acl->default_deny = default_deny; + return acl; } -static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 }; +static int testmasks[9] = { 0, 128, 192, 224, 240, 248, 252, 254, 255 }; /** Test whether AF_INET or AF_INET6 sockaddr is included in the given access * control list, returning 1 if it is, and 0 if not. */ -static int is_included_in_acl(int list_length, struct ip_and_mask (*list)[], union mysockaddr* test) +static int is_included_in_acl(int list_length, + struct ip_and_mask (*list)[], + union mysockaddr *test) { - NULLCHECK( test ); + NULLCHECK(test); - int i; + int i; - for (i=0; i < list_length; i++) { - struct ip_and_mask *entry = &(*list)[i]; - int testbits; - unsigned char *raw_address1 = NULL, *raw_address2 = NULL; + for (i = 0; i < list_length; i++) { + struct ip_and_mask *entry = &(*list)[i]; + int testbits; + unsigned char *raw_address1 = NULL, *raw_address2 = NULL; - debug("checking acl entry %d (%d/%d)", i, test->generic.sa_family, entry->ip.family); + debug("checking acl entry %d (%d/%d)", i, test->generic.sa_family, + entry->ip.family); - if (test->generic.sa_family != entry->ip.family) { - continue; - } - - if (test->generic.sa_family == AF_INET) { - debug("it's an AF_INET"); - raw_address1 = (unsigned char*) &test->v4.sin_addr; - raw_address2 = (unsigned char*) &entry->ip.v4.sin_addr; - } - else if (test->generic.sa_family == AF_INET6) { - debug("it's an AF_INET6"); - raw_address1 = (unsigned char*) &test->v6.sin6_addr; - raw_address2 = (unsigned char*) &entry->ip.v6.sin6_addr; - } - else { - fatal( "Can't check an ACL for this address type." ); - } - - debug("testbits=%d", entry->mask); - - for (testbits = entry->mask; testbits > 0; testbits -= 8) { - debug("testbits=%d, c1=%02x, c2=%02x", testbits, raw_address1[0], raw_address2[0]); - if (testbits >= 8) { - if (raw_address1[0] != raw_address2[0]) { goto no_match; } - } - else { - if ((raw_address1[0] & testmasks[testbits%8]) != - (raw_address2[0] & testmasks[testbits%8]) ) { - goto no_match; - } - } - - raw_address1++; - raw_address2++; - } - - return 1; - - no_match: ; - debug("no match"); + if (test->generic.sa_family != entry->ip.family) { + continue; } - return 0; -} - -int acl_includes( struct acl * acl, union mysockaddr * addr ) -{ - NULLCHECK( acl ); - - if ( 0 == acl->len ) { - return !( acl->default_deny ); + if (test->generic.sa_family == AF_INET) { + debug("it's an AF_INET"); + raw_address1 = (unsigned char *) &test->v4.sin_addr; + raw_address2 = (unsigned char *) &entry->ip.v4.sin_addr; + } else if (test->generic.sa_family == AF_INET6) { + debug("it's an AF_INET6"); + raw_address1 = (unsigned char *) &test->v6.sin6_addr; + raw_address2 = (unsigned char *) &entry->ip.v6.sin6_addr; + } else { + fatal("Can't check an ACL for this address type."); } - else { - return is_included_in_acl( acl->len, acl->entries, addr ); + + debug("testbits=%d", entry->mask); + + for (testbits = entry->mask; testbits > 0; testbits -= 8) { + debug("testbits=%d, c1=%02x, c2=%02x", testbits, + raw_address1[0], raw_address2[0]); + if (testbits >= 8) { + if (raw_address1[0] != raw_address2[0]) { + goto no_match; + } + } else { + if ((raw_address1[0] & testmasks[testbits % 8]) != + (raw_address2[0] & testmasks[testbits % 8])) { + goto no_match; + } + } + + raw_address1++; + raw_address2++; } + + return 1; + + no_match:; + debug("no match"); + } + + return 0; } -int acl_default_deny( struct acl * acl ) +int acl_includes(struct acl *acl, union mysockaddr *addr) { - NULLCHECK( acl ); - return acl->default_deny; + NULLCHECK(acl); + + if (0 == acl->len) { + return !(acl->default_deny); + } else { + return is_included_in_acl(acl->len, acl->entries, addr); + } } -void acl_destroy( struct acl * acl ) +int acl_default_deny(struct acl *acl) { - free( acl->entries ); - acl->len = 0; - acl->entries = NULL; - free( acl ); + NULLCHECK(acl); + return acl->default_deny; } +void acl_destroy(struct acl *acl) +{ + free(acl->entries); + acl->len = 0; + acl->entries = NULL; + free(acl); +} diff --git a/src/server/acl.h b/src/server/acl.h index 8c4af3c..7f40677 100644 --- a/src/server/acl.h +++ b/src/server/acl.h @@ -4,9 +4,9 @@ #include "parse.h" struct acl { - int len; - int default_deny; - struct ip_and_mask (*entries)[]; + int len; + int default_deny; + struct ip_and_mask (*entries)[]; }; /** Allocate a new acl structure, parsing the given lines to sockaddr @@ -17,21 +17,21 @@ struct acl { * default_deny controls the behaviour of an empty list: if true, all * requests will be denied. If true, all requests will be accepted. */ -struct acl * acl_create( int len, char **lines, int default_deny ); +struct acl *acl_create(int len, char **lines, int default_deny); /** Check to see whether an address is allowed by an acl. * See acl_create for how the default_deny setting affects this. */ -int acl_includes( struct acl *, union mysockaddr *); +int acl_includes(struct acl *, union mysockaddr *); /** Get the default_deny status */ -int acl_default_deny( struct acl * ); +int acl_default_deny(struct acl *); /** Free the acl structure and the internal acl entries table. */ -void acl_destroy( struct acl * ); +void acl_destroy(struct acl *); #endif diff --git a/src/server/bitset.h b/src/server/bitset.h index ed0ffd2..bb64577 100644 --- a/src/server/bitset.h +++ b/src/server/bitset.h @@ -12,8 +12,8 @@ * poking at the bits directly without using these * accessors/macros */ -typedef uint64_t bitfield_word_t; -typedef bitfield_word_t * bitfield_p; +typedef uint64_t bitfield_word_t; +typedef bitfield_word_t *bitfield_p; #define BITFIELD_WORD_SIZE sizeof(bitfield_word_t) #define BITS_PER_WORD (BITFIELD_WORD_SIZE * 8) @@ -30,65 +30,78 @@ typedef bitfield_word_t * bitfield_p; ((_bytes + (BITFIELD_WORD_SIZE-1)) / BITFIELD_WORD_SIZE) /** Return the bit value ''idx'' in array ''b'' */ -static inline int bit_get(bitfield_p b, uint64_t idx) { - return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD-1))) & 1; +static inline int bit_get(bitfield_p b, uint64_t idx) +{ + return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD - 1))) & 1; } /** Return 1 if the bit at ''idx'' in array ''b'' is set */ -static inline int bit_is_set(bitfield_p b, uint64_t idx) { - return bit_get(b, idx); +static inline int bit_is_set(bitfield_p b, uint64_t idx) +{ + return bit_get(b, idx); } + /** Return 1 if the bit at ''idx'' in array ''b'' is clear */ -static inline int bit_is_clear(bitfield_p b, uint64_t idx) { - return !bit_get(b, idx); +static inline int bit_is_clear(bitfield_p b, uint64_t idx) +{ + return !bit_get(b, idx); } + /** Tests whether the bit at ''idx'' in array ''b'' has value ''value'' */ -static inline int bit_has_value(bitfield_p b, uint64_t idx, int value) { - return bit_get(b, idx) == !!value; +static inline int bit_has_value(bitfield_p b, uint64_t idx, int value) +{ + return bit_get(b, idx) == ! !value; } + /** Sets the bit ''idx'' in array ''b'' */ -static inline void bit_set(bitfield_p b, uint64_t idx) { - BIT_WORD(b, idx) |= BIT_MASK(idx); +static inline void bit_set(bitfield_p b, uint64_t idx) +{ + BIT_WORD(b, idx) |= BIT_MASK(idx); } + /** Clears the bit ''idx'' in array ''b'' */ -static inline void bit_clear(bitfield_p b, uint64_t idx) { - BIT_WORD(b, idx) &= ~BIT_MASK(idx); +static inline void bit_clear(bitfield_p b, uint64_t idx) +{ + BIT_WORD(b, idx) &= ~BIT_MASK(idx); } + /** Sets ''len'' bits in array ''b'' starting at offset ''from'' */ static inline void bit_set_range(bitfield_p b, uint64_t from, uint64_t len) { - for ( ; (from % BITS_PER_WORD) != 0 && len > 0 ; len-- ) { - bit_set( b, from++ ); - } + for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) { + bit_set(b, from++); + } - if (len >= BITS_PER_WORD) { - memset(&BIT_WORD(b, from), 0xff, len / 8 ); - from += len; - len = len % BITS_PER_WORD; - from -= len; - } + if (len >= BITS_PER_WORD) { + memset(&BIT_WORD(b, from), 0xff, len / 8); + from += len; + len = len % BITS_PER_WORD; + from -= len; + } - for ( ; len > 0 ; len-- ) { - bit_set( b, from++ ); - } + for (; len > 0; len--) { + bit_set(b, from++); + } } + /** Clears ''len'' bits in array ''b'' starting at offset ''from'' */ -static inline void bit_clear_range(bitfield_p b, uint64_t from, uint64_t len) +static inline void bit_clear_range(bitfield_p b, uint64_t from, + uint64_t len) { - for ( ; (from % BITS_PER_WORD) != 0 && len > 0 ; len-- ) { - bit_clear( b, from++ ); - } + for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) { + bit_clear(b, from++); + } - if (len >= BITS_PER_WORD) { - memset(&BIT_WORD(b, from), 0, len / 8 ); - from += len; - len = len % BITS_PER_WORD; - from -= len; - } + if (len >= BITS_PER_WORD) { + memset(&BIT_WORD(b, from), 0, len / 8); + from += len; + len = len % BITS_PER_WORD; + from -= len; + } - for ( ; len > 0 ; len-- ) { - bit_clear( b, from++ ); - } + for (; len > 0; len--) { + bit_clear(b, from++); + } } /** Counts the number of contiguous bits in array ''b'', starting at ''from'' @@ -96,52 +109,54 @@ static inline void bit_clear_range(bitfield_p b, uint64_t from, uint64_t len) * bits that are the same as the first one specified. If ''run_is_set'' is * non-NULL, the value of that bit is placed into it. */ -static inline uint64_t bit_run_count(bitfield_p b, uint64_t from, uint64_t len, int *run_is_set) { - uint64_t count = 0; - int first_value = bit_get(b, from); - bitfield_word_t word_match = first_value ? -1 : 0; +static inline uint64_t bit_run_count(bitfield_p b, uint64_t from, + uint64_t len, int *run_is_set) +{ + uint64_t count = 0; + int first_value = bit_get(b, from); + bitfield_word_t word_match = first_value ? -1 : 0; - if ( run_is_set != NULL ) { - *run_is_set = first_value; + if (run_is_set != NULL) { + *run_is_set = first_value; + } + + for (; ((from + count) % BITS_PER_WORD) != 0 && len > 0; len--) { + if (bit_has_value(b, from + count, first_value)) { + count++; + } else { + return count; } + } - for ( ; ((from + count) % BITS_PER_WORD) != 0 && len > 0; len--) { - if (bit_has_value(b, from + count, first_value)) { - count++; - } else { - return count; - } + for (; len >= BITS_PER_WORD; len -= BITS_PER_WORD) { + if (BIT_WORD(b, from + count) == word_match) { + count += BITS_PER_WORD; + } else { + break; } + } - for ( ; len >= BITS_PER_WORD ; len -= BITS_PER_WORD ) { - if (BIT_WORD(b, from + count) == word_match) { - count += BITS_PER_WORD; - } else { - break; - } + for (; len > 0; len--) { + if (bit_has_value(b, from + count, first_value)) { + count++; } + } - for ( ; len > 0; len-- ) { - if ( bit_has_value(b, from + count, first_value) ) { - count++; - } - } - - return count; + return count; } enum bitset_stream_events { - BITSET_STREAM_UNSET = 0, - BITSET_STREAM_SET = 1, - BITSET_STREAM_ON = 2, - BITSET_STREAM_OFF = 3 + BITSET_STREAM_UNSET = 0, + BITSET_STREAM_SET = 1, + BITSET_STREAM_ON = 2, + BITSET_STREAM_OFF = 3 }; #define BITSET_STREAM_EVENTS_ENUM_SIZE 4 struct bitset_stream_entry { - enum bitset_stream_events event; - uint64_t from; - uint64_t len; + enum bitset_stream_events event; + uint64_t from; + uint64_t len; }; /** Limit the stream size to 1MB for now. @@ -152,14 +167,14 @@ struct bitset_stream_entry { #define BITSET_STREAM_SIZE ( ( 1024 * 1024 ) / sizeof( struct bitset_stream_entry ) ) struct bitset_stream { - struct bitset_stream_entry entries[BITSET_STREAM_SIZE]; - int in; - int out; - int size; - pthread_mutex_t mutex; - pthread_cond_t cond_not_full; - pthread_cond_t cond_not_empty; - uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE]; + struct bitset_stream_entry entries[BITSET_STREAM_SIZE]; + int in; + int out; + int size; + pthread_mutex_t mutex; + pthread_cond_t cond_not_full; + pthread_cond_t cond_not_empty; + uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE]; }; @@ -169,47 +184,49 @@ struct bitset_stream { * written reliably by multiple threads. */ struct bitset { - pthread_mutex_t lock; - uint64_t size; - int resolution; - struct bitset_stream *stream; - int stream_enabled; - bitfield_word_t bits[]; + pthread_mutex_t lock; + uint64_t size; + int resolution; + struct bitset_stream *stream; + int stream_enabled; + bitfield_word_t bits[]; }; /** Allocate a bitset for a file of the given size, and chunks of the * given resolution. */ -static inline struct bitset *bitset_alloc( uint64_t size, int resolution ) +static inline struct bitset *bitset_alloc(uint64_t size, int resolution) { - // calculate a size to allocate that is a multiple of the size of the - // bitfield word - size_t bitfield_size = - BIT_WORDS_FOR_SIZE((( size + resolution - 1 ) / resolution)) * sizeof( bitfield_word_t ); - struct bitset *bitset = xmalloc(sizeof( struct bitset ) + ( bitfield_size / 8 ) ); + // calculate a size to allocate that is a multiple of the size of the + // bitfield word + size_t bitfield_size = + BIT_WORDS_FOR_SIZE(((size + resolution - + 1) / resolution)) * sizeof(bitfield_word_t); + struct bitset *bitset = + xmalloc(sizeof(struct bitset) + (bitfield_size / 8)); - bitset->size = size; - bitset->resolution = resolution; - /* don't actually need to call pthread_mutex_destroy '*/ - pthread_mutex_init(&bitset->lock, NULL); - bitset->stream = xmalloc( sizeof( struct bitset_stream ) ); - pthread_mutex_init( &bitset->stream->mutex, NULL ); + bitset->size = size; + bitset->resolution = resolution; + /* don't actually need to call pthread_mutex_destroy ' */ + pthread_mutex_init(&bitset->lock, NULL); + bitset->stream = xmalloc(sizeof(struct bitset_stream)); + pthread_mutex_init(&bitset->stream->mutex, NULL); - /* Technically don't need to call pthread_cond_destroy either */ - pthread_cond_init( &bitset->stream->cond_not_full, NULL ); - pthread_cond_init( &bitset->stream->cond_not_empty, NULL ); + /* Technically don't need to call pthread_cond_destroy either */ + pthread_cond_init(&bitset->stream->cond_not_full, NULL); + pthread_cond_init(&bitset->stream->cond_not_empty, NULL); - return bitset; + return bitset; } -static inline void bitset_free( struct bitset * set ) +static inline void bitset_free(struct bitset *set) { - /* TODO: free our mutex... */ + /* TODO: free our mutex... */ - free( set->stream ); - set->stream = NULL; + free(set->stream); + set->stream = NULL; - free( set ); + free(set); } #define INT_FIRST_AND_LAST \ @@ -224,215 +241,201 @@ static inline void bitset_free( struct bitset * set ) FATAL_IF_NEGATIVE(pthread_mutex_unlock(&set->lock), "Error unlocking bitset") -static inline void bitset_stream_enqueue( - struct bitset * set, - enum bitset_stream_events event, - uint64_t from, - uint64_t len -) +static inline void bitset_stream_enqueue(struct bitset *set, + enum bitset_stream_events event, + uint64_t from, uint64_t len) { - struct bitset_stream * stream = set->stream; + struct bitset_stream *stream = set->stream; - pthread_mutex_lock( &stream->mutex ); + pthread_mutex_lock(&stream->mutex); - while ( stream->size == BITSET_STREAM_SIZE ) { - pthread_cond_wait( &stream->cond_not_full, &stream->mutex ); - } + while (stream->size == BITSET_STREAM_SIZE) { + pthread_cond_wait(&stream->cond_not_full, &stream->mutex); + } - stream->entries[stream->in].event = event; - stream->entries[stream->in].from = from; - stream->entries[stream->in].len = len; - stream->queued_bytes[event] += len; + stream->entries[stream->in].event = event; + stream->entries[stream->in].from = from; + stream->entries[stream->in].len = len; + stream->queued_bytes[event] += len; - stream->size++; - stream->in++; - stream->in %= BITSET_STREAM_SIZE; + stream->size++; + stream->in++; + stream->in %= BITSET_STREAM_SIZE; - pthread_mutex_unlock( & stream->mutex ); - pthread_cond_signal( &stream->cond_not_empty ); + pthread_mutex_unlock(&stream->mutex); + pthread_cond_signal(&stream->cond_not_empty); - return; + return; } -static inline void bitset_stream_dequeue( - struct bitset * set, - struct bitset_stream_entry * out -) +static inline void bitset_stream_dequeue(struct bitset *set, + struct bitset_stream_entry *out) { - struct bitset_stream * stream = set->stream; - struct bitset_stream_entry * dequeued; + struct bitset_stream *stream = set->stream; + struct bitset_stream_entry *dequeued; - pthread_mutex_lock( &stream->mutex ); + pthread_mutex_lock(&stream->mutex); - while ( stream->size == 0 ) { - pthread_cond_wait( &stream->cond_not_empty, &stream->mutex ); - } + while (stream->size == 0) { + pthread_cond_wait(&stream->cond_not_empty, &stream->mutex); + } - dequeued = &stream->entries[stream->out]; + dequeued = &stream->entries[stream->out]; - if ( out != NULL ) { - out->event = dequeued->event; - out->from = dequeued->from; - out->len = dequeued->len; - } + if (out != NULL) { + out->event = dequeued->event; + out->from = dequeued->from; + out->len = dequeued->len; + } - stream->queued_bytes[dequeued->event] -= dequeued->len; - stream->size--; - stream->out++; - stream->out %= BITSET_STREAM_SIZE; + stream->queued_bytes[dequeued->event] -= dequeued->len; + stream->size--; + stream->out++; + stream->out %= BITSET_STREAM_SIZE; - pthread_mutex_unlock( &stream->mutex ); - pthread_cond_signal( &stream->cond_not_full ); + pthread_mutex_unlock(&stream->mutex); + pthread_cond_signal(&stream->cond_not_full); - return; + return; } -static inline size_t bitset_stream_size( struct bitset * set ) +static inline size_t bitset_stream_size(struct bitset *set) { - size_t size; + size_t size; - pthread_mutex_lock( &set->stream->mutex ); - size = set->stream->size; - pthread_mutex_unlock( &set->stream->mutex ); + pthread_mutex_lock(&set->stream->mutex); + size = set->stream->size; + pthread_mutex_unlock(&set->stream->mutex); - return size; + return size; } -static inline uint64_t bitset_stream_queued_bytes( - struct bitset * set, - enum bitset_stream_events event -) +static inline uint64_t bitset_stream_queued_bytes(struct bitset *set, + enum bitset_stream_events + event) { - uint64_t total; + uint64_t total; - pthread_mutex_lock( &set->stream->mutex ); - total = set->stream->queued_bytes[event]; - pthread_mutex_unlock( &set->stream->mutex ); + pthread_mutex_lock(&set->stream->mutex); + total = set->stream->queued_bytes[event]; + pthread_mutex_unlock(&set->stream->mutex); - return total; + return total; } -static inline void bitset_enable_stream( struct bitset * set ) +static inline void bitset_enable_stream(struct bitset *set) { - BITSET_LOCK; - set->stream_enabled = 1; - bitset_stream_enqueue( set, BITSET_STREAM_ON, 0, set->size ); - BITSET_UNLOCK; + BITSET_LOCK; + set->stream_enabled = 1; + bitset_stream_enqueue(set, BITSET_STREAM_ON, 0, set->size); + BITSET_UNLOCK; } -static inline void bitset_disable_stream( struct bitset * set ) +static inline void bitset_disable_stream(struct bitset *set) { - BITSET_LOCK; - bitset_stream_enqueue( set, BITSET_STREAM_OFF, 0, set->size ); - set->stream_enabled = 0; - BITSET_UNLOCK; + BITSET_LOCK; + bitset_stream_enqueue(set, BITSET_STREAM_OFF, 0, set->size); + set->stream_enabled = 0; + BITSET_UNLOCK; } /** Set the bits in a bitset which correspond to the given bytes in the larger * file. */ -static inline void bitset_set_range( - struct bitset * set, - uint64_t from, - uint64_t len) +static inline void bitset_set_range(struct bitset *set, + uint64_t from, uint64_t len) { - INT_FIRST_AND_LAST; - BITSET_LOCK; - bit_set_range(set->bits, first, bitlen); + INT_FIRST_AND_LAST; + BITSET_LOCK; + bit_set_range(set->bits, first, bitlen); - if ( set->stream_enabled ) { - bitset_stream_enqueue( set, BITSET_STREAM_SET, from, len ); - } + if (set->stream_enabled) { + bitset_stream_enqueue(set, BITSET_STREAM_SET, from, len); + } - BITSET_UNLOCK; + BITSET_UNLOCK; } /** Set every bit in the bitset. */ -static inline void bitset_set( struct bitset * set ) +static inline void bitset_set(struct bitset *set) { - bitset_set_range(set, 0, set->size); + bitset_set_range(set, 0, set->size); } /** Clear the bits in a bitset which correspond to the given bytes in the * larger file. */ -static inline void bitset_clear_range( - struct bitset * set, - uint64_t from, - uint64_t len) +static inline void bitset_clear_range(struct bitset *set, + uint64_t from, uint64_t len) { - INT_FIRST_AND_LAST; - BITSET_LOCK; - bit_clear_range(set->bits, first, bitlen); + INT_FIRST_AND_LAST; + BITSET_LOCK; + bit_clear_range(set->bits, first, bitlen); - if ( set->stream_enabled ) { - bitset_stream_enqueue( set, BITSET_STREAM_UNSET, from, len ); - } + if (set->stream_enabled) { + bitset_stream_enqueue(set, BITSET_STREAM_UNSET, from, len); + } - BITSET_UNLOCK; + BITSET_UNLOCK; } /** Clear every bit in the bitset. */ -static inline void bitset_clear( struct bitset * set ) +static inline void bitset_clear(struct bitset *set) { - bitset_clear_range(set, 0, set->size); + bitset_clear_range(set, 0, set->size); } /** As per bitset_run_count but also tells you whether the run it found was set * or unset, atomically. */ -static inline uint64_t bitset_run_count_ex( - struct bitset * set, - uint64_t from, - uint64_t len, - int* run_is_set -) +static inline uint64_t bitset_run_count_ex(struct bitset *set, + uint64_t from, + uint64_t len, int *run_is_set) { - uint64_t run; + uint64_t run; - /* Clip our requests to the end of the bitset, avoiding uint underflow. */ - if ( from > set->size ) { - return 0; - } - len = ( len + from ) > set->size ? ( set->size - from ) : len; + /* Clip our requests to the end of the bitset, avoiding uint underflow. */ + if (from > set->size) { + return 0; + } + len = (len + from) > set->size ? (set->size - from) : len; - INT_FIRST_AND_LAST; + INT_FIRST_AND_LAST; - BITSET_LOCK; - run = bit_run_count(set->bits, first, bitlen, run_is_set) * set->resolution; - run -= (from % set->resolution); - BITSET_UNLOCK; + BITSET_LOCK; + run = + bit_run_count(set->bits, first, bitlen, + run_is_set) * set->resolution; + run -= (from % set->resolution); + BITSET_UNLOCK; - return run; + return run; } /** Counts the number of contiguous bytes that are represented as a run in * the bit field. */ -static inline uint64_t bitset_run_count( - struct bitset * set, - uint64_t from, - uint64_t len) +static inline uint64_t bitset_run_count(struct bitset *set, + uint64_t from, uint64_t len) { - return bitset_run_count_ex( set, from, len, NULL ); + return bitset_run_count_ex(set, from, len, NULL); } /** Tests whether the bit field is clear for the given file offset. */ -static inline int bitset_is_clear_at( struct bitset * set, uint64_t at ) +static inline int bitset_is_clear_at(struct bitset *set, uint64_t at) { - return bit_is_clear(set->bits, at/set->resolution); + return bit_is_clear(set->bits, at / set->resolution); } /** Tests whether the bit field is set for the given file offset. */ -static inline int bitset_is_set_at( struct bitset * set, uint64_t at ) +static inline int bitset_is_set_at(struct bitset *set, uint64_t at) { - return bit_is_set(set->bits, at/set->resolution); + return bit_is_set(set->bits, at / set->resolution); } #endif - diff --git a/src/server/client.c b/src/server/client.c index fe8a0a5..972cf77 100644 --- a/src/server/client.c +++ b/src/server/client.c @@ -18,72 +18,74 @@ // When this signal is invoked, we call shutdown() on the client fd, which // results in the thread being wound up -void client_killswitch_hit(int signal __attribute__ ((unused)), siginfo_t *info, void *ptr __attribute__ ((unused))) +void client_killswitch_hit(int signal + __attribute__ ((unused)), siginfo_t * info, + void *ptr __attribute__ ((unused))) { - int fd = info->si_value.sival_int; - warn( "Killswitch for fd %i activated, calling shutdown on socket", fd ); + int fd = info->si_value.sival_int; + warn("Killswitch for fd %i activated, calling shutdown on socket", fd); - FATAL_IF( - -1 == shutdown( fd, SHUT_RDWR ), - SHOW_ERRNO( "Failed to shutdown() the socket, killing the server" ) - ); + FATAL_IF(-1 == shutdown(fd, SHUT_RDWR), + SHOW_ERRNO + ("Failed to shutdown() the socket, killing the server") + ); } -struct client *client_create( struct server *serve, int socket ) +struct client *client_create(struct server *serve, int socket) { - NULLCHECK( serve ); + NULLCHECK(serve); - struct client *c; - struct sigevent evp = { - .sigev_notify = SIGEV_SIGNAL, - .sigev_signo = CLIENT_KILLSWITCH_SIGNAL - }; + struct client *c; + struct sigevent evp = { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = CLIENT_KILLSWITCH_SIGNAL + }; - /* - * Our killswitch closes this socket, forcing read() and write() calls - * blocked on it to return with an error. The thread then close()s the - * socket itself, avoiding races. - */ - evp.sigev_value.sival_int = socket; + /* + * Our killswitch closes this socket, forcing read() and write() calls + * blocked on it to return with an error. The thread then close()s the + * socket itself, avoiding races. + */ + evp.sigev_value.sival_int = socket; - c = xmalloc( sizeof( struct client ) ); - c->stopped = 0; - c->socket = socket; - c->serve = serve; + c = xmalloc(sizeof(struct client)); + c->stopped = 0; + c->socket = socket; + c->serve = serve; - c->stop_signal = self_pipe_create(); + c->stop_signal = self_pipe_create(); - FATAL_IF_NEGATIVE( - timer_create( CLOCK_MONOTONIC, &evp, &(c->killswitch) ), - SHOW_ERRNO( "Failed to create killswitch timer" ) + FATAL_IF_NEGATIVE(timer_create + (CLOCK_MONOTONIC, &evp, &(c->killswitch)), + SHOW_ERRNO("Failed to create killswitch timer") ); - debug( "Alloced client %p with socket %d", c, socket ); - return c; + debug("Alloced client %p with socket %d", c, socket); + return c; } -void client_signal_stop( struct client *c) +void client_signal_stop(struct client *c) { - NULLCHECK( c); + NULLCHECK(c); - debug("client %p: signal stop (%d, %d)", c,c->stop_signal->read_fd, c->stop_signal->write_fd ); - self_pipe_signal( c->stop_signal ); + debug("client %p: signal stop (%d, %d)", c, c->stop_signal->read_fd, + c->stop_signal->write_fd); + self_pipe_signal(c->stop_signal); } -void client_destroy( struct client *client ) +void client_destroy(struct client *client) { - NULLCHECK( client ); + NULLCHECK(client); - FATAL_IF_NEGATIVE( - timer_delete( client->killswitch ), - SHOW_ERRNO( "Couldn't delete killswitch" ) + FATAL_IF_NEGATIVE(timer_delete(client->killswitch), + SHOW_ERRNO("Couldn't delete killswitch") ); - debug( "Destroying stop signal for client %p", client ); - self_pipe_destroy( client->stop_signal ); - debug( "Freeing client %p", client ); - free( client ); + debug("Destroying stop signal for client %p", client); + self_pipe_destroy(client->stop_signal); + debug("Freeing client %p", client); + free(client); } @@ -100,50 +102,51 @@ void client_destroy( struct client *client ) * allocated, we can proceed as normal and make one call to writeloop. * */ -void write_not_zeroes(struct client* client, uint64_t from, uint64_t len) +void write_not_zeroes(struct client *client, uint64_t from, uint64_t len) { - NULLCHECK( client ); - NULLCHECK( client->serve ); - NULLCHECK( client->serve->allocation_map ); + NULLCHECK(client); + NULLCHECK(client->serve); + NULLCHECK(client->serve->allocation_map); - struct bitset * map = client->serve->allocation_map; + struct bitset *map = client->serve->allocation_map; - while (len > 0) { - /* so we have to calculate how much of our input to consider - * next based on the bitmap of allocated blocks. This will be - * at a coarser resolution than the actual write, which may - * not fall on a block boundary at either end. So we look up - * how many blocks our write covers, then cut off the start - * and end to get the exact number of bytes. - */ + while (len > 0) { + /* so we have to calculate how much of our input to consider + * next based on the bitmap of allocated blocks. This will be + * at a coarser resolution than the actual write, which may + * not fall on a block boundary at either end. So we look up + * how many blocks our write covers, then cut off the start + * and end to get the exact number of bytes. + */ - uint64_t run = bitset_run_count(map, from, len); + uint64_t run = bitset_run_count(map, from, len); - debug("write_not_zeroes: from=%ld, len=%d, run=%d", from, len, run); + debug("write_not_zeroes: from=%ld, len=%d, run=%d", from, len, + run); - if (run > len) { - run = len; - debug("(run adjusted to %d)", run); - } + if (run > len) { + run = len; + debug("(run adjusted to %d)", run); + } - /* - // Useful but expensive - if (0) - { - uint64_t i; - fprintf(stderr, "full map resolution=%d: ", map->resolution); - for (i=0; iserve->size; i+=map->resolution) { - int here = (from >= i && from < i+map->resolution); + /* + // Useful but expensive + if (0) + { + uint64_t i; + fprintf(stderr, "full map resolution=%d: ", map->resolution); + for (i=0; iserve->size; i+=map->resolution) { + int here = (from >= i && from < i+map->resolution); - if (here) { fprintf(stderr, ">"); } - fprintf(stderr, bitset_is_set_at(map, i) ? "1" : "0"); - if (here) { fprintf(stderr, "<"); } - } - fprintf(stderr, "\n"); - } - */ + if (here) { fprintf(stderr, ">"); } + fprintf(stderr, bitset_is_set_at(map, i) ? "1" : "0"); + if (here) { fprintf(stderr, "<"); } + } + fprintf(stderr, "\n"); + } + */ - #define DO_READ(dst, len) ERROR_IF_NEGATIVE( \ +#define DO_READ(dst, len) ERROR_IF_NEGATIVE( \ readloop( \ client->socket, \ (dst), \ @@ -152,139 +155,136 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len) "read failed %ld+%d", from, (len) \ ) - if (bitset_is_set_at(map, from)) { - debug("writing the lot: from=%ld, run=%d", from, run); - /* already allocated, just write it all */ - DO_READ(client->mapped + from, run); - /* We know from our earlier call to bitset_run_count that the - * bitset is all-1s at this point, but we need to dirty it for the - * sake of the event stream - the actual bytes have changed, and we - * are interested in that fact. - */ - bitset_set_range( map, from, run ); - len -= run; - from += run; + if (bitset_is_set_at(map, from)) { + debug("writing the lot: from=%ld, run=%d", from, run); + /* already allocated, just write it all */ + DO_READ(client->mapped + from, run); + /* We know from our earlier call to bitset_run_count that the + * bitset is all-1s at this point, but we need to dirty it for the + * sake of the event stream - the actual bytes have changed, and we + * are interested in that fact. + */ + bitset_set_range(map, from, run); + len -= run; + from += run; + } else { + char zerobuffer[block_allocation_resolution]; + /* not allocated, read in block_allocation_resoution */ + while (run > 0) { + uint64_t blockrun = block_allocation_resolution - + (from % block_allocation_resolution); + if (blockrun > run) + blockrun = run; + + DO_READ(zerobuffer, blockrun); + + /* This reads the buffer twice in the worst case + * but we're leaning on memcmp failing early + * and memcpy being fast, rather than try to + * hand-optimized something specific. + */ + + int all_zeros = (zerobuffer[0] == 0) && + (0 == + memcmp(zerobuffer, zerobuffer + 1, blockrun - 1)); + + if (!all_zeros) { + memcpy(client->mapped + from, zerobuffer, blockrun); + bitset_set_range(map, from, blockrun); + /* at this point we could choose to + * short-cut the rest of the write for + * faster I/O but by continuing to do it + * the slow way we preserve as much + * sparseness as possible. + */ } - else { - char zerobuffer[block_allocation_resolution]; - /* not allocated, read in block_allocation_resoution */ - while (run > 0) { - uint64_t blockrun = block_allocation_resolution - - (from % block_allocation_resolution); - if (blockrun > run) - blockrun = run; + /* When the block is all_zeroes, no bytes have changed, so we + * don't need to put an event into the bitset stream. This may + * be surprising in the future. + */ - DO_READ(zerobuffer, blockrun); - - /* This reads the buffer twice in the worst case - * but we're leaning on memcmp failing early - * and memcpy being fast, rather than try to - * hand-optimized something specific. - */ - - int all_zeros = (zerobuffer[0] == 0) && - (0 == memcmp( zerobuffer, zerobuffer+1, blockrun-1 )); - - if ( !all_zeros ) { - memcpy(client->mapped+from, zerobuffer, blockrun); - bitset_set_range(map, from, blockrun); - /* at this point we could choose to - * short-cut the rest of the write for - * faster I/O but by continuing to do it - * the slow way we preserve as much - * sparseness as possible. - */ - } - /* When the block is all_zeroes, no bytes have changed, so we - * don't need to put an event into the bitset stream. This may - * be surprising in the future. - */ - - len -= blockrun; - run -= blockrun; - from += blockrun; - } - } + len -= blockrun; + run -= blockrun; + from += blockrun; + } } + } } -int fd_read_request( int fd, struct nbd_request_raw *out_request) +int fd_read_request(int fd, struct nbd_request_raw *out_request) { - return readloop(fd, out_request, sizeof(struct nbd_request_raw)); + return readloop(fd, out_request, sizeof(struct nbd_request_raw)); } /* Returns 1 if *request was filled with a valid request which we should * try to honour. 0 otherwise. */ -int client_read_request( struct client * client , struct nbd_request *out_request, int * disconnected ) +int client_read_request(struct client *client, + struct nbd_request *out_request, int *disconnected) { - NULLCHECK( client ); - NULLCHECK( out_request ); + NULLCHECK(client); + NULLCHECK(out_request); - struct nbd_request_raw request_raw; + struct nbd_request_raw request_raw; - if (fd_read_request(client->socket, &request_raw) == -1) { - *disconnected = 1; - switch( errno ){ - case 0: - warn( "EOF while reading request" ); - return 0; - case ECONNRESET: - warn( "Connection reset while" - " reading request" ); - return 0; - case ETIMEDOUT: - warn( "Connection timed out while" - " reading request" ); - return 0; - default: - /* FIXME: I've seen this happen, but I - * couldn't reproduce it so I'm leaving - * it here with a better debug output in - * the hope it'll spontaneously happen - * again. It should *probably* be an - * error() call, but I want to be sure. - * */ - fatal("Error reading request: %d, %s", - errno, - strerror( errno )); - } + if (fd_read_request(client->socket, &request_raw) == -1) { + *disconnected = 1; + switch (errno) { + case 0: + warn("EOF while reading request"); + return 0; + case ECONNRESET: + warn("Connection reset while" " reading request"); + return 0; + case ETIMEDOUT: + warn("Connection timed out while" " reading request"); + return 0; + default: + /* FIXME: I've seen this happen, but I + * couldn't reproduce it so I'm leaving + * it here with a better debug output in + * the hope it'll spontaneously happen + * again. It should *probably* be an + * error() call, but I want to be sure. + * */ + fatal("Error reading request: %d, %s", errno, strerror(errno)); } + } - nbd_r2h_request( &request_raw, out_request ); - return 1; + nbd_r2h_request(&request_raw, out_request); + return 1; } -int fd_write_reply( int fd, uint64_t handle, int error ) +int fd_write_reply(int fd, uint64_t handle, int error) { - struct nbd_reply reply; - struct nbd_reply_raw reply_raw; + struct nbd_reply reply; + struct nbd_reply_raw reply_raw; - reply.magic = REPLY_MAGIC; - reply.error = error; - reply.handle.w = handle; + reply.magic = REPLY_MAGIC; + reply.error = error; + reply.handle.w = handle; - nbd_h2r_reply( &reply, &reply_raw ); - debug( "Replying with handle=0x%08X, error=%"PRIu32, handle, error ); + nbd_h2r_reply(&reply, &reply_raw); + debug("Replying with handle=0x%08X, error=%" PRIu32, handle, error); - if( -1 == writeloop( fd, &reply_raw, sizeof( reply_raw ) ) ) { - switch( errno ) { - case ECONNRESET: - error( "Connection reset while writing reply" ); - break; - case EBADF: - fatal( "Tried to write to an invalid file descriptor" ); - break; - case EPIPE: - error( "Remote end closed" ); - break; - default: - fatal( "Unhandled error while writing: %d", errno ); - } + if (-1 == writeloop(fd, &reply_raw, sizeof(reply_raw))) { + switch (errno) { + case ECONNRESET: + error("Connection reset while writing reply"); + break; + case EBADF: + fatal("Tried to write to an invalid file descriptor"); + break; + case EPIPE: + error("Remote end closed"); + break; + default: + fatal("Unhandled error while writing: %d", errno); } + } - return 1; + return 1; } @@ -293,32 +293,32 @@ int fd_write_reply( int fd, uint64_t handle, int error ) * Returns 1; we don't check for errors on the write. * TODO: Check for errors on the write. */ -int client_write_reply( struct client * client, struct nbd_request *request, int error ) +int client_write_reply(struct client *client, struct nbd_request *request, + int error) { - return fd_write_reply( client->socket, request->handle.w, error); + return fd_write_reply(client->socket, request->handle.w, error); } -void client_write_init( struct client * client, uint64_t size ) +void client_write_init(struct client *client, uint64_t size) { - struct nbd_init init = {{0}}; - struct nbd_init_raw init_raw = {{0}}; + struct nbd_init init = { {0} }; + struct nbd_init_raw init_raw = { {0} }; - memcpy( init.passwd, INIT_PASSWD, sizeof( init.passwd ) ); - init.magic = INIT_MAGIC; - init.size = size; - /* As more features are implemented, this is the place to advertise - * them. - */ - init.flags = FLAG_HAS_FLAGS | FLAG_SEND_FLUSH | FLAG_SEND_FUA; - memset( init.reserved, 0, 124 ); + memcpy(init.passwd, INIT_PASSWD, sizeof(init.passwd)); + init.magic = INIT_MAGIC; + init.size = size; + /* As more features are implemented, this is the place to advertise + * them. + */ + init.flags = FLAG_HAS_FLAGS | FLAG_SEND_FLUSH | FLAG_SEND_FUA; + memset(init.reserved, 0, 124); - nbd_h2r_init( &init, &init_raw ); + nbd_h2r_init(&init, &init_raw); - ERROR_IF_NEGATIVE( - writeloop(client->socket, &init_raw, sizeof(init_raw)), - "Couldn't send hello" - ); + ERROR_IF_NEGATIVE(writeloop + (client->socket, &init_raw, sizeof(init_raw)), + "Couldn't send hello"); } @@ -326,43 +326,35 @@ void client_write_init( struct client * client, uint64_t size ) * client sends a write we can't honour - we need to get rid of the * bytes they've already written before we can look for another request. */ -void client_flush( struct client * client, size_t len ) +void client_flush(struct client *client, size_t len) { - int devnull = open("/dev/null", O_WRONLY); - FATAL_IF_NEGATIVE( devnull, - "Couldn't open /dev/null: %s", strerror(errno)); - int pipes[2]; - pipe( pipes ); + int devnull = open("/dev/null", O_WRONLY); + FATAL_IF_NEGATIVE(devnull, + "Couldn't open /dev/null: %s", strerror(errno)); + int pipes[2]; + pipe(pipes); - const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE; - size_t spliced = 0; + const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE; + size_t spliced = 0; - while ( spliced < len ) { - ssize_t received = splice( - client->socket, NULL, - pipes[1], NULL, - len-spliced, flags ); - FATAL_IF_NEGATIVE( received, - "splice error: %s", - strerror(errno)); - ssize_t junked = 0; - while( junked < received ) { - ssize_t junk; - junk = splice( - pipes[0], NULL, - devnull, NULL, - received, flags ); - FATAL_IF_NEGATIVE( junk, - "splice error: %s", - strerror(errno)); - junked += junk; - } - spliced += received; + while (spliced < len) { + ssize_t received = splice(client->socket, NULL, + pipes[1], NULL, + len - spliced, flags); + FATAL_IF_NEGATIVE(received, "splice error: %s", strerror(errno)); + ssize_t junked = 0; + while (junked < received) { + ssize_t junk; + junk = splice(pipes[0], NULL, devnull, NULL, received, flags); + FATAL_IF_NEGATIVE(junk, "splice error: %s", strerror(errno)); + junked += junk; } - debug("Flushed %d bytes", len); + spliced += received; + } + debug("Flushed %d bytes", len); - close( devnull ); + close(devnull); } @@ -371,369 +363,362 @@ void client_flush( struct client * client, size_t len ) * request_err is set to 0 if the client sent a bad request, in which * case we drop the connection. */ -int client_request_needs_reply( struct client * client, - struct nbd_request request ) +int client_request_needs_reply(struct client *client, + struct nbd_request request) { - /* The client is stupid, but don't take down the whole server as a result. - * We send a reply before disconnecting so that at least some indication of - * the problem is visible, and so proxies don't retry the same (bad) request - * forever. - */ - if (request.magic != REQUEST_MAGIC) { - warn("Bad magic 0x%08X from client", request.magic); - client_write_reply( client, &request, EBADMSG ); - client->disconnect = 1; // no need to flush - return 0; - } - - debug( - "request type=%"PRIu16", flags=%"PRIu16", from=%"PRIu64", len=%"PRIu32", handle=0x%08X", - request.type, request.flags, request.from, request.len, request.handle - ); - - /* check it's not out of range. NBD protocol requires ENOSPC to be - * returned in this instance - */ - if ( request.from+request.len > client->serve->size) { - warn("write request %"PRIu64"+%"PRIu32" out of range", - request.from, request.len - ); - if ( request.type == REQUEST_WRITE ) { - client_flush( client, request.len ); - } - client_write_reply( client, &request, ENOSPC ); - client->disconnect = 0; - return 0; + /* The client is stupid, but don't take down the whole server as a result. + * We send a reply before disconnecting so that at least some indication of + * the problem is visible, and so proxies don't retry the same (bad) request + * forever. + */ + if (request.magic != REQUEST_MAGIC) { + warn("Bad magic 0x%08X from client", request.magic); + client_write_reply(client, &request, EBADMSG); + client->disconnect = 1; // no need to flush + return 0; + } + + debug("request type=%" PRIu16 ", flags=%" PRIu16 ", from=%" PRIu64 + ", len=%" PRIu32 ", handle=0x%08X", request.type, request.flags, + request.from, request.len, request.handle); + + /* check it's not out of range. NBD protocol requires ENOSPC to be + * returned in this instance + */ + if (request.from + request.len > client->serve->size) { + warn("write request %" PRIu64 "+%" PRIu32 " out of range", + request.from, request.len); + if (request.type == REQUEST_WRITE) { + client_flush(client, request.len); } + client_write_reply(client, &request, ENOSPC); + client->disconnect = 0; + return 0; + } - switch (request.type) - { - case REQUEST_READ: - break; - case REQUEST_WRITE: - break; - case REQUEST_DISCONNECT: - debug("request disconnect"); - client->disconnect = 1; - return 0; - case REQUEST_FLUSH: - break; - default: - /* NBD prototcol says servers SHOULD return EINVAL to unknown - * commands */ - warn("Unknown request 0x%08X", request.type); - client_write_reply( client, &request, EINVAL ); - client->disconnect = 0; - return 0; - } - return 1; + switch (request.type) { + case REQUEST_READ: + break; + case REQUEST_WRITE: + break; + case REQUEST_DISCONNECT: + debug("request disconnect"); + client->disconnect = 1; + return 0; + case REQUEST_FLUSH: + break; + default: + /* NBD prototcol says servers SHOULD return EINVAL to unknown + * commands */ + warn("Unknown request 0x%08X", request.type); + client_write_reply(client, &request, EINVAL); + client->disconnect = 0; + return 0; + } + return 1; } -void client_reply_to_read( struct client* client, struct nbd_request request ) +void client_reply_to_read(struct client *client, + struct nbd_request request) { - off64_t offset; + off64_t offset; - debug("request read %ld+%d", request.from, request.len); - sock_set_tcp_cork( client->socket, 1 ); - client_write_reply( client, &request, 0 ); + debug("request read %ld+%d", request.from, request.len); + sock_set_tcp_cork(client->socket, 1); + client_write_reply(client, &request, 0); - offset = request.from; + offset = request.from; - /* If we get cut off partway through this sendfile, we don't - * want to kill the server. This should be an error. - */ - ERROR_IF_NEGATIVE( - sendfileloop( - client->socket, - client->fileno, - &offset, - request.len), - "sendfile failed from=%ld, len=%d", - offset, - request.len); + /* If we get cut off partway through this sendfile, we don't + * want to kill the server. This should be an error. + */ + ERROR_IF_NEGATIVE(sendfileloop(client->socket, + client->fileno, + &offset, + request.len), + "sendfile failed from=%ld, len=%d", + offset, request.len); - sock_set_tcp_cork( client->socket, 0 ); + sock_set_tcp_cork(client->socket, 0); } -void client_reply_to_write( struct client* client, struct nbd_request request ) +void client_reply_to_write(struct client *client, + struct nbd_request request) { - debug("request write from=%"PRIu64", len=%"PRIu32", handle=0x%08X", request.from, request.len, request.handle); - if (client->serve->allocation_map_built) { - write_not_zeroes( client, request.from, request.len ); - } - else { - debug("No allocation map, writing directly."); - /* If we get cut off partway through reading this data: - * */ - ERROR_IF_NEGATIVE( - readloop( client->socket, - client->mapped + request.from, - request.len), - "reading write data failed from=%ld, len=%d", - request.from, - request.len - ); + debug("request write from=%" PRIu64 ", len=%" PRIu32 ", handle=0x%08X", + request.from, request.len, request.handle); + if (client->serve->allocation_map_built) { + write_not_zeroes(client, request.from, request.len); + } else { + debug("No allocation map, writing directly."); + /* If we get cut off partway through reading this data: + * */ + ERROR_IF_NEGATIVE(readloop(client->socket, + client->mapped + request.from, + request.len), + "reading write data failed from=%ld, len=%d", + request.from, request.len); - /* the allocation_map is shared between client threads, and may be - * being built. We need to reflect the write in it, as it may be in - * a position the builder has already gone over. - */ - bitset_set_range(client->serve->allocation_map, request.from, request.len); - } + /* the allocation_map is shared between client threads, and may be + * being built. We need to reflect the write in it, as it may be in + * a position the builder has already gone over. + */ + bitset_set_range(client->serve->allocation_map, request.from, + request.len); + } - // Only flush if FUA is set - if (request.flags & CMD_FLAG_FUA) - { - /* multiple of page size */ - uint64_t from_rounded = request.from & (~(sysconf(_SC_PAGE_SIZE)-1)); - uint64_t len_rounded = request.len + (request.from - from_rounded); - debug("Calling msync from=%"PRIu64", len=%"PRIu64"",from_rounded, len_rounded); + // Only flush if FUA is set + if (request.flags & CMD_FLAG_FUA) { + /* multiple of page size */ + uint64_t from_rounded = + request.from & (~(sysconf(_SC_PAGE_SIZE) - 1)); + uint64_t len_rounded = request.len + (request.from - from_rounded); + debug("Calling msync from=%" PRIu64 ", len=%" PRIu64 "", + from_rounded, len_rounded); - FATAL_IF_NEGATIVE( - msync( client->mapped + from_rounded, + FATAL_IF_NEGATIVE(msync(client->mapped + from_rounded, len_rounded, MS_SYNC | MS_INVALIDATE), - "msync failed %ld %ld", request.from, request.len - ); - } - client_write_reply( client, &request, 0); + "msync failed %ld %ld", request.from, + request.len); + } + client_write_reply(client, &request, 0); } -void client_reply_to_flush( struct client* client, struct nbd_request request ) +void client_reply_to_flush(struct client *client, + struct nbd_request request) { - debug("request flush from=%"PRIu64", len=%"PRIu32", handle=0x%08X", request.from, request.len, request.handle); + debug("request flush from=%" PRIu64 ", len=%" PRIu32 ", handle=0x%08X", + request.from, request.len, request.handle); - ERROR_IF_NEGATIVE( - msync(client->mapped, client->mapped_size, MS_SYNC | MS_INVALIDATE), - "flush failed" - ); + ERROR_IF_NEGATIVE(msync + (client->mapped, client->mapped_size, + MS_SYNC | MS_INVALIDATE), "flush failed"); - client_write_reply( client, &request, 0); + client_write_reply(client, &request, 0); } -void client_reply( struct client* client, struct nbd_request request ) +void client_reply(struct client *client, struct nbd_request request) { - switch (request.type) { - case REQUEST_READ: - client_reply_to_read( client, request ); - break; - case REQUEST_WRITE: - client_reply_to_write( client, request ); - break; - case REQUEST_FLUSH: - client_reply_to_flush( client, request ); - break; - } + switch (request.type) { + case REQUEST_READ: + client_reply_to_read(client, request); + break; + case REQUEST_WRITE: + client_reply_to_write(client, request); + break; + case REQUEST_FLUSH: + client_reply_to_flush(client, request); + break; + } } /* Starts a timer that will kill the whole process if disarm is not called * within a timeout (see CLIENT_HANDLE_TIMEOUT). */ -void client_arm_killswitch( struct client* client ) +void client_arm_killswitch(struct client *client) { - struct itimerspec its = { - .it_value = { .tv_nsec = 0, .tv_sec = CLIENT_HANDLER_TIMEOUT }, - .it_interval = { .tv_nsec = 0, .tv_sec = 0 } - }; + struct itimerspec its = { + .it_value = {.tv_nsec = 0,.tv_sec = CLIENT_HANDLER_TIMEOUT}, + .it_interval = {.tv_nsec = 0,.tv_sec = 0} + }; - if ( !client->serve->use_killswitch ) { - return; - } + if (!client->serve->use_killswitch) { + return; + } - debug( "Arming killswitch" ); + debug("Arming killswitch"); - FATAL_IF_NEGATIVE( - timer_settime( client->killswitch, 0, &its, NULL ), - SHOW_ERRNO( "Failed to arm killswitch" ) + FATAL_IF_NEGATIVE(timer_settime(client->killswitch, 0, &its, NULL), + SHOW_ERRNO("Failed to arm killswitch") ); - return; + return; } -void client_disarm_killswitch( struct client* client ) +void client_disarm_killswitch(struct client *client) { - struct itimerspec its = { - .it_value = { .tv_nsec = 0, .tv_sec = 0 }, - .it_interval = { .tv_nsec = 0, .tv_sec = 0 } - }; + struct itimerspec its = { + .it_value = {.tv_nsec = 0,.tv_sec = 0}, + .it_interval = {.tv_nsec = 0,.tv_sec = 0} + }; - if ( !client->serve->use_killswitch ) { - return; - } + if (!client->serve->use_killswitch) { + return; + } - debug( "Disarming killswitch" ); + debug("Disarming killswitch"); - FATAL_IF_NEGATIVE( - timer_settime( client->killswitch, 0, &its, NULL ), - SHOW_ERRNO( "Failed to disarm killswitch" ) + FATAL_IF_NEGATIVE(timer_settime(client->killswitch, 0, &its, NULL), + SHOW_ERRNO("Failed to disarm killswitch") ); - return; + return; } /* Returns 0 if we should continue trying to serve requests */ -int client_serve_request(struct client* client) +int client_serve_request(struct client *client) { - struct nbd_request request = {0}; - int stop = 1; - int disconnected = 0; - fd_set rfds, efds; - int fd_count; + struct nbd_request request = { 0 }; + int stop = 1; + int disconnected = 0; + fd_set rfds, efds; + int fd_count; - /* wait until there are some bytes on the fd before committing to reads - * FIXME: this whole scheme is broken because we're using blocking reads. - * read() can block directly after a select anyway, and it's possible that, - * without the killswitch, we'd hang forever. With the killswitch, we just - * hang for "a while". The Right Thing to do is to rewrite client.c to be - * non-blocking. - */ + /* wait until there are some bytes on the fd before committing to reads + * FIXME: this whole scheme is broken because we're using blocking reads. + * read() can block directly after a select anyway, and it's possible that, + * without the killswitch, we'd hang forever. With the killswitch, we just + * hang for "a while". The Right Thing to do is to rewrite client.c to be + * non-blocking. + */ - FD_ZERO( &rfds ); - FD_SET( client->socket, &rfds ); - self_pipe_fd_set( client->stop_signal, &rfds ); + FD_ZERO(&rfds); + FD_SET(client->socket, &rfds); + self_pipe_fd_set(client->stop_signal, &rfds); - FD_ZERO( &efds ); - FD_SET( client->socket, &efds ); + FD_ZERO(&efds); + FD_SET(client->socket, &efds); - fd_count = sock_try_select( FD_SETSIZE, &rfds, NULL, &efds, NULL ); + fd_count = sock_try_select(FD_SETSIZE, &rfds, NULL, &efds, NULL); - if ( fd_count == 0 ) { - /* This "can't ever happen" */ - fatal( "No FDs selected, and no timeout!" ); - } - else if ( fd_count < 0 ) { fatal( "Select failed" ); } + if (fd_count == 0) { + /* This "can't ever happen" */ + fatal("No FDs selected, and no timeout!"); + } else if (fd_count < 0) { + fatal("Select failed"); + } - if ( self_pipe_fd_isset( client->stop_signal, &rfds ) ){ - debug("Client received stop signal."); - return 1; // Don't try to serve more requests - } + if (self_pipe_fd_isset(client->stop_signal, &rfds)) { + debug("Client received stop signal."); + return 1; // Don't try to serve more requests + } - if ( FD_ISSET( client->socket, &efds ) ) { - debug( "Client connection closed" ); - return 1; - } + if (FD_ISSET(client->socket, &efds)) { + debug("Client connection closed"); + return 1; + } - /* We arm / disarm around the whole request cycle. The reason for this is - * that the remote peer could uncleanly die at any point; if we're stuck on - * a blocking read(), then that will hang for (almost) forever. This is bad - * in general, makes the server respond only to kill -9, and breaks - * outward mirroring in a most unpleasant way. - * - * Don't forget to disarm before exiting, no matter what! - * - * The replication is simple: open a connection to the flexnbd server, write - * a single byte, and then wait. - * - */ - client_arm_killswitch( client ); + /* We arm / disarm around the whole request cycle. The reason for this is + * that the remote peer could uncleanly die at any point; if we're stuck on + * a blocking read(), then that will hang for (almost) forever. This is bad + * in general, makes the server respond only to kill -9, and breaks + * outward mirroring in a most unpleasant way. + * + * Don't forget to disarm before exiting, no matter what! + * + * The replication is simple: open a connection to the flexnbd server, write + * a single byte, and then wait. + * + */ + client_arm_killswitch(client); - if ( !client_read_request( client, &request, &disconnected ) ) { - client_disarm_killswitch( client ); - return stop; - } - if ( disconnected ) { - client_disarm_killswitch( client ); - return stop; - } - - if ( !client_request_needs_reply( client, request ) ) { - client_disarm_killswitch( client ); - return client->disconnect; - } - - { - if ( !server_is_closed( client->serve ) ) { - client_reply( client, request ); - stop = 0; - } - } - - client_disarm_killswitch( client ); + if (!client_read_request(client, &request, &disconnected)) { + client_disarm_killswitch(client); return stop; + } + if (disconnected) { + client_disarm_killswitch(client); + return stop; + } + + if (!client_request_needs_reply(client, request)) { + client_disarm_killswitch(client); + return client->disconnect; + } + + { + if (!server_is_closed(client->serve)) { + client_reply(client, request); + stop = 0; + } + } + + client_disarm_killswitch(client); + return stop; } -void client_send_hello(struct client* client) +void client_send_hello(struct client *client) { - client_write_init( client, client->serve->size ); + client_write_init(client, client->serve->size); } -void client_cleanup(struct client* client, - int fatal __attribute__ ((unused)) ) +void client_cleanup(struct client *client, + int fatal __attribute__ ((unused))) { - info("client cleanup for client %p", client); + info("client cleanup for client %p", client); - /* If the thread hits an error, we need to ensure this is off */ - client_disarm_killswitch( client ); + /* If the thread hits an error, we need to ensure this is off */ + client_disarm_killswitch(client); - if (client->socket) { - FATAL_IF_NEGATIVE( close(client->socket), - "Error closing client socket %d", - client->socket ); - debug("Closed client socket fd %d", client->socket); - client->socket = -1; - } - if (client->mapped) { - munmap(client->mapped, client->serve->size); - } - if (client->fileno) { - FATAL_IF_NEGATIVE( close(client->fileno), - "Error closing file %d", - client->fileno ); - debug("Closed client file fd %d", client->fileno ); - client->fileno = -1; - } + if (client->socket) { + FATAL_IF_NEGATIVE(close(client->socket), + "Error closing client socket %d", + client->socket); + debug("Closed client socket fd %d", client->socket); + client->socket = -1; + } + if (client->mapped) { + munmap(client->mapped, client->serve->size); + } + if (client->fileno) { + FATAL_IF_NEGATIVE(close(client->fileno), + "Error closing file %d", client->fileno); + debug("Closed client file fd %d", client->fileno); + client->fileno = -1; + } - if ( server_acl_locked( client->serve ) ) { server_unlock_acl( client->serve ); } + if (server_acl_locked(client->serve)) { + server_unlock_acl(client->serve); + } } -void* client_serve(void* client_uncast) +void *client_serve(void *client_uncast) { - struct client* client = (struct client*) client_uncast; + struct client *client = (struct client *) client_uncast; - error_set_handler((cleanup_handler*) client_cleanup, client); + error_set_handler((cleanup_handler *) client_cleanup, client); - info("client: mmaping file"); - FATAL_IF_NEGATIVE( - open_and_mmap( - client->serve->filename, - &client->fileno, - &client->mapped_size, - (void**) &client->mapped - ), - "Couldn't open/mmap file %s: %s", client->serve->filename, strerror( errno ) + info("client: mmaping file"); + FATAL_IF_NEGATIVE(open_and_mmap(client->serve->filename, + &client->fileno, + &client->mapped_size, + (void **) &client->mapped), + "Couldn't open/mmap file %s: %s", + client->serve->filename, strerror(errno) ); - FATAL_IF_NEGATIVE( - madvise( client->mapped, client->serve->size, MADV_RANDOM ), - SHOW_ERRNO( "Failed to madvise() %s", client->serve->filename ) + FATAL_IF_NEGATIVE(madvise + (client->mapped, client->serve->size, MADV_RANDOM), + SHOW_ERRNO("Failed to madvise() %s", + client->serve->filename) ); - debug( "Opened client file fd %d", client->fileno); - debug("client: sending hello"); - client_send_hello(client); + debug("Opened client file fd %d", client->fileno); + debug("client: sending hello"); + client_send_hello(client); - debug("client: serving requests"); - while (client_serve_request(client) == 0) - ; - debug("client: stopped serving requests"); - client->stopped = 1; + debug("client: serving requests"); + while (client_serve_request(client) == 0); + debug("client: stopped serving requests"); + client->stopped = 1; - if ( client->disconnect ){ - debug("client: control arrived" ); - server_control_arrived( client->serve ); - } + if (client->disconnect) { + debug("client: control arrived"); + server_control_arrived(client->serve); + } - debug("Cleaning client %p up normally in thread %p", client, pthread_self()); - client_cleanup(client, 0); - debug("Client thread done" ); + debug("Cleaning client %p up normally in thread %p", client, + pthread_self()); + client_cleanup(client, 0); + debug("Client thread done"); - return NULL; + return NULL; } - diff --git a/src/server/client.h b/src/server/client.h index a03ea44..56b1458 100644 --- a/src/server/client.h +++ b/src/server/client.h @@ -19,41 +19,40 @@ struct client { - /* When we call pthread_join, if the thread is already dead - * we can get an ESRCH. Since we have no other way to tell - * if that ESRCH is from a dead thread or a thread that never - * existed, we use a `stopped` flag to indicate a thread which - * did exist, but went away. Only check this after a - * pthread_join call. - */ - int stopped; - int socket; + /* When we call pthread_join, if the thread is already dead + * we can get an ESRCH. Since we have no other way to tell + * if that ESRCH is from a dead thread or a thread that never + * existed, we use a `stopped` flag to indicate a thread which + * did exist, but went away. Only check this after a + * pthread_join call. + */ + int stopped; + int socket; - int fileno; - char* mapped; + int fileno; + char *mapped; - uint64_t mapped_size; + uint64_t mapped_size; - struct self_pipe * stop_signal; + struct self_pipe *stop_signal; - struct server* serve; /* FIXME: remove above duplication */ + struct server *serve; /* FIXME: remove above duplication */ - /* Have we seen a REQUEST_DISCONNECT message? */ - int disconnect; + /* Have we seen a REQUEST_DISCONNECT message? */ + int disconnect; - /* kill the whole server if a request has been outstanding too long, - * assuming use_killswitch is set in serve - */ - timer_t killswitch; + /* kill the whole server if a request has been outstanding too long, + * assuming use_killswitch is set in serve + */ + timer_t killswitch; }; -void client_killswitch_hit(int signal, siginfo_t *info, void *ptr); +void client_killswitch_hit(int signal, siginfo_t * info, void *ptr); -void* client_serve(void* client_uncast); -struct client * client_create( struct server * serve, int socket ); -void client_destroy( struct client * client ); -void client_signal_stop( struct client * client ); +void *client_serve(void *client_uncast); +struct client *client_create(struct server *serve, int socket); +void client_destroy(struct client *client); +void client_signal_stop(struct client *client); #endif - diff --git a/src/server/control.c b/src/server/control.c index 63f0720..394854e 100644 --- a/src/server/control.c +++ b/src/server/control.c @@ -44,590 +44,570 @@ #include -struct control * control_create( - struct flexnbd * flexnbd, - const char * csn) +struct control *control_create(struct flexnbd *flexnbd, const char *csn) { - struct control * control = xmalloc( sizeof( struct control ) ); + struct control *control = xmalloc(sizeof(struct control)); - NULLCHECK( csn ); + NULLCHECK(csn); - control->flexnbd = flexnbd; - control->socket_name = csn; - control->open_signal = self_pipe_create(); - control->close_signal = self_pipe_create(); - control->mirror_state_mbox = mbox_create(); + control->flexnbd = flexnbd; + control->socket_name = csn; + control->open_signal = self_pipe_create(); + control->close_signal = self_pipe_create(); + control->mirror_state_mbox = mbox_create(); - return control; + return control; } -void control_signal_close( struct control * control) +void control_signal_close(struct control *control) { - NULLCHECK( control ); - self_pipe_signal( control->close_signal ); + NULLCHECK(control); + self_pipe_signal(control->close_signal); } -void control_destroy( struct control * control ) +void control_destroy(struct control *control) { - NULLCHECK( control ); + NULLCHECK(control); - mbox_destroy( control->mirror_state_mbox ); - self_pipe_destroy( control->close_signal ); - self_pipe_destroy( control->open_signal ); - free( control ); + mbox_destroy(control->mirror_state_mbox); + self_pipe_destroy(control->close_signal); + self_pipe_destroy(control->open_signal); + free(control); } -struct control_client * control_client_create( - struct flexnbd * flexnbd, - int client_fd , - struct mbox * state_mbox ) +struct control_client *control_client_create(struct flexnbd *flexnbd, + int client_fd, + struct mbox *state_mbox) { - NULLCHECK( flexnbd ); + NULLCHECK(flexnbd); - struct control_client * control_client = - xmalloc( sizeof( struct control_client ) ); + struct control_client *control_client = + xmalloc(sizeof(struct control_client)); - control_client->socket = client_fd; - control_client->flexnbd = flexnbd; - control_client->mirror_state_mbox = state_mbox; - return control_client; + control_client->socket = client_fd; + control_client->flexnbd = flexnbd; + control_client->mirror_state_mbox = state_mbox; + return control_client; } -void control_client_destroy( struct control_client * client ) +void control_client_destroy(struct control_client *client) { - NULLCHECK( client ); - free( client ); + NULLCHECK(client); + free(client); } -void control_respond(struct control_client * client); +void control_respond(struct control_client *client); -void control_handle_client( struct control * control, int client_fd ) +void control_handle_client(struct control *control, int client_fd) { - NULLCHECK( control ); - NULLCHECK( control->flexnbd ); - struct control_client * control_client = - control_client_create( - control->flexnbd, - client_fd , - control->mirror_state_mbox); + NULLCHECK(control); + NULLCHECK(control->flexnbd); + struct control_client *control_client = + control_client_create(control->flexnbd, + client_fd, + control->mirror_state_mbox); - /* We intentionally don't spawn a thread for the client here. - * This is to avoid having more than one thread potentially - * waiting on the migration commit status. - */ - control_respond( control_client ); + /* We intentionally don't spawn a thread for the client here. + * This is to avoid having more than one thread potentially + * waiting on the migration commit status. + */ + control_respond(control_client); } -void control_accept_client( struct control * control ) +void control_accept_client(struct control *control) { - int client_fd; - union mysockaddr client_address; - socklen_t addrlen = sizeof( union mysockaddr ); + int client_fd; + union mysockaddr client_address; + socklen_t addrlen = sizeof(union mysockaddr); - client_fd = accept( control->control_fd, &client_address.generic, &addrlen ); - FATAL_IF( -1 == client_fd, "control accept failed" ); + client_fd = + accept(control->control_fd, &client_address.generic, &addrlen); + FATAL_IF(-1 == client_fd, "control accept failed"); - control_handle_client( control, client_fd ); + control_handle_client(control, client_fd); } -int control_accept( struct control * control ) +int control_accept(struct control *control) { - NULLCHECK( control ); + NULLCHECK(control); - fd_set fds; + fd_set fds; - FD_ZERO( &fds ); - FD_SET( control->control_fd, &fds ); - self_pipe_fd_set( control->close_signal, &fds ); - debug("Control thread selecting"); - FATAL_UNLESS( 0 < select( FD_SETSIZE, &fds, NULL, NULL, NULL ), - "Control select failed." ); + FD_ZERO(&fds); + FD_SET(control->control_fd, &fds); + self_pipe_fd_set(control->close_signal, &fds); + debug("Control thread selecting"); + FATAL_UNLESS(0 < select(FD_SETSIZE, &fds, NULL, NULL, NULL), + "Control select failed."); - if ( self_pipe_fd_isset( control->close_signal, &fds ) ){ - return 0; - } + if (self_pipe_fd_isset(control->close_signal, &fds)) { + return 0; + } - if ( FD_ISSET( control->control_fd, &fds ) ) { - control_accept_client( control ); - } - return 1; + if (FD_ISSET(control->control_fd, &fds)) { + control_accept_client(control); + } + return 1; } -void control_accept_loop( struct control * control ) +void control_accept_loop(struct control *control) { - while( control_accept( control ) ); + while (control_accept(control)); } -int open_control_socket( const char * socket_name ) +int open_control_socket(const char *socket_name) { - struct sockaddr_un bind_address; - int control_fd; + struct sockaddr_un bind_address; + int control_fd; - if (!socket_name) { - fatal( "Tried to open a control socket without a socket name" ); - } + if (!socket_name) { + fatal("Tried to open a control socket without a socket name"); + } - control_fd = socket(AF_UNIX, SOCK_STREAM, 0); - FATAL_IF_NEGATIVE(control_fd , - "Couldn't create control socket"); + control_fd = socket(AF_UNIX, SOCK_STREAM, 0); + FATAL_IF_NEGATIVE(control_fd, "Couldn't create control socket"); - memset(&bind_address, 0, sizeof(struct sockaddr_un)); - bind_address.sun_family = AF_UNIX; - strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1); + memset(&bind_address, 0, sizeof(struct sockaddr_un)); + bind_address.sun_family = AF_UNIX; + strncpy(bind_address.sun_path, socket_name, + sizeof(bind_address.sun_path) - 1); - //unlink(socket_name); /* ignore failure */ + //unlink(socket_name); /* ignore failure */ - FATAL_IF_NEGATIVE( - bind(control_fd , &bind_address, sizeof(bind_address)), - "Couldn't bind control socket to %s: %s", - socket_name, strerror( errno ) + FATAL_IF_NEGATIVE(bind + (control_fd, &bind_address, sizeof(bind_address)), + "Couldn't bind control socket to %s: %s", + socket_name, strerror(errno) ); - FATAL_IF_NEGATIVE( - listen(control_fd , 5), - "Couldn't listen on control socket" - ); - return control_fd; + FATAL_IF_NEGATIVE(listen(control_fd, 5), + "Couldn't listen on control socket"); + return control_fd; } -void control_listen(struct control* control) +void control_listen(struct control *control) { - NULLCHECK( control ); - control->control_fd = open_control_socket( control->socket_name ); + NULLCHECK(control); + control->control_fd = open_control_socket(control->socket_name); } -void control_wait_for_open_signal( struct control * control ) +void control_wait_for_open_signal(struct control *control) { - fd_set fds; - FD_ZERO( &fds ); - self_pipe_fd_set( control->open_signal, &fds ); - FATAL_IF_NEGATIVE( select( FD_SETSIZE, &fds, NULL, NULL, NULL ), - "select() failed" ); + fd_set fds; + FD_ZERO(&fds); + self_pipe_fd_set(control->open_signal, &fds); + FATAL_IF_NEGATIVE(select(FD_SETSIZE, &fds, NULL, NULL, NULL), + "select() failed"); - self_pipe_signal_clear( control->open_signal ); + self_pipe_signal_clear(control->open_signal); } -void control_serve( struct control * control ) +void control_serve(struct control *control) { - NULLCHECK( control ); + NULLCHECK(control); - control_wait_for_open_signal( control ); - control_listen( control ); - while( control_accept( control ) ); + control_wait_for_open_signal(control); + control_listen(control); + while (control_accept(control)); } -void control_cleanup( - struct control * control, - int fatal __attribute__((unused)) ) +void control_cleanup(struct control *control, + int fatal __attribute__ ((unused))) { - NULLCHECK( control ); - unlink( control->socket_name ); - close( control->control_fd ); + NULLCHECK(control); + unlink(control->socket_name); + close(control->control_fd); } -void * control_runner( void * control_uncast ) +void *control_runner(void *control_uncast) { - debug("Control thread"); - NULLCHECK( control_uncast ); - struct control * control = (struct control *)control_uncast; + debug("Control thread"); + NULLCHECK(control_uncast); + struct control *control = (struct control *) control_uncast; - error_set_handler( (cleanup_handler*)control_cleanup, control ); + error_set_handler((cleanup_handler *) control_cleanup, control); - control_serve( control ); + control_serve(control); - control_cleanup( control, 0 ); - pthread_exit( NULL ); + control_cleanup(control, 0); + pthread_exit(NULL); } #define write_socket(msg) write(client_fd, (msg "\n"), strlen((msg))+1) -void control_write_mirror_response( enum mirror_state mirror_state, int client_fd ) +void control_write_mirror_response(enum mirror_state mirror_state, + int client_fd) { - switch (mirror_state) { - case MS_INIT: - case MS_UNKNOWN: - write_socket( "1: Mirror failed to initialise" ); - fatal( "Impossible mirror state: %d", mirror_state ); - case MS_FAIL_CONNECT: - write_socket( "1: Mirror failed to connect"); - break; - case MS_FAIL_REJECTED: - write_socket( "1: Mirror was rejected" ); - break; - case MS_FAIL_NO_HELLO: - write_socket( "1: Remote server failed to respond"); - break; - case MS_FAIL_SIZE_MISMATCH: - write_socket( "1: Remote size does not match local size" ); - break; - case MS_ABANDONED: - write_socket( "1: Mirroring abandoned" ); - break; - case MS_GO: - case MS_DONE: /* Yes, I know we know better, but it's simpler this way */ - write_socket( "0: Mirror started" ); - break; - default: - fatal( "Unhandled mirror state: %d", mirror_state ); - } + switch (mirror_state) { + case MS_INIT: + case MS_UNKNOWN: + write_socket("1: Mirror failed to initialise"); + fatal("Impossible mirror state: %d", mirror_state); + case MS_FAIL_CONNECT: + write_socket("1: Mirror failed to connect"); + break; + case MS_FAIL_REJECTED: + write_socket("1: Mirror was rejected"); + break; + case MS_FAIL_NO_HELLO: + write_socket("1: Remote server failed to respond"); + break; + case MS_FAIL_SIZE_MISMATCH: + write_socket("1: Remote size does not match local size"); + break; + case MS_ABANDONED: + write_socket("1: Mirroring abandoned"); + break; + case MS_GO: + case MS_DONE: /* Yes, I know we know better, but it's simpler this way */ + write_socket("0: Mirror started"); + break; + default: + fatal("Unhandled mirror state: %d", mirror_state); + } } + #undef write_socket /* Call this in the thread where you want to receive the mirror state */ -enum mirror_state control_client_mirror_wait( - struct control_client* client) +enum mirror_state control_client_mirror_wait(struct control_client *client) { - NULLCHECK( client ); - NULLCHECK( client->mirror_state_mbox ); + NULLCHECK(client); + NULLCHECK(client->mirror_state_mbox); - struct mbox * mbox = client->mirror_state_mbox; - enum mirror_state mirror_state; - enum mirror_state * contents; + struct mbox *mbox = client->mirror_state_mbox; + enum mirror_state mirror_state; + enum mirror_state *contents; - contents = (enum mirror_state*)mbox_receive( mbox ); - NULLCHECK( contents ); + contents = (enum mirror_state *) mbox_receive(mbox); + NULLCHECK(contents); - mirror_state = *contents; + mirror_state = *contents; - free( contents ); + free(contents); - return mirror_state; + return mirror_state; } #define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1) /** Command parser to start mirror process from socket input */ -int control_mirror(struct control_client* client, int linesc, char** lines) +int control_mirror(struct control_client *client, int linesc, char **lines) { - NULLCHECK( client ); + NULLCHECK(client); - struct flexnbd * flexnbd = client->flexnbd; - union mysockaddr *connect_to = xmalloc( sizeof( union mysockaddr ) ); - union mysockaddr *connect_from = NULL; - uint64_t max_Bps = UINT64_MAX; - int action_at_finish; - int raw_port; + struct flexnbd *flexnbd = client->flexnbd; + union mysockaddr *connect_to = xmalloc(sizeof(union mysockaddr)); + union mysockaddr *connect_from = NULL; + uint64_t max_Bps = UINT64_MAX; + int action_at_finish; + int raw_port; - if (linesc < 2) { - write_socket("1: mirror takes at least two parameters"); - return -1; + if (linesc < 2) { + write_socket("1: mirror takes at least two parameters"); + return -1; + } + + if (parse_ip_to_sockaddr(&connect_to->generic, lines[0]) == 0) { + write_socket("1: bad IP address"); + return -1; + } + + raw_port = atoi(lines[1]); + if (raw_port < 0 || raw_port > 65535) { + write_socket("1: bad IP port number"); + return -1; + } + connect_to->v4.sin_port = htobe16(raw_port); + + action_at_finish = ACTION_EXIT; + if (linesc > 2) { + if (strcmp("exit", lines[2]) == 0) { + action_at_finish = ACTION_EXIT; + } else if (strcmp("unlink", lines[2]) == 0) { + action_at_finish = ACTION_UNLINK; + } else if (strcmp("nothing", lines[2]) == 0) { + action_at_finish = ACTION_NOTHING; + } else { + write_socket("1: action must be 'exit' or 'nothing'"); + return -1; + } + } + + if (linesc > 3) { + connect_from = xmalloc(sizeof(union mysockaddr)); + if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) { + write_socket("1: bad bind address"); + return -1; + } + } + + if (linesc > 4) { + errno = 0; + max_Bps = strtoull(lines[4], NULL, 10); + if (errno == ERANGE) { + write_socket("1: max_bps out of range"); + return -1; + } else if (errno != 0) { + write_socket("1: max_bps couldn't be parsed"); + return -1; + } + } + + + if (linesc > 5) { + write_socket("1: unrecognised parameters to mirror"); + return -1; + } + + struct server *serve = flexnbd_server(flexnbd); + + server_lock_start_mirror(serve); + { + if (server_mirror_can_start(serve)) { + serve->mirror_super = mirror_super_create(serve->filename, + connect_to, + connect_from, + max_Bps, + action_at_finish, + client-> + mirror_state_mbox); + serve->mirror = serve->mirror_super->mirror; + server_prevent_mirror_start(serve); + } else { + if (serve->mirror_super) { + warn("Tried to start a second mirror run"); + write_socket("1: mirror already running"); + } else { + warn("Cannot start mirroring, shutting down"); + write_socket("1: shutting down"); + } } - if (parse_ip_to_sockaddr(&connect_to->generic, lines[0]) == 0) { - write_socket("1: bad IP address"); - return -1; - } + } + server_unlock_start_mirror(serve); - raw_port = atoi(lines[1]); - if (raw_port < 0 || raw_port > 65535) { - write_socket("1: bad IP port number"); - return -1; - } - connect_to->v4.sin_port = htobe16(raw_port); + /* Do this outside the lock to minimise the length of time the + * sighandler can block the serve thread + */ + if (serve->mirror_super) { + FATAL_IF(0 != pthread_create(&serve->mirror_super->thread, + NULL, + mirror_super_runner, + serve), + "Failed to create mirror thread"); - action_at_finish = ACTION_EXIT; - if (linesc > 2) { - if (strcmp("exit", lines[2]) == 0) { - action_at_finish = ACTION_EXIT; - } - else if (strcmp( "unlink", lines[2]) == 0 ) { - action_at_finish = ACTION_UNLINK; - } - else if (strcmp("nothing", lines[2]) == 0) { - action_at_finish = ACTION_NOTHING; - } - else { - write_socket("1: action must be 'exit' or 'nothing'"); - return -1; - } - } + debug("Control thread mirror super waiting"); + enum mirror_state state = control_client_mirror_wait(client); + debug("Control thread writing response"); + control_write_mirror_response(state, client->socket); + } - if (linesc > 3) { - connect_from = xmalloc( sizeof( union mysockaddr ) ); - if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) { - write_socket("1: bad bind address"); - return -1; - } - } + debug("Control thread going away."); - if (linesc > 4) { - errno = 0; - max_Bps = strtoull( lines[4], NULL, 10 ); - if ( errno == ERANGE ) { - write_socket( "1: max_bps out of range" ); - return -1; - } else if ( errno != 0 ) { - write_socket( "1: max_bps couldn't be parsed" ); - return -1; - } - } - - - if (linesc > 5) { - write_socket("1: unrecognised parameters to mirror"); - return -1; - } - - struct server * serve = flexnbd_server(flexnbd); - - server_lock_start_mirror( serve ); - { - if ( server_mirror_can_start( serve ) ) { - serve->mirror_super = mirror_super_create( - serve->filename, - connect_to, - connect_from, - max_Bps , - action_at_finish, - client->mirror_state_mbox ); - serve->mirror = serve->mirror_super->mirror; - server_prevent_mirror_start( serve ); - } else { - if ( serve->mirror_super ) { - warn( "Tried to start a second mirror run" ); - write_socket( "1: mirror already running" ); - } else { - warn( "Cannot start mirroring, shutting down" ); - write_socket( "1: shutting down" ); - } - } - - } - server_unlock_start_mirror( serve ); - - /* Do this outside the lock to minimise the length of time the - * sighandler can block the serve thread - */ - if ( serve->mirror_super ) { - FATAL_IF( 0 != pthread_create( - &serve->mirror_super->thread, - NULL, - mirror_super_runner, - serve - ), - "Failed to create mirror thread" - ); - - debug("Control thread mirror super waiting"); - enum mirror_state state = - control_client_mirror_wait( client ); - debug("Control thread writing response"); - control_write_mirror_response( state, client->socket ); - } - - debug( "Control thread going away." ); - - return 0; + return 0; } -int control_mirror_max_bps( struct control_client* client, int linesc, char** lines ) +int control_mirror_max_bps(struct control_client *client, int linesc, + char **lines) { - NULLCHECK( client ); - NULLCHECK( client->flexnbd ); + NULLCHECK(client); + NULLCHECK(client->flexnbd); - struct server* serve = flexnbd_server( client->flexnbd ); - uint64_t max_Bps; + struct server *serve = flexnbd_server(client->flexnbd); + uint64_t max_Bps; - if ( !serve->mirror_super ) { - write_socket( "1: Not currently mirroring" ); - return -1; - } + if (!serve->mirror_super) { + write_socket("1: Not currently mirroring"); + return -1; + } - if ( linesc != 1 ) { - write_socket( "1: Bad format" ); - return -1; - } + if (linesc != 1) { + write_socket("1: Bad format"); + return -1; + } - errno = 0; - max_Bps = strtoull( lines[0], NULL, 10 ); - if ( errno == ERANGE ) { - write_socket( "1: max_bps out of range" ); - return -1; - } else if ( errno != 0 ) { - write_socket( "1: max_bps couldn't be parsed" ); - return -1; - } + errno = 0; + max_Bps = strtoull(lines[0], NULL, 10); + if (errno == ERANGE) { + write_socket("1: max_bps out of range"); + return -1; + } else if (errno != 0) { + write_socket("1: max_bps couldn't be parsed"); + return -1; + } - serve->mirror->max_bytes_per_second = max_Bps; - write_socket( "0: updated" ); + serve->mirror->max_bytes_per_second = max_Bps; + write_socket("0: updated"); - return 0; + return 0; } #undef write_socket /** Command parser to alter access control list from socket input */ -int control_acl(struct control_client* client, int linesc, char** lines) +int control_acl(struct control_client *client, int linesc, char **lines) { - NULLCHECK( client ); - NULLCHECK( client->flexnbd ); - struct flexnbd * flexnbd = client->flexnbd; + NULLCHECK(client); + NULLCHECK(client->flexnbd); + struct flexnbd *flexnbd = client->flexnbd; - int default_deny = flexnbd_default_deny( flexnbd ); - struct acl * new_acl = acl_create( linesc, lines, default_deny ); + int default_deny = flexnbd_default_deny(flexnbd); + struct acl *new_acl = acl_create(linesc, lines, default_deny); - if (new_acl->len != linesc) { - warn("Bad ACL spec: %s", lines[new_acl->len] ); - write(client->socket, "1: bad spec: ", 13); - write(client->socket, lines[new_acl->len], - strlen(lines[new_acl->len])); - write(client->socket, "\n", 1); - acl_destroy( new_acl ); - } - else { - flexnbd_replace_acl( flexnbd, new_acl ); - info("ACL set"); - write( client->socket, "0: updated\n", 11); - } + if (new_acl->len != linesc) { + warn("Bad ACL spec: %s", lines[new_acl->len]); + write(client->socket, "1: bad spec: ", 13); + write(client->socket, lines[new_acl->len], + strlen(lines[new_acl->len])); + write(client->socket, "\n", 1); + acl_destroy(new_acl); + } else { + flexnbd_replace_acl(flexnbd, new_acl); + info("ACL set"); + write(client->socket, "0: updated\n", 11); + } - return 0; + return 0; } -int control_break( - struct control_client* client, - int linesc __attribute__ ((unused)), - char** lines __attribute__((unused)) - ) +int control_break(struct control_client *client, + int linesc __attribute__ ((unused)), + char **lines __attribute__ ((unused)) + ) { - NULLCHECK( client ); - NULLCHECK( client->flexnbd ); + NULLCHECK(client); + NULLCHECK(client->flexnbd); - int result = 0; - struct flexnbd* flexnbd = client->flexnbd; + int result = 0; + struct flexnbd *flexnbd = client->flexnbd; - struct server * serve = flexnbd_server( flexnbd ); + struct server *serve = flexnbd_server(flexnbd); - server_lock_start_mirror( serve ); - { - if ( server_is_mirroring( serve ) ) { + server_lock_start_mirror(serve); + { + if (server_is_mirroring(serve)) { - info( "Signaling to abandon mirror" ); - server_abandon_mirror( serve ); - debug( "Abandon signaled" ); + info("Signaling to abandon mirror"); + server_abandon_mirror(serve); + debug("Abandon signaled"); - if ( server_is_closed( serve ) ) { - info( "Mirror completed while canceling" ); - write( client->socket, - "1: mirror completed\n", 20 ); - } - else { - info( "Mirror successfully stopped." ); - write( client->socket, - "0: mirror stopped\n", 18 ); - result = 1; - } + if (server_is_closed(serve)) { + info("Mirror completed while canceling"); + write(client->socket, "1: mirror completed\n", 20); + } else { + info("Mirror successfully stopped."); + write(client->socket, "0: mirror stopped\n", 18); + result = 1; + } - } else { - warn( "Not mirroring." ); - write( client->socket, "1: not mirroring\n", 17 ); - } + } else { + warn("Not mirroring."); + write(client->socket, "1: not mirroring\n", 17); } - server_unlock_start_mirror( serve ); + } + server_unlock_start_mirror(serve); - return result; + return result; } /** FIXME: add some useful statistics */ -int control_status( - struct control_client* client, - int linesc __attribute__ ((unused)), - char** lines __attribute__((unused)) - ) +int control_status(struct control_client *client, + int linesc __attribute__ ((unused)), + char **lines __attribute__ ((unused)) + ) { - NULLCHECK( client ); - NULLCHECK( client->flexnbd ); - struct status * status = flexnbd_status_create( client->flexnbd ); + NULLCHECK(client); + NULLCHECK(client->flexnbd); + struct status *status = flexnbd_status_create(client->flexnbd); - write( client->socket, "0: ", 3 ); - status_write( status, client->socket ); - status_destroy( status ); + write(client->socket, "0: ", 3); + status_write(status, client->socket); + status_destroy(status); - return 0; + return 0; } -void control_client_cleanup(struct control_client* client, - int fatal __attribute__ ((unused)) ) +void control_client_cleanup(struct control_client *client, + int fatal __attribute__ ((unused))) { - if (client->socket) { close(client->socket); } + if (client->socket) { + close(client->socket); + } - /* This is wrongness */ - if ( server_acl_locked( client->flexnbd->serve ) ) { server_unlock_acl( client->flexnbd->serve ); } + /* This is wrongness */ + if (server_acl_locked(client->flexnbd->serve)) { + server_unlock_acl(client->flexnbd->serve); + } - control_client_destroy( client ); + control_client_destroy(client); } /** Master command parser for control socket connections, delegates quickly */ -void control_respond(struct control_client * client) +void control_respond(struct control_client *client) { - char **lines = NULL; + char **lines = NULL; - error_set_handler((cleanup_handler*) control_client_cleanup, client); + error_set_handler((cleanup_handler *) control_client_cleanup, client); - int i, linesc; - linesc = read_lines_until_blankline(client->socket, 256, &lines); + int i, linesc; + linesc = read_lines_until_blankline(client->socket, 256, &lines); - if (linesc < 1) - { - write(client->socket, "9: missing command\n", 19); - /* ignore failure */ + if (linesc < 1) { + write(client->socket, "9: missing command\n", 19); + /* ignore failure */ + } else if (strcmp(lines[0], "acl") == 0) { + info("acl command received"); + if (control_acl(client, linesc - 1, lines + 1) < 0) { + debug("acl command failed"); } - else if (strcmp(lines[0], "acl") == 0) { - info("acl command received" ); - if (control_acl(client, linesc-1, lines+1) < 0) { - debug("acl command failed"); - } + } else if (strcmp(lines[0], "mirror") == 0) { + info("mirror command received"); + if (control_mirror(client, linesc - 1, lines + 1) < 0) { + debug("mirror command failed"); } - else if (strcmp(lines[0], "mirror") == 0) { - info("mirror command received" ); - if (control_mirror(client, linesc-1, lines+1) < 0) { - debug("mirror command failed"); - } + } else if (strcmp(lines[0], "break") == 0) { + info("break command received"); + if (control_break(client, linesc - 1, lines + 1) < 0) { + debug("break command failed"); } - else if (strcmp(lines[0], "break") == 0) { - info( "break command received" ); - if ( control_break( client, linesc-1, lines+1) < 0) { - debug( "break command failed" ); - } + } else if (strcmp(lines[0], "status") == 0) { + info("status command received"); + if (control_status(client, linesc - 1, lines + 1) < 0) { + debug("status command failed"); } - else if (strcmp(lines[0], "status") == 0) { - info("status command received" ); - if (control_status(client, linesc-1, lines+1) < 0) { - debug("status command failed"); - } - } else if ( strcmp( lines[0], "mirror_max_bps" ) == 0 ) { - info( "mirror_max_bps command received" ); - if( control_mirror_max_bps( client, linesc-1, lines+1 ) < 0 ) { - debug( "mirror_max_bps command failed" ); - } - } - else { - write(client->socket, "10: unknown command\n", 23); + } else if (strcmp(lines[0], "mirror_max_bps") == 0) { + info("mirror_max_bps command received"); + if (control_mirror_max_bps(client, linesc - 1, lines + 1) < 0) { + debug("mirror_max_bps command failed"); } + } else { + write(client->socket, "10: unknown command\n", 23); + } - for (i=0; icontrol = - control_create( flexnbd, s_ctrl_sock ); - } - else { - flexnbd->control = NULL; - } + NULLCHECK(flexnbd); + if (s_ctrl_sock) { + flexnbd->control = control_create(flexnbd, s_ctrl_sock); + } else { + flexnbd->control = NULL; + } - flexnbd->signal_fd = flexnbd_build_signal_fd(); + flexnbd->signal_fd = flexnbd_build_signal_fd(); } -struct flexnbd * flexnbd_create_serving( - char* s_ip_address, - char* s_port, - char* s_file, - char* s_ctrl_sock, - int default_deny, - int acl_entries, - char** s_acl_entries, - int max_nbd_clients, - int use_killswitch) +struct flexnbd *flexnbd_create_serving(char *s_ip_address, + char *s_port, + char *s_file, + char *s_ctrl_sock, + int default_deny, + int acl_entries, + char **s_acl_entries, + int max_nbd_clients, + int use_killswitch) { - struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) ); - flexnbd->serve = server_create( - flexnbd, - s_ip_address, - s_port, - s_file, - default_deny, - acl_entries, - s_acl_entries, - max_nbd_clients, - use_killswitch, - 1); - flexnbd_create_shared( flexnbd, s_ctrl_sock ); + struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd)); + flexnbd->serve = server_create(flexnbd, + s_ip_address, + s_port, + s_file, + default_deny, + acl_entries, + s_acl_entries, + max_nbd_clients, use_killswitch, 1); + flexnbd_create_shared(flexnbd, s_ctrl_sock); - // Beats installing one handler per client instance - if ( use_killswitch ) { - struct sigaction act = { - .sa_sigaction = client_killswitch_hit, - .sa_flags = SA_RESTART | SA_SIGINFO - }; + // Beats installing one handler per client instance + if (use_killswitch) { + struct sigaction act = { + .sa_sigaction = client_killswitch_hit, + .sa_flags = SA_RESTART | SA_SIGINFO + }; - FATAL_UNLESS( - 0 == sigaction( CLIENT_KILLSWITCH_SIGNAL, &act, NULL ), - "Installing client killswitch signal failed" - ); - } + FATAL_UNLESS(0 == sigaction(CLIENT_KILLSWITCH_SIGNAL, &act, NULL), + "Installing client killswitch signal failed"); + } - return flexnbd; + return flexnbd; } -struct flexnbd * flexnbd_create_listening( - char* s_ip_address, - char* s_port, - char* s_file, - char* s_ctrl_sock, - int default_deny, - int acl_entries, - char** s_acl_entries ) +struct flexnbd *flexnbd_create_listening(char *s_ip_address, + char *s_port, + char *s_file, + char *s_ctrl_sock, + int default_deny, + int acl_entries, + char **s_acl_entries) { - struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) ); - flexnbd->serve = server_create( - flexnbd, - s_ip_address, - s_port, - s_file, - default_deny, - acl_entries, - s_acl_entries, - 1, 0, 0); - flexnbd_create_shared( flexnbd, s_ctrl_sock ); + struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd)); + flexnbd->serve = server_create(flexnbd, + s_ip_address, + s_port, + s_file, + default_deny, + acl_entries, s_acl_entries, 1, 0, 0); + flexnbd_create_shared(flexnbd, s_ctrl_sock); - // listen can't use killswitch, as mirror may pause on sending things - // for a very long time. + // listen can't use killswitch, as mirror may pause on sending things + // for a very long time. - return flexnbd; + return flexnbd; } -void flexnbd_spawn_control(struct flexnbd * flexnbd ) +void flexnbd_spawn_control(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - NULLCHECK( flexnbd->control ); + NULLCHECK(flexnbd); + NULLCHECK(flexnbd->control); - pthread_t * control_thread = &flexnbd->control->thread; + pthread_t *control_thread = &flexnbd->control->thread; - FATAL_UNLESS( 0 == pthread_create( - control_thread, - NULL, - control_runner, - flexnbd->control ), - "Couldn't create the control thread" ); + FATAL_UNLESS(0 == pthread_create(control_thread, + NULL, + control_runner, + flexnbd->control), + "Couldn't create the control thread"); } -void flexnbd_stop_control( struct flexnbd * flexnbd ) +void flexnbd_stop_control(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - NULLCHECK( flexnbd->control ); + NULLCHECK(flexnbd); + NULLCHECK(flexnbd->control); - control_signal_close( flexnbd->control ); - pthread_t tid = flexnbd->control->thread; - FATAL_UNLESS( 0 == pthread_join( tid, NULL ), - "Failed joining the control thread" ); - debug( "Control thread %p pthread_join returned", tid ); + control_signal_close(flexnbd->control); + pthread_t tid = flexnbd->control->thread; + FATAL_UNLESS(0 == pthread_join(tid, NULL), + "Failed joining the control thread"); + debug("Control thread %p pthread_join returned", tid); } -int flexnbd_signal_fd( struct flexnbd * flexnbd ) +int flexnbd_signal_fd(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - return flexnbd->signal_fd; + NULLCHECK(flexnbd); + return flexnbd->signal_fd; } -void flexnbd_destroy( struct flexnbd * flexnbd ) +void flexnbd_destroy(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - if ( flexnbd->control ) { - control_destroy( flexnbd->control ); - } + NULLCHECK(flexnbd); + if (flexnbd->control) { + control_destroy(flexnbd->control); + } - close( flexnbd->signal_fd ); - free( flexnbd ); + close(flexnbd->signal_fd); + free(flexnbd); } -struct server * flexnbd_server( struct flexnbd * flexnbd ) +struct server *flexnbd_server(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - return flexnbd->serve; + NULLCHECK(flexnbd); + return flexnbd->serve; } -void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl ) +void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl) { - NULLCHECK( flexnbd ); - server_replace_acl( flexnbd_server(flexnbd), acl ); + NULLCHECK(flexnbd); + server_replace_acl(flexnbd_server(flexnbd), acl); } -struct status * flexnbd_status_create( struct flexnbd * flexnbd ) +struct status *flexnbd_status_create(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - struct status * status; + NULLCHECK(flexnbd); + struct status *status; - status = status_create( flexnbd_server( flexnbd ) ); - return status; + status = status_create(flexnbd_server(flexnbd)); + return status; } -void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve ) +void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve) { - NULLCHECK( flexnbd ); - flexnbd->serve = serve; + NULLCHECK(flexnbd); + flexnbd->serve = serve; } /* Get the default_deny of the current server object. */ -int flexnbd_default_deny( struct flexnbd * flexnbd ) +int flexnbd_default_deny(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - return server_default_deny( flexnbd->serve ); + NULLCHECK(flexnbd); + return server_default_deny(flexnbd->serve); } -void make_writable( const char * filename ) +void make_writable(const char *filename) { - NULLCHECK( filename ); - FATAL_IF_NEGATIVE( chmod( filename, S_IWUSR ), - "Couldn't chmod %s: %s", - filename, - strerror( errno ) ); + NULLCHECK(filename); + FATAL_IF_NEGATIVE(chmod(filename, S_IWUSR), + "Couldn't chmod %s: %s", filename, strerror(errno)); } -int flexnbd_serve( struct flexnbd * flexnbd ) +int flexnbd_serve(struct flexnbd *flexnbd) { - NULLCHECK( flexnbd ); - int success; - struct self_pipe * open_signal = NULL; + NULLCHECK(flexnbd); + int success; + struct self_pipe *open_signal = NULL; - if ( flexnbd->control ){ - debug( "Spawning control thread" ); - flexnbd_spawn_control( flexnbd ); - open_signal = flexnbd->control->open_signal; - } + if (flexnbd->control) { + debug("Spawning control thread"); + flexnbd_spawn_control(flexnbd); + open_signal = flexnbd->control->open_signal; + } - success = do_serve( flexnbd->serve, open_signal ); - debug("do_serve success is %d", success ); + success = do_serve(flexnbd->serve, open_signal); + debug("do_serve success is %d", success); - if ( flexnbd->control ) { - debug( "Stopping control thread" ); - flexnbd_stop_control( flexnbd ); - debug("Control thread stopped"); - } + if (flexnbd->control) { + debug("Stopping control thread"); + flexnbd_stop_control(flexnbd); + debug("Control thread stopped"); + } - return success; + return success; } - diff --git a/src/server/flexnbd.h b/src/server/flexnbd.h index b5b3238..5377eb0 100644 --- a/src/server/flexnbd.h +++ b/src/server/flexnbd.h @@ -13,54 +13,51 @@ /* Carries the "globals". */ struct flexnbd { - /* Our serve pointer should never be dereferenced outside a - * flexnbd_switch_lock/unlock pair. - */ - struct server * serve; + /* Our serve pointer should never be dereferenced outside a + * flexnbd_switch_lock/unlock pair. + */ + struct server *serve; - /* We only have a control object if a control socket name was - * passed on the command line. - */ - struct control * control; + /* We only have a control object if a control socket name was + * passed on the command line. + */ + struct control *control; - /* File descriptor for a signalfd(2) signal stream. */ - int signal_fd; + /* File descriptor for a signalfd(2) signal stream. */ + int signal_fd; }; -struct flexnbd * flexnbd_create(void); -struct flexnbd * flexnbd_create_serving( - char* s_ip_address, - char* s_port, - char* s_file, - char* s_ctrl_sock, - int default_deny, - int acl_entries, - char** s_acl_entries, - int max_nbd_clients, - int use_killswitch); +struct flexnbd *flexnbd_create(void); +struct flexnbd *flexnbd_create_serving(char *s_ip_address, + char *s_port, + char *s_file, + char *s_ctrl_sock, + int default_deny, + int acl_entries, + char **s_acl_entries, + int max_nbd_clients, + int use_killswitch); -struct flexnbd * flexnbd_create_listening( - char* s_ip_address, - char* s_port, - char* s_file, - char* s_ctrl_sock, - int default_deny, - int acl_entries, - char** s_acl_entries ); +struct flexnbd *flexnbd_create_listening(char *s_ip_address, + char *s_port, + char *s_file, + char *s_ctrl_sock, + int default_deny, + int acl_entries, + char **s_acl_entries); -void flexnbd_destroy( struct flexnbd * ); +void flexnbd_destroy(struct flexnbd *); enum mirror_state; -enum mirror_state flexnbd_get_mirror_state( struct flexnbd * ); -int flexnbd_default_deny( struct flexnbd * ); -void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve ); -int flexnbd_signal_fd( struct flexnbd * flexnbd ); +enum mirror_state flexnbd_get_mirror_state(struct flexnbd *); +int flexnbd_default_deny(struct flexnbd *); +void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve); +int flexnbd_signal_fd(struct flexnbd *flexnbd); -int flexnbd_serve( struct flexnbd * flexnbd ); -int flexnbd_proxy( struct flexnbd * flexnbd ); -struct server * flexnbd_server( struct flexnbd * flexnbd ); -void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl ); -struct status * flexnbd_status_create( struct flexnbd * flexnbd ); +int flexnbd_serve(struct flexnbd *flexnbd); +int flexnbd_proxy(struct flexnbd *flexnbd); +struct server *flexnbd_server(struct flexnbd *flexnbd); +void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl); +struct status *flexnbd_status_create(struct flexnbd *flexnbd); #endif - diff --git a/src/server/flexthread.c b/src/server/flexthread.c index ef1d7df..4af8792 100644 --- a/src/server/flexthread.c +++ b/src/server/flexthread.c @@ -4,72 +4,70 @@ #include -struct flexthread_mutex * flexthread_mutex_create(void) +struct flexthread_mutex *flexthread_mutex_create(void) { - struct flexthread_mutex * ftm = - xmalloc( sizeof( struct flexthread_mutex ) ); + struct flexthread_mutex *ftm = + xmalloc(sizeof(struct flexthread_mutex)); - FATAL_UNLESS( 0 == pthread_mutex_init( &ftm->mutex, NULL ), - "Mutex initialisation failed" ); - return ftm; + FATAL_UNLESS(0 == pthread_mutex_init(&ftm->mutex, NULL), + "Mutex initialisation failed"); + return ftm; } -void flexthread_mutex_destroy( struct flexthread_mutex * ftm ) +void flexthread_mutex_destroy(struct flexthread_mutex *ftm) { - NULLCHECK( ftm ); + NULLCHECK(ftm); - if( flexthread_mutex_held( ftm ) ) { - flexthread_mutex_unlock( ftm ); - } - else if ( (pthread_t)NULL != ftm->holder ) { - /* This "should never happen": if we can try to destroy - * a mutex currently held by another thread, there's a - * logic bug somewhere. I know the test here is racy, - * but there's not a lot we can do about it at this - * point. - */ - fatal( "Attempted to destroy a flexthread_mutex"\ - " held by another thread!" ); - } + if (flexthread_mutex_held(ftm)) { + flexthread_mutex_unlock(ftm); + } else if ((pthread_t) NULL != ftm->holder) { + /* This "should never happen": if we can try to destroy + * a mutex currently held by another thread, there's a + * logic bug somewhere. I know the test here is racy, + * but there's not a lot we can do about it at this + * point. + */ + fatal("Attempted to destroy a flexthread_mutex" + " held by another thread!"); + } - FATAL_UNLESS( 0 == pthread_mutex_destroy( &ftm->mutex ), - "Mutex destroy failed" ); - free( ftm ); + FATAL_UNLESS(0 == pthread_mutex_destroy(&ftm->mutex), + "Mutex destroy failed"); + free(ftm); } -int flexthread_mutex_lock( struct flexthread_mutex * ftm ) +int flexthread_mutex_lock(struct flexthread_mutex *ftm) { - NULLCHECK( ftm ); + NULLCHECK(ftm); - int failure = pthread_mutex_lock( &ftm->mutex ); - if ( 0 == failure ) { - ftm->holder = pthread_self(); - } + int failure = pthread_mutex_lock(&ftm->mutex); + if (0 == failure) { + ftm->holder = pthread_self(); + } - return failure; + return failure; } -int flexthread_mutex_unlock( struct flexthread_mutex * ftm ) +int flexthread_mutex_unlock(struct flexthread_mutex *ftm) { - NULLCHECK( ftm ); + NULLCHECK(ftm); - pthread_t orig = ftm->holder; - ftm->holder = (pthread_t)NULL; - int failure = pthread_mutex_unlock( &ftm->mutex ); - if ( 0 != failure ) { - ftm->holder = orig; - } - return failure; + pthread_t orig = ftm->holder; + ftm->holder = (pthread_t) NULL; + int failure = pthread_mutex_unlock(&ftm->mutex); + if (0 != failure) { + ftm->holder = orig; + } + return failure; } -int flexthread_mutex_held( struct flexthread_mutex * ftm ) +int flexthread_mutex_held(struct flexthread_mutex *ftm) { - NULLCHECK( ftm ); - return pthread_self() == ftm->holder; + NULLCHECK(ftm); + return pthread_self() == ftm->holder; } - diff --git a/src/server/flexthread.h b/src/server/flexthread.h index 6a39097..c218766 100644 --- a/src/server/flexthread.h +++ b/src/server/flexthread.h @@ -15,15 +15,15 @@ */ struct flexthread_mutex { - pthread_mutex_t mutex; - pthread_t holder; + pthread_mutex_t mutex; + pthread_t holder; }; -struct flexthread_mutex * flexthread_mutex_create(void); -void flexthread_mutex_destroy( struct flexthread_mutex * ); +struct flexthread_mutex *flexthread_mutex_create(void); +void flexthread_mutex_destroy(struct flexthread_mutex *); -int flexthread_mutex_lock( struct flexthread_mutex * ); -int flexthread_mutex_unlock( struct flexthread_mutex * ); -int flexthread_mutex_held( struct flexthread_mutex * ); +int flexthread_mutex_lock(struct flexthread_mutex *); +int flexthread_mutex_unlock(struct flexthread_mutex *); +int flexthread_mutex_held(struct flexthread_mutex *); #endif diff --git a/src/server/mbox.c b/src/server/mbox.c index 3e96785..4c7298d 100644 --- a/src/server/mbox.c +++ b/src/server/mbox.c @@ -3,75 +3,75 @@ #include -struct mbox * mbox_create( void ) +struct mbox *mbox_create(void) { - struct mbox * mbox = xmalloc( sizeof( struct mbox ) ); - FATAL_UNLESS( 0 == pthread_cond_init( &mbox->filled_cond, NULL ), - "Failed to initialise a condition variable" ); - FATAL_UNLESS( 0 == pthread_cond_init( &mbox->emptied_cond, NULL ), - "Failed to initialise a condition variable" ); - FATAL_UNLESS( 0 == pthread_mutex_init( &mbox->mutex, NULL ), - "Failed to initialise a mutex" ); - return mbox; + struct mbox *mbox = xmalloc(sizeof(struct mbox)); + FATAL_UNLESS(0 == pthread_cond_init(&mbox->filled_cond, NULL), + "Failed to initialise a condition variable"); + FATAL_UNLESS(0 == pthread_cond_init(&mbox->emptied_cond, NULL), + "Failed to initialise a condition variable"); + FATAL_UNLESS(0 == pthread_mutex_init(&mbox->mutex, NULL), + "Failed to initialise a mutex"); + return mbox; } -void mbox_post( struct mbox * mbox, void * contents ) +void mbox_post(struct mbox *mbox, void *contents) { - pthread_mutex_lock( &mbox->mutex ); - { - if (mbox->full){ - pthread_cond_wait( &mbox->emptied_cond, &mbox->mutex ); - } - mbox->contents = contents; - mbox->full = 1; - while( 0 != pthread_cond_signal( &mbox->filled_cond ) ); + pthread_mutex_lock(&mbox->mutex); + { + if (mbox->full) { + pthread_cond_wait(&mbox->emptied_cond, &mbox->mutex); } - pthread_mutex_unlock( &mbox->mutex ); + mbox->contents = contents; + mbox->full = 1; + while (0 != pthread_cond_signal(&mbox->filled_cond)); + } + pthread_mutex_unlock(&mbox->mutex); } -void * mbox_contents( struct mbox * mbox ) +void *mbox_contents(struct mbox *mbox) { - return mbox->contents; + return mbox->contents; } -int mbox_is_full( struct mbox * mbox ) +int mbox_is_full(struct mbox *mbox) { - return mbox->full; + return mbox->full; } -void * mbox_receive( struct mbox * mbox ) +void *mbox_receive(struct mbox *mbox) { - NULLCHECK( mbox ); - void * result; + NULLCHECK(mbox); + void *result; - pthread_mutex_lock( &mbox->mutex ); - { - if ( !mbox->full ) { - pthread_cond_wait( &mbox->filled_cond, &mbox->mutex ); - } - mbox->full = 0; - result = mbox->contents; - mbox->contents = NULL; - - while( 0 != pthread_cond_signal( &mbox->emptied_cond)); + pthread_mutex_lock(&mbox->mutex); + { + if (!mbox->full) { + pthread_cond_wait(&mbox->filled_cond, &mbox->mutex); } - pthread_mutex_unlock( &mbox->mutex ); + mbox->full = 0; + result = mbox->contents; + mbox->contents = NULL; - return result; + while (0 != pthread_cond_signal(&mbox->emptied_cond)); + } + pthread_mutex_unlock(&mbox->mutex); + + return result; } -void mbox_destroy( struct mbox * mbox ) +void mbox_destroy(struct mbox *mbox) { - NULLCHECK( mbox ); + NULLCHECK(mbox); - while( 0 != pthread_cond_destroy( &mbox->emptied_cond ) ); - while( 0 != pthread_cond_destroy( &mbox->filled_cond ) ); + while (0 != pthread_cond_destroy(&mbox->emptied_cond)); + while (0 != pthread_cond_destroy(&mbox->filled_cond)); - while( 0 != pthread_mutex_destroy( &mbox->mutex ) ); + while (0 != pthread_mutex_destroy(&mbox->mutex)); - free( mbox ); + free(mbox); } diff --git a/src/server/mbox.h b/src/server/mbox.h index 3af54d8..87735f9 100644 --- a/src/server/mbox.h +++ b/src/server/mbox.h @@ -14,42 +14,42 @@ struct mbox { - void * contents; + void *contents; /** Marker to tell us if there's content in the box. * Keeping this separate allows us to use NULL for the contents. */ - int full; + int full; /** This gets signaled by mbox_post, and waited on by * mbox_receive */ - pthread_cond_t filled_cond; + pthread_cond_t filled_cond; /** This is signaled by mbox_receive, and waited on by mbox_post */ - pthread_cond_t emptied_cond; - pthread_mutex_t mutex; + pthread_cond_t emptied_cond; + pthread_mutex_t mutex; }; /* Create an mbox. */ -struct mbox * mbox_create(void); +struct mbox *mbox_create(void); /* Put something in the mbox, blocking if it's already full. * That something can be NULL if you want. */ -void mbox_post( struct mbox *, void *); +void mbox_post(struct mbox *, void *); /* See what's in the mbox. This isn't thread-safe. */ -void * mbox_contents( struct mbox *); +void *mbox_contents(struct mbox *); /* See if anything has been put into the mbox. This isn't thread-safe. * */ -int mbox_is_full( struct mbox *); +int mbox_is_full(struct mbox *); /* Get the contents from the mbox, blocking if there's nothing there. */ -void * mbox_receive( struct mbox *); +void *mbox_receive(struct mbox *); /* Free the mbox and destroy the associated pthread bits. */ -void mbox_destroy( struct mbox *); +void mbox_destroy(struct mbox *); #endif diff --git a/src/server/mirror.c b/src/server/mirror.c index bd25008..b1d917b 100644 --- a/src/server/mirror.c +++ b/src/server/mirror.c @@ -47,79 +47,78 @@ /* We use this to keep track of the socket request data we need to send */ struct xfer { - /* Store the bytes we need to send before the data, or receive back */ - union { - struct nbd_request_raw req_raw; - struct nbd_reply_raw rsp_raw; - } hdr; + /* Store the bytes we need to send before the data, or receive back */ + union { + struct nbd_request_raw req_raw; + struct nbd_reply_raw rsp_raw; + } hdr; - /* what in mirror->mapped we should write, and how much of it we've done */ - uint64_t from; - uint64_t len; - uint64_t written; + /* what in mirror->mapped we should write, and how much of it we've done */ + uint64_t from; + uint64_t len; + uint64_t written; - /* number of bytes of response read */ - uint64_t read; + /* number of bytes of response read */ + uint64_t read; }; struct mirror_ctrl { - struct server *serve; - struct mirror *mirror; + struct server *serve; + struct mirror *mirror; - /* libev stuff */ - struct ev_loop *ev_loop; - ev_timer begin_watcher; - ev_io read_watcher; - ev_io write_watcher; - ev_timer timeout_watcher; - ev_timer limit_watcher; - ev_io abandon_watcher; + /* libev stuff */ + struct ev_loop *ev_loop; + ev_timer begin_watcher; + ev_io read_watcher; + ev_io write_watcher; + ev_timer timeout_watcher; + ev_timer limit_watcher; + ev_io abandon_watcher; - /* We set this if the bitset stream is getting uncomfortably full, and unset - * once it's emptier */ - int clear_events; + /* We set this if the bitset stream is getting uncomfortably full, and unset + * once it's emptier */ + int clear_events; - /* This is set once all clients have been closed, to let the mirror know - * it's safe to finish once the queue is empty */ - int clients_closed; + /* This is set once all clients have been closed, to let the mirror know + * it's safe to finish once the queue is empty */ + int clients_closed; - /* Use this to keep track of what we're copying at any moment */ - struct xfer xfer; + /* Use this to keep track of what we're copying at any moment */ + struct xfer xfer; }; -struct mirror * mirror_alloc( - union mysockaddr * connect_to, - union mysockaddr * connect_from, - uint64_t max_Bps, - enum mirror_finish_action action_at_finish, - struct mbox * commit_signal) +struct mirror *mirror_alloc(union mysockaddr *connect_to, + union mysockaddr *connect_from, + uint64_t max_Bps, + enum mirror_finish_action action_at_finish, + struct mbox *commit_signal) { - struct mirror * mirror; + struct mirror *mirror; - mirror = xmalloc(sizeof(struct mirror)); - mirror->connect_to = connect_to; - mirror->connect_from = connect_from; - mirror->max_bytes_per_second = max_Bps; - mirror->action_at_finish = action_at_finish; - mirror->commit_signal = commit_signal; - mirror->commit_state = MS_UNKNOWN; - mirror->abandon_signal = self_pipe_create(); + mirror = xmalloc(sizeof(struct mirror)); + mirror->connect_to = connect_to; + mirror->connect_from = connect_from; + mirror->max_bytes_per_second = max_Bps; + mirror->action_at_finish = action_at_finish; + mirror->commit_signal = commit_signal; + mirror->commit_state = MS_UNKNOWN; + mirror->abandon_signal = self_pipe_create(); - if ( mirror->abandon_signal == NULL ) { - warn( "Couldn't create mirror abandon signal" ); - return NULL; - } + if (mirror->abandon_signal == NULL) { + warn("Couldn't create mirror abandon signal"); + return NULL; + } - return mirror; + return mirror; } -void mirror_set_state_f( struct mirror * mirror, enum mirror_state state ) +void mirror_set_state_f(struct mirror *mirror, enum mirror_state state) { - NULLCHECK( mirror ); - mirror->commit_state = state; + NULLCHECK(mirror); + mirror->commit_state = state; } #define mirror_set_state( mirror, state ) do{\ @@ -127,92 +126,83 @@ void mirror_set_state_f( struct mirror * mirror, enum mirror_state state ) mirror_set_state_f( mirror, state );\ } while(0) -enum mirror_state mirror_get_state( struct mirror * mirror ) +enum mirror_state mirror_get_state(struct mirror *mirror) { - NULLCHECK( mirror ); - return mirror->commit_state; + NULLCHECK(mirror); + return mirror->commit_state; } #define mirror_state_is( mirror, state ) mirror_get_state( mirror ) == state -void mirror_init( struct mirror * mirror, const char * filename ) +void mirror_init(struct mirror *mirror, const char *filename) { - int map_fd; - uint64_t size; + int map_fd; + uint64_t size; - NULLCHECK( mirror ); - NULLCHECK( filename ); + NULLCHECK(mirror); + NULLCHECK(filename); - FATAL_IF_NEGATIVE( - open_and_mmap( - filename, - &map_fd, - &size, - (void**) &mirror->mapped - ), - "Failed to open and mmap %s", - filename - ); + FATAL_IF_NEGATIVE(open_and_mmap(filename, + &map_fd, + &size, + (void **) &mirror->mapped), + "Failed to open and mmap %s", filename); - FATAL_IF_NEGATIVE( - madvise( mirror->mapped, size, MADV_SEQUENTIAL ), - SHOW_ERRNO( "Failed to madvise() %s", filename ) + FATAL_IF_NEGATIVE(madvise(mirror->mapped, size, MADV_SEQUENTIAL), + SHOW_ERRNO("Failed to madvise() %s", filename) ); } /* Call this before a mirror attempt. */ -void mirror_reset( struct mirror * mirror ) +void mirror_reset(struct mirror *mirror) { - NULLCHECK( mirror ); - mirror_set_state( mirror, MS_INIT ); + NULLCHECK(mirror); + mirror_set_state(mirror, MS_INIT); - mirror->all_dirty = 0; - mirror->migration_started = 0; - mirror->offset = 0; + mirror->all_dirty = 0; + mirror->migration_started = 0; + mirror->offset = 0; - return; + return; } -struct mirror * mirror_create( - const char * filename, - union mysockaddr * connect_to, - union mysockaddr * connect_from, - uint64_t max_Bps, - int action_at_finish, - struct mbox * commit_signal) +struct mirror *mirror_create(const char *filename, + union mysockaddr *connect_to, + union mysockaddr *connect_from, + uint64_t max_Bps, + int action_at_finish, + struct mbox *commit_signal) { - /* FIXME: shouldn't map_fd get closed? */ - struct mirror * mirror; + /* FIXME: shouldn't map_fd get closed? */ + struct mirror *mirror; - mirror = mirror_alloc( connect_to, - connect_from, - max_Bps, - action_at_finish, - commit_signal); + mirror = mirror_alloc(connect_to, + connect_from, + max_Bps, action_at_finish, commit_signal); - mirror_init( mirror, filename ); - mirror_reset( mirror ); + mirror_init(mirror, filename); + mirror_reset(mirror); - return mirror; + return mirror; } -void mirror_destroy( struct mirror *mirror ) +void mirror_destroy(struct mirror *mirror) { - NULLCHECK( mirror ); - self_pipe_destroy( mirror->abandon_signal ); - free(mirror->connect_to); - free(mirror->connect_from); - free(mirror); + NULLCHECK(mirror); + self_pipe_destroy(mirror->abandon_signal); + free(mirror->connect_to); + free(mirror->connect_from); + free(mirror); } /** The mirror code will split NBD writes, making them this long as a maximum */ -static const int mirror_longest_write = 8<<20; +static const int mirror_longest_write = 8 << 20; /* This must not be called if there's any chance of further I/O. Methods to * ensure this include: @@ -220,134 +210,134 @@ static const int mirror_longest_write = 8<<20; * - call server_forbid_new_clients() followed by a successful * server_close_clients() ; server_join_clients() */ -void mirror_on_exit( struct server * serve ) +void mirror_on_exit(struct server *serve) { - /* If we're still here, we can shut the server down. - * - * - */ - debug("serve_signal_close"); - serve_signal_close( serve ); + /* If we're still here, we can shut the server down. + * + * + */ + debug("serve_signal_close"); + serve_signal_close(serve); - /* We have to wait until the server is closed before unlocking - * IO. This is because the client threads check to see if the - * server is still open before reading or writing inside their - * own locks. If we don't wait for the close, there's no way to - * guarantee the server thread will win the race and we risk the - * clients seeing a "successful" write to a dead disc image. - */ - debug("serve_wait_for_close"); - serve_wait_for_close( serve ); + /* We have to wait until the server is closed before unlocking + * IO. This is because the client threads check to see if the + * server is still open before reading or writing inside their + * own locks. If we don't wait for the close, there's no way to + * guarantee the server thread will win the race and we risk the + * clients seeing a "successful" write to a dead disc image. + */ + debug("serve_wait_for_close"); + serve_wait_for_close(serve); - if ( ACTION_UNLINK == serve->mirror->action_at_finish ) { - debug("Unlinking %s", serve->filename ); - server_unlink( serve ); - } + if (ACTION_UNLINK == serve->mirror->action_at_finish) { + debug("Unlinking %s", serve->filename); + server_unlink(serve); + } - debug("Sending disconnect"); - socket_nbd_disconnect( serve->mirror->client ); - info("Mirror sent."); + debug("Sending disconnect"); + socket_nbd_disconnect(serve->mirror->client); + info("Mirror sent."); } -void mirror_cleanup( struct server * serve, - int fatal __attribute__((unused))) +void mirror_cleanup(struct server *serve, + int fatal __attribute__ ((unused))) { - NULLCHECK( serve ); - struct mirror * mirror = serve->mirror; - NULLCHECK( mirror ); - info( "Cleaning up mirror thread"); + NULLCHECK(serve); + struct mirror *mirror = serve->mirror; + NULLCHECK(mirror); + info("Cleaning up mirror thread"); - if ( mirror->mapped ) { - munmap( mirror->mapped, serve->size ); - } - mirror->mapped = NULL; + if (mirror->mapped) { + munmap(mirror->mapped, serve->size); + } + mirror->mapped = NULL; - if( mirror->client && mirror->client > 0 ){ - close( mirror->client ); - } - mirror->client = -1; + if (mirror->client && mirror->client > 0) { + close(mirror->client); + } + mirror->client = -1; } -int mirror_connect( struct mirror * mirror, uint64_t local_size ) +int mirror_connect(struct mirror *mirror, uint64_t local_size) { - struct sockaddr * connect_from = NULL; - int connected = 0; + struct sockaddr *connect_from = NULL; + int connected = 0; - if ( mirror->connect_from ) { - connect_from = &mirror->connect_from->generic; - } + if (mirror->connect_from) { + connect_from = &mirror->connect_from->generic; + } - NULLCHECK( mirror->connect_to ); + NULLCHECK(mirror->connect_to); - mirror->client = socket_connect(&mirror->connect_to->generic, connect_from); - if ( 0 < mirror->client ) { - fd_set fds; - struct timeval tv = { MS_HELLO_TIME_SECS, 0}; - FD_ZERO( &fds ); - FD_SET( mirror->client, &fds ); + mirror->client = + socket_connect(&mirror->connect_to->generic, connect_from); + if (0 < mirror->client) { + fd_set fds; + struct timeval tv = { MS_HELLO_TIME_SECS, 0 }; + FD_ZERO(&fds); + FD_SET(mirror->client, &fds); - FATAL_UNLESS( 0 <= select( FD_SETSIZE, &fds, NULL, NULL, &tv ), - "Select failed." ); + FATAL_UNLESS(0 <= select(FD_SETSIZE, &fds, NULL, NULL, &tv), + "Select failed."); - if( FD_ISSET( mirror->client, &fds ) ){ - uint64_t remote_size; - uint32_t remote_flags; - if ( socket_nbd_read_hello( mirror->client, &remote_size, &remote_flags ) ) { - if( remote_size == local_size ){ - connected = 1; - mirror_set_state( mirror, MS_GO ); - } - else { - warn("Remote size (%d) doesn't match local (%d)", - remote_size, local_size ); - mirror_set_state( mirror, MS_FAIL_SIZE_MISMATCH ); - } - } - else { - warn( "Mirror attempt rejected." ); - mirror_set_state( mirror, MS_FAIL_REJECTED ); - } + if (FD_ISSET(mirror->client, &fds)) { + uint64_t remote_size; + uint32_t remote_flags; + if (socket_nbd_read_hello + (mirror->client, &remote_size, &remote_flags)) { + if (remote_size == local_size) { + connected = 1; + mirror_set_state(mirror, MS_GO); + } else { + warn("Remote size (%d) doesn't match local (%d)", + remote_size, local_size); + mirror_set_state(mirror, MS_FAIL_SIZE_MISMATCH); } - else { - warn( "No NBD Hello received." ); - mirror_set_state( mirror, MS_FAIL_NO_HELLO ); - } - - if ( !connected ) { close( mirror->client ); } - } - else { - warn( "Mirror failed to connect."); - mirror_set_state( mirror, MS_FAIL_CONNECT ); + } else { + warn("Mirror attempt rejected."); + mirror_set_state(mirror, MS_FAIL_REJECTED); + } + } else { + warn("No NBD Hello received."); + mirror_set_state(mirror, MS_FAIL_NO_HELLO); } - return connected; + if (!connected) { + close(mirror->client); + } + } else { + warn("Mirror failed to connect."); + mirror_set_state(mirror, MS_FAIL_CONNECT); + } + + return connected; } -int mirror_should_quit( struct mirror * mirror ) +int mirror_should_quit(struct mirror *mirror) { - switch( mirror->action_at_finish ) { - case ACTION_EXIT: - case ACTION_UNLINK: - return 1; - default: - return 0; - } + switch (mirror->action_at_finish) { + case ACTION_EXIT: + case ACTION_UNLINK: + return 1; + default: + return 0; + } } /* Bandwidth limiting - we hang around if bps is too high, unless we need to * empty out the bitset stream a bit */ -int mirror_should_wait( struct mirror_ctrl *ctrl ) +int mirror_should_wait(struct mirror_ctrl *ctrl) { - int bps_over = server_mirror_bps( ctrl->serve ) > - ctrl->serve->mirror->max_bytes_per_second; + int bps_over = server_mirror_bps(ctrl->serve) > + ctrl->serve->mirror->max_bytes_per_second; - int stream_full = bitset_stream_size( ctrl->serve->allocation_map ) > - ( BITSET_STREAM_SIZE / 2 ); + int stream_full = bitset_stream_size(ctrl->serve->allocation_map) > + (BITSET_STREAM_SIZE / 2); - return bps_over && !stream_full; + return bps_over && !stream_full; } /* @@ -358,515 +348,530 @@ int mirror_should_wait( struct mirror_ctrl *ctrl ) * * iterates through the bitmap, finding a dirty run to form the basis of the * next transfer, then puts it together. */ -int mirror_setup_next_xfer( struct mirror_ctrl *ctrl ) +int mirror_setup_next_xfer(struct mirror_ctrl *ctrl) { - struct mirror* mirror = ctrl->mirror; - struct server* serve = ctrl->serve; - struct bitset_stream_entry e = { .event = BITSET_STREAM_UNSET }; - uint64_t current = mirror->offset, run = 0, size = serve->size; + struct mirror *mirror = ctrl->mirror; + struct server *serve = ctrl->serve; + struct bitset_stream_entry e = {.event = BITSET_STREAM_UNSET }; + uint64_t current = mirror->offset, run = 0, size = serve->size; - /* Technically, we'd be interested in UNSET events too, but they are never - * generated. TODO if that changes. - * - * We use ctrl->clear_events to start emptying the stream when it's half - * full, and stop when it's a quarter full. This stops a busy client from - * stalling a migration forever. FIXME: made-up numbers. - */ - if ( mirror->offset < serve->size && bitset_stream_size( serve->allocation_map ) > BITSET_STREAM_SIZE / 2 ) { - ctrl->clear_events = 1; + /* Technically, we'd be interested in UNSET events too, but they are never + * generated. TODO if that changes. + * + * We use ctrl->clear_events to start emptying the stream when it's half + * full, and stop when it's a quarter full. This stops a busy client from + * stalling a migration forever. FIXME: made-up numbers. + */ + if (mirror->offset < serve->size + && bitset_stream_size(serve->allocation_map) > + BITSET_STREAM_SIZE / 2) { + ctrl->clear_events = 1; + } + + + while ((mirror->offset == serve->size || ctrl->clear_events) + && e.event != BITSET_STREAM_SET) { + uint64_t events = bitset_stream_size(serve->allocation_map); + + if (events == 0) { + break; } + debug("Dequeueing event"); + bitset_stream_dequeue(ctrl->serve->allocation_map, &e); + debug("Dequeued event %i, %zu, %zu", e.event, e.from, e.len); - while ( ( mirror->offset == serve->size || ctrl->clear_events ) && e.event != BITSET_STREAM_SET ) { - uint64_t events = bitset_stream_size( serve->allocation_map ); - - if ( events == 0 ) { - break; - } - - debug("Dequeueing event"); - bitset_stream_dequeue( ctrl->serve->allocation_map, &e ); - debug("Dequeued event %i, %zu, %zu", e.event, e.from, e.len); - - if ( events < ( BITSET_STREAM_SIZE / 4 ) ) { - ctrl->clear_events = 0; - } + if (events < (BITSET_STREAM_SIZE / 4)) { + ctrl->clear_events = 0; } + } - if ( e.event == BITSET_STREAM_SET ) { - current = e.from; - run = e.len; - } else if ( current < serve->size ) { - current = mirror->offset; - run = mirror_longest_write; + if (e.event == BITSET_STREAM_SET) { + current = e.from; + run = e.len; + } else if (current < serve->size) { + current = mirror->offset; + run = mirror_longest_write; - /* Adjust final block if necessary */ - if ( current + run > serve->size ) { - run = size - current; - } - mirror->offset += run; - } else { - return 0; + /* Adjust final block if necessary */ + if (current + run > serve->size) { + run = size - current; } + mirror->offset += run; + } else { + return 0; + } - debug( "Next transfer: current=%"PRIu64", run=%"PRIu64, current, run ); - struct nbd_request req = { - .magic = REQUEST_MAGIC, - .type = REQUEST_WRITE, - .handle.b = ".MIRROR.", - .from = current, - .len = run - }; - nbd_h2r_request( &req, &ctrl->xfer.hdr.req_raw ); + debug("Next transfer: current=%" PRIu64 ", run=%" PRIu64, current, + run); + struct nbd_request req = { + .magic = REQUEST_MAGIC, + .type = REQUEST_WRITE, + .handle.b = ".MIRROR.", + .from = current, + .len = run + }; + nbd_h2r_request(&req, &ctrl->xfer.hdr.req_raw); - ctrl->xfer.from = current; - ctrl->xfer.len = run; + ctrl->xfer.from = current; + ctrl->xfer.len = run; - ctrl->xfer.written = 0; - ctrl->xfer.read = 0; + ctrl->xfer.written = 0; + ctrl->xfer.read = 0; - return 1; + return 1; } // ONLY CALL THIS AFTER CLOSING CLIENTS -void mirror_complete( struct server *serve ) +void mirror_complete(struct server *serve) { - /* FIXME: Pretty sure this is broken, if action != !QUIT. Just moving code - * around for now, can fix it later. Action is always quit in production */ - if ( mirror_should_quit( serve->mirror ) ) { - debug("exit!"); - /* FIXME: This depends on blocking I/O right now, so make sure we are */ - sock_set_nonblock( serve->mirror->client, 0 ); - mirror_on_exit( serve ); - info("Server closed, quitting after successful migration"); - } + /* FIXME: Pretty sure this is broken, if action != !QUIT. Just moving code + * around for now, can fix it later. Action is always quit in production */ + if (mirror_should_quit(serve->mirror)) { + debug("exit!"); + /* FIXME: This depends on blocking I/O right now, so make sure we are */ + sock_set_nonblock(serve->mirror->client, 0); + mirror_on_exit(serve); + info("Server closed, quitting after successful migration"); + } - mirror_set_state( serve->mirror, MS_DONE ); - return; + mirror_set_state(serve->mirror, MS_DONE); + return; } -static void mirror_write_cb( struct ev_loop *loop, ev_io *w, int revents ) +static void mirror_write_cb(struct ev_loop *loop, ev_io * w, int revents) { - struct mirror_ctrl* ctrl = (struct mirror_ctrl*) w->data; - NULLCHECK( ctrl ); + struct mirror_ctrl *ctrl = (struct mirror_ctrl *) w->data; + NULLCHECK(ctrl); - struct xfer *xfer = &ctrl->xfer; + struct xfer *xfer = &ctrl->xfer; - size_t to_write, hdr_size = sizeof( struct nbd_request_raw ); - char *data_loc; - ssize_t count; - - if ( !( revents & EV_WRITE ) ) { - warn( "No write event signalled in mirror write callback" ); - return; - } - - debug( "Mirror write callback invoked with events %d. fd: %i", revents, ctrl->mirror->client ); - - /* FIXME: We can end up corking multiple times in unusual circumstances; this - * is annoying, but harmless */ - if ( xfer->written == 0 ) { - sock_set_tcp_cork( ctrl->mirror->client, 1 ); - } - - if ( xfer->written < hdr_size ) { - data_loc = ( (char*) &xfer->hdr.req_raw ) + ctrl->xfer.written; - to_write = hdr_size - xfer->written; - } else { - data_loc = ctrl->mirror->mapped + xfer->from + ( xfer->written - hdr_size ); - to_write = xfer->len - ( ctrl->xfer.written - hdr_size ); - } - - // Actually write some bytes - if ( ( count = write( ctrl->mirror->client, data_loc, to_write ) ) < 0 ) { - if ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR ) { - warn( SHOW_ERRNO( "Couldn't write to listener" ) ); - ev_break( loop, EVBREAK_ONE ); - } - return; - } - debug( "Wrote %"PRIu64" bytes", count ); - debug( "to_write was %"PRIu64", xfer->written was %"PRIu64, to_write, xfer->written ); - - // We wrote some bytes, so reset the timer and keep track for the next pass - if ( count > 0 ) { - ctrl->xfer.written += count; - ev_timer_again( ctrl->ev_loop, &ctrl->timeout_watcher ); - } - - // All bytes written, so now we need to read the NBD reply back. - if ( ctrl->xfer.written == ctrl->xfer.len + hdr_size ) { - sock_set_tcp_cork( ctrl->mirror->client, 0 ) ; - ev_io_start( loop, &ctrl->read_watcher ); - ev_io_stop( loop, &ctrl->write_watcher ); - } + size_t to_write, hdr_size = sizeof(struct nbd_request_raw); + char *data_loc; + ssize_t count; + if (!(revents & EV_WRITE)) { + warn("No write event signalled in mirror write callback"); return; + } + + debug("Mirror write callback invoked with events %d. fd: %i", revents, + ctrl->mirror->client); + + /* FIXME: We can end up corking multiple times in unusual circumstances; this + * is annoying, but harmless */ + if (xfer->written == 0) { + sock_set_tcp_cork(ctrl->mirror->client, 1); + } + + if (xfer->written < hdr_size) { + data_loc = ((char *) &xfer->hdr.req_raw) + ctrl->xfer.written; + to_write = hdr_size - xfer->written; + } else { + data_loc = + ctrl->mirror->mapped + xfer->from + (xfer->written - hdr_size); + to_write = xfer->len - (ctrl->xfer.written - hdr_size); + } + + // Actually write some bytes + if ((count = write(ctrl->mirror->client, data_loc, to_write)) < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { + warn(SHOW_ERRNO("Couldn't write to listener")); + ev_break(loop, EVBREAK_ONE); + } + return; + } + debug("Wrote %" PRIu64 " bytes", count); + debug("to_write was %" PRIu64 ", xfer->written was %" PRIu64, to_write, + xfer->written); + + // We wrote some bytes, so reset the timer and keep track for the next pass + if (count > 0) { + ctrl->xfer.written += count; + ev_timer_again(ctrl->ev_loop, &ctrl->timeout_watcher); + } + // All bytes written, so now we need to read the NBD reply back. + if (ctrl->xfer.written == ctrl->xfer.len + hdr_size) { + sock_set_tcp_cork(ctrl->mirror->client, 0); + ev_io_start(loop, &ctrl->read_watcher); + ev_io_stop(loop, &ctrl->write_watcher); + } + + return; } -static void mirror_read_cb( struct ev_loop *loop, ev_io *w, int revents ) +static void mirror_read_cb(struct ev_loop *loop, ev_io * w, int revents) { - struct mirror_ctrl* ctrl = (struct mirror_ctrl*) w->data; - NULLCHECK( ctrl ); + struct mirror_ctrl *ctrl = (struct mirror_ctrl *) w->data; + NULLCHECK(ctrl); - struct mirror *m = ctrl->mirror; - NULLCHECK( m ); + struct mirror *m = ctrl->mirror; + NULLCHECK(m); - struct xfer *xfer = &ctrl->xfer; - NULLCHECK( xfer ); - - if ( !( revents & EV_READ ) ) { - warn( "No read event signalled in mirror read callback" ); - return; - } - - struct nbd_reply rsp; - ssize_t count; - uint64_t left = sizeof( struct nbd_reply_raw ) - xfer->read; - - debug( "Mirror read callback invoked with events %d. fd:%i", revents, m->client ); - - /* Start / continue reading the NBD response from the mirror. */ - if ( ( count = read( m->client, ((void*) &xfer->hdr.rsp_raw) + xfer->read, left ) ) < 0 ) { - if ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR ) { - warn( SHOW_ERRNO( "Couldn't read from listener" ) ); - ev_break( loop, EVBREAK_ONE ); - } - debug( SHOW_ERRNO( "Couldn't read from listener (non-scary)" ) ); - return; - } - - if ( count == 0 ) { - warn( "EOF reading response from server!" ); - ev_break( loop, EVBREAK_ONE ); - return; - } - - // We read some bytes, so reset the timer - ev_timer_again( ctrl->ev_loop, &ctrl->timeout_watcher ); - - debug( "Read %i bytes", count ); - debug( "left was %"PRIu64", xfer->read was %"PRIu64, left, xfer->read ); - xfer->read += count; - - if ( xfer->read < sizeof( struct nbd_reply_raw ) ) { - // Haven't read the whole response yet - return; - } - - nbd_r2h_reply( &xfer->hdr.rsp_raw, &rsp ); - - // validate reply, break event loop if bad - if ( rsp.magic != REPLY_MAGIC ) { - warn( "Bad reply magic from listener" ); - ev_break( loop, EVBREAK_ONE ); - return; - } - - if ( rsp.error != 0 ) { - warn( "Error returned from listener: %i", rsp.error ); - ev_break( loop, EVBREAK_ONE ); - return; - } - - if ( memcmp( ".MIRROR.", rsp.handle.b, 8 ) != 0 ) { - warn( "Bad handle returned from listener" ); - ev_break( loop, EVBREAK_ONE ); - return; - } - - /* transfer was completed, so now we need to either set up the next - * transfer of this pass, set up the first transfer of the next pass, or - * complete the migration */ - xfer->read = 0; - xfer->written = 0; - - /* We don't account for bytes written in this mode, to stop high-throughput - * discs getting stuck in "drain the event queue!" mode forever - */ - if ( !ctrl->clear_events ) { - m->all_dirty += xfer->len; - } - - - /* This next bit could take a little while, which is fine */ - ev_timer_stop( ctrl->ev_loop, &ctrl->timeout_watcher ); - - /* Set up the next transfer, which may be offset + mirror_longest_write - * or an event from the bitset stream. When offset hits serve->size, - * xfers will be constructed solely from the event stream. Once our estimate - * of time left reaches a sensible number (or the event stream empties), - * we stop new clients from connecting, disconnect existing ones, then - * continue emptying the bitstream. Once it's empty again, we're finished. - */ - int next_xfer = mirror_setup_next_xfer( ctrl ); - debug( "next_xfer: %d", next_xfer ); - - /* Regardless of time estimates, if there's no waiting transfer, we can start closing clients down. */ - if ( !ctrl->clients_closed && ( !next_xfer || server_mirror_eta( ctrl->serve ) < MS_CONVERGE_TIME_SECS ) ) { - info( "Closing clients to allow mirroring to converge" ); - server_forbid_new_clients( ctrl->serve ); - server_close_clients( ctrl->serve ); - server_join_clients( ctrl->serve ); - ctrl->clients_closed = 1; - - /* One more try - a new event may have been pushed since our last check */ - if ( !next_xfer ) { - next_xfer = mirror_setup_next_xfer( ctrl ); - } - } - - if ( ctrl->clients_closed && !next_xfer ) { - mirror_complete( ctrl->serve ); - ev_break( loop, EVBREAK_ONE ); - return; - } - - /* This is a guard Just In Case */ - ERROR_IF( !next_xfer, "Unknown problem - no next transfer to do!" ); - - ev_io_stop( loop, &ctrl->read_watcher ); - - /* FIXME: Should we ignore the bwlimit after server_close_clients has been called? */ - - if ( mirror_should_wait( ctrl ) ) { - /* We're over the bandwidth limit, so don't move onto the next transfer - * yet. Our limit_watcher will move us on once we're OK. timeout_watcher - * was disabled further up, so don't need to stop it here too */ - debug( "max_bps exceeded, waiting" ); - ev_timer_again( loop, &ctrl->limit_watcher ); - } else { - /* We're waiting for the socket to become writable again, so re-enable */ - ev_timer_again( loop, &ctrl->timeout_watcher ); - ev_io_start( loop, &ctrl->write_watcher ); - } + struct xfer *xfer = &ctrl->xfer; + NULLCHECK(xfer); + if (!(revents & EV_READ)) { + warn("No read event signalled in mirror read callback"); return; + } + + struct nbd_reply rsp; + ssize_t count; + uint64_t left = sizeof(struct nbd_reply_raw) - xfer->read; + + debug("Mirror read callback invoked with events %d. fd:%i", revents, + m->client); + + /* Start / continue reading the NBD response from the mirror. */ + if ((count = + read(m->client, ((void *) &xfer->hdr.rsp_raw) + xfer->read, + left)) < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { + warn(SHOW_ERRNO("Couldn't read from listener")); + ev_break(loop, EVBREAK_ONE); + } + debug(SHOW_ERRNO("Couldn't read from listener (non-scary)")); + return; + } + + if (count == 0) { + warn("EOF reading response from server!"); + ev_break(loop, EVBREAK_ONE); + return; + } + // We read some bytes, so reset the timer + ev_timer_again(ctrl->ev_loop, &ctrl->timeout_watcher); + + debug("Read %i bytes", count); + debug("left was %" PRIu64 ", xfer->read was %" PRIu64, left, + xfer->read); + xfer->read += count; + + if (xfer->read < sizeof(struct nbd_reply_raw)) { + // Haven't read the whole response yet + return; + } + + nbd_r2h_reply(&xfer->hdr.rsp_raw, &rsp); + + // validate reply, break event loop if bad + if (rsp.magic != REPLY_MAGIC) { + warn("Bad reply magic from listener"); + ev_break(loop, EVBREAK_ONE); + return; + } + + if (rsp.error != 0) { + warn("Error returned from listener: %i", rsp.error); + ev_break(loop, EVBREAK_ONE); + return; + } + + if (memcmp(".MIRROR.", rsp.handle.b, 8) != 0) { + warn("Bad handle returned from listener"); + ev_break(loop, EVBREAK_ONE); + return; + } + + /* transfer was completed, so now we need to either set up the next + * transfer of this pass, set up the first transfer of the next pass, or + * complete the migration */ + xfer->read = 0; + xfer->written = 0; + + /* We don't account for bytes written in this mode, to stop high-throughput + * discs getting stuck in "drain the event queue!" mode forever + */ + if (!ctrl->clear_events) { + m->all_dirty += xfer->len; + } + + + /* This next bit could take a little while, which is fine */ + ev_timer_stop(ctrl->ev_loop, &ctrl->timeout_watcher); + + /* Set up the next transfer, which may be offset + mirror_longest_write + * or an event from the bitset stream. When offset hits serve->size, + * xfers will be constructed solely from the event stream. Once our estimate + * of time left reaches a sensible number (or the event stream empties), + * we stop new clients from connecting, disconnect existing ones, then + * continue emptying the bitstream. Once it's empty again, we're finished. + */ + int next_xfer = mirror_setup_next_xfer(ctrl); + debug("next_xfer: %d", next_xfer); + + /* Regardless of time estimates, if there's no waiting transfer, we can start closing clients down. */ + if (!ctrl->clients_closed + && (!next_xfer + || server_mirror_eta(ctrl->serve) < MS_CONVERGE_TIME_SECS)) { + info("Closing clients to allow mirroring to converge"); + server_forbid_new_clients(ctrl->serve); + server_close_clients(ctrl->serve); + server_join_clients(ctrl->serve); + ctrl->clients_closed = 1; + + /* One more try - a new event may have been pushed since our last check */ + if (!next_xfer) { + next_xfer = mirror_setup_next_xfer(ctrl); + } + } + + if (ctrl->clients_closed && !next_xfer) { + mirror_complete(ctrl->serve); + ev_break(loop, EVBREAK_ONE); + return; + } + + /* This is a guard Just In Case */ + ERROR_IF(!next_xfer, "Unknown problem - no next transfer to do!"); + + ev_io_stop(loop, &ctrl->read_watcher); + + /* FIXME: Should we ignore the bwlimit after server_close_clients has been called? */ + + if (mirror_should_wait(ctrl)) { + /* We're over the bandwidth limit, so don't move onto the next transfer + * yet. Our limit_watcher will move us on once we're OK. timeout_watcher + * was disabled further up, so don't need to stop it here too */ + debug("max_bps exceeded, waiting"); + ev_timer_again(loop, &ctrl->limit_watcher); + } else { + /* We're waiting for the socket to become writable again, so re-enable */ + ev_timer_again(loop, &ctrl->timeout_watcher); + ev_io_start(loop, &ctrl->write_watcher); + } + + return; } -static void mirror_timeout_cb( struct ev_loop *loop, ev_timer *w __attribute__((unused)), int revents ) +static void mirror_timeout_cb(struct ev_loop *loop, ev_timer * w + __attribute__ ((unused)), int revents) { - if ( !(revents & EV_TIMER ) ) { - warn( "Mirror timeout called but no timer event signalled" ); - return; - } - - info( "Mirror timeout signalled" ); - ev_break( loop, EVBREAK_ONE ); + if (!(revents & EV_TIMER)) { + warn("Mirror timeout called but no timer event signalled"); return; + } + + info("Mirror timeout signalled"); + ev_break(loop, EVBREAK_ONE); + return; } -static void mirror_abandon_cb( struct ev_loop *loop, ev_io *w, int revents ) +static void mirror_abandon_cb(struct ev_loop *loop, ev_io * w, int revents) { - struct mirror_ctrl* ctrl = (struct mirror_ctrl*) w->data; - NULLCHECK( ctrl ); + struct mirror_ctrl *ctrl = (struct mirror_ctrl *) w->data; + NULLCHECK(ctrl); - if ( !(revents & EV_READ ) ) { - warn( "Mirror abandon called but no abandon event signalled" ); - return; - } - - debug( "Abandon message received" ); - mirror_set_state( ctrl->mirror, MS_ABANDONED ); - self_pipe_signal_clear( ctrl->mirror->abandon_signal ); - ev_break( loop, EVBREAK_ONE ); + if (!(revents & EV_READ)) { + warn("Mirror abandon called but no abandon event signalled"); return; + } + + debug("Abandon message received"); + mirror_set_state(ctrl->mirror, MS_ABANDONED); + self_pipe_signal_clear(ctrl->mirror->abandon_signal); + ev_break(loop, EVBREAK_ONE); + return; } -static void mirror_limit_cb( struct ev_loop *loop, ev_timer *w, int revents ) +static void mirror_limit_cb(struct ev_loop *loop, ev_timer * w, + int revents) { - struct mirror_ctrl* ctrl = (struct mirror_ctrl*) w->data; - NULLCHECK( ctrl ); - - if ( !(revents & EV_TIMER ) ) { - warn( "Mirror limit callback executed but no timer event signalled" ); - return; - } - - if ( mirror_should_wait( ctrl ) ) { - debug( "max_bps exceeded, waiting", ctrl->mirror->max_bytes_per_second ); - ev_timer_again( loop, w ); - } else { - /* We're below the limit, so do the next request */ - debug("max_bps not exceeded, performing next transfer" ); - ev_io_start( loop, &ctrl->write_watcher ); - ev_timer_stop( loop, &ctrl->limit_watcher ); - ev_timer_again( loop, &ctrl->timeout_watcher ); - } + struct mirror_ctrl *ctrl = (struct mirror_ctrl *) w->data; + NULLCHECK(ctrl); + if (!(revents & EV_TIMER)) { + warn("Mirror limit callback executed but no timer event signalled"); return; + } + + if (mirror_should_wait(ctrl)) { + debug("max_bps exceeded, waiting", + ctrl->mirror->max_bytes_per_second); + ev_timer_again(loop, w); + } else { + /* We're below the limit, so do the next request */ + debug("max_bps not exceeded, performing next transfer"); + ev_io_start(loop, &ctrl->write_watcher); + ev_timer_stop(loop, &ctrl->limit_watcher); + ev_timer_again(loop, &ctrl->timeout_watcher); + } + + return; } /* We use this to periodically check whether the allocation map has built, and * if it has, start migrating. If it's not finished, then enabling the bitset * stream does not go well for us. */ -static void mirror_begin_cb( struct ev_loop *loop, ev_timer *w, int revents ) +static void mirror_begin_cb(struct ev_loop *loop, ev_timer * w, + int revents) { - struct mirror_ctrl* ctrl = (struct mirror_ctrl*) w->data; - NULLCHECK( ctrl ); - - if ( !(revents & EV_TIMER ) ) { - warn( "Mirror limit callback executed but no timer event signalled" ); - return; - } - - if ( ctrl->serve->allocation_map_built || ctrl->serve->allocation_map_not_built ) { - info( "allocation map builder is finished, beginning migration" ); - ev_timer_stop( loop, w ); - /* Start by writing xfer 0 to the listener */ - ev_io_start( loop, &ctrl->write_watcher ); - /* We want to timeout during the first write as well as subsequent ones */ - ev_timer_again( loop, &ctrl->timeout_watcher ); - /* We're now interested in events */ - bitset_enable_stream( ctrl->serve->allocation_map ); - } else { - /* not done yet, so wait another second */ - ev_timer_again( loop, w ); - } + struct mirror_ctrl *ctrl = (struct mirror_ctrl *) w->data; + NULLCHECK(ctrl); + if (!(revents & EV_TIMER)) { + warn("Mirror limit callback executed but no timer event signalled"); return; + } + + if (ctrl->serve->allocation_map_built + || ctrl->serve->allocation_map_not_built) { + info("allocation map builder is finished, beginning migration"); + ev_timer_stop(loop, w); + /* Start by writing xfer 0 to the listener */ + ev_io_start(loop, &ctrl->write_watcher); + /* We want to timeout during the first write as well as subsequent ones */ + ev_timer_again(loop, &ctrl->timeout_watcher); + /* We're now interested in events */ + bitset_enable_stream(ctrl->serve->allocation_map); + } else { + /* not done yet, so wait another second */ + ev_timer_again(loop, w); + } + + return; } -void mirror_run( struct server *serve ) +void mirror_run(struct server *serve) { - NULLCHECK( serve ); - NULLCHECK( serve->mirror ); + NULLCHECK(serve); + NULLCHECK(serve->mirror); - struct mirror *m = serve->mirror; + struct mirror *m = serve->mirror; - m->migration_started = monotonic_time_ms(); - info("Starting mirror" ); - - /* mirror_setup_next_xfer won't be able to cope with this, so special-case - * it here. There can't be any writes going on, so don't bother locking - * anything. - * - */ - if ( serve->size == 0 ) { - info( "0-byte image special case" ); - mirror_complete( serve ); - return; - } - - struct mirror_ctrl ctrl; - memset( &ctrl, 0, sizeof( struct mirror_ctrl ) ); - - ctrl.serve = serve; - ctrl.mirror = m; - - ctrl.ev_loop = EV_DEFAULT; - - /* gcc warns with -Wstrict-aliasing on -O2. clang doesn't - * implement this warning. Seems to be the fault of ev.h */ - ev_init( &ctrl.begin_watcher, mirror_begin_cb ); - ctrl.begin_watcher.repeat = 1.0; // We check bps every second. seems sane. - ctrl.begin_watcher.data = (void*) &ctrl; - - ev_io_init( &ctrl.read_watcher, mirror_read_cb, m->client, EV_READ ); - ctrl.read_watcher.data = (void*) &ctrl; - - ev_io_init( &ctrl.write_watcher, mirror_write_cb, m->client, EV_WRITE ); - ctrl.write_watcher.data = (void*) &ctrl; - - ev_init( &ctrl.timeout_watcher, mirror_timeout_cb ); - - char * env_request_limit = getenv( "FLEXNBD_MS_REQUEST_LIMIT_SECS" ); - double timeout_limit = MS_REQUEST_LIMIT_SECS_F; - - if ( NULL != env_request_limit ) { - char *endptr = NULL; - errno = 0; - double limit = strtod( env_request_limit, &endptr ); - warn( SHOW_ERRNO( "Got %f from strtod", limit ) ); - - if ( errno == 0 ) { - timeout_limit = limit; - } - } - - ctrl.timeout_watcher.repeat = timeout_limit; - - ev_init( &ctrl.limit_watcher, mirror_limit_cb ); - ctrl.limit_watcher.repeat = 1.0; // We check bps every second. seems sane. - ctrl.limit_watcher.data = (void*) &ctrl; - - ev_init( &ctrl.abandon_watcher, mirror_abandon_cb ); - ev_io_set( &ctrl.abandon_watcher, m->abandon_signal->read_fd, EV_READ ); - ctrl.abandon_watcher.data = (void*) &ctrl; - ev_io_start( ctrl.ev_loop, &ctrl.abandon_watcher ); - - ERROR_UNLESS( - mirror_setup_next_xfer( &ctrl ), - "Couldn't find first transfer for mirror!" - ); - - - if ( serve->allocation_map_built ) { - /* Start by writing xfer 0 to the listener */ - ev_io_start( ctrl.ev_loop, &ctrl.write_watcher ); - /* We want to timeout during the first write as well as subsequent ones */ - ev_timer_again( ctrl.ev_loop, &ctrl.timeout_watcher ); - bitset_enable_stream( serve->allocation_map ); - } else { - debug( "Waiting for allocation map to be built" ); - ev_timer_again( ctrl.ev_loop, &ctrl.begin_watcher ); - } - - /* Everything up to here is blocking. We switch to non-blocking so we - * can handle rate-limiting and weird error conditions better. TODO: We - * should expand the event loop upwards so we can do the same there too */ - sock_set_nonblock( m->client, 1 ); - - info( "Entering event loop" ); - ev_run( ctrl.ev_loop, 0 ); - info( "Exited event loop" ); - - /* Parent code might expect a non-blocking socket */ - sock_set_nonblock( m->client, 0 ); - - - /* Errors in the event loop don't track I/O lock state or try to restore - * it to something sane - they just terminate the event loop with state != - * MS_DONE. We re-allow new clients here if necessary. - */ - if ( m->action_at_finish == ACTION_NOTHING || m->commit_state != MS_DONE ) { - server_allow_new_clients( serve ); - } - - /* Returning here says "mirroring complete" to the runner. The error - * call retries the migration from scratch. */ - - if ( m->commit_state != MS_DONE ) { - /* mirror_reset will be called before a retry, so keeping hold of events - * between now and our next mirroring attempt is not useful - */ - bitset_disable_stream( serve->allocation_map ); - error( "Event loop exited, but mirroring is not complete" ); - } + m->migration_started = monotonic_time_ms(); + info("Starting mirror"); + /* mirror_setup_next_xfer won't be able to cope with this, so special-case + * it here. There can't be any writes going on, so don't bother locking + * anything. + * + */ + if (serve->size == 0) { + info("0-byte image special case"); + mirror_complete(serve); return; + } + + struct mirror_ctrl ctrl; + memset(&ctrl, 0, sizeof(struct mirror_ctrl)); + + ctrl.serve = serve; + ctrl.mirror = m; + + ctrl.ev_loop = EV_DEFAULT; + + /* gcc warns with -Wstrict-aliasing on -O2. clang doesn't + * implement this warning. Seems to be the fault of ev.h */ + ev_init(&ctrl.begin_watcher, mirror_begin_cb); + ctrl.begin_watcher.repeat = 1.0; // We check bps every second. seems sane. + ctrl.begin_watcher.data = (void *) &ctrl; + + ev_io_init(&ctrl.read_watcher, mirror_read_cb, m->client, EV_READ); + ctrl.read_watcher.data = (void *) &ctrl; + + ev_io_init(&ctrl.write_watcher, mirror_write_cb, m->client, EV_WRITE); + ctrl.write_watcher.data = (void *) &ctrl; + + ev_init(&ctrl.timeout_watcher, mirror_timeout_cb); + + char *env_request_limit = getenv("FLEXNBD_MS_REQUEST_LIMIT_SECS"); + double timeout_limit = MS_REQUEST_LIMIT_SECS_F; + + if (NULL != env_request_limit) { + char *endptr = NULL; + errno = 0; + double limit = strtod(env_request_limit, &endptr); + warn(SHOW_ERRNO("Got %f from strtod", limit)); + + if (errno == 0) { + timeout_limit = limit; + } + } + + ctrl.timeout_watcher.repeat = timeout_limit; + + ev_init(&ctrl.limit_watcher, mirror_limit_cb); + ctrl.limit_watcher.repeat = 1.0; // We check bps every second. seems sane. + ctrl.limit_watcher.data = (void *) &ctrl; + + ev_init(&ctrl.abandon_watcher, mirror_abandon_cb); + ev_io_set(&ctrl.abandon_watcher, m->abandon_signal->read_fd, EV_READ); + ctrl.abandon_watcher.data = (void *) &ctrl; + ev_io_start(ctrl.ev_loop, &ctrl.abandon_watcher); + + ERROR_UNLESS(mirror_setup_next_xfer(&ctrl), + "Couldn't find first transfer for mirror!"); + + + if (serve->allocation_map_built) { + /* Start by writing xfer 0 to the listener */ + ev_io_start(ctrl.ev_loop, &ctrl.write_watcher); + /* We want to timeout during the first write as well as subsequent ones */ + ev_timer_again(ctrl.ev_loop, &ctrl.timeout_watcher); + bitset_enable_stream(serve->allocation_map); + } else { + debug("Waiting for allocation map to be built"); + ev_timer_again(ctrl.ev_loop, &ctrl.begin_watcher); + } + + /* Everything up to here is blocking. We switch to non-blocking so we + * can handle rate-limiting and weird error conditions better. TODO: We + * should expand the event loop upwards so we can do the same there too */ + sock_set_nonblock(m->client, 1); + + info("Entering event loop"); + ev_run(ctrl.ev_loop, 0); + info("Exited event loop"); + + /* Parent code might expect a non-blocking socket */ + sock_set_nonblock(m->client, 0); + + + /* Errors in the event loop don't track I/O lock state or try to restore + * it to something sane - they just terminate the event loop with state != + * MS_DONE. We re-allow new clients here if necessary. + */ + if (m->action_at_finish == ACTION_NOTHING + || m->commit_state != MS_DONE) { + server_allow_new_clients(serve); + } + + /* Returning here says "mirroring complete" to the runner. The error + * call retries the migration from scratch. */ + + if (m->commit_state != MS_DONE) { + /* mirror_reset will be called before a retry, so keeping hold of events + * between now and our next mirroring attempt is not useful + */ + bitset_disable_stream(serve->allocation_map); + error("Event loop exited, but mirroring is not complete"); + } + + return; } -void mbox_post_mirror_state( struct mbox * mbox, enum mirror_state st ) +void mbox_post_mirror_state(struct mbox *mbox, enum mirror_state st) { - NULLCHECK( mbox ); - enum mirror_state * contents = xmalloc( sizeof( enum mirror_state ) ); + NULLCHECK(mbox); + enum mirror_state *contents = xmalloc(sizeof(enum mirror_state)); - *contents = st; + *contents = st; - mbox_post( mbox, contents ); + mbox_post(mbox, contents); } -void mirror_signal_commit( struct mirror * mirror ) +void mirror_signal_commit(struct mirror *mirror) { - NULLCHECK( mirror ); + NULLCHECK(mirror); - mbox_post_mirror_state( mirror->commit_signal, - mirror_get_state( mirror ) ); + mbox_post_mirror_state(mirror->commit_signal, + mirror_get_state(mirror)); } /** Thread launched to drive mirror process @@ -876,105 +881,102 @@ void mirror_signal_commit( struct mirror * mirror ) * retries can be cleanly handled without a bespoke error handling * mechanism. * */ -void* mirror_runner(void* serve_params_uncast) +void *mirror_runner(void *serve_params_uncast) { - /* The supervisor thread relies on there not being any ERROR - * calls until after the mirror_signal_commit() call in this - * function. - * However, *after* that, we should call ERROR_* instead of - * FATAL_* wherever possible. + /* The supervisor thread relies on there not being any ERROR + * calls until after the mirror_signal_commit() call in this + * function. + * However, *after* that, we should call ERROR_* instead of + * FATAL_* wherever possible. + */ + struct server *serve = (struct server *) serve_params_uncast; + + NULLCHECK(serve); + NULLCHECK(serve->mirror); + struct mirror *mirror = serve->mirror; + + error_set_handler((cleanup_handler *) mirror_cleanup, serve); + + info("Connecting to mirror"); + + time_t start_time = time(NULL); + int connected = mirror_connect(mirror, serve->size); + mirror_signal_commit(mirror); + if (!connected) { + goto abandon_mirror; + } + + /* After this point, if we see a failure we need to disconnect + * and retry everything from mirror_set_state(_, MS_INIT), but + * *without* signaling the commit or abandoning the mirror. + * */ + + if ((time(NULL) - start_time) > MS_CONNECT_TIME_SECS) { + /* If we get here, then we managed to connect but the + * control thread feeding status back to the user will + * have gone away, leaving the user without meaningful + * feedback. In this instance, they have to assume a + * failure, so we can't afford to let the mirror happen. + * We have to set the state to avoid a race. */ - struct server *serve = (struct server*) serve_params_uncast; + mirror_set_state(mirror, MS_FAIL_CONNECT); + warn("Mirror connected, but too slowly"); + goto abandon_mirror; + } - NULLCHECK( serve ); - NULLCHECK( serve->mirror ); - struct mirror * mirror = serve->mirror; + mirror_run(serve); - error_set_handler( (cleanup_handler *) mirror_cleanup, serve ); + /* On success, this is unnecessary, and harmless ( mirror_cleanup does it + * for us ). But if we've failed and are going to retry on the next run, we + * must close this socket here to have any chance of it succeeding. + */ + if (!(mirror->client < 0)) { + sock_try_close(mirror->client); + mirror->client = -1; + } - info( "Connecting to mirror" ); - - time_t start_time = time(NULL); - int connected = mirror_connect( mirror, serve->size ); - mirror_signal_commit( mirror ); - if ( !connected ) { goto abandon_mirror; } - - /* After this point, if we see a failure we need to disconnect - * and retry everything from mirror_set_state(_, MS_INIT), but - * *without* signaling the commit or abandoning the mirror. - * */ - - if ( (time(NULL) - start_time) > MS_CONNECT_TIME_SECS ){ - /* If we get here, then we managed to connect but the - * control thread feeding status back to the user will - * have gone away, leaving the user without meaningful - * feedback. In this instance, they have to assume a - * failure, so we can't afford to let the mirror happen. - * We have to set the state to avoid a race. - */ - mirror_set_state( mirror, MS_FAIL_CONNECT ); - warn( "Mirror connected, but too slowly" ); - goto abandon_mirror; - } - - mirror_run( serve ); - - /* On success, this is unnecessary, and harmless ( mirror_cleanup does it - * for us ). But if we've failed and are going to retry on the next run, we - * must close this socket here to have any chance of it succeeding. - */ - if ( !(mirror->client < 0) ) { - sock_try_close( mirror->client ); - mirror->client = -1; - } - -abandon_mirror: - return NULL; + abandon_mirror: + return NULL; } -struct mirror_super * mirror_super_create( - const char * filename, - union mysockaddr * connect_to, - union mysockaddr * connect_from, - uint64_t max_Bps, - enum mirror_finish_action action_at_finish, - struct mbox * state_mbox) +struct mirror_super *mirror_super_create(const char *filename, + union mysockaddr *connect_to, + union mysockaddr *connect_from, + uint64_t max_Bps, + enum mirror_finish_action + action_at_finish, + struct mbox *state_mbox) { - struct mirror_super * super = xmalloc( sizeof( struct mirror_super) ); - super->mirror = mirror_create( - filename, - connect_to, - connect_from, - max_Bps, - action_at_finish, - mbox_create() ) ; - super->state_mbox = state_mbox; - return super; + struct mirror_super *super = xmalloc(sizeof(struct mirror_super)); + super->mirror = mirror_create(filename, + connect_to, + connect_from, + max_Bps, + action_at_finish, mbox_create()); + super->state_mbox = state_mbox; + return super; } /* Post the current state of the mirror into super->state_mbox.*/ -void mirror_super_signal_committed( - struct mirror_super * super , - enum mirror_state commit_state ) +void mirror_super_signal_committed(struct mirror_super *super, + enum mirror_state commit_state) { - NULLCHECK( super ); - NULLCHECK( super->state_mbox ); + NULLCHECK(super); + NULLCHECK(super->state_mbox); - mbox_post_mirror_state( - super->state_mbox, - commit_state ); + mbox_post_mirror_state(super->state_mbox, commit_state); } -void mirror_super_destroy( struct mirror_super * super ) +void mirror_super_destroy(struct mirror_super *super) { - NULLCHECK( super ); + NULLCHECK(super); - mbox_destroy( super->mirror->commit_signal ); - mirror_destroy( super->mirror ); - free( super ); + mbox_destroy(super->mirror->commit_signal); + mirror_destroy(super->mirror); + free(super); } @@ -983,90 +985,87 @@ void mirror_super_destroy( struct mirror_super * super ) * The mirror and mirror_super objects are never freed, and the * mirror_super_runner thread is never joined. */ -void * mirror_super_runner( void * serve_uncast ) +void *mirror_super_runner(void *serve_uncast) { - struct server * serve = (struct server *) serve_uncast; - NULLCHECK( serve ); - NULLCHECK( serve->mirror ); - NULLCHECK( serve->mirror_super ); + struct server *serve = (struct server *) serve_uncast; + NULLCHECK(serve); + NULLCHECK(serve->mirror); + NULLCHECK(serve->mirror_super); - int first_pass = 1; - int should_retry = 0; - int success = 0, abandoned = 0; + int first_pass = 1; + int should_retry = 0; + int success = 0, abandoned = 0; - struct mirror * mirror = serve->mirror; - struct mirror_super * super = serve->mirror_super; + struct mirror *mirror = serve->mirror; + struct mirror_super *super = serve->mirror_super; - do { - FATAL_IF( 0 != pthread_create( - &mirror->thread, - NULL, - mirror_runner, - serve), - "Failed to create mirror thread"); + do { + FATAL_IF(0 != pthread_create(&mirror->thread, + NULL, + mirror_runner, + serve), + "Failed to create mirror thread"); - debug("Supervisor waiting for commit signal"); - enum mirror_state * commit_state = - mbox_receive( mirror->commit_signal ); + debug("Supervisor waiting for commit signal"); + enum mirror_state *commit_state = + mbox_receive(mirror->commit_signal); - debug( "Supervisor got commit signal" ); - if ( first_pass ) { - /* Only retry if the connection attempt was successful. Otherwise - * the user will see an error reported while we're still trying to - * retry behind the scenes. This may race with migration completing - * but since we "shouldn't retry" in that case either, that's fine - */ - should_retry = *commit_state == MS_GO; - - /* Only send this signal the first time */ - mirror_super_signal_committed( - super, - *commit_state); - debug("Mirror supervisor committed"); - } - /* We only care about the value of the commit signal on - * the first pass, so this is ok - */ - free( commit_state ); - - debug("Supervisor waiting for mirror thread" ); - pthread_join( mirror->thread, NULL ); - - /* If we can't connect to the remote end, the watcher for the abandon - * signal never gets installed at the moment, which is why we also check - * it here. */ - abandoned = - mirror_get_state( mirror ) == MS_ABANDONED || - self_pipe_signal_clear( mirror->abandon_signal ); - - success = MS_DONE == mirror_get_state( mirror ); - - - if( success ){ - info( "Mirror supervisor success, exiting" ); - } else if ( abandoned ) { - info( "Mirror abandoned" ); - should_retry = 0; - } else if ( should_retry ) { - info( "Mirror failed, retrying" ); - } else { - info( "Mirror failed before commit, giving up" ); - } - - first_pass = 0; - - if ( should_retry ) { - /* We don't want to hammer the destination too - * hard, so if this is a retry, insert a delay. */ - sleep( MS_RETRY_DELAY_SECS ); - - /* We also have to reset the bitmap to be sure - * we transfer everything */ - mirror_reset( mirror ); - } + debug("Supervisor got commit signal"); + if (first_pass) { + /* Only retry if the connection attempt was successful. Otherwise + * the user will see an error reported while we're still trying to + * retry behind the scenes. This may race with migration completing + * but since we "shouldn't retry" in that case either, that's fine + */ + should_retry = *commit_state == MS_GO; + /* Only send this signal the first time */ + mirror_super_signal_committed(super, *commit_state); + debug("Mirror supervisor committed"); } - while ( should_retry && !success ); + /* We only care about the value of the commit signal on + * the first pass, so this is ok + */ + free(commit_state); - return NULL; + debug("Supervisor waiting for mirror thread"); + pthread_join(mirror->thread, NULL); + + /* If we can't connect to the remote end, the watcher for the abandon + * signal never gets installed at the moment, which is why we also check + * it here. */ + abandoned = + mirror_get_state(mirror) == MS_ABANDONED || + self_pipe_signal_clear(mirror->abandon_signal); + + success = MS_DONE == mirror_get_state(mirror); + + + if (success) { + info("Mirror supervisor success, exiting"); + } else if (abandoned) { + info("Mirror abandoned"); + should_retry = 0; + } else if (should_retry) { + info("Mirror failed, retrying"); + } else { + info("Mirror failed before commit, giving up"); + } + + first_pass = 0; + + if (should_retry) { + /* We don't want to hammer the destination too + * hard, so if this is a retry, insert a delay. */ + sleep(MS_RETRY_DELAY_SECS); + + /* We also have to reset the bitmap to be sure + * we transfer everything */ + mirror_reset(mirror); + } + + } + while (should_retry && !success); + + return NULL; } diff --git a/src/server/mirror.h b/src/server/mirror.h index d390fdf..7601bee 100644 --- a/src/server/mirror.h +++ b/src/server/mirror.h @@ -58,65 +58,65 @@ enum mirror_state; #define MS_REQUEST_LIMIT_SECS_F 60.0 enum mirror_finish_action { - ACTION_EXIT, - ACTION_UNLINK, - ACTION_NOTHING + ACTION_EXIT, + ACTION_UNLINK, + ACTION_NOTHING }; enum mirror_state { - MS_UNKNOWN, - MS_INIT, - MS_GO, - MS_ABANDONED, - MS_DONE, - MS_FAIL_CONNECT, - MS_FAIL_REJECTED, - MS_FAIL_NO_HELLO, - MS_FAIL_SIZE_MISMATCH + MS_UNKNOWN, + MS_INIT, + MS_GO, + MS_ABANDONED, + MS_DONE, + MS_FAIL_CONNECT, + MS_FAIL_REJECTED, + MS_FAIL_NO_HELLO, + MS_FAIL_SIZE_MISMATCH }; struct mirror { - pthread_t thread; + pthread_t thread; - /* Signal to this then join the thread if you want to abandon mirroring */ - struct self_pipe * abandon_signal; + /* Signal to this then join the thread if you want to abandon mirroring */ + struct self_pipe *abandon_signal; - union mysockaddr * connect_to; - union mysockaddr * connect_from; - int client; - const char * filename; + union mysockaddr *connect_to; + union mysockaddr *connect_from; + int client; + const char *filename; - /* Limiter, used to restrict migration speed Only dirty bytes (those going - * over the network) are considered */ - uint64_t max_bytes_per_second; + /* Limiter, used to restrict migration speed Only dirty bytes (those going + * over the network) are considered */ + uint64_t max_bytes_per_second; - enum mirror_finish_action action_at_finish; + enum mirror_finish_action action_at_finish; - char *mapped; + char *mapped; - /* We need to send every byte at least once; we do so by */ - uint64_t offset; + /* We need to send every byte at least once; we do so by */ + uint64_t offset; - enum mirror_state commit_state; + enum mirror_state commit_state; - /* commit_signal is sent immediately after attempting to connect - * and checking the remote size, whether successful or not. - */ - struct mbox * commit_signal; + /* commit_signal is sent immediately after attempting to connect + * and checking the remote size, whether successful or not. + */ + struct mbox *commit_signal; - /* The time (from monotonic_time_ms()) the migration was started. Can be - * used to calculate bps, etc. */ - uint64_t migration_started; + /* The time (from monotonic_time_ms()) the migration was started. Can be + * used to calculate bps, etc. */ + uint64_t migration_started; - /* Running count of all bytes we've transferred */ - uint64_t all_dirty; + /* Running count of all bytes we've transferred */ + uint64_t all_dirty; }; struct mirror_super { - struct mirror * mirror; - pthread_t thread; - struct mbox * state_mbox; + struct mirror *mirror; + pthread_t thread; + struct mbox *state_mbox; }; @@ -127,15 +127,13 @@ struct mirror_super { struct server; struct flexnbd; -struct mirror_super * mirror_super_create( - const char * filename, - union mysockaddr * connect_to, - union mysockaddr * connect_from, - uint64_t max_Bps, - enum mirror_finish_action action_at_finish, - struct mbox * state_mbox - ); -void * mirror_super_runner( void * serve_uncast ); +struct mirror_super *mirror_super_create(const char *filename, + union mysockaddr *connect_to, + union mysockaddr *connect_from, + uint64_t max_Bps, + enum mirror_finish_action + action_at_finish, + struct mbox *state_mbox); +void *mirror_super_runner(void *serve_uncast); #endif - diff --git a/src/server/mode.c b/src/server/mode.c index 47dbffc..6082e04 100644 --- a/src/server/mode.c +++ b/src/server/mode.c @@ -8,526 +8,517 @@ static struct option serve_options[] = { - GETOPT_HELP, - GETOPT_ADDR, - GETOPT_PORT, - GETOPT_FILE, - GETOPT_SOCK, - GETOPT_DENY, - GETOPT_QUIET, - GETOPT_KILLSWITCH, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_ADDR, + GETOPT_PORT, + GETOPT_FILE, + GETOPT_SOCK, + GETOPT_DENY, + GETOPT_QUIET, + GETOPT_KILLSWITCH, + GETOPT_VERBOSE, + {0} }; + static char serve_short_options[] = "hl:p:f:s:dk" SOPT_QUIET SOPT_VERBOSE; static char serve_help_text[] = - "Usage: flexnbd " CMD_SERVE " [*]\n\n" - "Serve FILE from ADDR:PORT, with an optional control socket at SOCK.\n\n" - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address to serve on.\n" - "\t--" OPT_PORT ",-p \tThe port to serve on.\n" - "\t--" OPT_FILE ",-f \tThe file to serve.\n" - "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" - "\t--" OPT_KILLSWITCH",-k \tKill the server if a request takes 120 seconds.\n" - SOCK_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_SERVE " [*]\n\n" + "Serve FILE from ADDR:PORT, with an optional control socket at SOCK.\n\n" + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address to serve on.\n" + "\t--" OPT_PORT ",-p \tThe port to serve on.\n" + "\t--" OPT_FILE ",-f \tThe file to serve.\n" + "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" + "\t--" OPT_KILLSWITCH + ",-k \tKill the server if a request takes 120 seconds.\n" SOCK_LINE + VERBOSE_LINE QUIET_LINE; static struct option listen_options[] = { - GETOPT_HELP, - GETOPT_ADDR, - GETOPT_PORT, - GETOPT_FILE, - GETOPT_SOCK, - GETOPT_DENY, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_ADDR, + GETOPT_PORT, + GETOPT_FILE, + GETOPT_SOCK, + GETOPT_DENY, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char listen_short_options[] = "hl:p:f:s:d" SOPT_QUIET SOPT_VERBOSE; static char listen_help_text[] = - "Usage: flexnbd " CMD_LISTEN " [*]\n\n" - "Listen for an incoming migration on ADDR:PORT." - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address to listen on.\n" - "\t--" OPT_PORT ",-p \tThe port to listen on.\n" - "\t--" OPT_FILE ",-f \tThe file to serve.\n" - "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" - SOCK_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_LISTEN " [*]\n\n" + "Listen for an incoming migration on ADDR:PORT." + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address to listen on.\n" + "\t--" OPT_PORT ",-p \tThe port to listen on.\n" + "\t--" OPT_FILE ",-f \tThe file to serve.\n" + "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" + SOCK_LINE VERBOSE_LINE QUIET_LINE; static struct option read_options[] = { - GETOPT_HELP, - GETOPT_ADDR, - GETOPT_PORT, - GETOPT_FROM, - GETOPT_SIZE, - GETOPT_BIND, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_ADDR, + GETOPT_PORT, + GETOPT_FROM, + GETOPT_SIZE, + GETOPT_BIND, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char read_short_options[] = "hl:p:F:S:b:" SOPT_QUIET SOPT_VERBOSE; static char read_help_text[] = - "Usage: flexnbd " CMD_READ " \n\n" - "Read SIZE bytes from a server at ADDR:PORT to stdout, starting at OFFSET.\n\n" - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address to read from.\n" - "\t--" OPT_PORT ",-p \tThe port to read from.\n" - "\t--" OPT_FROM ",-F \tByte offset to read from.\n" - "\t--" OPT_SIZE ",-S \tBytes to read.\n" - BIND_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_READ " \n\n" + "Read SIZE bytes from a server at ADDR:PORT to stdout, starting at OFFSET.\n\n" + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address to read from.\n" + "\t--" OPT_PORT ",-p \tThe port to read from.\n" + "\t--" OPT_FROM ",-F \tByte offset to read from.\n" + "\t--" OPT_SIZE ",-S \tBytes to read.\n" + BIND_LINE VERBOSE_LINE QUIET_LINE; static struct option *write_options = read_options; static char *write_short_options = read_short_options; static char write_help_text[] = - "Usage: flexnbd " CMD_WRITE" \n\n" - "Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n" - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address to write to.\n" - "\t--" OPT_PORT ",-p \tThe port to write to.\n" - "\t--" OPT_FROM ",-F \tByte offset to write from.\n" - "\t--" OPT_SIZE ",-S \tBytes to write.\n" - BIND_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_WRITE " \n\n" + "Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n" + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address to write to.\n" + "\t--" OPT_PORT ",-p \tThe port to write to.\n" + "\t--" OPT_FROM ",-F \tByte offset to write from.\n" + "\t--" OPT_SIZE ",-S \tBytes to write.\n" + BIND_LINE VERBOSE_LINE QUIET_LINE; static struct option acl_options[] = { - GETOPT_HELP, - GETOPT_SOCK, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char acl_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char acl_help_text[] = - "Usage: flexnbd " CMD_ACL " [+]\n\n" - "Set the access control list for a server with control socket SOCK.\n\n" - HELP_LINE - SOCK_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_ACL " [+]\n\n" + "Set the access control list for a server with control socket SOCK.\n\n" + HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE; static struct option mirror_speed_options[] = { - GETOPT_HELP, - GETOPT_SOCK, - GETOPT_MAX_SPEED, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_MAX_SPEED, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char mirror_speed_short_options[] = "hs:m:" SOPT_QUIET SOPT_VERBOSE; static char mirror_speed_help_text[] = - "Usage: flexnbd " CMD_MIRROR_SPEED " \n\n" - "Set the maximum speed of a migration from a mirring server listening on SOCK.\n\n" - HELP_LINE - SOCK_LINE - MAX_SPEED_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_MIRROR_SPEED " \n\n" + "Set the maximum speed of a migration from a mirring server listening on SOCK.\n\n" + HELP_LINE SOCK_LINE MAX_SPEED_LINE VERBOSE_LINE QUIET_LINE; static struct option mirror_options[] = { - GETOPT_HELP, - GETOPT_SOCK, - GETOPT_ADDR, - GETOPT_PORT, - GETOPT_UNLINK, - GETOPT_BIND, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_ADDR, + GETOPT_PORT, + GETOPT_UNLINK, + GETOPT_BIND, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char mirror_short_options[] = "hs:l:p:ub:" SOPT_QUIET SOPT_VERBOSE; static char mirror_help_text[] = - "Usage: flexnbd " CMD_MIRROR " \n\n" - "Start mirroring from the server with control socket SOCK to one at ADDR:PORT.\n\n" - HELP_LINE - "\t--" OPT_ADDR ",-l \tThe address to mirror to.\n" - "\t--" OPT_PORT ",-p \tThe port to mirror to.\n" - SOCK_LINE - "\t--" OPT_UNLINK ",-u\tUnlink the local file when done.\n" - BIND_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_MIRROR " \n\n" + "Start mirroring from the server with control socket SOCK to one at ADDR:PORT.\n\n" + HELP_LINE + "\t--" OPT_ADDR ",-l \tThe address to mirror to.\n" + "\t--" OPT_PORT ",-p \tThe port to mirror to.\n" + SOCK_LINE + "\t--" OPT_UNLINK ",-u\tUnlink the local file when done.\n" + BIND_LINE VERBOSE_LINE QUIET_LINE; static struct option break_options[] = { - GETOPT_HELP, - GETOPT_SOCK, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char break_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char break_help_text[] = - "Usage: flexnbd " CMD_BREAK " \n\n" - "Stop mirroring from the server with control socket SOCK.\n\n" - HELP_LINE - SOCK_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_BREAK " \n\n" + "Stop mirroring from the server with control socket SOCK.\n\n" + HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE; static struct option status_options[] = { - GETOPT_HELP, - GETOPT_SOCK, - GETOPT_QUIET, - GETOPT_VERBOSE, - {0} + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} }; + static char status_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char status_help_text[] = - "Usage: flexnbd " CMD_STATUS " \n\n" - "Get the status for a server with control socket SOCK.\n\n" - HELP_LINE - SOCK_LINE - VERBOSE_LINE - QUIET_LINE; + "Usage: flexnbd " CMD_STATUS " \n\n" + "Get the status for a server with control socket SOCK.\n\n" + HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE; char help_help_text_arr[] = - "Usage: flexnbd [cmd options]\n\n" - "Commands:\n" - "\tflexnbd serve\n" - "\tflexnbd listen\n" - "\tflexnbd read\n" - "\tflexnbd write\n" - "\tflexnbd acl\n" - "\tflexnbd mirror\n" - "\tflexnbd mirror-speed\n" - "\tflexnbd break\n" - "\tflexnbd status\n" - "\tflexnbd help\n\n" - "See flexnbd help for further info\n"; + "Usage: flexnbd [cmd options]\n\n" + "Commands:\n" + "\tflexnbd serve\n" + "\tflexnbd listen\n" + "\tflexnbd read\n" + "\tflexnbd write\n" + "\tflexnbd acl\n" + "\tflexnbd mirror\n" + "\tflexnbd mirror-speed\n" + "\tflexnbd break\n" + "\tflexnbd status\n" + "\tflexnbd help\n\n" "See flexnbd help for further info\n"; /* Slightly odd array/pointer pair to stop the compiler from complaining * about symbol sizes */ -char * help_help_text = help_help_text_arr; +char *help_help_text = help_help_text_arr; -void do_read(struct mode_readwrite_params* params); -void do_write(struct mode_readwrite_params* params); -void do_remote_command(char* command, char* mode, int argc, char** argv); +void do_read(struct mode_readwrite_params *params); +void do_write(struct mode_readwrite_params *params); +void do_remote_command(char *command, char *mode, int argc, char **argv); -void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char **sock, int *default_deny, int *use_killswitch ) +void read_serve_param(int c, char **ip_addr, char **ip_port, char **file, + char **sock, int *default_deny, int *use_killswitch) { - switch(c){ - case 'h': - fprintf(stdout, "%s\n", serve_help_text ); - exit( 0 ); - case 'l': - *ip_addr = optarg; - break; - case 'p': - *ip_port = optarg; - break; - case 'f': - *file = optarg; - break; - case 's': - *sock = optarg; - break; - case 'd': - *default_deny = 1; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - case 'k': - *use_killswitch = 1; - break; - default: - exit_err( serve_help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", serve_help_text); + exit(0); + case 'l': + *ip_addr = optarg; + break; + case 'p': + *ip_port = optarg; + break; + case 'f': + *file = optarg; + break; + case 's': + *sock = optarg; + break; + case 'd': + *default_deny = 1; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + case 'k': + *use_killswitch = 1; + break; + default: + exit_err(serve_help_text); + break; + } } -void read_listen_param( int c, - char **ip_addr, - char **ip_port, - char **file, - char **sock, - int *default_deny ) +void read_listen_param(int c, + char **ip_addr, + char **ip_port, + char **file, char **sock, int *default_deny) { - switch(c){ - case 'h': - fprintf(stdout, "%s\n", listen_help_text ); - exit(0); - case 'l': - *ip_addr = optarg; - break; - case 'p': - *ip_port = optarg; - break; - case 'f': - *file = optarg; - break; - case 's': - *sock = optarg; - break; - case 'd': - *default_deny = 1; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( listen_help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", listen_help_text); + exit(0); + case 'l': + *ip_addr = optarg; + break; + case 'p': + *ip_port = optarg; + break; + case 'f': + *file = optarg; + break; + case 's': + *sock = optarg; + break; + case 'd': + *default_deny = 1; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(listen_help_text); + break; + } } -void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **bind_addr, char **from, char **size, char *err_text ) +void read_readwrite_param(int c, char **ip_addr, char **ip_port, + char **bind_addr, char **from, char **size, + char *err_text) { - switch(c){ - case 'h': - fprintf(stdout, "%s\n", err_text ); - exit( 0 ); - case 'l': - *ip_addr = optarg; - break; - case 'p': - *ip_port = optarg; - break; - case 'F': - *from = optarg; - break; - case 'S': - *size = optarg; - break; - case 'b': - *bind_addr = optarg; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( err_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", err_text); + exit(0); + case 'l': + *ip_addr = optarg; + break; + case 'p': + *ip_port = optarg; + break; + case 'F': + *from = optarg; + break; + case 'S': + *size = optarg; + break; + case 'b': + *bind_addr = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(err_text); + break; + } } -void read_sock_param( int c, char **sock, char *help_text ) +void read_sock_param(int c, char **sock, char *help_text) { - switch(c){ - case 'h': - fprintf( stdout, "%s\n", help_text ); - exit( 0 ); - case 's': - *sock = optarg; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", help_text); + exit(0); + case 's': + *sock = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(help_text); + break; + } } -void read_acl_param( int c, char **sock ) +void read_acl_param(int c, char **sock) { - read_sock_param( c, sock, acl_help_text ); + read_sock_param(c, sock, acl_help_text); } -void read_mirror_speed_param( - int c, - char **sock, - char **max_speed -) +void read_mirror_speed_param(int c, char **sock, char **max_speed) { - switch( c ) { - case 'h': - fprintf( stdout, "%s\n", mirror_speed_help_text ); - exit( 0 ); - case 's': - *sock = optarg; - break; - case 'm': - *max_speed = optarg; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( mirror_speed_help_text ); - break; + switch (c) { + case 'h': + fprintf(stdout, "%s\n", mirror_speed_help_text); + exit(0); + case 's': + *sock = optarg; + break; + case 'm': + *max_speed = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(mirror_speed_help_text); + break; - } + } } -void read_mirror_param( - int c, - char **sock, - char **ip_addr, - char **ip_port, - int *unlink, - char **bind_addr ) +void read_mirror_param(int c, + char **sock, + char **ip_addr, + char **ip_port, int *unlink, char **bind_addr) { - switch( c ){ - case 'h': - fprintf( stdout, "%s\n", mirror_help_text ); - exit( 0 ); - case 's': - *sock = optarg; - break; - case 'l': - *ip_addr = optarg; - break; - case 'p': - *ip_port = optarg; - break; - case 'u': - *unlink = 1; - break; - case 'b': - *bind_addr = optarg; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( mirror_help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", mirror_help_text); + exit(0); + case 's': + *sock = optarg; + break; + case 'l': + *ip_addr = optarg; + break; + case 'p': + *ip_port = optarg; + break; + case 'u': + *unlink = 1; + break; + case 'b': + *bind_addr = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(mirror_help_text); + break; + } } -void read_break_param( int c, char **sock ) +void read_break_param(int c, char **sock) { - switch( c ) { - case 'h': - fprintf( stdout, "%s\n", break_help_text ); - exit( 0 ); - case 's': - *sock = optarg; - break; - case 'q': - log_level = QUIET_LOG_LEVEL; - break; - case 'v': - log_level = VERBOSE_LOG_LEVEL; - break; - default: - exit_err( break_help_text ); - break; - } + switch (c) { + case 'h': + fprintf(stdout, "%s\n", break_help_text); + exit(0); + case 's': + *sock = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err(break_help_text); + break; + } } -void read_status_param( int c, char **sock ) +void read_status_param(int c, char **sock) { - read_sock_param( c, sock, status_help_text ); + read_sock_param(c, sock, status_help_text); } -int mode_serve( int argc, char *argv[] ) +int mode_serve(int argc, char *argv[]) { - int c; - char *ip_addr = NULL; - char *ip_port = NULL; - char *file = NULL; - char *sock = NULL; - int default_deny = 0; // not on by default - int use_killswitch = 0; - int err = 0; + int c; + char *ip_addr = NULL; + char *ip_port = NULL; + char *file = NULL; + char *sock = NULL; + int default_deny = 0; // not on by default + int use_killswitch = 0; + int err = 0; - int success; + int success; - struct flexnbd * flexnbd; + struct flexnbd *flexnbd; - while (1) { - c = getopt_long(argc, argv, serve_short_options, serve_options, NULL); - if ( c == -1 ) { break; } - - read_serve_param( c, &ip_addr, &ip_port, &file, &sock, &default_deny, &use_killswitch ); + while (1) { + c = getopt_long(argc, argv, serve_short_options, serve_options, + NULL); + if (c == -1) { + break; } - if ( NULL == ip_addr || NULL == ip_port ) { - err = 1; - fprintf( stderr, "both --addr and --port are required.\n" ); - } - if ( NULL == file ) { - err = 1; - fprintf( stderr, "--file is required\n" ); - } - if ( err ) { exit_err( serve_help_text ); } + read_serve_param(c, &ip_addr, &ip_port, &file, &sock, + &default_deny, &use_killswitch); + } - flexnbd = flexnbd_create_serving( ip_addr, ip_port, file, sock, default_deny, argc - optind, argv + optind, MAX_NBD_CLIENTS, use_killswitch ); - info( "Serving file %s", file ); - success = flexnbd_serve( flexnbd ); - flexnbd_destroy( flexnbd ); + if (NULL == ip_addr || NULL == ip_port) { + err = 1; + fprintf(stderr, "both --addr and --port are required.\n"); + } + if (NULL == file) { + err = 1; + fprintf(stderr, "--file is required\n"); + } + if (err) { + exit_err(serve_help_text); + } - return success ? 0 : 1; + flexnbd = + flexnbd_create_serving(ip_addr, ip_port, file, sock, default_deny, + argc - optind, argv + optind, + MAX_NBD_CLIENTS, use_killswitch); + info("Serving file %s", file); + success = flexnbd_serve(flexnbd); + flexnbd_destroy(flexnbd); + + return success ? 0 : 1; } -int mode_listen( int argc, char *argv[] ) +int mode_listen(int argc, char *argv[]) { - int c; - char *ip_addr = NULL; - char *ip_port = NULL; - char *file = NULL; - char *sock = NULL; - int default_deny = 0; // not on by default - int err = 0; + int c; + char *ip_addr = NULL; + char *ip_port = NULL; + char *file = NULL; + char *sock = NULL; + int default_deny = 0; // not on by default + int err = 0; - int success; + int success; - struct flexnbd * flexnbd; + struct flexnbd *flexnbd; - while (1) { - c = getopt_long(argc, argv, listen_short_options, listen_options, NULL); - if ( c == -1 ) { break; } - - read_listen_param( c, &ip_addr, &ip_port, - &file, &sock, &default_deny ); + while (1) { + c = getopt_long(argc, argv, listen_short_options, listen_options, + NULL); + if (c == -1) { + break; } - if ( NULL == ip_addr || NULL == ip_port ) { - err = 1; - fprintf( stderr, "both --addr and --port are required.\n" ); - } - if ( NULL == file ) { - err = 1; - fprintf( stderr, "--file is required\n" ); - } - if ( err ) { exit_err( listen_help_text ); } + read_listen_param(c, &ip_addr, &ip_port, + &file, &sock, &default_deny); + } - flexnbd = flexnbd_create_listening( - ip_addr, - ip_port, - file, - sock, - default_deny, - argc - optind, - argv + optind); - success = flexnbd_serve( flexnbd ); - flexnbd_destroy( flexnbd ); + if (NULL == ip_addr || NULL == ip_port) { + err = 1; + fprintf(stderr, "both --addr and --port are required.\n"); + } + if (NULL == file) { + err = 1; + fprintf(stderr, "--file is required\n"); + } + if (err) { + exit_err(listen_help_text); + } - return success ? 0 : 1; + flexnbd = flexnbd_create_listening(ip_addr, + ip_port, + file, + sock, + default_deny, + argc - optind, argv + optind); + success = flexnbd_serve(flexnbd); + flexnbd_destroy(flexnbd); + + return success ? 0 : 1; } @@ -545,340 +536,354 @@ int mode_listen( int argc, char *argv[] ) * char *s_length, * char *s_filename ) */ -void params_readwrite( - int write_not_read, - struct mode_readwrite_params* out, - char* s_ip_address, - char* s_port, - char* s_bind_address, - char* s_from, - char* s_length_or_filename -) +void params_readwrite(int write_not_read, + struct mode_readwrite_params *out, + char *s_ip_address, + char *s_port, + char *s_bind_address, + char *s_from, char *s_length_or_filename) { - FATAL_IF_NULL(s_ip_address, "No IP address supplied"); - FATAL_IF_NULL(s_port, "No port number supplied"); - FATAL_IF_NULL(s_from, "No from supplied"); - FATAL_IF_NULL(s_length_or_filename, "No length supplied"); + FATAL_IF_NULL(s_ip_address, "No IP address supplied"); + FATAL_IF_NULL(s_port, "No port number supplied"); + FATAL_IF_NULL(s_from, "No from supplied"); + FATAL_IF_NULL(s_length_or_filename, "No length supplied"); - FATAL_IF_ZERO( - parse_ip_to_sockaddr(&out->connect_to.generic, s_ip_address), - "Couldn't parse connection address '%s'", - s_ip_address - ); + FATAL_IF_ZERO(parse_ip_to_sockaddr + (&out->connect_to.generic, s_ip_address), + "Couldn't parse connection address '%s'", s_ip_address); - if (s_bind_address != NULL && - parse_ip_to_sockaddr(&out->connect_from.generic, s_bind_address) == 0) { - fatal("Couldn't parse bind address '%s'", s_bind_address); - } + if (s_bind_address != NULL && + parse_ip_to_sockaddr(&out->connect_from.generic, + s_bind_address) == 0) { + fatal("Couldn't parse bind address '%s'", s_bind_address); + } - parse_port( s_port, &out->connect_to.v4 ); + parse_port(s_port, &out->connect_to.v4); - long signed_from = atol(s_from); - FATAL_IF_NEGATIVE( signed_from, - "Can't read from a negative offset %d.", signed_from); - out->from = signed_from; + long signed_from = atol(s_from); + FATAL_IF_NEGATIVE(signed_from, + "Can't read from a negative offset %d.", + signed_from); + out->from = signed_from; - if (write_not_read) { - if (s_length_or_filename[0]-48 < 10) { - out->len = atol(s_length_or_filename); - out->data_fd = 0; - } - else { - out->data_fd = open( - s_length_or_filename, O_RDONLY); - FATAL_IF_NEGATIVE(out->data_fd, - "Couldn't open %s", s_length_or_filename); - off64_t signed_len = lseek64(out->data_fd, 0, SEEK_END); - FATAL_IF_NEGATIVE(signed_len, - "Couldn't find length of %s", s_length_or_filename); - out->len = signed_len; - FATAL_IF_NEGATIVE( - lseek64(out->data_fd, 0, SEEK_SET), - "Couldn't rewind %s", s_length_or_filename - ); - } - } - else { - out->len = atol(s_length_or_filename); - out->data_fd = 1; - } -} - - -int mode_read( int argc, char *argv[] ) -{ - int c; - char *ip_addr = NULL; - char *ip_port = NULL; - char *bind_addr = NULL; - char *from = NULL; - char *size = NULL; - int err = 0; - - struct mode_readwrite_params readwrite; - - while (1){ - c = getopt_long(argc, argv, read_short_options, read_options, NULL); - - if ( c == -1 ) { break; } - - read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size, read_help_text ); - } - - if ( NULL == ip_addr || NULL == ip_port ) { - err = 1; - fprintf( stderr, "both --addr and --port are required.\n" ); - } - if ( NULL == from || NULL == size ) { - err = 1; - fprintf( stderr, "both --from and --size are required.\n" ); - } - if ( err ) { exit_err( read_help_text ); } - - memset( &readwrite, 0, sizeof( readwrite ) ); - params_readwrite( 0, &readwrite, ip_addr, ip_port, bind_addr, from, size ); - do_read( &readwrite ); - return 0; -} - -int mode_write( int argc, char *argv[] ) -{ - int c; - char *ip_addr = NULL; - char *ip_port = NULL; - char *bind_addr = NULL; - char *from = NULL; - char *size = NULL; - int err = 0; - - struct mode_readwrite_params readwrite; - - while (1){ - c = getopt_long(argc, argv, write_short_options, write_options, NULL); - if ( c == -1 ) { break; } - - read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size, write_help_text ); - } - - if ( NULL == ip_addr || NULL == ip_port ) { - err = 1; - fprintf( stderr, "both --addr and --port are required.\n" ); - } - if ( NULL == from || NULL == size ) { - err = 1; - fprintf( stderr, "both --from and --size are required.\n" ); - } - if ( err ) { exit_err( write_help_text ); } - - memset( &readwrite, 0, sizeof( readwrite ) ); - params_readwrite( 1, &readwrite, ip_addr, ip_port, bind_addr, from, size ); - do_write( &readwrite ); - return 0; -} - -int mode_acl( int argc, char *argv[] ) -{ - int c; - char *sock = NULL; - - while (1) { - c = getopt_long( argc, argv, acl_short_options, acl_options, NULL ); - if ( c == -1 ) { break; } - read_acl_param( c, &sock ); - } - - if ( NULL == sock ){ - fprintf( stderr, "--sock is required.\n" ); - exit_err( acl_help_text ); - } - - /* Don't use the CMD_ACL macro here, "acl" is the remote command - * name, not the cli option - */ - do_remote_command( "acl", sock, argc - optind, argv + optind ); - - return 0; -} - - -int mode_mirror_speed( int argc, char *argv[] ) -{ - int c; - char *sock = NULL; - char *speed = NULL; - - while( 1 ) { - c = getopt_long( argc, argv, mirror_speed_short_options, mirror_speed_options, NULL ); - if ( -1 == c ) { break; } - read_mirror_speed_param( c, &sock, &speed ); - } - - if ( NULL == sock ) { - fprintf( stderr, "--sock is required.\n" ); - exit_err( mirror_speed_help_text ); - } - - if ( NULL == speed ) { - fprintf( stderr, "--max-speed is required.\n"); - exit_err( mirror_speed_help_text ); - } - - do_remote_command( "mirror_max_bps", sock, 1, &speed ); - return 0; -} - - -int mode_mirror( int argc, char *argv[] ) -{ - int c; - char *sock = NULL; - char *remote_argv[4] = {0}; - int err = 0; - int unlink = 0; - - remote_argv[2] = "exit"; - - while (1) { - c = getopt_long( argc, argv, mirror_short_options, mirror_options, NULL); - if ( -1 == c ) { break; } - read_mirror_param( c, - &sock, - &remote_argv[0], - &remote_argv[1], - &unlink, - &remote_argv[3] ); - } - - if ( NULL == sock ){ - fprintf( stderr, "--sock is required.\n" ); - err = 1; - } - if ( NULL == remote_argv[0] || NULL == remote_argv[1] ) { - fprintf( stderr, "both --addr and --port are required.\n"); - err = 1; - } - if ( err ) { exit_err( mirror_help_text ); } - if ( unlink ) { remote_argv[2] = "unlink"; } - - if (remote_argv[3] == NULL) { - do_remote_command( "mirror", sock, 3, remote_argv ); - } - else { - do_remote_command( "mirror", sock, 4, remote_argv ); - } - - return 0; -} - - -int mode_break( int argc, char *argv[] ) -{ - int c; - char *sock = NULL; - - while (1) { - c = getopt_long( argc, argv, break_short_options, break_options, NULL ); - if ( -1 == c ) { break; } - read_break_param( c, &sock ); - } - - if ( NULL == sock ){ - fprintf( stderr, "--sock is required.\n" ); - exit_err( break_help_text ); - } - - do_remote_command( "break", sock, argc - optind, argv + optind ); - - return 0; -} - -int mode_status( int argc, char *argv[] ) -{ - int c; - char *sock = NULL; - - while (1) { - c = getopt_long( argc, argv, status_short_options, status_options, NULL ); - if ( -1 == c ) { break; } - read_status_param( c, &sock ); - } - - if ( NULL == sock ){ - fprintf( stderr, "--sock is required.\n" ); - exit_err( status_help_text ); - } - - do_remote_command( "status", sock, argc - optind, argv + optind ); - - return 0; -} - -int mode_help( int argc, char *argv[] ) -{ - char *cmd; - char *help_text = NULL; - - if ( argc < 1 ){ - help_text = help_help_text; + if (write_not_read) { + if (s_length_or_filename[0] - 48 < 10) { + out->len = atol(s_length_or_filename); + out->data_fd = 0; } else { - cmd = argv[0]; - if (IS_CMD( CMD_SERVE, cmd ) ) { - help_text = serve_help_text; - } else if ( IS_CMD( CMD_LISTEN, cmd ) ) { - help_text = listen_help_text; - } else if ( IS_CMD( CMD_READ, cmd ) ) { - help_text = read_help_text; - } else if ( IS_CMD( CMD_WRITE, cmd ) ) { - help_text = write_help_text; - } else if ( IS_CMD( CMD_ACL, cmd ) ) { - help_text = acl_help_text; - } else if ( IS_CMD( CMD_MIRROR, cmd ) ) { - help_text = mirror_help_text; - } else if ( IS_CMD( CMD_STATUS, cmd ) ) { - help_text = status_help_text; - } else { exit_err( help_help_text ); } + out->data_fd = open(s_length_or_filename, O_RDONLY); + FATAL_IF_NEGATIVE(out->data_fd, + "Couldn't open %s", s_length_or_filename); + off64_t signed_len = lseek64(out->data_fd, 0, SEEK_END); + FATAL_IF_NEGATIVE(signed_len, + "Couldn't find length of %s", + s_length_or_filename); + out->len = signed_len; + FATAL_IF_NEGATIVE(lseek64(out->data_fd, 0, SEEK_SET), + "Couldn't rewind %s", s_length_or_filename); } - - fprintf( stdout, "%s\n", help_text ); - return 0; + } else { + out->len = atol(s_length_or_filename); + out->data_fd = 1; + } } -void mode(char* mode, int argc, char **argv) +int mode_read(int argc, char *argv[]) { - if ( IS_CMD( CMD_SERVE, mode ) ) { - exit( mode_serve( argc, argv ) ); + int c; + char *ip_addr = NULL; + char *ip_port = NULL; + char *bind_addr = NULL; + char *from = NULL; + char *size = NULL; + int err = 0; + + struct mode_readwrite_params readwrite; + + while (1) { + c = getopt_long(argc, argv, read_short_options, read_options, + NULL); + + if (c == -1) { + break; } - else if ( IS_CMD( CMD_LISTEN, mode ) ) { - exit( mode_listen( argc, argv ) ); - } - else if ( IS_CMD( CMD_READ, mode ) ) { - mode_read( argc, argv ); - } - else if ( IS_CMD( CMD_WRITE, mode ) ) { - mode_write( argc, argv ); - } - else if ( IS_CMD( CMD_ACL, mode ) ) { - mode_acl( argc, argv ); - } else if ( IS_CMD ( CMD_MIRROR_SPEED, mode ) ) { - mode_mirror_speed( argc, argv ); - } - else if ( IS_CMD( CMD_MIRROR, mode ) ) { - mode_mirror( argc, argv ); - } - else if ( IS_CMD( CMD_BREAK, mode ) ) { - mode_break( argc, argv ); - } - else if ( IS_CMD( CMD_STATUS, mode ) ) { - mode_status( argc, argv ); - } - else if ( IS_CMD( CMD_HELP, mode ) ) { - mode_help( argc-1, argv+1 ); - } - else { - mode_help( argc-1, argv+1 ); - exit( 1 ); - } - exit(0); + + read_readwrite_param(c, &ip_addr, &ip_port, &bind_addr, &from, + &size, read_help_text); + } + + if (NULL == ip_addr || NULL == ip_port) { + err = 1; + fprintf(stderr, "both --addr and --port are required.\n"); + } + if (NULL == from || NULL == size) { + err = 1; + fprintf(stderr, "both --from and --size are required.\n"); + } + if (err) { + exit_err(read_help_text); + } + + memset(&readwrite, 0, sizeof(readwrite)); + params_readwrite(0, &readwrite, ip_addr, ip_port, bind_addr, from, + size); + do_read(&readwrite); + return 0; } +int mode_write(int argc, char *argv[]) +{ + int c; + char *ip_addr = NULL; + char *ip_port = NULL; + char *bind_addr = NULL; + char *from = NULL; + char *size = NULL; + int err = 0; + + struct mode_readwrite_params readwrite; + + while (1) { + c = getopt_long(argc, argv, write_short_options, write_options, + NULL); + if (c == -1) { + break; + } + + read_readwrite_param(c, &ip_addr, &ip_port, &bind_addr, &from, + &size, write_help_text); + } + + if (NULL == ip_addr || NULL == ip_port) { + err = 1; + fprintf(stderr, "both --addr and --port are required.\n"); + } + if (NULL == from || NULL == size) { + err = 1; + fprintf(stderr, "both --from and --size are required.\n"); + } + if (err) { + exit_err(write_help_text); + } + + memset(&readwrite, 0, sizeof(readwrite)); + params_readwrite(1, &readwrite, ip_addr, ip_port, bind_addr, from, + size); + do_write(&readwrite); + return 0; +} + +int mode_acl(int argc, char *argv[]) +{ + int c; + char *sock = NULL; + + while (1) { + c = getopt_long(argc, argv, acl_short_options, acl_options, NULL); + if (c == -1) { + break; + } + read_acl_param(c, &sock); + } + + if (NULL == sock) { + fprintf(stderr, "--sock is required.\n"); + exit_err(acl_help_text); + } + + /* Don't use the CMD_ACL macro here, "acl" is the remote command + * name, not the cli option + */ + do_remote_command("acl", sock, argc - optind, argv + optind); + + return 0; +} + + +int mode_mirror_speed(int argc, char *argv[]) +{ + int c; + char *sock = NULL; + char *speed = NULL; + + while (1) { + c = getopt_long(argc, argv, mirror_speed_short_options, + mirror_speed_options, NULL); + if (-1 == c) { + break; + } + read_mirror_speed_param(c, &sock, &speed); + } + + if (NULL == sock) { + fprintf(stderr, "--sock is required.\n"); + exit_err(mirror_speed_help_text); + } + + if (NULL == speed) { + fprintf(stderr, "--max-speed is required.\n"); + exit_err(mirror_speed_help_text); + } + + do_remote_command("mirror_max_bps", sock, 1, &speed); + return 0; +} + + +int mode_mirror(int argc, char *argv[]) +{ + int c; + char *sock = NULL; + char *remote_argv[4] = { 0 }; + int err = 0; + int unlink = 0; + + remote_argv[2] = "exit"; + + while (1) { + c = getopt_long(argc, argv, mirror_short_options, mirror_options, + NULL); + if (-1 == c) { + break; + } + read_mirror_param(c, + &sock, + &remote_argv[0], + &remote_argv[1], &unlink, &remote_argv[3]); + } + + if (NULL == sock) { + fprintf(stderr, "--sock is required.\n"); + err = 1; + } + if (NULL == remote_argv[0] || NULL == remote_argv[1]) { + fprintf(stderr, "both --addr and --port are required.\n"); + err = 1; + } + if (err) { + exit_err(mirror_help_text); + } + if (unlink) { + remote_argv[2] = "unlink"; + } + + if (remote_argv[3] == NULL) { + do_remote_command("mirror", sock, 3, remote_argv); + } else { + do_remote_command("mirror", sock, 4, remote_argv); + } + + return 0; +} + + +int mode_break(int argc, char *argv[]) +{ + int c; + char *sock = NULL; + + while (1) { + c = getopt_long(argc, argv, break_short_options, break_options, + NULL); + if (-1 == c) { + break; + } + read_break_param(c, &sock); + } + + if (NULL == sock) { + fprintf(stderr, "--sock is required.\n"); + exit_err(break_help_text); + } + + do_remote_command("break", sock, argc - optind, argv + optind); + + return 0; +} + +int mode_status(int argc, char *argv[]) +{ + int c; + char *sock = NULL; + + while (1) { + c = getopt_long(argc, argv, status_short_options, status_options, + NULL); + if (-1 == c) { + break; + } + read_status_param(c, &sock); + } + + if (NULL == sock) { + fprintf(stderr, "--sock is required.\n"); + exit_err(status_help_text); + } + + do_remote_command("status", sock, argc - optind, argv + optind); + + return 0; +} + +int mode_help(int argc, char *argv[]) +{ + char *cmd; + char *help_text = NULL; + + if (argc < 1) { + help_text = help_help_text; + } else { + cmd = argv[0]; + if (IS_CMD(CMD_SERVE, cmd)) { + help_text = serve_help_text; + } else if (IS_CMD(CMD_LISTEN, cmd)) { + help_text = listen_help_text; + } else if (IS_CMD(CMD_READ, cmd)) { + help_text = read_help_text; + } else if (IS_CMD(CMD_WRITE, cmd)) { + help_text = write_help_text; + } else if (IS_CMD(CMD_ACL, cmd)) { + help_text = acl_help_text; + } else if (IS_CMD(CMD_MIRROR, cmd)) { + help_text = mirror_help_text; + } else if (IS_CMD(CMD_STATUS, cmd)) { + help_text = status_help_text; + } else { + exit_err(help_help_text); + } + } + + fprintf(stdout, "%s\n", help_text); + return 0; +} + + +void mode(char *mode, int argc, char **argv) +{ + if (IS_CMD(CMD_SERVE, mode)) { + exit(mode_serve(argc, argv)); + } else if (IS_CMD(CMD_LISTEN, mode)) { + exit(mode_listen(argc, argv)); + } else if (IS_CMD(CMD_READ, mode)) { + mode_read(argc, argv); + } else if (IS_CMD(CMD_WRITE, mode)) { + mode_write(argc, argv); + } else if (IS_CMD(CMD_ACL, mode)) { + mode_acl(argc, argv); + } else if (IS_CMD(CMD_MIRROR_SPEED, mode)) { + mode_mirror_speed(argc, argv); + } else if (IS_CMD(CMD_MIRROR, mode)) { + mode_mirror(argc, argv); + } else if (IS_CMD(CMD_BREAK, mode)) { + mode_break(argc, argv); + } else if (IS_CMD(CMD_STATUS, mode)) { + mode_status(argc, argv); + } else if (IS_CMD(CMD_HELP, mode)) { + mode_help(argc - 1, argv + 1); + } else { + mode_help(argc - 1, argv + 1); + exit(1); + } + exit(0); +} diff --git a/src/server/serve.c b/src/server/serve.c index b7b8e44..e5cc588 100644 --- a/src/server/serve.c +++ b/src/server/serve.c @@ -21,97 +21,93 @@ #include #include -struct server * server_create ( - struct flexnbd * flexnbd, - char* s_ip_address, - char* s_port, - char* s_file, - int default_deny, - int acl_entries, - char** s_acl_entries, - int max_nbd_clients, - int use_killswitch, - int success) +struct server *server_create(struct flexnbd *flexnbd, + char *s_ip_address, + char *s_port, + char *s_file, + int default_deny, + int acl_entries, + char **s_acl_entries, + int max_nbd_clients, + int use_killswitch, int success) { - NULLCHECK( flexnbd ); - struct server * out; - out = xmalloc( sizeof( struct server ) ); - out->flexnbd = flexnbd; - out->success = success; - out->max_nbd_clients = max_nbd_clients; - out->use_killswitch = use_killswitch; + NULLCHECK(flexnbd); + struct server *out; + out = xmalloc(sizeof(struct server)); + out->flexnbd = flexnbd; + out->success = success; + out->max_nbd_clients = max_nbd_clients; + out->use_killswitch = use_killswitch; - server_allow_new_clients( out ); + server_allow_new_clients(out); - out->nbd_client = xmalloc( max_nbd_clients * sizeof( struct client_tbl_entry ) ); - out->tcp_backlog = 10; /* does this need to be settable? */ + out->nbd_client = + xmalloc(max_nbd_clients * sizeof(struct client_tbl_entry)); + out->tcp_backlog = 10; /* does this need to be settable? */ - FATAL_IF_NULL(s_ip_address, "No IP address supplied"); - FATAL_IF_NULL(s_port, "No port number supplied"); - FATAL_IF_NULL(s_file, "No filename supplied"); - NULLCHECK( s_ip_address ); - FATAL_IF_ZERO( - parse_ip_to_sockaddr(&out->bind_to.generic, s_ip_address), - "Couldn't parse server address '%s' (use 0 if " - "you want to bind to all IPs)", - s_ip_address - ); + FATAL_IF_NULL(s_ip_address, "No IP address supplied"); + FATAL_IF_NULL(s_port, "No port number supplied"); + FATAL_IF_NULL(s_file, "No filename supplied"); + NULLCHECK(s_ip_address); + FATAL_IF_ZERO(parse_ip_to_sockaddr + (&out->bind_to.generic, s_ip_address), + "Couldn't parse server address '%s' (use 0 if " + "you want to bind to all IPs)", s_ip_address); - out->acl = acl_create( acl_entries, s_acl_entries, default_deny ); - if (out->acl && out->acl->len != acl_entries) { - fatal("Bad ACL entry '%s'", s_acl_entries[out->acl->len]); - } + out->acl = acl_create(acl_entries, s_acl_entries, default_deny); + if (out->acl && out->acl->len != acl_entries) { + fatal("Bad ACL entry '%s'", s_acl_entries[out->acl->len]); + } - parse_port( s_port, &out->bind_to.v4 ); + parse_port(s_port, &out->bind_to.v4); - out->filename = s_file; + out->filename = s_file; - out->l_acl = flexthread_mutex_create(); - out->l_start_mirror = flexthread_mutex_create(); + out->l_acl = flexthread_mutex_create(); + out->l_start_mirror = flexthread_mutex_create(); - out->mirror_can_start = 1; + out->mirror_can_start = 1; - out->close_signal = self_pipe_create(); - out->acl_updated_signal = self_pipe_create(); + out->close_signal = self_pipe_create(); + out->acl_updated_signal = self_pipe_create(); - NULLCHECK( out->close_signal ); - NULLCHECK( out->acl_updated_signal ); + NULLCHECK(out->close_signal); + NULLCHECK(out->acl_updated_signal); - log_context = s_file; + log_context = s_file; - return out; + return out; } -void server_destroy( struct server * serve ) +void server_destroy(struct server *serve) { - self_pipe_destroy( serve->acl_updated_signal ); - serve->acl_updated_signal = NULL; - self_pipe_destroy( serve->close_signal ); - serve->close_signal = NULL; + self_pipe_destroy(serve->acl_updated_signal); + serve->acl_updated_signal = NULL; + self_pipe_destroy(serve->close_signal); + serve->close_signal = NULL; - flexthread_mutex_destroy( serve->l_start_mirror ); - flexthread_mutex_destroy( serve->l_acl ); + flexthread_mutex_destroy(serve->l_start_mirror); + flexthread_mutex_destroy(serve->l_acl); - if ( serve->acl ) { - acl_destroy( serve->acl ); - serve->acl = NULL; - } + if (serve->acl) { + acl_destroy(serve->acl); + serve->acl = NULL; + } - free( serve->nbd_client ); - free( serve ); + free(serve->nbd_client); + free(serve); } -void server_unlink( struct server * serve ) +void server_unlink(struct server *serve) { - NULLCHECK( serve ); - NULLCHECK( serve->filename ); + NULLCHECK(serve); + NULLCHECK(serve->filename); - FATAL_IF_NEGATIVE( unlink( serve->filename ), - "Failed to unlink %s: %s", - serve->filename, - strerror( errno ) ); + FATAL_IF_NEGATIVE(unlink(serve->filename), + "Failed to unlink %s: %s", + serve->filename, strerror(errno)); } @@ -122,150 +118,149 @@ void server_unlink( struct server * serve ) do { NULLCHECK( s ); \ FATAL_IF( 0 != flexthread_mutex_unlock( s->f ), msg ); } while (0) -void server_lock_acl( struct server *serve ) +void server_lock_acl(struct server *serve) { - debug("ACL locking"); + debug("ACL locking"); - SERVER_LOCK( serve, l_acl, "Problem with ACL lock" ); + SERVER_LOCK(serve, l_acl, "Problem with ACL lock"); } -void server_unlock_acl( struct server *serve ) +void server_unlock_acl(struct server *serve) { - debug( "ACL unlocking" ); + debug("ACL unlocking"); - SERVER_UNLOCK( serve, l_acl, "Problem with ACL unlock" ); + SERVER_UNLOCK(serve, l_acl, "Problem with ACL unlock"); } -int server_acl_locked( struct server * serve ) +int server_acl_locked(struct server *serve) { - NULLCHECK( serve ); - return flexthread_mutex_held( serve->l_acl ); + NULLCHECK(serve); + return flexthread_mutex_held(serve->l_acl); } -void server_lock_start_mirror( struct server *serve ) +void server_lock_start_mirror(struct server *serve) { - debug("Mirror start locking"); + debug("Mirror start locking"); - SERVER_LOCK( serve, l_start_mirror, "Problem with start mirror lock" ); + SERVER_LOCK(serve, l_start_mirror, "Problem with start mirror lock"); } -void server_unlock_start_mirror( struct server *serve ) +void server_unlock_start_mirror(struct server *serve) { - debug("Mirror start unlocking"); + debug("Mirror start unlocking"); - SERVER_UNLOCK( serve, l_start_mirror, "Problem with start mirror unlock" ); + SERVER_UNLOCK(serve, l_start_mirror, + "Problem with start mirror unlock"); } -int server_start_mirror_locked( struct server * serve ) +int server_start_mirror_locked(struct server *serve) { - NULLCHECK( serve ); - return flexthread_mutex_held( serve->l_start_mirror ); + NULLCHECK(serve); + return flexthread_mutex_held(serve->l_start_mirror); } /** Return the actual port the server bound to. This is used because we * are allowed to pass "0" on the command-line. */ -int server_port( struct server * server ) +int server_port(struct server *server) { - NULLCHECK( server ); - union mysockaddr addr; - socklen_t len = sizeof( addr.v4 ); + NULLCHECK(server); + union mysockaddr addr; + socklen_t len = sizeof(addr.v4); - if ( getsockname( server->server_fd, &addr.v4, &len ) < 0 ) { - fatal( "Failed to get the port number." ); - } + if (getsockname(server->server_fd, &addr.v4, &len) < 0) { + fatal("Failed to get the port number."); + } - return be16toh( addr.v4.sin_port ); + return be16toh(addr.v4.sin_port); } /** Prepares a listening socket for the NBD server, binding etc. */ -void serve_open_server_socket(struct server* params) +void serve_open_server_socket(struct server *params) { - NULLCHECK( params ); + NULLCHECK(params); - params->server_fd = socket(params->bind_to.generic.sa_family == AF_INET ? - PF_INET : PF_INET6, SOCK_STREAM, 0); + params->server_fd = + socket(params->bind_to.generic.sa_family == + AF_INET ? PF_INET : PF_INET6, SOCK_STREAM, 0); - FATAL_IF_NEGATIVE( params->server_fd, "Couldn't create server socket" ); + FATAL_IF_NEGATIVE(params->server_fd, "Couldn't create server socket"); - /* We need SO_REUSEADDR so that when we switch from listening to - * serving we don't have to change address if we don't want to. - * - * If this fails, it's not necessarily bad in principle, but at - * this point in the code we can't tell if it's going to be a - * problem. It's also indicative of something odd going on, so - * we barf. - */ - FATAL_IF_NEGATIVE( - sock_set_reuseaddr( params->server_fd, 1 ), "Couldn't set SO_REUSEADDR" + /* We need SO_REUSEADDR so that when we switch from listening to + * serving we don't have to change address if we don't want to. + * + * If this fails, it's not necessarily bad in principle, but at + * this point in the code we can't tell if it's going to be a + * problem. It's also indicative of something odd going on, so + * we barf. + */ + FATAL_IF_NEGATIVE(sock_set_reuseaddr(params->server_fd, 1), + "Couldn't set SO_REUSEADDR"); + + /* TCP_NODELAY makes everything not be slow. If we can't set + * this, again, there's something odd going on which we don't + * understand. + */ + FATAL_IF_NEGATIVE(sock_set_tcp_nodelay(params->server_fd, 1), + "Couldn't set TCP_NODELAY"); + + /* If we can't bind, presumably that's because someone else is + * squatting on our ip/port combo, or the ip isn't yet + * configured. Ideally we want to retry this. */ + FATAL_UNLESS_ZERO(sock_try_bind + (params->server_fd, ¶ms->bind_to.generic), + SHOW_ERRNO("Failed to bind() socket") ); - /* TCP_NODELAY makes everything not be slow. If we can't set - * this, again, there's something odd going on which we don't - * understand. - */ - FATAL_IF_NEGATIVE( - sock_set_tcp_nodelay( params->server_fd, 1 ), "Couldn't set TCP_NODELAY" - ); - - /* If we can't bind, presumably that's because someone else is - * squatting on our ip/port combo, or the ip isn't yet - * configured. Ideally we want to retry this. */ - FATAL_UNLESS_ZERO( - sock_try_bind( params->server_fd, ¶ms->bind_to.generic ), - SHOW_ERRNO( "Failed to bind() socket" ) - ); - - FATAL_IF_NEGATIVE( - listen(params->server_fd, params->tcp_backlog), - "Couldn't listen on server socket" - ); + FATAL_IF_NEGATIVE(listen(params->server_fd, params->tcp_backlog), + "Couldn't listen on server socket"); } -int tryjoin_client_thread( struct client_tbl_entry *entry, int (*joinfunc)(pthread_t, void **) ) +int tryjoin_client_thread(struct client_tbl_entry *entry, + int (*joinfunc) (pthread_t, void **)) { - NULLCHECK( entry ); - NULLCHECK( joinfunc ); + NULLCHECK(entry); + NULLCHECK(joinfunc); - int was_closed = 0; - void * status=NULL; + int was_closed = 0; + void *status = NULL; - if (entry->thread != 0) { - char s_client_address[128]; + if (entry->thread != 0) { + char s_client_address[128]; - sockaddr_address_string( &entry->address.generic, &s_client_address[0], 128 ); + sockaddr_address_string(&entry->address.generic, + &s_client_address[0], 128); - debug( "%s(%p,...)", joinfunc == pthread_join ? "joining" : "tryjoining", entry->thread ); - int join_errno = joinfunc(entry->thread, &status); + debug("%s(%p,...)", + joinfunc == pthread_join ? "joining" : "tryjoining", + entry->thread); + int join_errno = joinfunc(entry->thread, &status); - /* join_errno can legitimately be ESRCH if the thread is - * already dead, but the client still needs tidying up. */ - if (join_errno != 0 && !entry->client->stopped ) { - debug( "join_errno was %s, stopped was %d", strerror( join_errno ), entry->client->stopped ); - FATAL_UNLESS( join_errno == EBUSY, - "Problem with joining thread %p: %s", - entry->thread, - strerror(join_errno) ); - } - else if ( join_errno == 0 ) { - debug("nbd thread %016x exited (%s) with status %ld", - entry->thread, - s_client_address, - (uintptr_t)status); - client_destroy( entry->client ); - entry->client = NULL; - entry->thread = 0; - was_closed = 1; - } + /* join_errno can legitimately be ESRCH if the thread is + * already dead, but the client still needs tidying up. */ + if (join_errno != 0 && !entry->client->stopped) { + debug("join_errno was %s, stopped was %d", + strerror(join_errno), entry->client->stopped); + FATAL_UNLESS(join_errno == EBUSY, + "Problem with joining thread %p: %s", + entry->thread, strerror(join_errno)); + } else if (join_errno == 0) { + debug("nbd thread %016x exited (%s) with status %ld", + entry->thread, s_client_address, (uintptr_t) status); + client_destroy(entry->client); + entry->client = NULL; + entry->thread = 0; + was_closed = 1; } + } - return was_closed; + return was_closed; } @@ -282,17 +277,18 @@ int tryjoin_client_thread( struct client_tbl_entry *entry, int (*joinfunc)(pthre * including their signal pipes, won't be cleaned up until the next new * client connection attempt. */ -int cleanup_client_thread( struct client_tbl_entry * entry ) +int cleanup_client_thread(struct client_tbl_entry *entry) { - return tryjoin_client_thread( entry, pthread_tryjoin_np ); + return tryjoin_client_thread(entry, pthread_tryjoin_np); } -void cleanup_client_threads( struct client_tbl_entry * entries, size_t entries_len ) +void cleanup_client_threads(struct client_tbl_entry *entries, + size_t entries_len) { - size_t i; - for( i = 0; i < entries_len; i++ ) { - cleanup_client_thread( &entries[i] ); - } + size_t i; + for (i = 0; i < entries_len; i++) { + cleanup_client_thread(&entries[i]); + } } @@ -301,47 +297,47 @@ void cleanup_client_threads( struct client_tbl_entry * entries, size_t entries_l * This function will not return until pthread_join has returned, so * ensures that the client thread is dead. */ -int join_client_thread( struct client_tbl_entry *entry ) +int join_client_thread(struct client_tbl_entry *entry) { - return tryjoin_client_thread( entry, pthread_join ); + return tryjoin_client_thread(entry, pthread_join); } /** We can only accommodate MAX_NBD_CLIENTS connections at once. This function * goes through the current list, waits for any threads that have finished * and returns the next slot free (or -1 if there are none). */ -int cleanup_and_find_client_slot(struct server* params) +int cleanup_and_find_client_slot(struct server *params) { - NULLCHECK( params ); + NULLCHECK(params); - int slot=-1, i; + int slot = -1, i; - cleanup_client_threads( params->nbd_client, params->max_nbd_clients ); + cleanup_client_threads(params->nbd_client, params->max_nbd_clients); - for ( i = 0; i < params->max_nbd_clients; i++ ) { - if( params->nbd_client[i].thread == 0 && slot == -1 ){ - slot = i; - break; - } + for (i = 0; i < params->max_nbd_clients; i++) { + if (params->nbd_client[i].thread == 0 && slot == -1) { + slot = i; + break; } + } - return slot; + return slot; } -int server_count_clients( struct server *params ) +int server_count_clients(struct server *params) { - NULLCHECK( params ); - int i, count = 0; - - cleanup_client_threads( params->nbd_client, params->max_nbd_clients ); + NULLCHECK(params); + int i, count = 0; - for ( i = 0 ; i < params->max_nbd_clients ; i++ ) { - if ( params->nbd_client[i].thread != 0 ) { - count++; - } + cleanup_client_threads(params->nbd_client, params->max_nbd_clients); + + for (i = 0; i < params->max_nbd_clients; i++) { + if (params->nbd_client[i].thread != 0) { + count++; } + } - return count; + return count; } @@ -349,64 +345,65 @@ int server_count_clients( struct server *params ) * to the current acl. If params->acl is NULL, the result will be 1, * otherwise it will be the result of acl_includes(). */ -int server_acl_accepts( struct server *params, union mysockaddr * client_address ) +int server_acl_accepts(struct server *params, + union mysockaddr *client_address) { - NULLCHECK( params ); - NULLCHECK( client_address ); + NULLCHECK(params); + NULLCHECK(client_address); - struct acl * acl; - int accepted; + struct acl *acl; + int accepted; - server_lock_acl( params ); - { - acl = params->acl; - accepted = acl ? acl_includes( acl, client_address ) : 1; - } - server_unlock_acl( params ); + server_lock_acl(params); + { + acl = params->acl; + accepted = acl ? acl_includes(acl, client_address) : 1; + } + server_unlock_acl(params); - return accepted; + return accepted; } -int server_should_accept_client( - struct server * params, - union mysockaddr * client_address, - char *s_client_address, - size_t s_client_address_len ) +int server_should_accept_client(struct server *params, + union mysockaddr *client_address, + char *s_client_address, + size_t s_client_address_len) { - NULLCHECK( params ); - NULLCHECK( client_address ); - NULLCHECK( s_client_address ); + NULLCHECK(params); + NULLCHECK(client_address); + NULLCHECK(s_client_address); - const char* result = sockaddr_address_string( - &client_address->generic, s_client_address, s_client_address_len - ); + const char *result = + sockaddr_address_string(&client_address->generic, s_client_address, + s_client_address_len); - if ( NULL == result ) { - warn( "Rejecting client %s: Bad client_address", s_client_address ); - return 0; - } + if (NULL == result) { + warn("Rejecting client %s: Bad client_address", s_client_address); + return 0; + } - if ( !server_acl_accepts( params, client_address ) ) { - warn( "Rejecting client %s: Access control error", s_client_address ); - debug( "We %s have an acl, and default_deny is %s", - (params->acl ? "do" : "do not"), - (params->acl->default_deny ? "true" : "false") ); - return 0; - } + if (!server_acl_accepts(params, client_address)) { + warn("Rejecting client %s: Access control error", + s_client_address); + debug("We %s have an acl, and default_deny is %s", + (params->acl ? "do" : "do not"), + (params->acl->default_deny ? "true" : "false")); + return 0; + } - return 1; + return 1; } -int spawn_client_thread( - struct client * client_params, - pthread_t *out_thread) +int spawn_client_thread(struct client *client_params, + pthread_t * out_thread) { - int result = pthread_create(out_thread, NULL, client_serve, client_params); + int result = + pthread_create(out_thread, NULL, client_serve, client_params); - return result; + return result; } @@ -414,167 +411,176 @@ int spawn_client_thread( * to handle it. Rejects the connection if there is an ACL, and the far end's * address doesn't match, or if there are too many clients already connected. */ -void accept_nbd_client( - struct server* params, - int client_fd, - union mysockaddr* client_address) +void accept_nbd_client(struct server *params, + int client_fd, union mysockaddr *client_address) { - NULLCHECK(params); - NULLCHECK(client_address); + NULLCHECK(params); + NULLCHECK(client_address); - struct client* client_params; - int slot; - char s_client_address[64] = {0}; + struct client *client_params; + int slot; + char s_client_address[64] = { 0 }; - FATAL_IF_NEGATIVE( sock_set_keepalive_params( client_fd, CLIENT_KEEPALIVE_TIME, CLIENT_KEEPALIVE_INTVL, CLIENT_KEEPALIVE_PROBES), - "Error setting keepalive parameters on client socket fd %d", client_fd ); + FATAL_IF_NEGATIVE(sock_set_keepalive_params + (client_fd, CLIENT_KEEPALIVE_TIME, + CLIENT_KEEPALIVE_INTVL, CLIENT_KEEPALIVE_PROBES), + "Error setting keepalive parameters on client socket fd %d", + client_fd); - if ( !server_should_accept_client( params, client_address, s_client_address, 64 ) ) { - FATAL_IF_NEGATIVE( close( client_fd ), - "Error closing client socket fd %d", client_fd ); - debug("Closed client socket fd %d", client_fd); - return; - } + if (!server_should_accept_client + (params, client_address, s_client_address, 64)) { + FATAL_IF_NEGATIVE(close(client_fd), + "Error closing client socket fd %d", client_fd); + debug("Closed client socket fd %d", client_fd); + return; + } - slot = cleanup_and_find_client_slot(params); - if (slot < 0) { - warn("too many clients to accept connection"); - FATAL_IF_NEGATIVE( close( client_fd ), - "Error closing client socket fd %d", client_fd ); - debug("Closed client socket fd %d", client_fd); - return; - } + slot = cleanup_and_find_client_slot(params); + if (slot < 0) { + warn("too many clients to accept connection"); + FATAL_IF_NEGATIVE(close(client_fd), + "Error closing client socket fd %d", client_fd); + debug("Closed client socket fd %d", client_fd); + return; + } - info( "Client %s accepted on fd %d.", s_client_address, client_fd ); - client_params = client_create( params, client_fd ); + info("Client %s accepted on fd %d.", s_client_address, client_fd); + client_params = client_create(params, client_fd); - params->nbd_client[slot].client = client_params; - memcpy(¶ms->nbd_client[slot].address, client_address, - sizeof(union mysockaddr)); + params->nbd_client[slot].client = client_params; + memcpy(¶ms->nbd_client[slot].address, client_address, + sizeof(union mysockaddr)); - pthread_t * thread = ¶ms->nbd_client[slot].thread; + pthread_t *thread = ¶ms->nbd_client[slot].thread; - if ( 0 != spawn_client_thread( client_params, thread ) ) { - debug( "Thread creation problem." ); - client_destroy( client_params ); - FATAL_IF_NEGATIVE( close(client_fd), - "Error closing client socket fd %d", client_fd ); - debug("Closed client socket fd %d", client_fd); - return; - } + if (0 != spawn_client_thread(client_params, thread)) { + debug("Thread creation problem."); + client_destroy(client_params); + FATAL_IF_NEGATIVE(close(client_fd), + "Error closing client socket fd %d", client_fd); + debug("Closed client socket fd %d", client_fd); + return; + } - debug("nbd thread %p started (%s)", params->nbd_client[slot].thread, s_client_address); + debug("nbd thread %p started (%s)", params->nbd_client[slot].thread, + s_client_address); } -void server_audit_clients( struct server * serve) +void server_audit_clients(struct server *serve) { - NULLCHECK( serve ); + NULLCHECK(serve); - int i; - struct client_tbl_entry * entry; + int i; + struct client_tbl_entry *entry; - /* There's an apparent race here. If the acl updates while - * we're traversing the nbd_clients array, the earlier entries - * won't have been audited against the later acl. This isn't a - * problem though, because in order to update the acl - * server_replace_acl must have been called, so the - * server_accept loop will see a second acl_updated signal as - * soon as it hits select, and a second audit will be run. - */ - for( i = 0; i < serve->max_nbd_clients; i++ ) { - entry = &serve->nbd_client[i]; - if ( 0 == entry->thread ) { continue; } - if ( server_acl_accepts( serve, &entry->address ) ) { continue; } - client_signal_stop( entry->client ); + /* There's an apparent race here. If the acl updates while + * we're traversing the nbd_clients array, the earlier entries + * won't have been audited against the later acl. This isn't a + * problem though, because in order to update the acl + * server_replace_acl must have been called, so the + * server_accept loop will see a second acl_updated signal as + * soon as it hits select, and a second audit will be run. + */ + for (i = 0; i < serve->max_nbd_clients; i++) { + entry = &serve->nbd_client[i]; + if (0 == entry->thread) { + continue; } + if (server_acl_accepts(serve, &entry->address)) { + continue; + } + client_signal_stop(entry->client); + } } -int server_is_closed(struct server* serve) +int server_is_closed(struct server *serve) { - NULLCHECK( serve ); - return fd_is_closed( serve->server_fd ); + NULLCHECK(serve); + return fd_is_closed(serve->server_fd); } -void server_close_clients( struct server *params ) +void server_close_clients(struct server *params) { - NULLCHECK(params); + NULLCHECK(params); - info("closing all clients"); + info("closing all clients"); - int i; /* , j; */ - struct client_tbl_entry *entry; + int i; /* , j; */ + struct client_tbl_entry *entry; - for( i = 0; i < params->max_nbd_clients; i++ ) { - entry = ¶ms->nbd_client[i]; + for (i = 0; i < params->max_nbd_clients; i++) { + entry = ¶ms->nbd_client[i]; - if ( entry->thread != 0 ) { - debug( "Stop signaling client %p", entry->client ); - client_signal_stop( entry->client ); - } + if (entry->thread != 0) { + debug("Stop signaling client %p", entry->client); + client_signal_stop(entry->client); } - /* We don't join the clients here. When we enter the final - * mirror pass, we get the IO lock, then wait for the server_fd - * to close before sending the data, to be sure that no new - * clients can be accepted which might think they've written - * to the disc. However, an existing client thread can be - * waiting for the IO lock already, so if we try to join it - * here, we deadlock. - * - * The client threads will be joined in serve_cleanup. - * - */ + } + /* We don't join the clients here. When we enter the final + * mirror pass, we get the IO lock, then wait for the server_fd + * to close before sending the data, to be sure that no new + * clients can be accepted which might think they've written + * to the disc. However, an existing client thread can be + * waiting for the IO lock already, so if we try to join it + * here, we deadlock. + * + * The client threads will be joined in serve_cleanup. + * + */ } /** Replace the current acl with a new one. The old one will be thrown * away. */ -void server_replace_acl( struct server *serve, struct acl * new_acl ) +void server_replace_acl(struct server *serve, struct acl *new_acl) { - NULLCHECK(serve); - NULLCHECK(new_acl); + NULLCHECK(serve); + NULLCHECK(new_acl); - /* We need to lock around updates to the acl in case we try to - * destroy the old acl while checking against it. - */ - server_lock_acl( serve ); - { - struct acl * old_acl = serve->acl; - serve->acl = new_acl; - /* We should always have an old_acl, but just in case... */ - if ( old_acl ) { acl_destroy( old_acl ); } + /* We need to lock around updates to the acl in case we try to + * destroy the old acl while checking against it. + */ + server_lock_acl(serve); + { + struct acl *old_acl = serve->acl; + serve->acl = new_acl; + /* We should always have an old_acl, but just in case... */ + if (old_acl) { + acl_destroy(old_acl); } - server_unlock_acl( serve ); + } + server_unlock_acl(serve); - self_pipe_signal( serve->acl_updated_signal ); + self_pipe_signal(serve->acl_updated_signal); } -void server_prevent_mirror_start( struct server *serve ) +void server_prevent_mirror_start(struct server *serve) { - NULLCHECK( serve ); + NULLCHECK(serve); - serve->mirror_can_start = 0; + serve->mirror_can_start = 0; } -void server_allow_mirror_start( struct server *serve ) +void server_allow_mirror_start(struct server *serve) { - NULLCHECK( serve ); + NULLCHECK(serve); - serve->mirror_can_start = 1; + serve->mirror_can_start = 1; } /* Only call this with the mirror start lock held */ -int server_mirror_can_start( struct server *serve ) +int server_mirror_can_start(struct server *serve) { - NULLCHECK( serve ); + NULLCHECK(serve); - return serve->mirror_can_start; + return serve->mirror_can_start; } @@ -582,306 +588,318 @@ int server_mirror_can_start( struct server *serve ) * to communicate that via the process exit status. because otherwise * the supervisor will assume the migration completed. */ -int serve_shutdown_is_graceful( struct server *params ) +int serve_shutdown_is_graceful(struct server *params) { - int is_mirroring = 0; - server_lock_start_mirror( params ); - { - if ( server_is_mirroring( params ) ) { - is_mirroring = 1; - warn( "Stop signal received while mirroring." ); - server_prevent_mirror_start( params ); - } + int is_mirroring = 0; + server_lock_start_mirror(params); + { + if (server_is_mirroring(params)) { + is_mirroring = 1; + warn("Stop signal received while mirroring."); + server_prevent_mirror_start(params); } - server_unlock_start_mirror( params ); + } + server_unlock_start_mirror(params); - return !is_mirroring; + return !is_mirroring; } /** Accept either an NBD or control socket connection, dispatch appropriately */ -int server_accept( struct server * params ) +int server_accept(struct server *params) { - NULLCHECK( params ); - debug("accept loop starting"); - union mysockaddr client_address; - fd_set fds; - socklen_t socklen=sizeof(client_address); - /* We select on this fd to receive OS signals (only a few of - * which we're interested in, see flexnbd.c */ - int signal_fd = flexnbd_signal_fd( params->flexnbd ); - int should_continue = 1; + NULLCHECK(params); + debug("accept loop starting"); + union mysockaddr client_address; + fd_set fds; + socklen_t socklen = sizeof(client_address); + /* We select on this fd to receive OS signals (only a few of + * which we're interested in, see flexnbd.c */ + int signal_fd = flexnbd_signal_fd(params->flexnbd); + int should_continue = 1; - FD_ZERO(&fds); - FD_SET(params->server_fd, &fds); - if( 0 < signal_fd ) { FD_SET(signal_fd, &fds); } - self_pipe_fd_set( params->close_signal, &fds ); - self_pipe_fd_set( params->acl_updated_signal, &fds ); + FD_ZERO(&fds); + FD_SET(params->server_fd, &fds); + if (0 < signal_fd) { + FD_SET(signal_fd, &fds); + } + self_pipe_fd_set(params->close_signal, &fds); + self_pipe_fd_set(params->acl_updated_signal, &fds); - FATAL_IF_NEGATIVE( - sock_try_select(FD_SETSIZE, &fds, NULL, NULL, NULL), - SHOW_ERRNO( "select() failed" ) + FATAL_IF_NEGATIVE(sock_try_select(FD_SETSIZE, &fds, NULL, NULL, NULL), + SHOW_ERRNO("select() failed") ); - if ( self_pipe_fd_isset( params->close_signal, &fds ) ){ - server_close_clients( params ); - should_continue = 0; + if (self_pipe_fd_isset(params->close_signal, &fds)) { + server_close_clients(params); + should_continue = 0; + } + + + if (0 < signal_fd && FD_ISSET(signal_fd, &fds)) { + debug("Stop signal received."); + server_close_clients(params); + params->success = params->success + && serve_shutdown_is_graceful(params); + should_continue = 0; + } + + + if (self_pipe_fd_isset(params->acl_updated_signal, &fds)) { + self_pipe_signal_clear(params->acl_updated_signal); + server_audit_clients(params); + } + + if (FD_ISSET(params->server_fd, &fds)) { + int client_fd = + accept(params->server_fd, &client_address.generic, &socklen); + + if (params->allow_new_clients) { + debug("Accepted nbd client socket fd %d", client_fd); + accept_nbd_client(params, client_fd, &client_address); + } else { + debug("New NBD client socket %d not allowed", client_fd); + sock_try_close(client_fd); } + } - - if ( 0 < signal_fd && FD_ISSET( signal_fd, &fds ) ){ - debug( "Stop signal received." ); - server_close_clients( params ); - params->success = params->success && serve_shutdown_is_graceful( params ); - should_continue = 0; - } - - - if ( self_pipe_fd_isset( params->acl_updated_signal, &fds ) ) { - self_pipe_signal_clear( params->acl_updated_signal ); - server_audit_clients( params ); - } - - if ( FD_ISSET( params->server_fd, &fds ) ){ - int client_fd = accept( params->server_fd, &client_address.generic, &socklen ); - - if ( params->allow_new_clients ) { - debug("Accepted nbd client socket fd %d", client_fd); - accept_nbd_client(params, client_fd, &client_address); - } else { - debug( "New NBD client socket %d not allowed", client_fd ); - sock_try_close( client_fd ); - } - } - - return should_continue; + return should_continue; } -void serve_accept_loop(struct server* params) +void serve_accept_loop(struct server *params) { - NULLCHECK( params ); - while( server_accept( params ) ); + NULLCHECK(params); + while (server_accept(params)); } -void* build_allocation_map_thread(void* serve_uncast) +void *build_allocation_map_thread(void *serve_uncast) { - NULLCHECK( serve_uncast ); + NULLCHECK(serve_uncast); - struct server* serve = (struct server*) serve_uncast; + struct server *serve = (struct server *) serve_uncast; - NULLCHECK( serve->filename ); - NULLCHECK( serve->allocation_map ); + NULLCHECK(serve->filename); + NULLCHECK(serve->allocation_map); - int fd = open( serve->filename, O_RDONLY ); - FATAL_IF_NEGATIVE( fd, "Couldn't open %s", serve->filename ); + int fd = open(serve->filename, O_RDONLY); + FATAL_IF_NEGATIVE(fd, "Couldn't open %s", serve->filename); - if ( build_allocation_map( serve->allocation_map, fd ) ) { - serve->allocation_map_built = 1; - } - else { - /* We can operate without it, but we can't free it without a race. - * All that happens if we leave it is that it gradually builds up an - * *incomplete* record of writes. Nobody will use it, as - * allocation_map_built == 0 for the lifetime of the process. - * - * The stream functionality can still be relied on. We don't need to - * worry about mirroring waiting for the allocation map to finish, - * because we already copy every byte at least once. If that changes in - * the future, we'll need to wait for the allocation map to finish or - * fail before we can complete the migration. - */ - serve->allocation_map_not_built = 1; - warn( "Didn't build allocation map for %s", serve->filename ); - } + if (build_allocation_map(serve->allocation_map, fd)) { + serve->allocation_map_built = 1; + } else { + /* We can operate without it, but we can't free it without a race. + * All that happens if we leave it is that it gradually builds up an + * *incomplete* record of writes. Nobody will use it, as + * allocation_map_built == 0 for the lifetime of the process. + * + * The stream functionality can still be relied on. We don't need to + * worry about mirroring waiting for the allocation map to finish, + * because we already copy every byte at least once. If that changes in + * the future, we'll need to wait for the allocation map to finish or + * fail before we can complete the migration. + */ + serve->allocation_map_not_built = 1; + warn("Didn't build allocation map for %s", serve->filename); + } - close( fd ); - return NULL; + close(fd); + return NULL; } /** Initialisation function that sets up the initial allocation map, i.e. so * we know which blocks of the file are allocated. */ -void serve_init_allocation_map(struct server* params) +void serve_init_allocation_map(struct server *params) { - NULLCHECK( params ); - NULLCHECK( params->filename ); + NULLCHECK(params); + NULLCHECK(params->filename); - int fd = open( params->filename, O_RDONLY ); - off64_t size; + int fd = open(params->filename, O_RDONLY); + off64_t size; - FATAL_IF_NEGATIVE(fd, "Couldn't open %s", params->filename ); - size = lseek64( fd, 0, SEEK_END ); + FATAL_IF_NEGATIVE(fd, "Couldn't open %s", params->filename); + size = lseek64(fd, 0, SEEK_END); - /* If discs are not in multiples of 512, then odd things happen, - * resulting in reads/writes past the ends of files. - */ - if ( size != (size & ~0x1ff)) { - warn("file does not fit into 512-byte sectors; the end of the file will be ignored."); - size &= ~0x1ff; + /* If discs are not in multiples of 512, then odd things happen, + * resulting in reads/writes past the ends of files. + */ + if (size != (size & ~0x1ff)) { + warn("file does not fit into 512-byte sectors; the end of the file will be ignored."); + size &= ~0x1ff; + } + + params->size = size; + FATAL_IF_NEGATIVE(size, "Couldn't find size of %s", params->filename); + + params->allocation_map = + bitset_alloc(params->size, block_allocation_resolution); + + int ok = pthread_create(¶ms->allocation_map_builder_thread, + NULL, + build_allocation_map_thread, + params); + + FATAL_IF_NEGATIVE(ok, "Couldn't create thread"); +} + + +void server_forbid_new_clients(struct server *serve) +{ + serve->allow_new_clients = 0; + return; +} + +void server_allow_new_clients(struct server *serve) +{ + serve->allow_new_clients = 1; + return; +} + +void server_join_clients(struct server *serve) +{ + int i; + void *status; + + for (i = 0; i < serve->max_nbd_clients; i++) { + pthread_t thread_id = serve->nbd_client[i].thread; + + if (thread_id != 0) { + debug("joining thread %p", thread_id); + int err = pthread_join(thread_id, &status); + if (0 == err) { + serve->nbd_client[i].thread = 0; + } else { + warn("Error %s (%i) joining thread %p", strerror(err), err, + thread_id); + } } + } - params->size = size; - FATAL_IF_NEGATIVE( size, "Couldn't find size of %s", - params->filename ); - - params->allocation_map = - bitset_alloc( params->size, block_allocation_resolution ); - - int ok = pthread_create( ¶ms->allocation_map_builder_thread, - NULL, - build_allocation_map_thread, - params ); - - FATAL_IF_NEGATIVE( ok, "Couldn't create thread" ); -} - - -void server_forbid_new_clients( struct server * serve ) -{ - serve->allow_new_clients = 0; - return; -} - -void server_allow_new_clients( struct server * serve ) -{ - serve->allow_new_clients = 1; - return; -} - -void server_join_clients( struct server * serve ) { - int i; - void* status; - - for (i=0; i < serve->max_nbd_clients; i++) { - pthread_t thread_id = serve->nbd_client[i].thread; - - if (thread_id != 0) { - debug( "joining thread %p", thread_id ); - int err = pthread_join( thread_id, &status ); - if ( 0 == err ) { - serve->nbd_client[i].thread = 0; - } else { - warn( "Error %s (%i) joining thread %p", strerror( err ), err, thread_id ); - } - } - } - - return; + return; } /* Tell the server to close all the things. */ -void serve_signal_close( struct server * serve ) +void serve_signal_close(struct server *serve) { - NULLCHECK( serve ); - info("signalling close"); - self_pipe_signal( serve->close_signal ); + NULLCHECK(serve); + info("signalling close"); + self_pipe_signal(serve->close_signal); } /* Block until the server closes the server_fd. */ -void serve_wait_for_close( struct server * serve ) +void serve_wait_for_close(struct server *serve) { - while( !fd_is_closed( serve->server_fd ) ){ - usleep(10000); - } + while (!fd_is_closed(serve->server_fd)) { + usleep(10000); + } } /* We've just had an DISCONNECT pair, so we need to shut down * and signal our listener that we can safely take over. */ -void server_control_arrived( struct server *serve ) +void server_control_arrived(struct server *serve) { - debug( "server_control_arrived" ); - NULLCHECK( serve ); + debug("server_control_arrived"); + NULLCHECK(serve); - if ( !serve->success ) { - serve->success = 1; - serve_signal_close( serve ); - } + if (!serve->success) { + serve->success = 1; + serve_signal_close(serve); + } } -void flexnbd_stop_control( struct flexnbd * flexnbd ); +void flexnbd_stop_control(struct flexnbd *flexnbd); /** Closes sockets, frees memory and waits for all client threads to finish */ -void serve_cleanup(struct server* params, - int fatal __attribute__ ((unused)) ) +void serve_cleanup(struct server *params, + int fatal __attribute__ ((unused))) { - NULLCHECK( params ); - void* status; + NULLCHECK(params); + void *status; - info("cleaning up"); + info("cleaning up"); - if (params->server_fd){ close(params->server_fd); } + if (params->server_fd) { + close(params->server_fd); + } - /* need to stop background build if we're killed very early on */ - pthread_cancel(params->allocation_map_builder_thread); - pthread_join(params->allocation_map_builder_thread, &status); + /* need to stop background build if we're killed very early on */ + pthread_cancel(params->allocation_map_builder_thread); + pthread_join(params->allocation_map_builder_thread, &status); - int need_mirror_lock; - need_mirror_lock = !server_start_mirror_locked( params ); + int need_mirror_lock; + need_mirror_lock = !server_start_mirror_locked(params); - if ( need_mirror_lock ) { server_lock_start_mirror( params ); } - { - if ( server_is_mirroring( params ) ) { - server_abandon_mirror( params ); - } - server_prevent_mirror_start( params ); + if (need_mirror_lock) { + server_lock_start_mirror(params); + } + { + if (server_is_mirroring(params)) { + server_abandon_mirror(params); } - if ( need_mirror_lock ) { server_unlock_start_mirror( params ); } + server_prevent_mirror_start(params); + } + if (need_mirror_lock) { + server_unlock_start_mirror(params); + } - server_join_clients( params ); + server_join_clients(params); - if (params->allocation_map) { - bitset_free( params->allocation_map ); - } + if (params->allocation_map) { + bitset_free(params->allocation_map); + } - if ( server_start_mirror_locked( params ) ) { - server_unlock_start_mirror( params ); - } + if (server_start_mirror_locked(params)) { + server_unlock_start_mirror(params); + } - if ( server_acl_locked( params ) ) { - server_unlock_acl( params ); - } + if (server_acl_locked(params)) { + server_unlock_acl(params); + } - /* if( params->flexnbd ) { */ - /* if ( params->flexnbd->control ) { */ - /* flexnbd_stop_control( params->flexnbd ); */ - /* } */ - /* flexnbd_destroy( params->flexnbd ); */ - /* } */ + /* if( params->flexnbd ) { */ + /* if ( params->flexnbd->control ) { */ + /* flexnbd_stop_control( params->flexnbd ); */ + /* } */ + /* flexnbd_destroy( params->flexnbd ); */ + /* } */ - /* server_destroy( params ); */ + /* server_destroy( params ); */ - debug( "Cleanup done"); + debug("Cleanup done"); } -int server_is_in_control( struct server *serve ) +int server_is_in_control(struct server *serve) { - NULLCHECK( serve ); - return serve->success; + NULLCHECK(serve); + return serve->success; } -int server_is_mirroring( struct server * serve ) +int server_is_mirroring(struct server *serve) { - NULLCHECK( serve ); - return !!serve->mirror_super; + NULLCHECK(serve); + return ! !serve->mirror_super; } -uint64_t server_mirror_bytes_remaining( struct server * serve ) +uint64_t server_mirror_bytes_remaining(struct server * serve) { - if ( server_is_mirroring( serve ) ) { - uint64_t bytes_to_xfer = - bitset_stream_queued_bytes( serve->allocation_map, BITSET_STREAM_SET ) + - ( serve->size - serve->mirror->offset ); + if (server_is_mirroring(serve)) { + uint64_t bytes_to_xfer = + bitset_stream_queued_bytes(serve->allocation_map, + BITSET_STREAM_SET) + (serve->size - + serve-> + mirror-> + offset); - return bytes_to_xfer; - } + return bytes_to_xfer; + } - return 0; + return 0; } /* Given historic bps measurements and number of bytes left to transfer, give @@ -889,82 +907,82 @@ uint64_t server_mirror_bytes_remaining( struct server * serve ) * complete, assuming no new bytes are written. */ -uint64_t server_mirror_eta( struct server * serve ) +uint64_t server_mirror_eta(struct server * serve) { - if ( server_is_mirroring( serve ) ) { - uint64_t bytes_to_xfer = server_mirror_bytes_remaining( serve ); - return bytes_to_xfer / ( server_mirror_bps( serve ) + 1 ); - } + if (server_is_mirroring(serve)) { + uint64_t bytes_to_xfer = server_mirror_bytes_remaining(serve); + return bytes_to_xfer / (server_mirror_bps(serve) + 1); + } - return 0; + return 0; } -uint64_t server_mirror_bps( struct server * serve ) +uint64_t server_mirror_bps(struct server * serve) { - if ( server_is_mirroring( serve ) ) { - uint64_t duration_ms = - monotonic_time_ms() - serve->mirror->migration_started; + if (server_is_mirroring(serve)) { + uint64_t duration_ms = + monotonic_time_ms() - serve->mirror->migration_started; - return serve->mirror->all_dirty / ( ( duration_ms / 1000 ) + 1 ); - } + return serve->mirror->all_dirty / ((duration_ms / 1000) + 1); + } - return 0; + return 0; } -void mirror_super_destroy( struct mirror_super * super ); +void mirror_super_destroy(struct mirror_super *super); /* This must only be called with the start_mirror lock held */ -void server_abandon_mirror( struct server * serve ) +void server_abandon_mirror(struct server *serve) { - NULLCHECK( serve ); - if ( serve->mirror_super ) { - /* FIXME: AWOOGA! RACE! - * We can set abandon_signal after mirror_super has checked it, but - * before the reset. However, mirror_reset doesn't clear abandon_signal - * so it'll just terminate early on the next pass. */ - ERROR_UNLESS( - self_pipe_signal( serve->mirror->abandon_signal ), - "Failed to signal abandon to mirror" - ); + NULLCHECK(serve); + if (serve->mirror_super) { + /* FIXME: AWOOGA! RACE! + * We can set abandon_signal after mirror_super has checked it, but + * before the reset. However, mirror_reset doesn't clear abandon_signal + * so it'll just terminate early on the next pass. */ + ERROR_UNLESS(self_pipe_signal(serve->mirror->abandon_signal), + "Failed to signal abandon to mirror"); - pthread_t tid = serve->mirror_super->thread; - pthread_join( tid, NULL ); - debug( "Mirror thread %p pthread_join returned", tid ); + pthread_t tid = serve->mirror_super->thread; + pthread_join(tid, NULL); + debug("Mirror thread %p pthread_join returned", tid); - server_allow_mirror_start( serve ); - mirror_super_destroy( serve->mirror_super ); + server_allow_mirror_start(serve); + mirror_super_destroy(serve->mirror_super); - serve->mirror = NULL; - serve->mirror_super = NULL; + serve->mirror = NULL; + serve->mirror_super = NULL; - debug( "Mirror supervisor done." ); - } + debug("Mirror supervisor done."); + } } -int server_default_deny( struct server * serve ) +int server_default_deny(struct server *serve) { - NULLCHECK( serve ); - return acl_default_deny( serve->acl ); + NULLCHECK(serve); + return acl_default_deny(serve->acl); } /** Full lifecycle of the server */ -int do_serve( struct server* params, struct self_pipe * open_signal ) +int do_serve(struct server *params, struct self_pipe *open_signal) { - NULLCHECK( params ); + NULLCHECK(params); - int success; + int success; - error_set_handler((cleanup_handler*) serve_cleanup, params); - serve_open_server_socket(params); + error_set_handler((cleanup_handler *) serve_cleanup, params); + serve_open_server_socket(params); - /* Only signal that we are open for business once the server - socket is open */ - if ( NULL != open_signal ) { self_pipe_signal( open_signal ); } + /* Only signal that we are open for business once the server + socket is open */ + if (NULL != open_signal) { + self_pipe_signal(open_signal); + } - serve_init_allocation_map(params); - serve_accept_loop(params); - success = params->success; - serve_cleanup(params, 0); + serve_init_allocation_map(params); + serve_accept_loop(params); + success = params->success; + serve_cleanup(params, 0); - return success; + return success; } diff --git a/src/server/serve.h b/src/server/serve.h index 1b697f2..f94e34f 100644 --- a/src/server/serve.h +++ b/src/server/serve.h @@ -3,20 +3,20 @@ #include #include -#include /* for sig_atomic_t */ +#include /* for sig_atomic_t */ #include "flexnbd.h" #include "parse.h" #include "acl.h" -static const int block_allocation_resolution = 4096;//128<<10; +static const int block_allocation_resolution = 4096; //128<<10; struct client_tbl_entry { - pthread_t thread; - union mysockaddr address; - struct client * client; + pthread_t thread; + union mysockaddr address; + struct client *client; }; @@ -25,146 +25,143 @@ struct client_tbl_entry { #define CLIENT_KEEPALIVE_INTVL 10 #define CLIENT_KEEPALIVE_PROBES 3 struct server { - /* The flexnbd wrapper this server is attached to */ - struct flexnbd * flexnbd; + /* The flexnbd wrapper this server is attached to */ + struct flexnbd *flexnbd; /** address/port to bind to */ - union mysockaddr bind_to; + union mysockaddr bind_to; /** (static) file name to serve */ - char* filename; + char *filename; /** TCP backlog for listen() */ - int tcp_backlog; + int tcp_backlog; /** (static) file name of UNIX control socket (or NULL if none) */ - char* control_socket_name; + char *control_socket_name; /** size of file */ - uint64_t size; + uint64_t size; /** to interrupt accept loop and clients, write() to close_signal[1] */ - struct self_pipe * close_signal; + struct self_pipe *close_signal; /** access control list */ - struct acl * acl; + struct acl *acl; /** acl_updated_signal will be signalled after the acl struct * has been replaced */ - struct self_pipe * acl_updated_signal; + struct self_pipe *acl_updated_signal; - /* Claimed around any updates to the ACL. */ - struct flexthread_mutex * l_acl; + /* Claimed around any updates to the ACL. */ + struct flexthread_mutex *l_acl; - /* Claimed around starting a mirror so that it doesn't race with - * shutting down on a SIGTERM. */ - struct flexthread_mutex * l_start_mirror; + /* Claimed around starting a mirror so that it doesn't race with + * shutting down on a SIGTERM. */ + struct flexthread_mutex *l_start_mirror; - struct mirror* mirror; - struct mirror_super * mirror_super; - /* This is used to stop the mirror from starting after we - * receive a SIGTERM */ - int mirror_can_start; + struct mirror *mirror; + struct mirror_super *mirror_super; + /* This is used to stop the mirror from starting after we + * receive a SIGTERM */ + int mirror_can_start; - int server_fd; - int control_fd; + int server_fd; + int control_fd; - /* the allocation_map keeps track of which blocks in the backing file - * have been allocated, or part-allocated on disc, with unallocated - * blocks presumed to contain zeroes (i.e. represented as sparse files - * by the filesystem). We can use this information when receiving - * incoming writes, and avoid writing zeroes to unallocated sections - * of the file which would needlessly increase disc usage. This - * bitmap will start at all-zeroes for an empty file, and tend towards - * all-ones as the file is written to (i.e. we assume that allocated - * blocks can never become unallocated again, as is the case with ext3 - * at least). - */ - struct bitset * allocation_map; - /* when starting up, this thread builds the allocation_map */ - pthread_t allocation_map_builder_thread; + /* the allocation_map keeps track of which blocks in the backing file + * have been allocated, or part-allocated on disc, with unallocated + * blocks presumed to contain zeroes (i.e. represented as sparse files + * by the filesystem). We can use this information when receiving + * incoming writes, and avoid writing zeroes to unallocated sections + * of the file which would needlessly increase disc usage. This + * bitmap will start at all-zeroes for an empty file, and tend towards + * all-ones as the file is written to (i.e. we assume that allocated + * blocks can never become unallocated again, as is the case with ext3 + * at least). + */ + struct bitset *allocation_map; + /* when starting up, this thread builds the allocation_map */ + pthread_t allocation_map_builder_thread; - /* when the thread has finished, it sets this to 1 */ - volatile sig_atomic_t allocation_map_built; - volatile sig_atomic_t allocation_map_not_built; + /* when the thread has finished, it sets this to 1 */ + volatile sig_atomic_t allocation_map_built; + volatile sig_atomic_t allocation_map_not_built; - int max_nbd_clients; - struct client_tbl_entry *nbd_client; + int max_nbd_clients; + struct client_tbl_entry *nbd_client; /** Should clients use the killswitch? */ - int use_killswitch; + int use_killswitch; /** If this isn't set, newly accepted clients will be closed immediately */ - int allow_new_clients; + int allow_new_clients; - /* Marker for whether this server has control over the data in - * the file, or if we're waiting to receive it from an inbound - * migration which hasn't yet finished. - * - * It's the value which controls the exit status of a serve or - * listen process. - */ - int success; + /* Marker for whether this server has control over the data in + * the file, or if we're waiting to receive it from an inbound + * migration which hasn't yet finished. + * + * It's the value which controls the exit status of a serve or + * listen process. + */ + int success; }; -struct server * server_create( - struct flexnbd * flexnbd, - char* s_ip_address, - char* s_port, - char* s_file, - int default_deny, - int acl_entries, - char** s_acl_entries, - int max_nbd_clients, - int use_killswitch, - int success ); -void server_destroy( struct server * ); -int server_is_closed(struct server* serve); -void serve_signal_close( struct server *serve ); -void serve_wait_for_close( struct server * serve ); -void server_replace_acl( struct server *serve, struct acl * acl); -void server_control_arrived( struct server *serve ); -int server_is_in_control( struct server *serve ); -int server_default_deny( struct server * serve ); -int server_acl_locked( struct server * serve ); -void server_lock_acl( struct server *serve ); -void server_unlock_acl( struct server *serve ); -void server_lock_start_mirror( struct server *serve ); -void server_unlock_start_mirror( struct server *serve ); -int server_is_mirroring( struct server * serve ); +struct server *server_create(struct flexnbd *flexnbd, + char *s_ip_address, + char *s_port, + char *s_file, + int default_deny, + int acl_entries, + char **s_acl_entries, + int max_nbd_clients, + int use_killswitch, int success); +void server_destroy(struct server *); +int server_is_closed(struct server *serve); +void serve_signal_close(struct server *serve); +void serve_wait_for_close(struct server *serve); +void server_replace_acl(struct server *serve, struct acl *acl); +void server_control_arrived(struct server *serve); +int server_is_in_control(struct server *serve); +int server_default_deny(struct server *serve); +int server_acl_locked(struct server *serve); +void server_lock_acl(struct server *serve); +void server_unlock_acl(struct server *serve); +void server_lock_start_mirror(struct server *serve); +void server_unlock_start_mirror(struct server *serve); +int server_is_mirroring(struct server *serve); -uint64_t server_mirror_bytes_remaining( struct server * serve ); -uint64_t server_mirror_eta( struct server * serve ); -uint64_t server_mirror_bps( struct server * serve ); +uint64_t server_mirror_bytes_remaining(struct server *serve); +uint64_t server_mirror_eta(struct server *serve); +uint64_t server_mirror_bps(struct server *serve); -void server_abandon_mirror( struct server * serve ); -void server_prevent_mirror_start( struct server *serve ); -void server_allow_mirror_start( struct server *serve ); -int server_mirror_can_start( struct server *serve ); +void server_abandon_mirror(struct server *serve); +void server_prevent_mirror_start(struct server *serve); +void server_allow_mirror_start(struct server *serve); +int server_mirror_can_start(struct server *serve); /* These three functions are used by mirror around the final pass, to close * existing clients and prevent new ones from being around */ -void server_forbid_new_clients( struct server *serve ); -void server_close_clients( struct server *serve ); -void server_join_clients( struct server *serve ); -void server_allow_new_clients( struct server *serve ); +void server_forbid_new_clients(struct server *serve); +void server_close_clients(struct server *serve); +void server_join_clients(struct server *serve); +void server_allow_new_clients(struct server *serve); /* Returns a count (ish) of the number of currently-running client threads */ -int server_count_clients( struct server *params ); +int server_count_clients(struct server *params); -void server_unlink( struct server * serve ); +void server_unlink(struct server *serve); -int do_serve( struct server *, struct self_pipe * ); +int do_serve(struct server *, struct self_pipe *); struct mode_readwrite_params { - union mysockaddr connect_to; - union mysockaddr connect_from; + union mysockaddr connect_to; + union mysockaddr connect_from; - uint64_t from; - uint32_t len; + uint64_t from; + uint32_t len; - int data_fd; - int client; + int data_fd; + int client; }; #endif - diff --git a/src/server/status.c b/src/server/status.c index 530bd7b..937e9fb 100644 --- a/src/server/status.c +++ b/src/server/status.c @@ -2,41 +2,44 @@ #include "serve.h" #include "util.h" -struct status * status_create( struct server * serve ) +struct status *status_create(struct server *serve) { - NULLCHECK( serve ); - struct status * status; + NULLCHECK(serve); + struct status *status; - status = xmalloc( sizeof( struct status ) ); - status->pid = getpid(); - status->size = serve->size; - status->has_control = serve->success; + status = xmalloc(sizeof(struct status)); + status->pid = getpid(); + status->size = serve->size; + status->has_control = serve->success; - status->clients_allowed = serve->allow_new_clients; - status->num_clients = server_count_clients( serve ); + status->clients_allowed = serve->allow_new_clients; + status->num_clients = server_count_clients(serve); - server_lock_start_mirror( serve ); + server_lock_start_mirror(serve); - status->is_mirroring = NULL != serve->mirror; - if ( status->is_mirroring ) { - status->migration_duration = monotonic_time_ms(); + status->is_mirroring = NULL != serve->mirror; + if (status->is_mirroring) { + status->migration_duration = monotonic_time_ms(); - if ( ( serve->mirror->migration_started ) < status->migration_duration ) { - status->migration_duration -= serve->mirror->migration_started; - } else { - status->migration_duration = 0; - } - status->migration_duration /= 1000; - status->migration_speed = server_mirror_bps( serve ); - status->migration_speed_limit = serve->mirror->max_bytes_per_second; - - status->migration_seconds_left = server_mirror_eta( serve ); - status->migration_bytes_left = server_mirror_bytes_remaining( serve ); + if ((serve->mirror->migration_started) < + status->migration_duration) { + status->migration_duration -= serve->mirror->migration_started; + } else { + status->migration_duration = 0; } + status->migration_duration /= 1000; + status->migration_speed = server_mirror_bps(serve); + status->migration_speed_limit = + serve->mirror->max_bytes_per_second; - server_unlock_start_mirror( serve ); + status->migration_seconds_left = server_mirror_eta(serve); + status->migration_bytes_left = + server_mirror_bytes_remaining(serve); + } - return status; + server_unlock_start_mirror(serve); + + return status; } @@ -48,33 +51,32 @@ struct status * status_create( struct server * serve ) #define PRINT_UINT64( var ) \ do{dprintf( fd, #var "=%"PRIu64" ", status->var );}while(0) -int status_write( struct status * status, int fd ) +int status_write(struct status *status, int fd) { - PRINT_INT( pid ); - PRINT_UINT64( size ); - PRINT_BOOL( is_mirroring ); - PRINT_BOOL( clients_allowed ); - PRINT_INT( num_clients ); - PRINT_BOOL( has_control ); + PRINT_INT(pid); + PRINT_UINT64(size); + PRINT_BOOL(is_mirroring); + PRINT_BOOL(clients_allowed); + PRINT_INT(num_clients); + PRINT_BOOL(has_control); - if ( status->is_mirroring ) { - PRINT_UINT64( migration_speed ); - PRINT_UINT64( migration_duration ); - PRINT_UINT64( migration_seconds_left ); - PRINT_UINT64( migration_bytes_left ); - if ( status->migration_speed_limit < UINT64_MAX ) { - PRINT_UINT64( migration_speed_limit ); - }; - } + if (status->is_mirroring) { + PRINT_UINT64(migration_speed); + PRINT_UINT64(migration_duration); + PRINT_UINT64(migration_seconds_left); + PRINT_UINT64(migration_bytes_left); + if (status->migration_speed_limit < UINT64_MAX) { + PRINT_UINT64(migration_speed_limit); + }; + } - dprintf(fd, "\n"); - return 1; + dprintf(fd, "\n"); + return 1; } -void status_destroy( struct status * status ) +void status_destroy(struct status *status) { - NULLCHECK( status ); - free( status ); + NULLCHECK(status); + free(status); } - diff --git a/src/server/status.h b/src/server/status.h index 068571b..642e71b 100644 --- a/src/server/status.h +++ b/src/server/status.h @@ -75,30 +75,29 @@ #include struct status { - pid_t pid; - uint64_t size; - int has_control; - int clients_allowed; - int num_clients; - int is_mirroring; + pid_t pid; + uint64_t size; + int has_control; + int clients_allowed; + int num_clients; + int is_mirroring; - uint64_t migration_duration; - uint64_t migration_speed; - uint64_t migration_speed_limit; - uint64_t migration_seconds_left; - uint64_t migration_bytes_left; + uint64_t migration_duration; + uint64_t migration_speed; + uint64_t migration_speed_limit; + uint64_t migration_seconds_left; + uint64_t migration_bytes_left; }; /** Create a status object for the given server. */ -struct status * status_create( struct server * ); +struct status *status_create(struct server *); /** Output the given status object to the given file descriptot */ -int status_write( struct status *, int fd ); +int status_write(struct status *, int fd); /** Free the status object */ -void status_destroy( struct status * ); +void status_destroy(struct status *); #endif - diff --git a/tests/unit/check_acl.c b/tests/unit/check_acl.c index bb12f81..6aac7ea 100644 --- a/tests/unit/check_acl.c +++ b/tests/unit/check_acl.c @@ -4,226 +4,221 @@ #include "acl.h" #include "util.h" -START_TEST( test_null_acl ) +START_TEST(test_null_acl) { - struct acl *acl = acl_create( 0,NULL, 0 ); + struct acl *acl = acl_create(0, NULL, 0); - fail_if( NULL == acl, "No acl alloced." ); - fail_unless( 0 == acl->len, "Incorrect length" ); + fail_if(NULL == acl, "No acl alloced."); + fail_unless(0 == acl->len, "Incorrect length"); } -END_TEST - -START_TEST( test_parses_single_line ) +END_TEST START_TEST(test_parses_single_line) { - char *lines[] = {"127.0.0.1"}; - struct acl * acl = acl_create( 1, lines, 0 ); + char *lines[] = { "127.0.0.1" }; + struct acl *acl = acl_create(1, lines, 0); - fail_unless( 1 == acl->len, "Incorrect length." ); - fail_if( NULL == acl->entries, "No entries present." ); + fail_unless(1 == acl->len, "Incorrect length."); + fail_if(NULL == acl->entries, "No entries present."); } -END_TEST -START_TEST( test_parses_multiple_lines ) +END_TEST START_TEST(test_parses_multiple_lines) { - char *lines[] = {"127.0.0.1", "::1"}; - struct acl * acl = acl_create( 2, lines, 0 ); - union mysockaddr e0, e1; + char *lines[] = { "127.0.0.1", "::1" }; + struct acl *acl = acl_create(2, lines, 0); + union mysockaddr e0, e1; - parse_ip_to_sockaddr( &e0.generic, lines[0] ); - parse_ip_to_sockaddr( &e1.generic, lines[1] ); + parse_ip_to_sockaddr(&e0.generic, lines[0]); + parse_ip_to_sockaddr(&e1.generic, lines[1]); - fail_unless( acl->len == 2, "Multiple lines not parsed" ); + fail_unless(acl->len == 2, "Multiple lines not parsed"); - struct ip_and_mask *entry; - entry = &(*acl->entries)[0]; - fail_unless(entry->ip.family == e0.family, "entry 0 has wrong family!"); - entry = &(*acl->entries)[1]; - fail_unless(entry->ip.family == e1.family, "entry 1 has wrong family!"); + struct ip_and_mask *entry; + entry = &(*acl->entries)[0]; + fail_unless(entry->ip.family == e0.family, + "entry 0 has wrong family!"); + entry = &(*acl->entries)[1]; + fail_unless(entry->ip.family == e1.family, + "entry 1 has wrong family!"); } -END_TEST -START_TEST( test_destroy_doesnt_crash ) +END_TEST START_TEST(test_destroy_doesnt_crash) { - char *lines[] = {"127.0.0.1"}; - struct acl * acl = acl_create( 1, lines, 0 ); + char *lines[] = { "127.0.0.1" }; + struct acl *acl = acl_create(1, lines, 0); - acl_destroy( acl ); + acl_destroy(acl); } -END_TEST - -START_TEST( test_includes_single_address ) +END_TEST START_TEST(test_includes_single_address) { - char *lines[] = {"127.0.0.1"}; - struct acl * acl = acl_create( 1, lines, 0 ); - union mysockaddr x; + char *lines[] = { "127.0.0.1" }; + struct acl *acl = acl_create(1, lines, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.1" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.1"); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); } + END_TEST - -START_TEST( test_includes_single_address_when_netmask_specified_ipv4 ) +START_TEST(test_includes_single_address_when_netmask_specified_ipv4) { - char *lines[] = {"127.0.0.1/24"}; - struct acl * acl = acl_create( 1, lines, 0 ); - union mysockaddr x; + char *lines[] = { "127.0.0.1/24" }; + struct acl *acl = acl_create(1, lines, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.0" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.0"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); - parse_ip_to_sockaddr( &x.generic, "127.0.0.1" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.1"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); - parse_ip_to_sockaddr( &x.generic, "127.0.0.255" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.255"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); } + END_TEST - -START_TEST( test_includes_single_address_when_netmask_specified_ipv6 ) +START_TEST(test_includes_single_address_when_netmask_specified_ipv6) { - char *lines[] = {"fe80::/10"}; - struct acl * acl = acl_create( 1, lines, 0 ); - union mysockaddr x; + char *lines[] = { "fe80::/10" }; + struct acl *acl = acl_create(1, lines, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "fe80::1" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "fe80::1"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); - parse_ip_to_sockaddr( &x.generic, "fe80::2" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "fe80::2"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); - parse_ip_to_sockaddr( &x.generic, "fe80:ffff:ffff::ffff" ); - fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); + parse_ip_to_sockaddr(&x.generic, "fe80:ffff:ffff::ffff"); + fail_unless(acl_includes(acl, &x), "Included address wasn't covered"); } + END_TEST - -START_TEST( test_includes_single_address_when_multiple_entries_exist ) +START_TEST(test_includes_single_address_when_multiple_entries_exist) { - char *lines[] = {"127.0.0.1", "::1"}; - struct acl * acl = acl_create( 2, lines, 0 ); - union mysockaddr e0; - union mysockaddr e1; + char *lines[] = { "127.0.0.1", "::1" }; + struct acl *acl = acl_create(2, lines, 0); + union mysockaddr e0; + union mysockaddr e1; - parse_ip_to_sockaddr( &e0.generic, "127.0.0.1" ); - parse_ip_to_sockaddr( &e1.generic, "::1" ); + parse_ip_to_sockaddr(&e0.generic, "127.0.0.1"); + parse_ip_to_sockaddr(&e1.generic, "::1"); - fail_unless( acl_includes( acl, &e0 ), "Included address 0 wasn't covered" ); - fail_unless( acl_includes( acl, &e1 ), "Included address 1 wasn't covered" ); + fail_unless(acl_includes(acl, &e0), + "Included address 0 wasn't covered"); + fail_unless(acl_includes(acl, &e1), + "Included address 1 wasn't covered"); } -END_TEST - -START_TEST( test_doesnt_include_other_address ) +END_TEST START_TEST(test_doesnt_include_other_address) { - char *lines[] = {"127.0.0.1"}; - struct acl * acl = acl_create( 1, lines, 0 ); - union mysockaddr x; + char *lines[] = { "127.0.0.1" }; + struct acl *acl = acl_create(1, lines, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.2" ); - fail_if( acl_includes( acl, &x ), "Excluded address was covered." ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.2"); + fail_if(acl_includes(acl, &x), "Excluded address was covered."); } + END_TEST - -START_TEST( test_doesnt_include_other_address_when_netmask_specified ) +START_TEST(test_doesnt_include_other_address_when_netmask_specified) { - char *lines[] = {"127.0.0.1/32"}; - struct acl * acl = acl_create( 1, lines, 0 ); - union mysockaddr x; + char *lines[] = { "127.0.0.1/32" }; + struct acl *acl = acl_create(1, lines, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.2" ); - fail_if( acl_includes( acl, &x ), "Excluded address was covered." ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.2"); + fail_if(acl_includes(acl, &x), "Excluded address was covered."); } + END_TEST - -START_TEST( test_doesnt_include_other_address_when_multiple_entries_exist ) +START_TEST(test_doesnt_include_other_address_when_multiple_entries_exist) { - char *lines[] = {"127.0.0.1", "::1"}; - struct acl * acl = acl_create( 2, lines, 0 ); - union mysockaddr e0; - union mysockaddr e1; + char *lines[] = { "127.0.0.1", "::1" }; + struct acl *acl = acl_create(2, lines, 0); + union mysockaddr e0; + union mysockaddr e1; - parse_ip_to_sockaddr( &e0.generic, "127.0.0.2" ); - parse_ip_to_sockaddr( &e1.generic, "::2" ); + parse_ip_to_sockaddr(&e0.generic, "127.0.0.2"); + parse_ip_to_sockaddr(&e1.generic, "::2"); - fail_if( acl_includes( acl, &e0 ), "Excluded address 0 was covered." ); - fail_if( acl_includes( acl, &e1 ), "Excluded address 1 was covered." ); + fail_if(acl_includes(acl, &e0), "Excluded address 0 was covered."); + fail_if(acl_includes(acl, &e1), "Excluded address 1 was covered."); } -END_TEST -START_TEST( test_default_deny_rejects ) +END_TEST START_TEST(test_default_deny_rejects) { - struct acl * acl = acl_create( 0, NULL, 1 ); - union mysockaddr x; + struct acl *acl = acl_create(0, NULL, 1); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.1" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.1"); - fail_if( acl_includes( acl, &x ), "Default deny accepted." ); + fail_if(acl_includes(acl, &x), "Default deny accepted."); } -END_TEST - -START_TEST( test_default_accept_rejects ) +END_TEST START_TEST(test_default_accept_rejects) { - struct acl * acl = acl_create( 0, NULL, 0 ); - union mysockaddr x; + struct acl *acl = acl_create(0, NULL, 0); + union mysockaddr x; - parse_ip_to_sockaddr( &x.generic, "127.0.0.1" ); + parse_ip_to_sockaddr(&x.generic, "127.0.0.1"); - fail_unless( acl_includes( acl, &x ), "Default accept rejected." ); + fail_unless(acl_includes(acl, &x), "Default accept rejected."); } -END_TEST - -Suite* acl_suite(void) +END_TEST Suite * acl_suite(void) { - Suite *s = suite_create("acl"); - TCase *tc_create = tcase_create("create"); - TCase *tc_includes = tcase_create("includes"); - TCase *tc_destroy = tcase_create("destroy"); + Suite *s = suite_create("acl"); + TCase *tc_create = tcase_create("create"); + TCase *tc_includes = tcase_create("includes"); + TCase *tc_destroy = tcase_create("destroy"); - tcase_add_test(tc_create, test_null_acl); - tcase_add_test(tc_create, test_parses_single_line); - tcase_add_test(tc_includes, test_parses_multiple_lines); + tcase_add_test(tc_create, test_null_acl); + tcase_add_test(tc_create, test_parses_single_line); + tcase_add_test(tc_includes, test_parses_multiple_lines); - tcase_add_test(tc_includes, test_includes_single_address); - tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv4); - tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv6); + tcase_add_test(tc_includes, test_includes_single_address); + tcase_add_test(tc_includes, + test_includes_single_address_when_netmask_specified_ipv4); + tcase_add_test(tc_includes, + test_includes_single_address_when_netmask_specified_ipv6); - tcase_add_test(tc_includes, test_includes_single_address_when_multiple_entries_exist); + tcase_add_test(tc_includes, + test_includes_single_address_when_multiple_entries_exist); - tcase_add_test(tc_includes, test_doesnt_include_other_address); - tcase_add_test(tc_includes, test_doesnt_include_other_address_when_netmask_specified); - tcase_add_test(tc_includes, test_doesnt_include_other_address_when_multiple_entries_exist); + tcase_add_test(tc_includes, test_doesnt_include_other_address); + tcase_add_test(tc_includes, + test_doesnt_include_other_address_when_netmask_specified); + tcase_add_test(tc_includes, + test_doesnt_include_other_address_when_multiple_entries_exist); - tcase_add_test(tc_includes, test_default_deny_rejects); - tcase_add_test(tc_includes, test_default_accept_rejects); + tcase_add_test(tc_includes, test_default_deny_rejects); + tcase_add_test(tc_includes, test_default_accept_rejects); - tcase_add_test(tc_destroy, test_destroy_doesnt_crash); + tcase_add_test(tc_destroy, test_destroy_doesnt_crash); - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_includes); - suite_add_tcase(s, tc_destroy); + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_includes); + suite_add_tcase(s, tc_destroy); - return s; + return s; } int main(void) { #ifdef DEBUG - log_level = 0; + log_level = 0; #else - log_level = 2; + log_level = 2; #endif - int number_failed; - Suite *s = acl_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - log_level = 0; - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = acl_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + log_level = 0; + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_bitset.c b/tests/unit/check_bitset.c index 36b4e55..100e96b 100644 --- a/tests/unit/check_bitset.c +++ b/tests/unit/check_bitset.c @@ -9,492 +9,473 @@ START_TEST(test_bit_set) { - uint64_t num = 0; - bitfield_p bits = (bitfield_p) # + uint64_t num = 0; + bitfield_p bits = (bitfield_p) & num; #define TEST_BIT_SET(bit, newvalue) \ bit_set(bits, (bit)); \ fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue)); - TEST_BIT_SET(0, 1); - TEST_BIT_SET(1, 3); - TEST_BIT_SET(2, 7); - TEST_BIT_SET(7, 0x87); - TEST_BIT_SET(63, 0x8000000000000087); + TEST_BIT_SET(0, 1); + TEST_BIT_SET(1, 3); + TEST_BIT_SET(2, 7); + TEST_BIT_SET(7, 0x87); + TEST_BIT_SET(63, 0x8000000000000087); } -END_TEST -START_TEST(test_bit_clear) +END_TEST START_TEST(test_bit_clear) { - uint64_t num = 0xffffffffffffffff; - bitfield_p bits = (bitfield_p) # + uint64_t num = 0xffffffffffffffff; + bitfield_p bits = (bitfield_p) & num; #define TEST_BIT_CLEAR(bit, newvalue) \ bit_clear(bits, (bit)); \ fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue)); - TEST_BIT_CLEAR(0, 0xfffffffffffffffe); - TEST_BIT_CLEAR(1, 0xfffffffffffffffc); - TEST_BIT_CLEAR(2, 0xfffffffffffffff8); - TEST_BIT_CLEAR(7, 0xffffffffffffff78); - TEST_BIT_CLEAR(63,0x7fffffffffffff78); + TEST_BIT_CLEAR(0, 0xfffffffffffffffe); + TEST_BIT_CLEAR(1, 0xfffffffffffffffc); + TEST_BIT_CLEAR(2, 0xfffffffffffffff8); + TEST_BIT_CLEAR(7, 0xffffffffffffff78); + TEST_BIT_CLEAR(63, 0x7fffffffffffff78); } -END_TEST -START_TEST(test_bit_tests) +END_TEST START_TEST(test_bit_tests) { - uint64_t num = 0x5555555555555555; - bitfield_p bits = (bitfield_p) # + uint64_t num = 0x5555555555555555; + bitfield_p bits = (bitfield_p) & num; - fail_unless(bit_has_value(bits, 0, 1), "bit_has_value malfunction"); - fail_unless(bit_has_value(bits, 1, 0), "bit_has_value malfunction"); - fail_unless(bit_has_value(bits, 63, 0), "bit_has_value malfunction"); - fail_unless(bit_is_set(bits, 0), "bit_is_set malfunction"); - fail_unless(bit_is_clear(bits, 1), "bit_is_clear malfunction"); - fail_unless(bit_is_set(bits, 62), "bit_is_set malfunction"); - fail_unless(bit_is_clear(bits, 63), "bit_is_clear malfunction"); + fail_unless(bit_has_value(bits, 0, 1), "bit_has_value malfunction"); + fail_unless(bit_has_value(bits, 1, 0), "bit_has_value malfunction"); + fail_unless(bit_has_value(bits, 63, 0), "bit_has_value malfunction"); + fail_unless(bit_is_set(bits, 0), "bit_is_set malfunction"); + fail_unless(bit_is_clear(bits, 1), "bit_is_clear malfunction"); + fail_unless(bit_is_set(bits, 62), "bit_is_set malfunction"); + fail_unless(bit_is_clear(bits, 63), "bit_is_clear malfunction"); } -END_TEST -START_TEST(test_bit_ranges) +END_TEST START_TEST(test_bit_ranges) { - bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)]; - uint64_t *longs = (uint64_t *) buffer; - uint64_t i; + bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)]; + uint64_t *longs = (uint64_t *) buffer; + uint64_t i; - memset(buffer, 0, 4160); + memset(buffer, 0, 4160); - for (i=0; i<64; i++) { - bit_set_range(buffer, i*64, i); - fail_unless( - longs[i] == (1ULL<bits; + map = bitset_alloc(6400, 100); + num = (uint64_t *) map->bits; - bitset_set_range(map,0,50); - ck_assert_int_eq(1, *num); - bitset_set_range(map,99,1); - ck_assert_int_eq(1, *num); - bitset_set_range(map,100,1); - ck_assert_int_eq(3, *num); - bitset_set_range(map,0,800); - ck_assert_int_eq(255, *num); - bitset_set_range(map,1499,2); - ck_assert_int_eq(0xc0ff, *num); - bitset_clear_range(map,1499,2); - ck_assert_int_eq(255, *num); + bitset_set_range(map, 0, 50); + ck_assert_int_eq(1, *num); + bitset_set_range(map, 99, 1); + ck_assert_int_eq(1, *num); + bitset_set_range(map, 100, 1); + ck_assert_int_eq(3, *num); + bitset_set_range(map, 0, 800); + ck_assert_int_eq(255, *num); + bitset_set_range(map, 1499, 2); + ck_assert_int_eq(0xc0ff, *num); + bitset_clear_range(map, 1499, 2); + ck_assert_int_eq(255, *num); - *num = 0; - bitset_set_range(map, 1499, 2); - bitset_clear_range(map, 1300, 200); - ck_assert_int_eq(0x8000, *num); + *num = 0; + bitset_set_range(map, 1499, 2); + bitset_clear_range(map, 1300, 200); + ck_assert_int_eq(0x8000, *num); - *num = 0; - bitset_set_range(map, 0, 6400); - ck_assert_int_eq(0xffffffffffffffff, *num); - bitset_clear_range(map, 3200, 400); - ck_assert_int_eq(0xfffffff0ffffffff, *num); + *num = 0; + bitset_set_range(map, 0, 6400); + ck_assert_int_eq(0xffffffffffffffff, *num); + bitset_clear_range(map, 3200, 400); + ck_assert_int_eq(0xfffffff0ffffffff, *num); } -END_TEST - -START_TEST( test_bitset_set ) +END_TEST START_TEST(test_bitset_set) { - struct bitset * map; - uint64_t run; + struct bitset *map; + uint64_t run; - map = bitset_alloc(64, 1); + map = bitset_alloc(64, 1); - assert_bitset_is( map, 0x0000000000000000 ); - bitset_set( map ); - assert_bitset_is( map, 0xffffffffffffffff ); - bitset_free( map ); + assert_bitset_is(map, 0x0000000000000000); + bitset_set(map); + assert_bitset_is(map, 0xffffffffffffffff); + bitset_free(map); - map = bitset_alloc( 6400, 100 ); - assert_bitset_is( map, 0x0000000000000000 ); - bitset_set( map ); - assert_bitset_is( map, 0xffffffffffffffff ); - bitset_free( map ); + map = bitset_alloc(6400, 100); + assert_bitset_is(map, 0x0000000000000000); + bitset_set(map); + assert_bitset_is(map, 0xffffffffffffffff); + bitset_free(map); - // Now do something large and representative - map = bitset_alloc( 53687091200, 4096 ); - bitset_set( map ); + // Now do something large and representative + map = bitset_alloc(53687091200, 4096); + bitset_set(map); - run = bitset_run_count( map, 0, 53687091200 ); - ck_assert_int_eq( run, 53687091200 ); - bitset_free( map ); + run = bitset_run_count(map, 0, 53687091200); + ck_assert_int_eq(run, 53687091200); + bitset_free(map); } -END_TEST - -START_TEST( test_bitset_clear ) +END_TEST START_TEST(test_bitset_clear) { - struct bitset * map; - uint64_t *num; - uint64_t run; + struct bitset *map; + uint64_t *num; + uint64_t run; - map = bitset_alloc(64, 1); - num = (uint64_t*) map->bits; + map = bitset_alloc(64, 1); + num = (uint64_t *) map->bits; - ck_assert_int_eq( 0x0000000000000000, *num ); - bitset_set( map ); - bitset_clear( map ); - ck_assert_int_eq( 0x0000000000000000, *num ); + ck_assert_int_eq(0x0000000000000000, *num); + bitset_set(map); + bitset_clear(map); + ck_assert_int_eq(0x0000000000000000, *num); - bitset_free( map ); + bitset_free(map); - // Now do something large and representative - map = bitset_alloc( 53687091200, 4096 ); - bitset_set( map ); - bitset_clear( map ); - run = bitset_run_count( map, 0, 53687091200 ); - ck_assert_int_eq( run, 53687091200 ); - bitset_free( map ); + // Now do something large and representative + map = bitset_alloc(53687091200, 4096); + bitset_set(map); + bitset_clear(map); + run = bitset_run_count(map, 0, 53687091200); + ck_assert_int_eq(run, 53687091200); + bitset_free(map); } -END_TEST -START_TEST( test_bitset_set_range ) +END_TEST START_TEST(test_bitset_set_range) { - struct bitset* map = bitset_alloc( 64, 1 ); - assert_bitset_is( map, 0x0000000000000000 ); + struct bitset *map = bitset_alloc(64, 1); + assert_bitset_is(map, 0x0000000000000000); - bitset_set_range( map, 8, 8 ); - assert_bitset_is( map, 0x000000000000ff00 ); + bitset_set_range(map, 8, 8); + assert_bitset_is(map, 0x000000000000ff00); - bitset_clear( map ); - assert_bitset_is( map, 0x0000000000000000 ); - bitset_set_range( map, 0, 0 ); - assert_bitset_is( map, 0x0000000000000000 ); + bitset_clear(map); + assert_bitset_is(map, 0x0000000000000000); + bitset_set_range(map, 0, 0); + assert_bitset_is(map, 0x0000000000000000); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST( test_bitset_clear_range ) +END_TEST START_TEST(test_bitset_clear_range) { - struct bitset* map = bitset_alloc( 64, 1 ); - bitset_set( map ); - assert_bitset_is( map, 0xffffffffffffffff ); + struct bitset *map = bitset_alloc(64, 1); + bitset_set(map); + assert_bitset_is(map, 0xffffffffffffffff); - bitset_clear_range( map, 8, 8 ); - assert_bitset_is( map, 0xffffffffffff00ff ); + bitset_clear_range(map, 8, 8); + assert_bitset_is(map, 0xffffffffffff00ff); - bitset_set( map ); - assert_bitset_is( map, 0xffffffffffffffff ); - bitset_clear_range( map, 0, 0 ); - assert_bitset_is( map, 0xffffffffffffffff ); + bitset_set(map); + assert_bitset_is(map, 0xffffffffffffffff); + bitset_clear_range(map, 0, 0); + assert_bitset_is(map, 0xffffffffffffffff); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST( test_bitset_run_count ) +END_TEST START_TEST(test_bitset_run_count) { - struct bitset* map = bitset_alloc( 64, 1 ); - uint64_t run; + struct bitset *map = bitset_alloc(64, 1); + uint64_t run; - assert_bitset_is( map, 0x0000000000000000 ); + assert_bitset_is(map, 0x0000000000000000); - run = bitset_run_count( map, 0, 64 ); - ck_assert_int_eq( 64, run ); + run = bitset_run_count(map, 0, 64); + ck_assert_int_eq(64, run); - bitset_set_range( map, 0, 32 ); - assert_bitset_is( map, 0x00000000ffffffff ); + bitset_set_range(map, 0, 32); + assert_bitset_is(map, 0x00000000ffffffff); - run = bitset_run_count( map, 0, 64 ); - ck_assert_int_eq( 32, run ); + run = bitset_run_count(map, 0, 64); + ck_assert_int_eq(32, run); - run = bitset_run_count( map, 0, 16 ); - ck_assert_int_eq( 16, run ); + run = bitset_run_count(map, 0, 16); + ck_assert_int_eq(16, run); - run = bitset_run_count( map, 16, 64 ); - ck_assert_int_eq( 16, run ); + run = bitset_run_count(map, 16, 64); + ck_assert_int_eq(16, run); - run = bitset_run_count( map, 31, 64 ); - ck_assert_int_eq( 1, run ); + run = bitset_run_count(map, 31, 64); + ck_assert_int_eq(1, run); - run = bitset_run_count( map, 32, 64 ); - ck_assert_int_eq( 32, run ); + run = bitset_run_count(map, 32, 64); + ck_assert_int_eq(32, run); - run = bitset_run_count( map, 32, 32 ); - ck_assert_int_eq( 32, run ); + run = bitset_run_count(map, 32, 32); + ck_assert_int_eq(32, run); - run = bitset_run_count( map, 32, 16 ); - ck_assert_int_eq( 16, run ); + run = bitset_run_count(map, 32, 16); + ck_assert_int_eq(16, run); - bitset_free( map ); + bitset_free(map); - map = bitset_alloc( 6400, 100 ); - assert_bitset_is( map, 0x0000000000000000 ); + map = bitset_alloc(6400, 100); + assert_bitset_is(map, 0x0000000000000000); - run = bitset_run_count( map, 0, 6400 ); - ck_assert_int_eq( 6400, run ); + run = bitset_run_count(map, 0, 6400); + ck_assert_int_eq(6400, run); - bitset_set_range( map, 0, 3200 ); + bitset_set_range(map, 0, 3200); - run = bitset_run_count( map, 0, 6400 ); - ck_assert_int_eq( 3200, run ); + run = bitset_run_count(map, 0, 6400); + ck_assert_int_eq(3200, run); - run = bitset_run_count( map, 1, 6400 ); - ck_assert_int_eq( 3199, run ); + run = bitset_run_count(map, 1, 6400); + ck_assert_int_eq(3199, run); - run = bitset_run_count( map, 3200, 6400 ); - ck_assert_int_eq( 3200, run ); + run = bitset_run_count(map, 3200, 6400); + ck_assert_int_eq(3200, run); - run = bitset_run_count( map, 6500, 6400 ); - ck_assert_int_eq( 0, run ); - bitset_free( map ); + run = bitset_run_count(map, 6500, 6400); + ck_assert_int_eq(0, run); + bitset_free(map); - // Now do something large and representative - map = bitset_alloc( 53687091200, 4096 ); - bitset_set( map ); - run = bitset_run_count( map, 0, 53687091200 ); - ck_assert_int_eq( run, 53687091200 ); + // Now do something large and representative + map = bitset_alloc(53687091200, 4096); + bitset_set(map); + run = bitset_run_count(map, 0, 53687091200); + ck_assert_int_eq(run, 53687091200); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST( test_bitset_set_range_doesnt_push_to_stream ) +END_TEST START_TEST(test_bitset_set_range_doesnt_push_to_stream) { - struct bitset *map = bitset_alloc( 64, 1 ); - bitset_set_range( map, 0, 64 ); - ck_assert_int_eq( 0, bitset_stream_size( map ) ); - bitset_free( map ); + struct bitset *map = bitset_alloc(64, 1); + bitset_set_range(map, 0, 64); + ck_assert_int_eq(0, bitset_stream_size(map)); + bitset_free(map); } -END_TEST -START_TEST( test_bitset_clear_range_doesnt_push_to_stream ) +END_TEST START_TEST(test_bitset_clear_range_doesnt_push_to_stream) { - struct bitset *map = bitset_alloc( 64, 1 ); - bitset_clear_range( map, 0, 64 ); - ck_assert_int_eq( 0, bitset_stream_size( map ) ); - bitset_free( map ); + struct bitset *map = bitset_alloc(64, 1); + bitset_clear_range(map, 0, 64); + ck_assert_int_eq(0, bitset_stream_size(map)); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_enable_stream) +END_TEST START_TEST(test_bitset_enable_stream) { - struct bitset *map = bitset_alloc( 64, 1 ); - struct bitset_stream_entry result; - memset( &result, 0, sizeof( result ) ); + struct bitset *map = bitset_alloc(64, 1); + struct bitset_stream_entry result; + memset(&result, 0, sizeof(result)); - bitset_enable_stream( map ); + bitset_enable_stream(map); - ck_assert_int_eq( 1, map->stream_enabled ); + ck_assert_int_eq(1, map->stream_enabled); - bitset_stream_dequeue( map, &result ); + bitset_stream_dequeue(map, &result); - ck_assert_int_eq( BITSET_STREAM_ON, result.event ); - ck_assert_int_eq( 0, result.from ); - ck_assert_int_eq( 64, result.len ); + ck_assert_int_eq(BITSET_STREAM_ON, result.event); + ck_assert_int_eq(0, result.from); + ck_assert_int_eq(64, result.len); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_disable_stream) +END_TEST START_TEST(test_bitset_disable_stream) { - struct bitset *map = bitset_alloc( 64, 1 ); - struct bitset_stream_entry result; - memset( &result, 0, sizeof( result ) ); + struct bitset *map = bitset_alloc(64, 1); + struct bitset_stream_entry result; + memset(&result, 0, sizeof(result)); - bitset_enable_stream( map ); - bitset_disable_stream( map ); + bitset_enable_stream(map); + bitset_disable_stream(map); - ck_assert_int_eq( 0, map->stream_enabled ); - ck_assert_int_eq( 2, bitset_stream_size( map ) ); + ck_assert_int_eq(0, map->stream_enabled); + ck_assert_int_eq(2, bitset_stream_size(map)); - bitset_stream_dequeue( map, NULL ); // ON - bitset_stream_dequeue( map, &result ); // OFF + bitset_stream_dequeue(map, NULL); // ON + bitset_stream_dequeue(map, &result); // OFF - ck_assert_int_eq( BITSET_STREAM_OFF, result.event ); - ck_assert_int_eq( 0, result.from ); - ck_assert_int_eq( 64, result.len ); + ck_assert_int_eq(BITSET_STREAM_OFF, result.event); + ck_assert_int_eq(0, result.from); + ck_assert_int_eq(64, result.len); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_stream_with_set_range) +END_TEST START_TEST(test_bitset_stream_with_set_range) { - struct bitset *map = bitset_alloc( 64, 1 ); - struct bitset_stream_entry result; - memset( &result, 0, sizeof( result ) ); + struct bitset *map = bitset_alloc(64, 1); + struct bitset_stream_entry result; + memset(&result, 0, sizeof(result)); - bitset_enable_stream( map ); - bitset_set_range( map, 0, 32 ); + bitset_enable_stream(map); + bitset_set_range(map, 0, 32); - ck_assert_int_eq( 2, bitset_stream_size( map ) ); + ck_assert_int_eq(2, bitset_stream_size(map)); - bitset_stream_dequeue( map, NULL ); // ON - bitset_stream_dequeue( map, &result ); // SET + bitset_stream_dequeue(map, NULL); // ON + bitset_stream_dequeue(map, &result); // SET - ck_assert_int_eq( BITSET_STREAM_SET, result.event ); - ck_assert_int_eq( 0, result.from ); - ck_assert_int_eq( 32, result.len ); + ck_assert_int_eq(BITSET_STREAM_SET, result.event); + ck_assert_int_eq(0, result.from); + ck_assert_int_eq(32, result.len); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_stream_with_clear_range) +END_TEST START_TEST(test_bitset_stream_with_clear_range) { - struct bitset *map = bitset_alloc( 64, 1 ); - struct bitset_stream_entry result; - memset( &result, 0, sizeof( result ) ); + struct bitset *map = bitset_alloc(64, 1); + struct bitset_stream_entry result; + memset(&result, 0, sizeof(result)); - bitset_enable_stream( map ); - bitset_clear_range( map, 0, 32 ); - ck_assert_int_eq( 2, bitset_stream_size( map ) ); + bitset_enable_stream(map); + bitset_clear_range(map, 0, 32); + ck_assert_int_eq(2, bitset_stream_size(map)); - bitset_stream_dequeue( map, NULL ); // ON - bitset_stream_dequeue( map, &result ); // UNSET + bitset_stream_dequeue(map, NULL); // ON + bitset_stream_dequeue(map, &result); // UNSET - ck_assert_int_eq( BITSET_STREAM_UNSET, result.event ); - ck_assert_int_eq( 0, result.from ); - ck_assert_int_eq( 32, result.len ); + ck_assert_int_eq(BITSET_STREAM_UNSET, result.event); + ck_assert_int_eq(0, result.from); + ck_assert_int_eq(32, result.len); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_stream_size) +END_TEST START_TEST(test_bitset_stream_size) { - struct bitset *map = bitset_alloc( 64, 1 ); - bitset_enable_stream( map ); - bitset_set_range( map, 0, 32 ); - bitset_set_range( map, 16, 32 ); - bitset_set_range( map, 7, 16 ); + struct bitset *map = bitset_alloc(64, 1); + bitset_enable_stream(map); + bitset_set_range(map, 0, 32); + bitset_set_range(map, 16, 32); + bitset_set_range(map, 7, 16); - bitset_clear_range( map, 0, 32 ); - bitset_clear_range( map, 16, 32 ); - bitset_clear_range( map, 48, 16 ); - bitset_disable_stream( map ); + bitset_clear_range(map, 0, 32); + bitset_clear_range(map, 16, 32); + bitset_clear_range(map, 48, 16); + bitset_disable_stream(map); - ck_assert_int_eq( 8, bitset_stream_size( map ) ); + ck_assert_int_eq(8, bitset_stream_size(map)); - bitset_free( map ); + bitset_free(map); } -END_TEST -START_TEST(test_bitset_stream_queued_bytes) +END_TEST START_TEST(test_bitset_stream_queued_bytes) { - struct bitset *map = bitset_alloc( 64, 1 ); - bitset_enable_stream( map ); - bitset_set_range( map, 0, 32 ); - bitset_set_range( map, 16, 32 ); - bitset_set_range( map, 7, 16 ); + struct bitset *map = bitset_alloc(64, 1); + bitset_enable_stream(map); + bitset_set_range(map, 0, 32); + bitset_set_range(map, 16, 32); + bitset_set_range(map, 7, 16); - bitset_clear_range( map, 0, 32 ); - bitset_clear_range( map, 16, 32 ); - bitset_clear_range( map, 48, 16 ); - bitset_clear_range( map, 0, 2 ); - bitset_disable_stream( map ); + bitset_clear_range(map, 0, 32); + bitset_clear_range(map, 16, 32); + bitset_clear_range(map, 48, 16); + bitset_clear_range(map, 0, 2); + bitset_disable_stream(map); - ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_ON ) ); - ck_assert_int_eq( 80, bitset_stream_queued_bytes( map, BITSET_STREAM_SET ) ); - ck_assert_int_eq( 82, bitset_stream_queued_bytes( map, BITSET_STREAM_UNSET ) ); - ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_OFF ) ); - bitset_free( map ); + ck_assert_int_eq(64, + bitset_stream_queued_bytes(map, BITSET_STREAM_ON)); + ck_assert_int_eq(80, + bitset_stream_queued_bytes(map, BITSET_STREAM_SET)); + ck_assert_int_eq(82, + bitset_stream_queued_bytes(map, BITSET_STREAM_UNSET)); + ck_assert_int_eq(64, + bitset_stream_queued_bytes(map, BITSET_STREAM_OFF)); + bitset_free(map); } -END_TEST -Suite* bitset_suite(void) +END_TEST Suite * bitset_suite(void) { - Suite *s = suite_create("bitset"); + Suite *s = suite_create("bitset"); - TCase *tc_bit = tcase_create("bit"); - tcase_add_test(tc_bit, test_bit_set); - tcase_add_test(tc_bit, test_bit_clear); - tcase_add_test(tc_bit, test_bit_tests); - tcase_add_test(tc_bit, test_bit_ranges); - tcase_add_test(tc_bit, test_bit_runs); - suite_add_tcase(s, tc_bit); + TCase *tc_bit = tcase_create("bit"); + tcase_add_test(tc_bit, test_bit_set); + tcase_add_test(tc_bit, test_bit_clear); + tcase_add_test(tc_bit, test_bit_tests); + tcase_add_test(tc_bit, test_bit_ranges); + tcase_add_test(tc_bit, test_bit_runs); + suite_add_tcase(s, tc_bit); - TCase *tc_bitset = tcase_create("bitset"); - tcase_add_test(tc_bitset, test_bitset); - tcase_add_test(tc_bitset, test_bitset_set); - tcase_add_test(tc_bitset, test_bitset_clear); - tcase_add_test(tc_bitset, test_bitset_run_count); - tcase_add_test(tc_bitset, test_bitset_set_range); - tcase_add_test(tc_bitset, test_bitset_clear_range); - tcase_add_test(tc_bitset, test_bitset_set_range_doesnt_push_to_stream); - tcase_add_test(tc_bitset, test_bitset_clear_range_doesnt_push_to_stream); - suite_add_tcase(s, tc_bitset); + TCase *tc_bitset = tcase_create("bitset"); + tcase_add_test(tc_bitset, test_bitset); + tcase_add_test(tc_bitset, test_bitset_set); + tcase_add_test(tc_bitset, test_bitset_clear); + tcase_add_test(tc_bitset, test_bitset_run_count); + tcase_add_test(tc_bitset, test_bitset_set_range); + tcase_add_test(tc_bitset, test_bitset_clear_range); + tcase_add_test(tc_bitset, test_bitset_set_range_doesnt_push_to_stream); + tcase_add_test(tc_bitset, + test_bitset_clear_range_doesnt_push_to_stream); + suite_add_tcase(s, tc_bitset); - TCase *tc_bitset_stream = tcase_create("bitset_stream"); - tcase_add_test(tc_bitset_stream, test_bitset_enable_stream); - tcase_add_test(tc_bitset_stream, test_bitset_disable_stream); - tcase_add_test(tc_bitset_stream, test_bitset_stream_with_set_range); - tcase_add_test(tc_bitset_stream, test_bitset_stream_with_clear_range); - tcase_add_test(tc_bitset_stream, test_bitset_stream_size); - tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes); - suite_add_tcase(s, tc_bitset_stream); + TCase *tc_bitset_stream = tcase_create("bitset_stream"); + tcase_add_test(tc_bitset_stream, test_bitset_enable_stream); + tcase_add_test(tc_bitset_stream, test_bitset_disable_stream); + tcase_add_test(tc_bitset_stream, test_bitset_stream_with_set_range); + tcase_add_test(tc_bitset_stream, test_bitset_stream_with_clear_range); + tcase_add_test(tc_bitset_stream, test_bitset_stream_size); + tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes); + suite_add_tcase(s, tc_bitset_stream); - return s; + return s; } int main(void) { - int number_failed; - Suite *s = bitset_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = bitset_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_client.c b/tests/unit/check_client.c index 188db10..3df7a13 100644 --- a/tests/unit/check_client.c +++ b/tests/unit/check_client.c @@ -9,114 +9,104 @@ #include -struct server fake_server = {0}; +struct server fake_server = { 0 }; + #define FAKE_SERVER &fake_server #define FAKE_SOCKET (42) -START_TEST( test_assigns_socket ) +START_TEST(test_assigns_socket) { - struct client * c; + struct client *c; - c = client_create( FAKE_SERVER, FAKE_SOCKET ); + c = client_create(FAKE_SERVER, FAKE_SOCKET); - fail_unless( 42 == c->socket, "Socket wasn't assigned." ); + fail_unless(42 == c->socket, "Socket wasn't assigned."); } -END_TEST - -START_TEST( test_assigns_server ) +END_TEST START_TEST(test_assigns_server) { - struct client * c; - /* can't predict the storage size so we can't allocate one on - * the stack - */ - c = client_create( FAKE_SERVER, FAKE_SOCKET ); + struct client *c; + /* can't predict the storage size so we can't allocate one on + * the stack + */ + c = client_create(FAKE_SERVER, FAKE_SOCKET); - fail_unless( FAKE_SERVER == c->serve, "Serve wasn't assigned." ); + fail_unless(FAKE_SERVER == c->serve, "Serve wasn't assigned."); } -END_TEST - -START_TEST( test_opens_stop_signal ) +END_TEST START_TEST(test_opens_stop_signal) { - struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET ); + struct client *c = client_create(FAKE_SERVER, FAKE_SOCKET); - client_signal_stop( c ); + client_signal_stop(c); - fail_unless( 1 == self_pipe_signal_clear( c->stop_signal ), - "No signal was sent." ); + fail_unless(1 == self_pipe_signal_clear(c->stop_signal), + "No signal was sent."); } -END_TEST +END_TEST int fd_is_closed(int); -int fd_is_closed(int); - -START_TEST( test_closes_stop_signal ) +START_TEST(test_closes_stop_signal) { - struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET ); - int read_fd = c->stop_signal->read_fd; - int write_fd = c->stop_signal->write_fd; + struct client *c = client_create(FAKE_SERVER, FAKE_SOCKET); + int read_fd = c->stop_signal->read_fd; + int write_fd = c->stop_signal->write_fd; - client_destroy( c ); + client_destroy(c); - fail_unless( fd_is_closed( read_fd ), "Stop signal wasn't destroyed." ); - fail_unless( fd_is_closed( write_fd ), "Stop signal wasn't destroyed." ); + fail_unless(fd_is_closed(read_fd), "Stop signal wasn't destroyed."); + fail_unless(fd_is_closed(write_fd), "Stop signal wasn't destroyed."); } -END_TEST - -START_TEST( test_read_request_quits_on_stop_signal ) +END_TEST START_TEST(test_read_request_quits_on_stop_signal) { - int fds[2]; - struct nbd_request nbdr; - pipe( fds ); - struct client *c = client_create( FAKE_SERVER, fds[0] ); - - client_signal_stop( c ); + int fds[2]; + struct nbd_request nbdr; + pipe(fds); + struct client *c = client_create(FAKE_SERVER, fds[0]); - int client_serve_request( struct client *); - fail_unless( 1 == client_serve_request( c ), "Didn't quit on stop." ); + client_signal_stop(c); - close( fds[0] ); - close( fds[1] ); + int client_serve_request(struct client *); + fail_unless(1 == client_serve_request(c), "Didn't quit on stop."); + + close(fds[0]); + close(fds[1]); } -END_TEST - -Suite *client_suite(void) +END_TEST Suite * client_suite(void) { - Suite *s = suite_create("client"); + Suite *s = suite_create("client"); - TCase *tc_create = tcase_create("create"); - TCase *tc_signal = tcase_create("signal"); - TCase *tc_destroy = tcase_create("destroy"); + TCase *tc_create = tcase_create("create"); + TCase *tc_signal = tcase_create("signal"); + TCase *tc_destroy = tcase_create("destroy"); - tcase_add_test(tc_create, test_assigns_socket); - tcase_add_test(tc_create, test_assigns_server); + tcase_add_test(tc_create, test_assigns_socket); + tcase_add_test(tc_create, test_assigns_server); - tcase_add_test(tc_signal, test_opens_stop_signal); - tcase_add_test(tc_signal, test_read_request_quits_on_stop_signal); + tcase_add_test(tc_signal, test_opens_stop_signal); + tcase_add_test(tc_signal, test_read_request_quits_on_stop_signal); - tcase_add_test( tc_destroy, test_closes_stop_signal ); + tcase_add_test(tc_destroy, test_closes_stop_signal); - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_signal); - suite_add_tcase(s, tc_destroy); + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_signal); + suite_add_tcase(s, tc_destroy); - return s; + return s; } int main(void) { - int number_failed; - - Suite *s = client_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; -} + int number_failed; + Suite *s = client_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} diff --git a/tests/unit/check_control.c b/tests/unit/check_control.c index fbb2ec9..2afd6dc 100644 --- a/tests/unit/check_control.c +++ b/tests/unit/check_control.c @@ -4,39 +4,36 @@ #include -START_TEST( test_assigns_sock_name ) +START_TEST(test_assigns_sock_name) { - struct flexnbd flexnbd = {0}; - char csn[] = "foobar"; + struct flexnbd flexnbd = { 0 }; + char csn[] = "foobar"; - struct control * control = control_create(&flexnbd, csn ); + struct control *control = control_create(&flexnbd, csn); - fail_unless( csn == control->socket_name, "Socket name not assigned" ); + fail_unless(csn == control->socket_name, "Socket name not assigned"); } -END_TEST - -Suite *control_suite(void) +END_TEST Suite * control_suite(void) { - Suite *s = suite_create("control"); + Suite *s = suite_create("control"); - TCase *tc_create = tcase_create("create"); + TCase *tc_create = tcase_create("create"); - tcase_add_test(tc_create, test_assigns_sock_name); - suite_add_tcase( s, tc_create ); + tcase_add_test(tc_create, test_assigns_sock_name); + suite_add_tcase(s, tc_create); - return s; + return s; } int main(void) { - int number_failed; - - Suite *s = control_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; -} + int number_failed; + Suite *s = control_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} diff --git a/tests/unit/check_flexnbd.c b/tests/unit/check_flexnbd.c index bff82e4..6c45814 100644 --- a/tests/unit/check_flexnbd.c +++ b/tests/unit/check_flexnbd.c @@ -3,42 +3,38 @@ #include -START_TEST( test_listening_assigns_sock ) +START_TEST(test_listening_assigns_sock) { - struct flexnbd * flexnbd = flexnbd_create_listening( - "127.0.0.1", - "4777", - "fakefile", - "fakesock", - 0, - 0, - NULL ); - fail_if( NULL == flexnbd->control->socket_name, "No socket was copied" ); + struct flexnbd *flexnbd = flexnbd_create_listening("127.0.0.1", + "4777", + "fakefile", + "fakesock", + 0, + 0, + NULL); + fail_if(NULL == flexnbd->control->socket_name, "No socket was copied"); } -END_TEST - -Suite *flexnbd_suite(void) +END_TEST Suite * flexnbd_suite(void) { - Suite *s = suite_create("flexnbd"); + Suite *s = suite_create("flexnbd"); - TCase *tc_create = tcase_create("create"); + TCase *tc_create = tcase_create("create"); - tcase_add_test(tc_create, test_listening_assigns_sock); - suite_add_tcase( s, tc_create ); + tcase_add_test(tc_create, test_listening_assigns_sock); + suite_add_tcase(s, tc_create); - return s; + return s; } int main(void) { - int number_failed; - - Suite *s = flexnbd_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; -} + int number_failed; + Suite *s = flexnbd_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} diff --git a/tests/unit/check_flexthread.c b/tests/unit/check_flexthread.c index 092ab5b..d6535a9 100644 --- a/tests/unit/check_flexthread.c +++ b/tests/unit/check_flexthread.c @@ -4,59 +4,57 @@ #include -START_TEST( test_mutex_create ) +START_TEST(test_mutex_create) { - struct flexthread_mutex * ftm = flexthread_mutex_create(); - NULLCHECK( ftm ); - flexthread_mutex_destroy( ftm ); + struct flexthread_mutex *ftm = flexthread_mutex_create(); + NULLCHECK(ftm); + flexthread_mutex_destroy(ftm); } -END_TEST - -START_TEST( test_mutex_lock ) +END_TEST START_TEST(test_mutex_lock) { - struct flexthread_mutex * ftm = flexthread_mutex_create(); + struct flexthread_mutex *ftm = flexthread_mutex_create(); - fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held before lock" ); - flexthread_mutex_lock( ftm ); - fail_unless( flexthread_mutex_held( ftm ), "Flexthread_mutex is not held inside lock" ); - flexthread_mutex_unlock( ftm ); - fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held after unlock" ); + fail_if(flexthread_mutex_held(ftm), + "Flexthread_mutex is held before lock"); + flexthread_mutex_lock(ftm); + fail_unless(flexthread_mutex_held(ftm), + "Flexthread_mutex is not held inside lock"); + flexthread_mutex_unlock(ftm); + fail_if(flexthread_mutex_held(ftm), + "Flexthread_mutex is held after unlock"); - flexthread_mutex_destroy( ftm ); + flexthread_mutex_destroy(ftm); } -END_TEST - -Suite* flexthread_suite(void) +END_TEST Suite * flexthread_suite(void) { - Suite *s = suite_create("flexthread"); - TCase *tc_create = tcase_create("create"); - TCase *tc_destroy = tcase_create("destroy"); + Suite *s = suite_create("flexthread"); + TCase *tc_create = tcase_create("create"); + TCase *tc_destroy = tcase_create("destroy"); - tcase_add_test( tc_create, test_mutex_create ); - tcase_add_test( tc_create, test_mutex_lock ); + tcase_add_test(tc_create, test_mutex_create); + tcase_add_test(tc_create, test_mutex_lock); - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_destroy); + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_destroy); - return s; + return s; } int main(void) { #ifdef DEBUG - log_level = 0; + log_level = 0; #else - log_level = 2; + log_level = 2; #endif - int number_failed; - Suite *s = flexthread_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - log_level = 0; - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = flexthread_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + log_level = 0; + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_ioutil.c b/tests/unit/check_ioutil.c index b1f26a5..dbe75ab 100644 --- a/tests/unit/check_ioutil.c +++ b/tests/unit/check_ioutil.c @@ -2,133 +2,125 @@ #include -START_TEST( test_read_until_newline_returns_line_length_plus_null ) +START_TEST(test_read_until_newline_returns_line_length_plus_null) { - int fds[2]; - int nread; - char buf[5] = {0}; - pipe(fds); + int fds[2]; + int nread; + char buf[5] = { 0 }; + pipe(fds); - write( fds[1], "1234\n", 5 ); - - nread = read_until_newline( fds[0], buf, 5 ); + write(fds[1], "1234\n", 5); - ck_assert_int_eq( 5, nread ); + nread = read_until_newline(fds[0], buf, 5); + + ck_assert_int_eq(5, nread); } -END_TEST - -START_TEST( test_read_until_newline_inserts_null ) +END_TEST START_TEST(test_read_until_newline_inserts_null) { - int fds[2]; - int nread; - char buf[5] = {0}; - pipe(fds); + int fds[2]; + int nread; + char buf[5] = { 0 }; + pipe(fds); - write( fds[1], "1234\n", 5 ); - - nread = read_until_newline( fds[0], buf, 5 ); + write(fds[1], "1234\n", 5); - ck_assert_int_eq( '\0', buf[4] ); + nread = read_until_newline(fds[0], buf, 5); + + ck_assert_int_eq('\0', buf[4]); } -END_TEST - -START_TEST( test_read_empty_line_inserts_null ) +END_TEST START_TEST(test_read_empty_line_inserts_null) { - int fds[2]; - int nread; - char buf[5] = {0}; - pipe(fds); + int fds[2]; + int nread; + char buf[5] = { 0 }; + pipe(fds); - write( fds[1], "\n", 1 ); - nread = read_until_newline( fds[0], buf, 1 ); + write(fds[1], "\n", 1); + nread = read_until_newline(fds[0], buf, 1); - ck_assert_int_eq( '\0', buf[0] ); - ck_assert_int_eq( 1, nread ); + ck_assert_int_eq('\0', buf[0]); + ck_assert_int_eq(1, nread); } -END_TEST - -START_TEST( test_read_eof_returns_err ) +END_TEST START_TEST(test_read_eof_returns_err) { - int fds[2]; - int nread; - char buf[5] = {0}; - pipe( fds ); + int fds[2]; + int nread; + char buf[5] = { 0 }; + pipe(fds); - close( fds[1] ); - nread = read_until_newline( fds[0], buf, 5 ); + close(fds[1]); + nread = read_until_newline(fds[0], buf, 5); - ck_assert_int_eq( -1, nread ); + ck_assert_int_eq(-1, nread); } -END_TEST - -START_TEST( test_read_eof_fills_line ) +END_TEST START_TEST(test_read_eof_fills_line) { - int fds[2]; - int nread; - char buf[5] = {0}; - pipe(fds); + int fds[2]; + int nread; + char buf[5] = { 0 }; + pipe(fds); - write( fds[1], "1234", 4 ); - close( fds[1] ); - nread = read_until_newline( fds[0], buf, 5 ); + write(fds[1], "1234", 4); + close(fds[1]); + nread = read_until_newline(fds[0], buf, 5); - ck_assert_int_eq( -1, nread ); - ck_assert_int_eq( '4', buf[3] ); + ck_assert_int_eq(-1, nread); + ck_assert_int_eq('4', buf[3]); } -END_TEST - -START_TEST( test_read_lines_until_blankline ) +END_TEST START_TEST(test_read_lines_until_blankline) { - char **lines = NULL; - int fds[2]; - int nlines; - pipe( fds ); + char **lines = NULL; + int fds[2]; + int nlines; + pipe(fds); - write( fds[1], "a\nb\nc\n\n", 7 ); + write(fds[1], "a\nb\nc\n\n", 7); - nlines = read_lines_until_blankline( fds[0], 256, &lines ); + nlines = read_lines_until_blankline(fds[0], 256, &lines); - ck_assert_int_eq( 3, nlines ); + ck_assert_int_eq(3, nlines); } -END_TEST - -Suite *ioutil_suite(void) +END_TEST Suite * ioutil_suite(void) { - Suite *s = suite_create("ioutil"); + Suite *s = suite_create("ioutil"); - TCase *tc_read_until_newline = tcase_create("read_until_newline"); - TCase *tc_read_lines_until_blankline = tcase_create("read_lines_until_blankline"); + TCase *tc_read_until_newline = tcase_create("read_until_newline"); + TCase *tc_read_lines_until_blankline = + tcase_create("read_lines_until_blankline"); - tcase_add_test(tc_read_until_newline, test_read_until_newline_returns_line_length_plus_null); - tcase_add_test(tc_read_until_newline, test_read_until_newline_inserts_null); - tcase_add_test(tc_read_until_newline, test_read_empty_line_inserts_null); - tcase_add_test(tc_read_until_newline, test_read_eof_returns_err); - tcase_add_test(tc_read_until_newline, test_read_eof_fills_line ); + tcase_add_test(tc_read_until_newline, + test_read_until_newline_returns_line_length_plus_null); + tcase_add_test(tc_read_until_newline, + test_read_until_newline_inserts_null); + tcase_add_test(tc_read_until_newline, + test_read_empty_line_inserts_null); + tcase_add_test(tc_read_until_newline, test_read_eof_returns_err); + tcase_add_test(tc_read_until_newline, test_read_eof_fills_line); - tcase_add_test(tc_read_lines_until_blankline, test_read_lines_until_blankline ); + tcase_add_test(tc_read_lines_until_blankline, + test_read_lines_until_blankline); - suite_add_tcase(s, tc_read_until_newline); - suite_add_tcase(s, tc_read_lines_until_blankline); + suite_add_tcase(s, tc_read_until_newline); + suite_add_tcase(s, tc_read_lines_until_blankline); - return s; + return s; } int main(void) { - int number_failed; - - Suite *s = ioutil_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; -} + int number_failed; + Suite *s = ioutil_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} diff --git a/tests/unit/check_mbox.c b/tests/unit/check_mbox.c index 5399531..0d6c3d3 100644 --- a/tests/unit/check_mbox.c +++ b/tests/unit/check_mbox.c @@ -4,83 +4,76 @@ #include #include -START_TEST( test_allocs_cvar ) +START_TEST(test_allocs_cvar) { - struct mbox * mbox = mbox_create(); - fail_if( NULL == mbox, "Nothing allocated" ); + struct mbox *mbox = mbox_create(); + fail_if(NULL == mbox, "Nothing allocated"); - pthread_cond_t cond_zero; - /* A freshly inited pthread_cond_t is set to {0} */ - memset( &cond_zero, 'X', sizeof( cond_zero ) ); - fail_if( memcmp( &cond_zero, &mbox->filled_cond, sizeof( cond_zero ) ) == 0 , - "Condition variable not allocated" ); - fail_if( memcmp( &cond_zero, &mbox->emptied_cond, sizeof( cond_zero ) ) == 0 , - "Condition variable not allocated" ); + pthread_cond_t cond_zero; + /* A freshly inited pthread_cond_t is set to {0} */ + memset(&cond_zero, 'X', sizeof(cond_zero)); + fail_if(memcmp(&cond_zero, &mbox->filled_cond, sizeof(cond_zero)) == 0, + "Condition variable not allocated"); + fail_if(memcmp(&cond_zero, &mbox->emptied_cond, sizeof(cond_zero)) == + 0, "Condition variable not allocated"); } -END_TEST - -START_TEST( test_post_stores_value ) +END_TEST START_TEST(test_post_stores_value) { - struct mbox * mbox = mbox_create(); - - void * deadbeef = (void *)0xDEADBEEF; - mbox_post( mbox, deadbeef ); + struct mbox *mbox = mbox_create(); - fail_unless( deadbeef == mbox_contents( mbox ), - "Contents were not posted" ); + void *deadbeef = (void *) 0xDEADBEEF; + mbox_post(mbox, deadbeef); + + fail_unless(deadbeef == mbox_contents(mbox), + "Contents were not posted"); } -END_TEST - -void * mbox_receive_runner( void * mbox_uncast ) +END_TEST void *mbox_receive_runner(void *mbox_uncast) { - struct mbox * mbox = (struct mbox *)mbox_uncast; - void * contents = NULL; + struct mbox *mbox = (struct mbox *) mbox_uncast; + void *contents = NULL; - contents = mbox_receive( mbox ); - return contents; + contents = mbox_receive(mbox); + return contents; } -START_TEST( test_receive_blocks_until_post ) +START_TEST(test_receive_blocks_until_post) { - struct mbox * mbox = mbox_create(); - pthread_t receiver; - pthread_create( &receiver, NULL, mbox_receive_runner, mbox ); - - void * deadbeef = (void *)0xDEADBEEF; - void * retval =NULL; - usleep(10000); - fail_unless( EBUSY == pthread_tryjoin_np( receiver, &retval ), - "Receiver thread wasn't blocked"); + struct mbox *mbox = mbox_create(); + pthread_t receiver; + pthread_create(&receiver, NULL, mbox_receive_runner, mbox); - mbox_post( mbox, deadbeef ); - fail_unless( 0 == pthread_join( receiver, &retval ), - "Failed to join the receiver thread" ); - fail_unless( retval == deadbeef, - "Return value was wrong" ); + void *deadbeef = (void *) 0xDEADBEEF; + void *retval = NULL; + usleep(10000); + fail_unless(EBUSY == pthread_tryjoin_np(receiver, &retval), + "Receiver thread wasn't blocked"); + + mbox_post(mbox, deadbeef); + fail_unless(0 == pthread_join(receiver, &retval), + "Failed to join the receiver thread"); + fail_unless(retval == deadbeef, "Return value was wrong"); } -END_TEST - -Suite* mbox_suite(void) +END_TEST Suite * mbox_suite(void) { - Suite *s = suite_create("mbox"); - TCase *tc_create = tcase_create("create"); - TCase *tc_post = tcase_create("post"); + Suite *s = suite_create("mbox"); + TCase *tc_create = tcase_create("create"); + TCase *tc_post = tcase_create("post"); - tcase_add_test(tc_create, test_allocs_cvar); + tcase_add_test(tc_create, test_allocs_cvar); - tcase_add_test( tc_post, test_post_stores_value ); - tcase_add_test( tc_post, test_receive_blocks_until_post); + tcase_add_test(tc_post, test_post_stores_value); + tcase_add_test(tc_post, test_receive_blocks_until_post); - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_post); + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_post); - return s; + return s; } @@ -88,17 +81,16 @@ Suite* mbox_suite(void) int main(void) { #ifdef DEBUG - log_level = 0; + log_level = 0; #else - log_level = 2; + log_level = 2; #endif - int number_failed; - Suite *s = mbox_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - log_level = 0; - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = mbox_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + log_level = 0; + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_nbdtypes.c b/tests/unit/check_nbdtypes.c index 9124063..b1ee034 100644 --- a/tests/unit/check_nbdtypes.c +++ b/tests/unit/check_nbdtypes.c @@ -4,257 +4,246 @@ START_TEST(test_init_passwd) { - struct nbd_init_raw init_raw; - struct nbd_init init; + struct nbd_init_raw init_raw; + struct nbd_init init; - memcpy( init_raw.passwd, INIT_PASSWD, 8 ); - - nbd_r2h_init( &init_raw, &init ); - memset( init_raw.passwd, 0, 8 ); - nbd_h2r_init( &init, &init_raw ); - - fail_unless( memcmp( init.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied." ); - fail_unless( memcmp( init_raw.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied back." ); + memcpy(init_raw.passwd, INIT_PASSWD, 8); + + nbd_r2h_init(&init_raw, &init); + memset(init_raw.passwd, 0, 8); + nbd_h2r_init(&init, &init_raw); + + fail_unless(memcmp(init.passwd, INIT_PASSWD, 8) == 0, + "The password was not copied."); + fail_unless(memcmp(init_raw.passwd, INIT_PASSWD, 8) == 0, + "The password was not copied back."); } -END_TEST - -START_TEST(test_init_magic) +END_TEST START_TEST(test_init_magic) { - struct nbd_init_raw init_raw; - struct nbd_init init; + struct nbd_init_raw init_raw; + struct nbd_init init; - init_raw.magic = 12345; - nbd_r2h_init( &init_raw, &init ); - fail_unless( be64toh( 12345 ) == init.magic, "Magic was not converted." ); + init_raw.magic = 12345; + nbd_r2h_init(&init_raw, &init); + fail_unless(be64toh(12345) == init.magic, "Magic was not converted."); - init.magic = 67890; - nbd_h2r_init( &init, &init_raw ); - fail_unless( htobe64( 67890 ) == init_raw.magic, "Magic was not converted back." ); + init.magic = 67890; + nbd_h2r_init(&init, &init_raw); + fail_unless(htobe64(67890) == init_raw.magic, + "Magic was not converted back."); } -END_TEST - -START_TEST(test_init_size) +END_TEST START_TEST(test_init_size) { - struct nbd_init_raw init_raw; - struct nbd_init init; + struct nbd_init_raw init_raw; + struct nbd_init init; - init_raw.size = 12345; - nbd_r2h_init( &init_raw, &init ); - fail_unless( be64toh( 12345 ) == init.size, "Size was not converted." ); + init_raw.size = 12345; + nbd_r2h_init(&init_raw, &init); + fail_unless(be64toh(12345) == init.size, "Size was not converted."); - init.size = 67890; - nbd_h2r_init( &init, &init_raw ); - fail_unless( htobe64( 67890 ) == init_raw.size, "Size was not converted back." ); + init.size = 67890; + nbd_h2r_init(&init, &init_raw); + fail_unless(htobe64(67890) == init_raw.size, + "Size was not converted back."); } -END_TEST - -START_TEST(test_request_magic ) +END_TEST START_TEST(test_request_magic) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - request_raw.magic = 12345; - nbd_r2h_request( &request_raw, &request ); - fail_unless( be32toh( 12345 ) == request.magic, "Magic was not converted." ); + request_raw.magic = 12345; + nbd_r2h_request(&request_raw, &request); + fail_unless(be32toh(12345) == request.magic, + "Magic was not converted."); - request.magic = 67890; - nbd_h2r_request( &request, &request_raw ); - fail_unless( htobe32( 67890 ) == request_raw.magic, "Magic was not converted back." ); + request.magic = 67890; + nbd_h2r_request(&request, &request_raw); + fail_unless(htobe32(67890) == request_raw.magic, + "Magic was not converted back."); } -END_TEST -START_TEST(test_request_type) +END_TEST START_TEST(test_request_type) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - request_raw.type = 123; - nbd_r2h_request( &request_raw, &request ); - fail_unless( be16toh( 123 ) == request.type, "Type was not converted." ); + request_raw.type = 123; + nbd_r2h_request(&request_raw, &request); + fail_unless(be16toh(123) == request.type, "Type was not converted."); - request.type = 234; - nbd_h2r_request( &request, &request_raw ); - fail_unless( htobe16( 234 ) == request_raw.type, "Type was not converted back." ); + request.type = 234; + nbd_h2r_request(&request, &request_raw); + fail_unless(htobe16(234) == request_raw.type, + "Type was not converted back."); } -END_TEST - - -START_TEST(test_request_flags) +END_TEST START_TEST(test_request_flags) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - request_raw.flags = 123; - nbd_r2h_request( &request_raw, &request ); - fail_unless( be16toh( 123 ) == request.flags, "Flags were not converted." ); + request_raw.flags = 123; + nbd_r2h_request(&request_raw, &request); + fail_unless(be16toh(123) == request.flags, + "Flags were not converted."); - request.flags = 234; - nbd_h2r_request( &request, &request_raw ); - fail_unless( htobe16( 234 ) == request_raw.flags, "Flags were not converted back." ); + request.flags = 234; + nbd_h2r_request(&request, &request_raw); + fail_unless(htobe16(234) == request_raw.flags, + "Flags were not converted back."); } -END_TEST - - -START_TEST(test_request_handle) +END_TEST START_TEST(test_request_handle) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - memcpy( request_raw.handle.b, "MYHANDLE", 8 ); - - nbd_r2h_request( &request_raw, &request ); - request_raw.handle.w = 0; - nbd_h2r_request( &request, &request_raw ); - - fail_unless( memcmp( request.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." ); - fail_unless( memcmp( request_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." ); + memcpy(request_raw.handle.b, "MYHANDLE", 8); + + nbd_r2h_request(&request_raw, &request); + request_raw.handle.w = 0; + nbd_h2r_request(&request, &request_raw); + + fail_unless(memcmp(request.handle.b, "MYHANDLE", 8) == 0, + "The handle was not copied."); + fail_unless(memcmp(request_raw.handle.b, "MYHANDLE", 8) == 0, + "The handle was not copied back."); } -END_TEST - - -START_TEST(test_request_from ) +END_TEST START_TEST(test_request_from) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - request_raw.from = 12345; - nbd_r2h_request( &request_raw, &request ); - fail_unless( be64toh( 12345 ) == request.from, "From was not converted." ); + request_raw.from = 12345; + nbd_r2h_request(&request_raw, &request); + fail_unless(be64toh(12345) == request.from, "From was not converted."); - request.from = 67890; - nbd_h2r_request( &request, &request_raw ); - fail_unless( htobe64( 67890 ) == request_raw.from, "From was not converted back." ); + request.from = 67890; + nbd_h2r_request(&request, &request_raw); + fail_unless(htobe64(67890) == request_raw.from, + "From was not converted back."); } -END_TEST - - -START_TEST(test_request_len ) +END_TEST START_TEST(test_request_len) { - struct nbd_request_raw request_raw; - struct nbd_request request; + struct nbd_request_raw request_raw; + struct nbd_request request; - request_raw.len = 12345; - nbd_r2h_request( &request_raw, &request ); - fail_unless( be32toh( 12345 ) == request.len, "Type was not converted." ); + request_raw.len = 12345; + nbd_r2h_request(&request_raw, &request); + fail_unless(be32toh(12345) == request.len, "Type was not converted."); - request.len = 67890; - nbd_h2r_request( &request, &request_raw ); - fail_unless( htobe32( 67890 ) == request_raw.len, "Type was not converted back." ); + request.len = 67890; + nbd_h2r_request(&request, &request_raw); + fail_unless(htobe32(67890) == request_raw.len, + "Type was not converted back."); } -END_TEST - -START_TEST(test_reply_magic ) +END_TEST START_TEST(test_reply_magic) { - struct nbd_reply_raw reply_raw; - struct nbd_reply reply; + struct nbd_reply_raw reply_raw; + struct nbd_reply reply; - reply_raw.magic = 12345; - nbd_r2h_reply( &reply_raw, &reply ); - fail_unless( be32toh( 12345 ) == reply.magic, "Magic was not converted." ); + reply_raw.magic = 12345; + nbd_r2h_reply(&reply_raw, &reply); + fail_unless(be32toh(12345) == reply.magic, "Magic was not converted."); - reply.magic = 67890; - nbd_h2r_reply( &reply, &reply_raw ); - fail_unless( htobe32( 67890 ) == reply_raw.magic, "Magic was not converted back." ); + reply.magic = 67890; + nbd_h2r_reply(&reply, &reply_raw); + fail_unless(htobe32(67890) == reply_raw.magic, + "Magic was not converted back."); } -END_TEST - -START_TEST(test_reply_error ) +END_TEST START_TEST(test_reply_error) { - struct nbd_reply_raw reply_raw; - struct nbd_reply reply; + struct nbd_reply_raw reply_raw; + struct nbd_reply reply; - reply_raw.error = 12345; - nbd_r2h_reply( &reply_raw, &reply ); - fail_unless( be32toh( 12345 ) == reply.error, "Error was not converted." ); + reply_raw.error = 12345; + nbd_r2h_reply(&reply_raw, &reply); + fail_unless(be32toh(12345) == reply.error, "Error was not converted."); - reply.error = 67890; - nbd_h2r_reply( &reply, &reply_raw ); - fail_unless( htobe32( 67890 ) == reply_raw.error, "Error was not converted back." ); + reply.error = 67890; + nbd_h2r_reply(&reply, &reply_raw); + fail_unless(htobe32(67890) == reply_raw.error, + "Error was not converted back."); } -END_TEST -START_TEST(test_reply_handle) +END_TEST START_TEST(test_reply_handle) { - struct nbd_reply_raw reply_raw; - struct nbd_reply reply; + struct nbd_reply_raw reply_raw; + struct nbd_reply reply; - memcpy( reply_raw.handle.b, "MYHANDLE", 8 ); - - nbd_r2h_reply( &reply_raw, &reply ); - reply_raw.handle.w = 0; - nbd_h2r_reply( &reply, &reply_raw ); - - fail_unless( memcmp( reply.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." ); - fail_unless( memcmp( reply_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." ); + memcpy(reply_raw.handle.b, "MYHANDLE", 8); + + nbd_r2h_reply(&reply_raw, &reply); + reply_raw.handle.w = 0; + nbd_h2r_reply(&reply, &reply_raw); + + fail_unless(memcmp(reply.handle.b, "MYHANDLE", 8) == 0, + "The handle was not copied."); + fail_unless(memcmp(reply_raw.handle.b, "MYHANDLE", 8) == 0, + "The handle was not copied back."); } -END_TEST - -START_TEST( test_convert_from ) +END_TEST START_TEST(test_convert_from) { - /* Check that we can correctly pull numbers out of an - * nbd_request_raw */ - struct nbd_request_raw request_raw; - struct nbd_request request; + /* Check that we can correctly pull numbers out of an + * nbd_request_raw */ + struct nbd_request_raw request_raw; + struct nbd_request request; - uint64_t target = 0x8000000000000000; + uint64_t target = 0x8000000000000000; - /* this is stored big-endian */ - request_raw.from = htobe64(target); + /* this is stored big-endian */ + request_raw.from = htobe64(target); - /* We expect this to convert big-endian to the host format */ - nbd_r2h_request( &request_raw, &request ); + /* We expect this to convert big-endian to the host format */ + nbd_r2h_request(&request_raw, &request); - fail_unless( target == request.from, "from was wrong" ); -} -END_TEST + fail_unless(target == request.from, "from was wrong"); +} -Suite *nbdtypes_suite(void) +END_TEST Suite * nbdtypes_suite(void) { - Suite *s = suite_create( "nbdtypes" ); - TCase *tc_init = tcase_create( "nbd_init" ); - TCase *tc_request = tcase_create( "nbd_request" ); - TCase *tc_reply = tcase_create( "nbd_reply" ); + Suite *s = suite_create("nbdtypes"); + TCase *tc_init = tcase_create("nbd_init"); + TCase *tc_request = tcase_create("nbd_request"); + TCase *tc_reply = tcase_create("nbd_reply"); - tcase_add_test( tc_init, test_init_passwd ); - tcase_add_test( tc_init, test_init_magic ); - tcase_add_test( tc_init, test_init_size ); - tcase_add_test( tc_request, test_request_magic ); - tcase_add_test( tc_request, test_request_type ); - tcase_add_test( tc_request, test_request_handle ); - tcase_add_test( tc_request, test_request_from ); - tcase_add_test( tc_request, test_request_len ); - tcase_add_test( tc_request, test_convert_from ); - tcase_add_test( tc_reply, test_reply_magic ); - tcase_add_test( tc_reply, test_reply_error ); - tcase_add_test( tc_reply, test_reply_handle ); + tcase_add_test(tc_init, test_init_passwd); + tcase_add_test(tc_init, test_init_magic); + tcase_add_test(tc_init, test_init_size); + tcase_add_test(tc_request, test_request_magic); + tcase_add_test(tc_request, test_request_type); + tcase_add_test(tc_request, test_request_handle); + tcase_add_test(tc_request, test_request_from); + tcase_add_test(tc_request, test_request_len); + tcase_add_test(tc_request, test_convert_from); + tcase_add_test(tc_reply, test_reply_magic); + tcase_add_test(tc_reply, test_reply_error); + tcase_add_test(tc_reply, test_reply_handle); - suite_add_tcase( s, tc_init ); - suite_add_tcase( s, tc_request ); - suite_add_tcase( s, tc_reply ); + suite_add_tcase(s, tc_init); + suite_add_tcase(s, tc_request); + suite_add_tcase(s, tc_reply); - return s; + return s; } int main(void) { - int number_failed; - Suite *s = nbdtypes_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = nbdtypes_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_parse.c b/tests/unit/check_parse.c index b30ee6d..3d9130a 100644 --- a/tests/unit/check_parse.c +++ b/tests/unit/check_parse.c @@ -3,45 +3,41 @@ #include -START_TEST( test_can_parse_ip_address_twice ) +START_TEST(test_can_parse_ip_address_twice) { - char ip_address[] = "127.0.0.1"; - struct sockaddr saddr; + char ip_address[] = "127.0.0.1"; + struct sockaddr saddr; - parse_ip_to_sockaddr( &saddr, ip_address ); - parse_ip_to_sockaddr( &saddr, ip_address ); + parse_ip_to_sockaddr(&saddr, ip_address); + parse_ip_to_sockaddr(&saddr, ip_address); } -END_TEST - - -Suite* parse_suite(void) +END_TEST Suite * parse_suite(void) { - Suite *s = suite_create("parse"); - TCase *tc_create = tcase_create("ip_to_sockaddr"); + Suite *s = suite_create("parse"); + TCase *tc_create = tcase_create("ip_to_sockaddr"); - tcase_add_test(tc_create, test_can_parse_ip_address_twice); + tcase_add_test(tc_create, test_can_parse_ip_address_twice); - suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_create); - return s; + return s; } #ifdef DEBUG -# define LOG_LEVEL 0 +#define LOG_LEVEL 0 #else -# define LOG_LEVEL 2 +#define LOG_LEVEL 2 #endif int main(void) { - log_level = LOG_LEVEL; - int number_failed; - Suite *s = parse_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + log_level = LOG_LEVEL; + int number_failed; + Suite *s = parse_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_readwrite.c b/tests/unit/check_readwrite.c index c158d7b..9f20bf9 100644 --- a/tests/unit/check_readwrite.c +++ b/tests/unit/check_readwrite.c @@ -21,173 +21,169 @@ -int fd_read_request( int, struct nbd_request_raw *); -int fd_write_reply( int, uint64_t, int ); +int fd_read_request(int, struct nbd_request_raw *); +int fd_write_reply(int, uint64_t, int); int marker; -void error_marker(void * unused __attribute__((unused)), - int fatal __attribute__((unused))) +void error_marker(void *unused __attribute__ ((unused)), + int fatal __attribute__ ((unused))) { - marker = 1; - return; + marker = 1; + return; } struct respond { - int sock_fds[2]; // server end - int do_fail; - pthread_t thread_id; - pthread_attr_t thread_attr; - struct nbd_request received; + int sock_fds[2]; // server end + int do_fail; + pthread_t thread_id; + pthread_attr_t thread_attr; + struct nbd_request received; }; -void * responder( void *respond_uncast ) +void *responder(void *respond_uncast) { - struct respond * resp = (struct respond *) respond_uncast; - int sock_fd = resp->sock_fds[1]; - struct nbd_request_raw request_raw; - uint64_t wrong_handle = 0x80; + struct respond *resp = (struct respond *) respond_uncast; + int sock_fd = resp->sock_fds[1]; + struct nbd_request_raw request_raw; + uint64_t wrong_handle = 0x80; - if( fd_read_request( sock_fd, &request_raw ) == -1){ - fprintf(stderr, "Problem with fd_read_request\n"); + if (fd_read_request(sock_fd, &request_raw) == -1) { + fprintf(stderr, "Problem with fd_read_request\n"); + } else { + nbd_r2h_request(&request_raw, &resp->received); + if (resp->do_fail) { + fd_write_reply(sock_fd, wrong_handle, 0); } else { - nbd_r2h_request( &request_raw, &resp->received); - if (resp->do_fail){ - fd_write_reply( sock_fd, wrong_handle, 0 ); - } - else { - fd_write_reply( sock_fd, resp->received.handle.w, 0 ); - } - write( sock_fd, "12345678", 8 ); + fd_write_reply(sock_fd, resp->received.handle.w, 0); } - return NULL; + write(sock_fd, "12345678", 8); + } + return NULL; } -struct respond * respond_create( int do_fail ) +struct respond *respond_create(int do_fail) { - struct respond * respond = (struct respond *)calloc( 1, sizeof( struct respond ) ); - socketpair( PF_UNIX, SOCK_STREAM, 0, respond->sock_fds ); - respond->do_fail = do_fail; + struct respond *respond = + (struct respond *) calloc(1, sizeof(struct respond)); + socketpair(PF_UNIX, SOCK_STREAM, 0, respond->sock_fds); + respond->do_fail = do_fail; - pthread_attr_init( &respond->thread_attr ); - pthread_create( &respond->thread_id, &respond->thread_attr, responder, respond ); + pthread_attr_init(&respond->thread_attr); + pthread_create(&respond->thread_id, &respond->thread_attr, responder, + respond); - return respond; + return respond; } -void respond_destroy( struct respond * respond ){ - NULLCHECK( respond ); - - pthread_join( respond->thread_id, NULL ); - pthread_attr_destroy( &respond->thread_attr ); - - close( respond->sock_fds[0] ); - close( respond->sock_fds[1] ); - free( respond ); -} - - -void * reader( void * nothing __attribute__((unused))) +void respond_destroy(struct respond *respond) { - DECLARE_ERROR_CONTEXT( error_context ); - error_set_handler( (cleanup_handler *)error_marker, error_context ); + NULLCHECK(respond); - struct respond * respond = respond_create( 1 ); - int devnull = open("/dev/null", O_WRONLY); - char outbuf[8] = {0}; + pthread_join(respond->thread_id, NULL); + pthread_attr_destroy(&respond->thread_attr); - socket_nbd_read( respond->sock_fds[0], 0, 8, devnull, outbuf, 1 ); - - return NULL; + close(respond->sock_fds[0]); + close(respond->sock_fds[1]); + free(respond); } -START_TEST( test_rejects_mismatched_handle ) + +void *reader(void *nothing __attribute__ ((unused))) +{ + DECLARE_ERROR_CONTEXT(error_context); + error_set_handler((cleanup_handler *) error_marker, error_context); + + struct respond *respond = respond_create(1); + int devnull = open("/dev/null", O_WRONLY); + char outbuf[8] = { 0 }; + + socket_nbd_read(respond->sock_fds[0], 0, 8, devnull, outbuf, 1); + + return NULL; +} + +START_TEST(test_rejects_mismatched_handle) { - error_init(); - pthread_t reader_thread; + error_init(); + pthread_t reader_thread; - log_level=5; - - marker = 0; - pthread_create( &reader_thread, NULL, reader, NULL ); - FATAL_UNLESS( 0 == pthread_join( reader_thread, NULL ), - "pthread_join failed"); - - log_level=2; + log_level = 5; - fail_unless( marker == 1, "Error handler wasn't called" ); + marker = 0; + pthread_create(&reader_thread, NULL, reader, NULL); + FATAL_UNLESS(0 == pthread_join(reader_thread, NULL), + "pthread_join failed"); + + log_level = 2; + + fail_unless(marker == 1, "Error handler wasn't called"); } -END_TEST - -START_TEST( test_accepts_matched_handle ) +END_TEST START_TEST(test_accepts_matched_handle) { - struct respond * respond = respond_create( 0 ); + struct respond *respond = respond_create(0); - int devnull = open("/dev/null", O_WRONLY); - char outbuf[8] = {0}; + int devnull = open("/dev/null", O_WRONLY); + char outbuf[8] = { 0 }; - socket_nbd_read( respond->sock_fds[0], 0, 8, devnull, outbuf, 1 ); + socket_nbd_read(respond->sock_fds[0], 0, 8, devnull, outbuf, 1); - respond_destroy( respond ); + respond_destroy(respond); } -END_TEST - -START_TEST( test_disconnect_doesnt_read_reply ) +END_TEST START_TEST(test_disconnect_doesnt_read_reply) { - struct respond * respond = respond_create( 1 ); + struct respond *respond = respond_create(1); - socket_nbd_disconnect( respond->sock_fds[0] ); + socket_nbd_disconnect(respond->sock_fds[0]); - respond_destroy( respond ); + respond_destroy(respond); } -END_TEST - -Suite* readwrite_suite(void) +END_TEST Suite * readwrite_suite(void) { - Suite *s = suite_create("readwrite"); - TCase *tc_transfer = tcase_create("entrust"); - TCase *tc_disconnect = tcase_create("disconnect"); + Suite *s = suite_create("readwrite"); + TCase *tc_transfer = tcase_create("entrust"); + TCase *tc_disconnect = tcase_create("disconnect"); - tcase_add_test(tc_transfer, test_rejects_mismatched_handle); - tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0); + tcase_add_test(tc_transfer, test_rejects_mismatched_handle); + tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0); - /* This test is a little funny. We respond with a dodgy handle - * and check that this *doesn't* cause a message rejection, - * because we want to know that the sender won't even try to - * read the response. - */ - tcase_add_exit_test( tc_disconnect, test_disconnect_doesnt_read_reply,0 ); + /* This test is a little funny. We respond with a dodgy handle + * and check that this *doesn't* cause a message rejection, + * because we want to know that the sender won't even try to + * read the response. + */ + tcase_add_exit_test(tc_disconnect, test_disconnect_doesnt_read_reply, + 0); - suite_add_tcase(s, tc_transfer); - suite_add_tcase(s, tc_disconnect); + suite_add_tcase(s, tc_transfer); + suite_add_tcase(s, tc_disconnect); - return s; + return s; } #ifdef DEBUG -# define LOG_LEVEL 0 +#define LOG_LEVEL 0 #else -# define LOG_LEVEL 2 +#define LOG_LEVEL 2 #endif int main(void) { - log_level = LOG_LEVEL; - int number_failed; - Suite *s = readwrite_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - log_level = 0; - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + log_level = LOG_LEVEL; + int number_failed; + Suite *s = readwrite_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + log_level = 0; + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_self_pipe.c b/tests/unit/check_self_pipe.c index c3026c9..fcc783f 100644 --- a/tests/unit/check_self_pipe.c +++ b/tests/unit/check_self_pipe.c @@ -9,190 +9,180 @@ #include "self_pipe.h" -START_TEST( test_opens_pipe ) +START_TEST(test_opens_pipe) { - struct self_pipe* sig; - char buf[] = " "; + struct self_pipe *sig; + char buf[] = " "; - sig = self_pipe_create(); + sig = self_pipe_create(); - write( sig->write_fd, "1", 1 ); - read( sig->read_fd, buf, 1 ); + write(sig->write_fd, "1", 1); + read(sig->read_fd, buf, 1); - fail_unless( buf[0] == '1', "Pipe does not seem to be open;" ); - self_pipe_destroy( sig ); -} -END_TEST - - -void * signal_thread( void * thing ) -{ - struct self_pipe *sig = (struct self_pipe *)thing; - usleep( 100000 ); - self_pipe_signal( sig ); - return NULL; + fail_unless(buf[0] == '1', "Pipe does not seem to be open;"); + self_pipe_destroy(sig); } -pthread_t start_signal_thread( struct self_pipe *sig ) +END_TEST void *signal_thread(void *thing) { - pthread_attr_t attr; - pthread_t thread_id; + struct self_pipe *sig = (struct self_pipe *) thing; + usleep(100000); + self_pipe_signal(sig); + return NULL; +} - pthread_attr_init( &attr ); - pthread_create( &thread_id, &attr, signal_thread, sig ); - pthread_attr_destroy( &attr ); +pthread_t start_signal_thread(struct self_pipe * sig) +{ + pthread_attr_t attr; + pthread_t thread_id; - return thread_id; + pthread_attr_init(&attr); + pthread_create(&thread_id, &attr, signal_thread, sig); + pthread_attr_destroy(&attr); + + return thread_id; } -START_TEST( test_signals ) +START_TEST(test_signals) { - struct self_pipe* sig; - fd_set fds; - pthread_t signal_thread_id; + struct self_pipe *sig; + fd_set fds; + pthread_t signal_thread_id; - sig = self_pipe_create(); + sig = self_pipe_create(); - FD_ZERO( &fds ); - self_pipe_fd_set( sig, &fds ); + FD_ZERO(&fds); + self_pipe_fd_set(sig, &fds); - signal_thread_id = start_signal_thread( sig ); - if ( select( FD_SETSIZE, &fds, NULL, NULL, NULL ) == -1 ) { - fail( strerror(errno) ); + signal_thread_id = start_signal_thread(sig); + if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) == -1) { + fail(strerror(errno)); + } + self_pipe_signal_clear(sig); + + fail_unless(self_pipe_fd_isset(sig, &fds), + "Signalled pipe was not FD_ISSET."); + pthread_join(signal_thread_id, NULL); + + self_pipe_destroy(sig); +} + +END_TEST START_TEST(test_clear_returns_immediately) +{ + struct self_pipe *sig; + sig = self_pipe_create(); + fail_unless(0 == self_pipe_signal_clear(sig), "Wrong clear result."); +} + +END_TEST START_TEST(test_destroy_closes_read_pipe) +{ + struct self_pipe *sig; + ssize_t read_len; + int orig_read_fd; + + sig = self_pipe_create(); + orig_read_fd = sig->read_fd; + self_pipe_destroy(sig); + + while ((read_len = read(orig_read_fd, "", 0)) == -1 && errno == EINTR); + + switch (read_len) { + case 0: + fail("The read fd wasn't closed."); + break; + case -1: + switch (errno) { + case EBADF: + /* This is what we want */ + break; + case EAGAIN: + fail("The read fd wasn't closed."); + break; + default: + fail(strerror(errno)); + break; } - self_pipe_signal_clear( sig ); - - fail_unless( self_pipe_fd_isset( sig, &fds ), "Signalled pipe was not FD_ISSET." ); - pthread_join( signal_thread_id, NULL ); - - self_pipe_destroy( sig ); + break; + default: + fail("The read fd wasn't closed, and had data in it."); + break; + } } -END_TEST - -START_TEST( test_clear_returns_immediately ) +END_TEST START_TEST(test_destroy_closes_write_pipe) { - struct self_pipe *sig; - sig = self_pipe_create(); - fail_unless( 0 == self_pipe_signal_clear( sig ), "Wrong clear result." ); -} -END_TEST + struct self_pipe *sig; + ssize_t write_len; + int orig_write_fd; + sig = self_pipe_create(); + orig_write_fd = sig->write_fd; + self_pipe_destroy(sig); -START_TEST( test_destroy_closes_read_pipe ) -{ - struct self_pipe* sig; - ssize_t read_len; - int orig_read_fd; + while ((write_len = write(orig_write_fd, "", 0)) == -1 + && errno == EINTR); - sig = self_pipe_create(); - orig_read_fd = sig->read_fd; - self_pipe_destroy( sig ); - - while( (read_len = read( orig_read_fd, "", 0 )) == -1 && errno == EINTR ); - - switch( read_len ) { - case 0: - fail("The read fd wasn't closed." ); - break; - case -1: - switch(errno) { - case EBADF: - /* This is what we want */ - break; - case EAGAIN: - fail( "The read fd wasn't closed." ); - break; - default: - fail( strerror( errno ) ); - break; - } - break; - default: - fail( "The read fd wasn't closed, and had data in it." ); - break; + switch (write_len) { + case 0: + fail("The write fd wasn't closed."); + break; + case -1: + switch (errno) { + case EPIPE: + case EBADF: + /* This is what we want */ + break; + case EAGAIN: + fail("The write fd wasn't closed."); + break; + default: + fail(strerror(errno)); + break; } -} -END_TEST - - -START_TEST( test_destroy_closes_write_pipe ) -{ - struct self_pipe * sig; - ssize_t write_len; - int orig_write_fd; - - sig = self_pipe_create(); - orig_write_fd = sig->write_fd; - self_pipe_destroy( sig ); - - while ( ( write_len = write( orig_write_fd, "", 0 ) ) == -1 && errno == EINTR ); - - switch( write_len ) { - case 0: - fail( "The write fd wasn't closed." ); - break; - case -1: - switch( errno ) { - case EPIPE: - case EBADF: - /* This is what we want */ - break; - case EAGAIN: - fail("The write fd wasn't closed." ); - break; - default: - fail( strerror( errno ) ); - break; - } - break; - default: - /* To get here, the write(_,_,0) would have to - * write some bytes. - */ - fail( "The write fd wasn't closed, and something REALLY WEIRD is going on." ); - break; - } - -} -END_TEST - - - -Suite *self_pipe_suite(void) -{ - Suite *s = suite_create("self_pipe"); - - TCase *tc_create = tcase_create("create"); - TCase *tc_signal = tcase_create("signal"); - TCase *tc_destroy = tcase_create("destroy"); - - tcase_add_test(tc_create, test_opens_pipe); - tcase_add_test(tc_signal, test_signals ); - tcase_add_test(tc_signal, test_clear_returns_immediately ); - tcase_add_test(tc_destroy, test_destroy_closes_read_pipe ); - tcase_add_test(tc_destroy, test_destroy_closes_write_pipe ); - /* We don't test that destroy free()'s the self_pipe pointer because - * that'll be caught by valgrind. + break; + default: + /* To get here, the write(_,_,0) would have to + * write some bytes. */ + fail("The write fd wasn't closed, and something REALLY WEIRD is going on."); + break; + } - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_signal); - suite_add_tcase(s, tc_destroy); +} - return s; +END_TEST Suite * self_pipe_suite(void) +{ + Suite *s = suite_create("self_pipe"); + + TCase *tc_create = tcase_create("create"); + TCase *tc_signal = tcase_create("signal"); + TCase *tc_destroy = tcase_create("destroy"); + + tcase_add_test(tc_create, test_opens_pipe); + tcase_add_test(tc_signal, test_signals); + tcase_add_test(tc_signal, test_clear_returns_immediately); + tcase_add_test(tc_destroy, test_destroy_closes_read_pipe); + tcase_add_test(tc_destroy, test_destroy_closes_write_pipe); + /* We don't test that destroy free()'s the self_pipe pointer because + * that'll be caught by valgrind. + */ + + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_signal); + suite_add_tcase(s, tc_destroy); + + return s; } int main(void) { - int number_failed; - - Suite *s = self_pipe_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; -} + int number_failed; + Suite *s = self_pipe_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} diff --git a/tests/unit/check_serve.c b/tests/unit/check_serve.c index b00bb1a..e0a2a67 100644 --- a/tests/unit/check_serve.c +++ b/tests/unit/check_serve.c @@ -15,9 +15,9 @@ #include #ifdef DEBUG -# define LOG_LEVEL 0 +#define LOG_LEVEL 0 #else -# define LOG_LEVEL 2 +#define LOG_LEVEL 2 #endif @@ -28,237 +28,245 @@ #define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0) #define myfail_unless( tst, msg ) myfail_if( !(tst), msg ) -char * dummy_file; +char *dummy_file; char *make_tmpfile(void) { - FILE *fp; - char *fn_buf; - char leader[] = "/tmp/check_serve"; + FILE *fp; + char *fn_buf; + char leader[] = "/tmp/check_serve"; - fn_buf = (char *)malloc( 1024 ); - strncpy( fn_buf, leader, sizeof( leader ) - 1); - snprintf( &fn_buf[sizeof( leader ) - 1], 10, "%d", getpid() ); - fp = fopen( fn_buf, "w" ); - fwrite( fn_buf, 1024, 1, fp ); - fclose( fp ); + fn_buf = (char *) malloc(1024); + strncpy(fn_buf, leader, sizeof(leader) - 1); + snprintf(&fn_buf[sizeof(leader) - 1], 10, "%d", getpid()); + fp = fopen(fn_buf, "w"); + fwrite(fn_buf, 1024, 1, fp); + fclose(fp); - return fn_buf; + return fn_buf; } -void setup( void ) +void setup(void) { - dummy_file = make_tmpfile(); + dummy_file = make_tmpfile(); } -void teardown( void ) +void teardown(void) { - if( dummy_file ){ unlink( dummy_file ); } - free( dummy_file ); - dummy_file = NULL; + if (dummy_file) { + unlink(dummy_file); + } + free(dummy_file); + dummy_file = NULL; } -START_TEST( test_replaces_acl ) +START_TEST(test_replaces_acl) { - struct flexnbd flexnbd; - flexnbd.signal_fd = -1; - struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); - struct acl * new_acl = acl_create( 0, NULL, 0 ); + struct flexnbd flexnbd; + flexnbd.signal_fd = -1; + struct server *s = + server_create(&flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, + 1, 0, 1); + struct acl *new_acl = acl_create(0, NULL, 0); - server_replace_acl( s, new_acl ); + server_replace_acl(s, new_acl); - myfail_unless( s->acl == new_acl, "ACL wasn't replaced." ); - server_destroy( s ); + myfail_unless(s->acl == new_acl, "ACL wasn't replaced."); + server_destroy(s); } -END_TEST - -START_TEST( test_signals_acl_updated ) +END_TEST START_TEST(test_signals_acl_updated) { - struct flexnbd flexnbd; - flexnbd.signal_fd = -1; - struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); - struct acl * new_acl = acl_create( 0, NULL, 0 ); + struct flexnbd flexnbd; + flexnbd.signal_fd = -1; + struct server *s = + server_create(&flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, + 1, 0, 1); + struct acl *new_acl = acl_create(0, NULL, 0); - server_replace_acl( s, new_acl ); + server_replace_acl(s, new_acl); - myfail_unless( 1 == self_pipe_signal_clear( s->acl_updated_signal ), - "No signal sent." ); - server_destroy( s ); + myfail_unless(1 == self_pipe_signal_clear(s->acl_updated_signal), + "No signal sent."); + server_destroy(s); } -END_TEST - -int connect_client( char *addr, int actual_port, char *source_addr ) +END_TEST int connect_client(char *addr, int actual_port, char *source_addr) { - int client_fd = -1; + int client_fd = -1; - struct addrinfo hint; - struct addrinfo *ailist, *aip; + struct addrinfo hint; + struct addrinfo *ailist, *aip; - memset( &hint, '\0', sizeof( struct addrinfo ) ); - hint.ai_socktype = SOCK_STREAM; + memset(&hint, '\0', sizeof(struct addrinfo)); + hint.ai_socktype = SOCK_STREAM; - myfail_if( getaddrinfo( addr, NULL, &hint, &ailist ) != 0, "getaddrinfo failed." ); + myfail_if(getaddrinfo(addr, NULL, &hint, &ailist) != 0, + "getaddrinfo failed."); - int connected = 0; - for( aip = ailist; aip; aip = aip->ai_next ) { - ((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port ); - client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol ); + int connected = 0; + for (aip = ailist; aip; aip = aip->ai_next) { + ((struct sockaddr_in *) aip->ai_addr)->sin_port = + htons(actual_port); + client_fd = + socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); - if (source_addr) { - struct sockaddr src; - if( !parse_ip_to_sockaddr(&src, source_addr)) { - close(client_fd); - continue; - } - bind(client_fd, &src, sizeof(struct sockaddr_in6)); - } - - if( client_fd == -1) { continue; } - if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) { - connected = 1; - break; - } - close( client_fd ); + if (source_addr) { + struct sockaddr src; + if (!parse_ip_to_sockaddr(&src, source_addr)) { + close(client_fd); + continue; + } + bind(client_fd, &src, sizeof(struct sockaddr_in6)); } - myfail_unless( connected, "Didn't connect." ); - return client_fd; + if (client_fd == -1) { + continue; + } + if (connect(client_fd, aip->ai_addr, aip->ai_addrlen) == 0) { + connected = 1; + break; + } + close(client_fd); + } + + myfail_unless(connected, "Didn't connect."); + return client_fd; } /* These are "internal" functions we need for the following test. We * shouldn't need them but there's no other way at the moment. */ -void serve_open_server_socket( struct server * ); -int server_port( struct server * ); -void server_accept( struct server * ); -int fd_is_closed( int ); -void server_close_clients( struct server * ); +void serve_open_server_socket(struct server *); +int server_port(struct server *); +void server_accept(struct server *); +int fd_is_closed(int); +void server_close_clients(struct server *); -START_TEST( test_acl_update_closes_bad_client ) +START_TEST(test_acl_update_closes_bad_client) { - /* This is the wrong way round. Rather than pulling the thread - * and socket out of the server structure, we should be testing - * a client socket. - */ - struct flexnbd flexnbd; - flexnbd.signal_fd = -1; - struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); - struct acl * new_acl = acl_create( 0, NULL, 1 ); - struct client * c; - struct client_tbl_entry * entry; + /* This is the wrong way round. Rather than pulling the thread + * and socket out of the server structure, we should be testing + * a client socket. + */ + struct flexnbd flexnbd; + flexnbd.signal_fd = -1; + struct server *s = + server_create(&flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, + 1, 0, 1); + struct acl *new_acl = acl_create(0, NULL, 1); + struct client *c; + struct client_tbl_entry *entry; - int actual_port; - int client_fd; - int server_fd; + int actual_port; + int client_fd; + int server_fd; - serve_open_server_socket( s ); - actual_port = server_port( s ); + serve_open_server_socket(s); + actual_port = server_port(s); - client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" ); - server_accept( s ); - entry = &s->nbd_client[0]; - c = entry->client; - /* At this point there should be an entry in the nbd_clients - * table and a background thread to run the client loop - */ - myfail_if( entry->thread == 0, "No client thread was started." ); - server_fd = c->socket; - myfail_if( fd_is_closed(server_fd), - "Sanity check failed - client socket wasn't open." ); + client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1"); + server_accept(s); + entry = &s->nbd_client[0]; + c = entry->client; + /* At this point there should be an entry in the nbd_clients + * table and a background thread to run the client loop + */ + myfail_if(entry->thread == 0, "No client thread was started."); + server_fd = c->socket; + myfail_if(fd_is_closed(server_fd), + "Sanity check failed - client socket wasn't open."); - server_replace_acl( s, new_acl ); + server_replace_acl(s, new_acl); - /* accept again, so that we can react to the acl replacement signal */ - server_accept( s ); + /* accept again, so that we can react to the acl replacement signal */ + server_accept(s); - /* Fail if we time out here */ - while( !fd_is_closed( server_fd ) ); + /* Fail if we time out here */ + while (!fd_is_closed(server_fd)); - close( client_fd ); - server_close_clients( s ); - server_destroy( s ); + close(client_fd); + server_close_clients(s); + server_destroy(s); } -END_TEST - -START_TEST( test_acl_update_leaves_good_client ) +END_TEST START_TEST(test_acl_update_leaves_good_client) { - struct flexnbd flexnbd; - flexnbd.signal_fd = -1; + struct flexnbd flexnbd; + flexnbd.signal_fd = -1; - struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); + struct server *s = + server_create(&flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, + 1, 0, 1); - char *lines[] = {"127.0.0.1"}; - struct acl * new_acl = acl_create( 1, lines, 1 ); - struct client * c; - struct client_tbl_entry * entry; + char *lines[] = { "127.0.0.1" }; + struct acl *new_acl = acl_create(1, lines, 1); + struct client *c; + struct client_tbl_entry *entry; - int actual_port; - int client_fd; - int server_fd; + int actual_port; + int client_fd; + int server_fd; - serve_open_server_socket( s ); - actual_port = server_port( s ); - client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" ); - server_accept( s ); - entry = &s->nbd_client[0]; - c = entry->client; - /* At this point there should be an entry in the nbd_clients - * table and a background thread to run the client loop - */ - myfail_if( entry->thread == 0, "No client thread was started." ); - server_fd = c->socket; - myfail_if( fd_is_closed(server_fd), - "Sanity check failed - client socket wasn't open." ); + serve_open_server_socket(s); + actual_port = server_port(s); + client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1"); + server_accept(s); + entry = &s->nbd_client[0]; + c = entry->client; + /* At this point there should be an entry in the nbd_clients + * table and a background thread to run the client loop + */ + myfail_if(entry->thread == 0, "No client thread was started."); + server_fd = c->socket; + myfail_if(fd_is_closed(server_fd), + "Sanity check failed - client socket wasn't open."); - server_replace_acl( s, new_acl ); - server_accept( s ); + server_replace_acl(s, new_acl); + server_accept(s); - myfail_if( self_pipe_signal_clear( c->stop_signal ), - "Client was told to stop." ); + myfail_if(self_pipe_signal_clear(c->stop_signal), + "Client was told to stop."); - close( client_fd ); - server_close_clients( s ); - server_destroy( s ); + close(client_fd); + server_close_clients(s); + server_destroy(s); } -END_TEST - -Suite* serve_suite(void) +END_TEST Suite * serve_suite(void) { - Suite *s = suite_create("serve"); - TCase *tc_acl_update = tcase_create("acl_update"); + Suite *s = suite_create("serve"); + TCase *tc_acl_update = tcase_create("acl_update"); - tcase_add_checked_fixture( tc_acl_update, setup, NULL ); + tcase_add_checked_fixture(tc_acl_update, setup, NULL); - tcase_add_test(tc_acl_update, test_replaces_acl); - tcase_add_test(tc_acl_update, test_signals_acl_updated); + tcase_add_test(tc_acl_update, test_replaces_acl); + tcase_add_test(tc_acl_update, test_signals_acl_updated); - tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client, 0); - tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, 0); + tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client, + 0); + tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, + 0); - suite_add_tcase(s, tc_acl_update); + suite_add_tcase(s, tc_acl_update); - return s; + return s; } int main(void) { - log_level = LOG_LEVEL; - error_init(); - int number_failed; - Suite *s = serve_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + log_level = LOG_LEVEL; + error_init(); + int number_failed; + Suite *s = serve_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_sockutil.c b/tests/unit/check_sockutil.c index 57626bb..dc7295f 100644 --- a/tests/unit/check_sockutil.c +++ b/tests/unit/check_sockutil.c @@ -6,110 +6,112 @@ #include -START_TEST( test_sockaddr_address_string_af_inet_converts_to_string ) +START_TEST(test_sockaddr_address_string_af_inet_converts_to_string) { - struct sockaddr sa; - struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; - char testbuf[128]; - const char* result; + struct sockaddr sa; + struct sockaddr_in *v4 = (struct sockaddr_in *) &sa; + char testbuf[128]; + const char *result; - v4->sin_family = AF_INET; - v4->sin_port = htons( 4777 ); - ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); + v4->sin_family = AF_INET; + v4->sin_port = htons(4777); + ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr)); - result = sockaddr_address_string( &sa, &testbuf[0], 128 ); - ck_assert( result != NULL ); + result = sockaddr_address_string(&sa, &testbuf[0], 128); + ck_assert(result != NULL); - ck_assert_str_eq( "192.168.0.1 port 4777", testbuf ); + ck_assert_str_eq("192.168.0.1 port 4777", testbuf); } + END_TEST - - -START_TEST( test_sockaddr_address_string_af_inet6_converts_to_string ) +START_TEST(test_sockaddr_address_string_af_inet6_converts_to_string) { - struct sockaddr_in6 v6_raw; - struct sockaddr_in6* v6 = &v6_raw; - struct sockaddr* sa = (struct sockaddr*) &v6_raw; + struct sockaddr_in6 v6_raw; + struct sockaddr_in6 *v6 = &v6_raw; + struct sockaddr *sa = (struct sockaddr *) &v6_raw; - char testbuf[128]; - const char* result; + char testbuf[128]; + const char *result; - v6->sin6_family = AF_INET6; - v6->sin6_port = htons( 4777 ); - ck_assert_int_eq( 1, inet_pton( AF_INET6, "fe80::1", &v6->sin6_addr )); + v6->sin6_family = AF_INET6; + v6->sin6_port = htons(4777); + ck_assert_int_eq(1, inet_pton(AF_INET6, "fe80::1", &v6->sin6_addr)); - result = sockaddr_address_string( sa, &testbuf[0], 128 ); - ck_assert( result != NULL ); + result = sockaddr_address_string(sa, &testbuf[0], 128); + ck_assert(result != NULL); - ck_assert_str_eq( "fe80::1 port 4777", testbuf ); + ck_assert_str_eq("fe80::1 port 4777", testbuf); } -END_TEST +END_TEST /* We don't know what it is, so we just call it "???" and return NULL */ -START_TEST( test_sockaddr_address_string_af_unspec_is_failure ) +START_TEST(test_sockaddr_address_string_af_unspec_is_failure) { - struct sockaddr sa; - struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; - char testbuf[128]; - const char* result; + struct sockaddr sa; + struct sockaddr_in *v4 = (struct sockaddr_in *) &sa; + char testbuf[128]; + const char *result; - v4->sin_family = AF_UNSPEC; - v4->sin_port = htons( 4777 ); - ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); + v4->sin_family = AF_UNSPEC; + v4->sin_port = htons(4777); + ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr)); - result = sockaddr_address_string( &sa, &testbuf[0], 128 ); - ck_assert( result == NULL ); + result = sockaddr_address_string(&sa, &testbuf[0], 128); + ck_assert(result == NULL); - ck_assert_str_eq( "???", testbuf ); + ck_assert_str_eq("???", testbuf); } -END_TEST +END_TEST /* This is a complete failure to parse, rather than a partial failure */ -START_TEST( test_sockaddr_address_string_doesnt_overflow_short_buffer ) +START_TEST(test_sockaddr_address_string_doesnt_overflow_short_buffer) { - struct sockaddr sa; - struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; - char testbuf[128]; - const char* result; + struct sockaddr sa; + struct sockaddr_in *v4 = (struct sockaddr_in *) &sa; + char testbuf[128]; + const char *result; - memset( testbuf, 0, 128 ); - v4->sin_family = AF_INET; - v4->sin_port = htons( 4777 ); - ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); - memset( &testbuf, 0, 128 ); + memset(testbuf, 0, 128); + v4->sin_family = AF_INET; + v4->sin_port = htons(4777); + ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr)); + memset(&testbuf, 0, 128); - result = sockaddr_address_string( &sa, &testbuf[0], 2 ); - ck_assert( result == NULL ); + result = sockaddr_address_string(&sa, &testbuf[0], 2); + ck_assert(result == NULL); - ck_assert_str_eq( "??", testbuf ); + ck_assert_str_eq("??", testbuf); } -END_TEST -Suite *sockutil_suite(void) +END_TEST Suite * sockutil_suite(void) { - Suite *s = suite_create("sockutil"); + Suite *s = suite_create("sockutil"); - TCase *tc_sockaddr_address_string = tcase_create("sockaddr_address_string"); + TCase *tc_sockaddr_address_string = + tcase_create("sockaddr_address_string"); - tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_inet_converts_to_string); - tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_inet6_converts_to_string); - tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_unspec_is_failure); - tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_doesnt_overflow_short_buffer); - suite_add_tcase(s, tc_sockaddr_address_string); + tcase_add_test(tc_sockaddr_address_string, + test_sockaddr_address_string_af_inet_converts_to_string); + tcase_add_test(tc_sockaddr_address_string, + test_sockaddr_address_string_af_inet6_converts_to_string); + tcase_add_test(tc_sockaddr_address_string, + test_sockaddr_address_string_af_unspec_is_failure); + tcase_add_test(tc_sockaddr_address_string, + test_sockaddr_address_string_doesnt_overflow_short_buffer); + suite_add_tcase(s, tc_sockaddr_address_string); - return s; + return s; } int main(void) { - int number_failed; + int number_failed; - Suite *s = sockutil_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + Suite *s = sockutil_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_status.c b/tests/unit/check_status.c index ea89d3b..8c37563 100644 --- a/tests/unit/check_status.c +++ b/tests/unit/check_status.c @@ -6,366 +6,331 @@ #include -struct server* mock_server(void) +struct server *mock_server(void) { - struct server* out = xmalloc( sizeof( struct server ) ); - out->l_start_mirror = flexthread_mutex_create(); - out->nbd_client = xmalloc( sizeof( struct client_tbl_entry ) * 4 ); - out->max_nbd_clients = 4; - out->size = 65536; + struct server *out = xmalloc(sizeof(struct server)); + out->l_start_mirror = flexthread_mutex_create(); + out->nbd_client = xmalloc(sizeof(struct client_tbl_entry) * 4); + out->max_nbd_clients = 4; + out->size = 65536; - out->allocation_map = bitset_alloc( 65536, 4096 ); + out->allocation_map = bitset_alloc(65536, 4096); - return out; + return out; } -struct server* mock_mirroring_server(void) +struct server *mock_mirroring_server(void) { - struct server *out = mock_server(); - out->mirror = xmalloc( sizeof( struct mirror ) ); - out->mirror_super = xmalloc( sizeof( struct mirror_super ) ); - return out; + struct server *out = mock_server(); + out->mirror = xmalloc(sizeof(struct mirror)); + out->mirror_super = xmalloc(sizeof(struct mirror_super)); + return out; } -void destroy_mock_server( struct server* serve ) +void destroy_mock_server(struct server *serve) { - if ( NULL != serve->mirror ) { - free( serve->mirror ); - } + if (NULL != serve->mirror) { + free(serve->mirror); + } - if ( NULL != serve->mirror_super ) { - free( serve->mirror_super ); - } + if (NULL != serve->mirror_super) { + free(serve->mirror_super); + } - flexthread_mutex_destroy( serve->l_start_mirror ); + flexthread_mutex_destroy(serve->l_start_mirror); - bitset_free( serve->allocation_map ); - free( serve->nbd_client ); - free( serve ); + bitset_free(serve->allocation_map); + free(serve->nbd_client); + free(serve); } -START_TEST( test_status_create ) +START_TEST(test_status_create) { - struct server * server = mock_server(); - struct status * status = status_create( server ); + struct server *server = mock_server(); + struct status *status = status_create(server); - fail_if( NULL == status, "Status wasn't allocated" ); - status_destroy( status ); - destroy_mock_server( server ); + fail_if(NULL == status, "Status wasn't allocated"); + status_destroy(status); + destroy_mock_server(server); } -END_TEST -START_TEST( test_gets_has_control ) +END_TEST START_TEST(test_gets_has_control) { - struct server * server = mock_server(); - server->success = 1; + struct server *server = mock_server(); + server->success = 1; - struct status * status = status_create( server ); + struct status *status = status_create(server); - fail_unless( status->has_control == 1, "has_control wasn't copied" ); - status_destroy( status ); - destroy_mock_server( server ); + fail_unless(status->has_control == 1, "has_control wasn't copied"); + status_destroy(status); + destroy_mock_server(server); } -END_TEST - -START_TEST( test_gets_is_mirroring ) +END_TEST START_TEST(test_gets_is_mirroring) { - struct server * server = mock_server(); - struct status * status = status_create( server ); + struct server *server = mock_server(); + struct status *status = status_create(server); - fail_if( status->is_mirroring, "is_mirroring was set" ); - status_destroy( status ); - destroy_mock_server( server ); + fail_if(status->is_mirroring, "is_mirroring was set"); + status_destroy(status); + destroy_mock_server(server); - server = mock_mirroring_server(); - status = status_create( server ); + server = mock_mirroring_server(); + status = status_create(server); - fail_unless( status->is_mirroring, "is_mirroring wasn't set" ); - status_destroy( status ); - destroy_mock_server( server ); + fail_unless(status->is_mirroring, "is_mirroring wasn't set"); + status_destroy(status); + destroy_mock_server(server); } -END_TEST -START_TEST( test_gets_clients_allowed ) +END_TEST START_TEST(test_gets_clients_allowed) { - struct server * server = mock_server(); - struct status * status = status_create( server ); + struct server *server = mock_server(); + struct status *status = status_create(server); - fail_if( status->clients_allowed, "clients_allowed was set" ); - status_destroy( status ); + fail_if(status->clients_allowed, "clients_allowed was set"); + status_destroy(status); - server->allow_new_clients = 1; - status = status_create( server ); + server->allow_new_clients = 1; + status = status_create(server); - fail_unless( status->clients_allowed, "clients_allowed was not set" ); - status_destroy( status ); - destroy_mock_server( server ); + fail_unless(status->clients_allowed, "clients_allowed was not set"); + status_destroy(status); + destroy_mock_server(server); } -END_TEST -START_TEST( test_gets_pid ) +END_TEST START_TEST(test_gets_pid) { - struct server * server = mock_server(); - struct status * status = status_create( server ); + struct server *server = mock_server(); + struct status *status = status_create(server); - fail_unless( getpid() == status->pid, "Pid wasn't gathered" ); + fail_unless(getpid() == status->pid, "Pid wasn't gathered"); - status_destroy( status ); - destroy_mock_server( server ); + status_destroy(status); + destroy_mock_server(server); } -END_TEST -START_TEST( test_gets_size ) +END_TEST START_TEST(test_gets_size) { - struct server * server = mock_server(); - server->size = 1024; + struct server *server = mock_server(); + server->size = 1024; - struct status * status = status_create( server ); + struct status *status = status_create(server); - fail_unless( 1024 == status->size, "Size wasn't gathered" ); + fail_unless(1024 == status->size, "Size wasn't gathered"); - status_destroy( status ); - destroy_mock_server( server ); + status_destroy(status); + destroy_mock_server(server); } -END_TEST -START_TEST( test_gets_migration_statistics ) +END_TEST START_TEST(test_gets_migration_statistics) { - struct server * server = mock_mirroring_server(); - server->mirror->all_dirty = 16384; - server->mirror->max_bytes_per_second = 32768; - server->mirror->offset = 0; + struct server *server = mock_mirroring_server(); + server->mirror->all_dirty = 16384; + server->mirror->max_bytes_per_second = 32768; + server->mirror->offset = 0; - /* we have a bit of a time dependency here */ - server->mirror->migration_started = monotonic_time_ms(); + /* we have a bit of a time dependency here */ + server->mirror->migration_started = monotonic_time_ms(); - struct status * status = status_create( server ); + struct status *status = status_create(server); - fail_unless ( - 0 == status->migration_duration || + fail_unless(0 == status->migration_duration || 1 == status->migration_duration || 2 == status->migration_duration, - "migration_duration is unreasonable!" - ); + "migration_duration is unreasonable!"); - fail_unless( - 16384 / ( status->migration_duration + 1 ) == status->migration_speed, - "migration_speed not calculated correctly" - ); + fail_unless(16384 / (status->migration_duration + 1) == + status->migration_speed, + "migration_speed not calculated correctly"); - fail_unless( 32768 == status->migration_speed_limit, "migration_speed_limit not read" ); + fail_unless(32768 == status->migration_speed_limit, + "migration_speed_limit not read"); - // ( size / current_bps ) + 1 happens to be 3 for this test - fail_unless( 3 == status->migration_seconds_left, "migration_seconds_left not gathered" ); + // ( size / current_bps ) + 1 happens to be 3 for this test + fail_unless(3 == status->migration_seconds_left, + "migration_seconds_left not gathered"); - status_destroy( status ); - destroy_mock_server( server ); + status_destroy(status); + destroy_mock_server(server); } + END_TEST - - #define RENDER_TEST_SETUP \ struct status status; \ int fds[2]; \ pipe( fds ); - -void fail_unless_rendered( int fd, char *fragment ) +void fail_unless_rendered(int fd, char *fragment) { - char buf[1024] = {0}; - char emsg[1024] = {0}; - char *found = NULL; + char buf[1024] = { 0 }; + char emsg[1024] = { 0 }; + char *found = NULL; - sprintf(emsg, "Fragment: %s not found", fragment ); + sprintf(emsg, "Fragment: %s not found", fragment); - fail_unless( read_until_newline( fd, buf, 1024 ) > 0, "Couldn't read" ); - found = strstr( buf, fragment ); - fail_if( NULL == found, emsg ); + fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read"); + found = strstr(buf, fragment); + fail_if(NULL == found, emsg); - return; + return; } -void fail_if_rendered( int fd, char *fragment ) +void fail_if_rendered(int fd, char *fragment) { - char buf[1024] = {0}; - char emsg[1024] = {0}; - char *found = NULL; + char buf[1024] = { 0 }; + char emsg[1024] = { 0 }; + char *found = NULL; - sprintf(emsg, "Fragment: %s found", fragment ); + sprintf(emsg, "Fragment: %s found", fragment); - fail_unless( read_until_newline( fd, buf, 1024 ) > 0, "Couldn't read" ); - found = strstr( buf, fragment ); - fail_unless( NULL == found, emsg ); + fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read"); + found = strstr(buf, fragment); + fail_unless(NULL == found, emsg); - return; + return; } -START_TEST( test_renders_has_control ) +START_TEST(test_renders_has_control) { - RENDER_TEST_SETUP + RENDER_TEST_SETUP status.has_control = 1; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "has_control=true"); - status.has_control = 1; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "has_control=true" ); - - status.has_control = 0; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "has_control=false" ); + status.has_control = 0; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "has_control=false"); } -END_TEST - -START_TEST( test_renders_is_mirroring ) +END_TEST START_TEST(test_renders_is_mirroring) { - RENDER_TEST_SETUP + RENDER_TEST_SETUP status.is_mirroring = 1; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "is_mirroring=true"); - status.is_mirroring = 1; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "is_mirroring=true" ); - - status.is_mirroring = 0; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "is_mirroring=false" ); + status.is_mirroring = 0; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "is_mirroring=false"); } -END_TEST -START_TEST( test_renders_clients_allowed ) +END_TEST START_TEST(test_renders_clients_allowed) { - RENDER_TEST_SETUP + RENDER_TEST_SETUP status.clients_allowed = 1; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "clients_allowed=true"); - status.clients_allowed = 1; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "clients_allowed=true" ); - - status.clients_allowed = 0; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "clients_allowed=false" ); + status.clients_allowed = 0; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "clients_allowed=false"); } -END_TEST -START_TEST( test_renders_num_clients ) +END_TEST START_TEST(test_renders_num_clients) { - RENDER_TEST_SETUP + RENDER_TEST_SETUP status.num_clients = 0; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "num_clients=0"); - status.num_clients = 0; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "num_clients=0" ); - - status.num_clients = 4000; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "num_clients=4000" ); + status.num_clients = 4000; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "num_clients=4000"); } -END_TEST - -START_TEST( test_renders_pid ) +END_TEST START_TEST(test_renders_pid) { - RENDER_TEST_SETUP - - status.pid = 42; - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "pid=42" ); + RENDER_TEST_SETUP status.pid = 42; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "pid=42"); } -END_TEST -START_TEST( test_renders_size ) +END_TEST START_TEST(test_renders_size) { - RENDER_TEST_SETUP - - status.size = ( (uint64_t)1 << 33 ); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "size=8589934592" ); + RENDER_TEST_SETUP status.size = ((uint64_t) 1 << 33); + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "size=8589934592"); } -END_TEST -START_TEST( test_renders_migration_statistics ) +END_TEST START_TEST(test_renders_migration_statistics) { - RENDER_TEST_SETUP + RENDER_TEST_SETUP status.is_mirroring = 0; + status.migration_duration = 8; + status.migration_speed = 40000000; + status.migration_speed_limit = 40000001; + status.migration_seconds_left = 1; + status.migration_bytes_left = 5000; - status.is_mirroring = 0; - status.migration_duration = 8; - status.migration_speed = 40000000; - status.migration_speed_limit = 40000001; - status.migration_seconds_left = 1; - status.migration_bytes_left = 5000; + status_write(&status, fds[1]); + fail_if_rendered(fds[0], "migration_duration"); - status_write( &status, fds[1] ); - fail_if_rendered( fds[0], "migration_duration" ); + status_write(&status, fds[1]); + fail_if_rendered(fds[0], "migration_speed"); - status_write( &status, fds[1] ); - fail_if_rendered( fds[0], "migration_speed" ); + status_write(&status, fds[1]); + fail_if_rendered(fds[0], "migration_speed_limit"); - status_write( &status, fds[1] ); - fail_if_rendered( fds[0], "migration_speed_limit" ); + status_write(&status, fds[1]); + fail_if_rendered(fds[0], "migration_seconds_left"); - status_write( &status, fds[1] ); - fail_if_rendered( fds[0], "migration_seconds_left" ); + status.is_mirroring = 1; - status.is_mirroring = 1; + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "migration_duration=8"); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "migration_duration=8" ); + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "migration_speed=40000000"); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "migration_speed=40000000" ); + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "migration_speed_limit=40000001"); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "migration_speed_limit=40000001" ); + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "migration_seconds_left=1"); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "migration_seconds_left=1" ); + status_write(&status, fds[1]); + fail_unless_rendered(fds[0], "migration_bytes_left=5000"); - status_write( &status, fds[1] ); - fail_unless_rendered( fds[0], "migration_bytes_left=5000" ); + status.migration_speed_limit = UINT64_MAX; - status.migration_speed_limit = UINT64_MAX; - - status_write( &status, fds[1] ); - fail_if_rendered( fds[0], "migration_speed_limit" ); + status_write(&status, fds[1]); + fail_if_rendered(fds[0], "migration_speed_limit"); } -END_TEST - -Suite *status_suite(void) +END_TEST Suite * status_suite(void) { - Suite *s = suite_create("status"); - TCase *tc_create = tcase_create("create"); - TCase *tc_render = tcase_create("render"); + Suite *s = suite_create("status"); + TCase *tc_create = tcase_create("create"); + TCase *tc_render = tcase_create("render"); - tcase_add_test(tc_create, test_status_create); - tcase_add_test(tc_create, test_gets_has_control); - tcase_add_test(tc_create, test_gets_is_mirroring); - tcase_add_test(tc_create, test_gets_clients_allowed); - tcase_add_test(tc_create, test_gets_pid); - tcase_add_test(tc_create, test_gets_size); - tcase_add_test(tc_create, test_gets_migration_statistics); + tcase_add_test(tc_create, test_status_create); + tcase_add_test(tc_create, test_gets_has_control); + tcase_add_test(tc_create, test_gets_is_mirroring); + tcase_add_test(tc_create, test_gets_clients_allowed); + tcase_add_test(tc_create, test_gets_pid); + tcase_add_test(tc_create, test_gets_size); + tcase_add_test(tc_create, test_gets_migration_statistics); - tcase_add_test(tc_render, test_renders_has_control); - tcase_add_test(tc_render, test_renders_is_mirroring); - tcase_add_test(tc_render, test_renders_clients_allowed); - tcase_add_test(tc_render, test_renders_num_clients); - tcase_add_test(tc_render, test_renders_pid); - tcase_add_test(tc_render, test_renders_size); - tcase_add_test(tc_render, test_renders_migration_statistics); + tcase_add_test(tc_render, test_renders_has_control); + tcase_add_test(tc_render, test_renders_is_mirroring); + tcase_add_test(tc_render, test_renders_clients_allowed); + tcase_add_test(tc_render, test_renders_num_clients); + tcase_add_test(tc_render, test_renders_pid); + tcase_add_test(tc_render, test_renders_size); + tcase_add_test(tc_render, test_renders_migration_statistics); - suite_add_tcase(s, tc_create); - suite_add_tcase(s, tc_render); + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_render); - return s; + return s; } int main(void) { - int number_failed; + int number_failed; - Suite *s = status_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + Suite *s = status_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } - diff --git a/tests/unit/check_util.c b/tests/unit/check_util.c index 63e2ade..5fdd588 100644 --- a/tests/unit/check_util.c +++ b/tests/unit/check_util.c @@ -9,165 +9,156 @@ struct cleanup_bucket { - struct self_pipe *called_signal; + struct self_pipe *called_signal; }; struct cleanup_bucket bkt; -void bucket_init(void){ - if ( bkt.called_signal ) { - self_pipe_destroy( bkt.called_signal ); - } - bkt.called_signal = self_pipe_create(); +void bucket_init(void) +{ + if (bkt.called_signal) { + self_pipe_destroy(bkt.called_signal); + } + bkt.called_signal = self_pipe_create(); } void setup(void) { - bkt.called_signal = NULL; + bkt.called_signal = NULL; } int handler_called(void) { - return self_pipe_signal_clear( bkt.called_signal ); + return self_pipe_signal_clear(bkt.called_signal); } -void dummy_cleanup( struct cleanup_bucket * foo, int fatal __attribute__((unused)) ) +void dummy_cleanup(struct cleanup_bucket *foo, int fatal + __attribute__ ((unused))) { - if (NULL != foo){ - self_pipe_signal( foo->called_signal ); - } + if (NULL != foo) { + self_pipe_signal(foo->called_signal); + } } void trigger_fatal(void) -{ - error_init(); - error_set_handler( (cleanup_handler*) dummy_cleanup, &bkt ); +{ + error_init(); + error_set_handler((cleanup_handler *) dummy_cleanup, &bkt); - log_level = 5; + log_level = 5; - fatal("Expected fatal error"); + fatal("Expected fatal error"); } -void trigger_error( void ) +void trigger_error(void) { - error_init(); - error_set_handler( (cleanup_handler *) dummy_cleanup, &bkt); - log_level = 4; - error("Expected error"); + error_init(); + error_set_handler((cleanup_handler *) dummy_cleanup, &bkt); + log_level = 4; + error("Expected error"); } -START_TEST( test_fatal_kills_process ) +START_TEST(test_fatal_kills_process) { - pid_t pid; + pid_t pid; - pid = fork(); + pid = fork(); - if ( pid == 0 ) { - trigger_fatal(); - /* If we get here, just block so the test timeout fails - * us */ - sleep(10); - } - else { - int kidret, kidstatus, result; - result = waitpid( pid, &kidret, 0 ); - fail_if( result < 0, "Wait failed." ); - fail_unless( WIFSIGNALED( kidret ), "Process didn't exit via signal" ); - kidstatus = WTERMSIG( kidret ); - ck_assert_int_eq( kidstatus, SIGABRT ); - } + if (pid == 0) { + trigger_fatal(); + /* If we get here, just block so the test timeout fails + * us */ + sleep(10); + } else { + int kidret, kidstatus, result; + result = waitpid(pid, &kidret, 0); + fail_if(result < 0, "Wait failed."); + fail_unless(WIFSIGNALED(kidret), "Process didn't exit via signal"); + kidstatus = WTERMSIG(kidret); + ck_assert_int_eq(kidstatus, SIGABRT); + } } -END_TEST - -void * error_thread( void *nothing __attribute__((unused)) ) +END_TEST void *error_thread(void *nothing __attribute__ ((unused))) { - trigger_error(); - return NULL; + trigger_error(); + return NULL; } -START_TEST( test_error_doesnt_kill_process ) +START_TEST(test_error_doesnt_kill_process) { - bucket_init(); - pthread_attr_t attr; - pthread_t tid; + bucket_init(); + pthread_attr_t attr; + pthread_t tid; - pthread_attr_init( &attr ); + pthread_attr_init(&attr); - pthread_create( &tid, &attr, error_thread, NULL ); - pthread_join( tid, NULL ); + pthread_create(&tid, &attr, error_thread, NULL); + pthread_join(tid, NULL); } -END_TEST - -START_TEST( test_error_calls_handler ) +END_TEST START_TEST(test_error_calls_handler) { - bucket_init(); + bucket_init(); - pthread_attr_t attr; - pthread_t tid; + pthread_attr_t attr; + pthread_t tid; - pthread_attr_init( &attr ); + pthread_attr_init(&attr); - pthread_create( &tid, &attr, error_thread, NULL ); - pthread_join( tid, NULL ); - fail_unless( handler_called(), "Handler wasn't called." ); + pthread_create(&tid, &attr, error_thread, NULL); + pthread_join(tid, NULL); + fail_unless(handler_called(), "Handler wasn't called."); } -END_TEST - -START_TEST( test_fatal_doesnt_call_handler ) +END_TEST START_TEST(test_fatal_doesnt_call_handler) { - bucket_init(); + bucket_init(); - pid_t kidpid; + pid_t kidpid; - kidpid = fork(); - if ( kidpid == 0 ) { - trigger_fatal(); - } - else { - int kidstatus; - int result = waitpid( kidpid, &kidstatus, 0 ); - fail_if( result < 0, "Wait failed" ); - fail_if( handler_called(), "Handler was called."); - } + kidpid = fork(); + if (kidpid == 0) { + trigger_fatal(); + } else { + int kidstatus; + int result = waitpid(kidpid, &kidstatus, 0); + fail_if(result < 0, "Wait failed"); + fail_if(handler_called(), "Handler was called."); + } } -END_TEST - -Suite* util_suite(void) +END_TEST Suite * util_suite(void) { - Suite *s = suite_create("util"); - TCase *tc_process = tcase_create("process"); - TCase *tc_handler = tcase_create("handler"); + Suite *s = suite_create("util"); + TCase *tc_process = tcase_create("process"); + TCase *tc_handler = tcase_create("handler"); - tcase_add_checked_fixture( tc_process, setup, NULL ); + tcase_add_checked_fixture(tc_process, setup, NULL); - tcase_add_test(tc_process, test_fatal_kills_process); - tcase_add_test(tc_process, test_error_doesnt_kill_process); - tcase_add_test(tc_handler, test_error_calls_handler ); - tcase_add_test(tc_handler, test_fatal_doesnt_call_handler); + tcase_add_test(tc_process, test_fatal_kills_process); + tcase_add_test(tc_process, test_error_doesnt_kill_process); + tcase_add_test(tc_handler, test_error_calls_handler); + tcase_add_test(tc_handler, test_fatal_doesnt_call_handler); - suite_add_tcase(s, tc_process); - suite_add_tcase(s, tc_handler); - - return s; + suite_add_tcase(s, tc_process); + suite_add_tcase(s, tc_handler); + + return s; } int main(void) { - int number_failed; - Suite *s = util_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - return (number_failed == 0) ? 0 : 1; + int number_failed; + Suite *s = util_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; } -