Formatted all code using indent

This commit is contained in:
Patrick J Cherry
2018-02-20 10:05:35 +00:00
parent 19a1127bde
commit f47f56d4c4
59 changed files with 7631 additions and 7762 deletions

3
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,3 @@
# Contribution guide
The code is formatted using the K&R style of "indent".

View File

@@ -13,228 +13,236 @@
#include "ioutil.h" #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 */ /* break blocking ioctls down */
const unsigned long max_length = 100*1024*1024; const unsigned long max_length = 100 * 1024 * 1024;
const unsigned int max_extents = 1000; const unsigned int max_extents = 1000;
unsigned long offset = 0; unsigned long offset = 0;
struct { struct {
struct fiemap fiemap; struct fiemap fiemap;
struct fiemap_extent extents[max_extents]; struct fiemap_extent extents[max_extents];
} fiemap_static; } fiemap_static;
struct fiemap* fiemap = (struct fiemap*) &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; fiemap->fm_length = max_length;
if ( offset + max_length > allocation_map->size ) { if (offset + max_length > allocation_map->size) {
fiemap->fm_length = allocation_map->size-offset; 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;
}
}
} }
info("Successfully built allocation map"); fiemap->fm_flags = FIEMAP_FLAG_SYNC;
return 1; 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. * size and out_size are intentionally of different types.
* lseek64() uses off64_t to signal errors in the sign bit. * lseek64() uses off64_t to signal errors in the sign bit.
* Since we check for these errors before trying to assign to * Since we check for these errors before trying to assign to
* *out_size, we know *out_size can never go negative. * *out_size, we know *out_size can never go negative.
*/ */
off64_t size; off64_t size;
/* O_DIRECT should not be used with mmap() */ /* O_DIRECT should not be used with mmap() */
*out_fd = open(filename, O_RDWR | O_NOATIME ); *out_fd = open(filename, O_RDWR | O_NOATIME);
if (*out_fd < 1) { if (*out_fd < 1) {
warn("open(%s) failed: does it exist?", filename); warn("open(%s) failed: does it exist?", filename);
return *out_fd; 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); return 0;
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;
} }
int writeloop(int filedes, const void *buffer, size_t size) int writeloop(int filedes, const void *buffer, size_t size)
{ {
size_t written=0; size_t written = 0;
while (written < size) { while (written < size) {
ssize_t result = write(filedes, buffer+written, size-written); ssize_t result = write(filedes, buffer + written, size - written);
if (result == -1) { if (result == -1) {
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
continue; // busy-wait continue; // busy-wait
} }
return -1; // failure return -1; // failure
}
written += result;
} }
return 0; written += result;
}
return 0;
} }
int readloop(int filedes, void *buffer, size_t size) int readloop(int filedes, void *buffer, size_t size)
{ {
size_t readden=0; size_t readden = 0;
while (readden < size) { while (readden < size) {
ssize_t result = read(filedes, buffer+readden, size-readden); ssize_t result = read(filedes, buffer + readden, size - readden);
if ( result == 0 /* EOF */ ) { if (result == 0 /* EOF */ ) {
warn( "end-of-file detected while reading after %i bytes", readden ); warn("end-of-file detected while reading after %i bytes",
return -1; readden);
} return -1;
if ( result == -1 ) {
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
continue; // busy-wait
}
return -1; // failure
}
readden += result;
} }
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; size_t sent = 0;
while (sent < count) { while (sent < count) {
ssize_t result = sendfile64(out_fd, in_fd, offset, count-sent); 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); 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) { if (result == -1) {
debug( "%s (%i) calling sendfile64()", strerror(errno), errno ); debug("%s (%i) calling sendfile64()", strerror(errno), errno);
return -1; return -1;
}
sent += result;
debug("sent=%ld, count=%ld", sent, count);
} }
debug("exiting sendfileloop"); sent += result;
return 0; debug("sent=%ld, count=%ld", sent, count);
}
debug("exiting sendfileloop");
return 0;
} }
#include <errno.h> #include <errno.h>
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; const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE | flags2;
size_t spliced=0; 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) { while (spliced < len) {
ssize_t result = splice(fd_in, off_in, fd_out, off_out, len, flags); ssize_t result =
if (result < 0) { splice(fd_in, off_in, fd_out, off_out, len, flags);
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); if (result < 0) {
if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK) ) { //debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len);
return spliced; if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK)) {
} return spliced;
else { } else {
return -1; return -1;
} }
} else { } else {
spliced += result; spliced += result;
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len); //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 splice_via_pipe_loop(int fd_in, int fd_out, size_t len)
{ {
int pipefd[2]; /* read end, write end */ int pipefd[2]; /* read end, write end */
size_t spliced=0; size_t spliced = 0;
if (pipe(pipefd) == -1) { if (pipe(pipefd) == -1) {
return -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) { s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0);
ssize_t run = len-spliced; if (s2 < 0) {
ssize_t s2, s1 = spliceloop(fd_in, NULL, pipefd[1], NULL, run, SPLICE_F_NONBLOCK); break;
/*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;
} }
close(pipefd[0]); spliced += s2;
close(pipefd[1]); }
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. /* 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 * Returns the number of read bytes: the length of the line without the
* newline, plus the trailing null. * 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++) { for (cur = 0; cur < bufsize; cur++) {
int result = read(fd, buf+cur, 1); int result = read(fd, buf + cur, 1);
if (result <= 0) { return -1; } if (result <= 0) {
if (buf[cur] == 10) { return -1;
buf[cur] = '\0';
break;
}
} }
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 read_lines_until_blankline(int fd, int max_line_length, char ***lines)
{ {
int lines_count = 0; int lines_count = 0;
char line[max_line_length+1]; char line[max_line_length + 1];
*lines = NULL; *lines = NULL;
memset(line, 0, max_line_length+1); memset(line, 0, max_line_length + 1);
while (1) { while (1) {
int readden = read_until_newline(fd, line, max_line_length); int readden = read_until_newline(fd, line, max_line_length);
/* readden will be: /* readden will be:
* 1 for an empty line * 1 for an empty line
* -1 for an eof * -1 for an eof
* -1 for a read error * -1 for a read error
*/ */
if (readden <= 1) { return lines_count; } if (readden <= 1) {
*lines = xrealloc(*lines, (lines_count+1) * sizeof(char*)); return lines_count;
(*lines)[lines_count] = strdup(line);
if ((*lines)[lines_count][0] == 0) {
return lines_count;
}
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 errno_old = errno;
int result = fcntl( fd_in, F_GETFL ) < 0; int result = fcntl(fd_in, F_GETFL) < 0;
errno = errno_old; errno = errno_old;
return result; return result;
} }
static inline int io_errno_permanent(void) 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 /* 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! */ * 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; size_t left;
ssize_t count; ssize_t count;
if ( iobuf->needle == 0 ) { if (iobuf->needle == 0) {
iobuf->size = default_size; iobuf->size = default_size;
} }
left = iobuf->size - iobuf->needle; left = iobuf->size - iobuf->needle;
debug( "Reading %"PRIu32" of %"PRIu32" bytes from fd %i", left, iobuf->size, fd ); 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 ) { if (count > 0) {
iobuf->needle += count; iobuf->needle += count;
debug( "read() returned %"PRIu32" bytes", count ); debug("read() returned %" PRIu32 " bytes", count);
} else if ( count == 0 ) { } else if (count == 0) {
warn( "read() returned EOF on fd %i", fd ); warn("read() returned EOF on fd %i", fd);
errno = 0; errno = 0;
return -1; return -1;
} else if ( count == -1 ) { } else if (count == -1) {
if ( io_errno_permanent() ) { if (io_errno_permanent()) {
warn( SHOW_ERRNO( "read() failed on fd %i", fd ) ); 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 );
} else { } else {
if ( io_errno_permanent() ) { debug(SHOW_ERRNO("read() returned 0 bytes"));
warn( SHOW_ERRNO( "write() failed on fd %i", fd ) ); count = 0;
} else {
debug( SHOW_ERRNO( "write() 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;
} }

View File

@@ -3,16 +3,16 @@
#include <sys/types.h> #include <sys/types.h>
struct iobuf { struct iobuf {
unsigned char *buf; unsigned char *buf;
size_t size; size_t size;
size_t needle; size_t needle;
}; };
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);
ssize_t iobuf_write( int fd, struct iobuf* iobuf ); ssize_t iobuf_write(int fd, struct iobuf *iobuf);
#include "serve.h" #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 /** Scan the file opened in ''fd'', set bits in ''allocation_map'' that
* correspond to which blocks are physically allocated on disc (or part- * 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" * 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. * 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 /** Repeat a write() operation that succeeds partially until ''size'' bytes
* are written, or an error is returned, when it returns -1 as usual. * 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 /** Repeat a sendfile() operation that succeeds partially until ''size'' bytes
* are written, or an error is returned, when it returns -1 as usual. * 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. */ /** 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 /** 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 * 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 * 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. * 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 /** 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 * 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 * ''out_size'' and the address of the mmap in ''out_map''. If anything goes
* wrong, returns -1 setting errno, otherwise 0. * 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. /** 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 #endif

View File

@@ -2,7 +2,7 @@
#define MODE_H #define MODE_H
void mode(char* mode, int argc, char **argv); void mode(char *mode, int argc, char **argv);
#include <getopt.h> #include <getopt.h>
@@ -68,9 +68,9 @@ void mode(char* mode, int argc, char **argv);
"\t--" OPT_VERBOSE ",-" SOPT_VERBOSE "\t\tOutput debug information.\n" "\t--" OPT_VERBOSE ",-" SOPT_VERBOSE "\t\tOutput debug information.\n"
#ifdef DEBUG #ifdef DEBUG
# define VERBOSE_LOG_LEVEL 0 #define VERBOSE_LOG_LEVEL 0
#else #else
# define VERBOSE_LOG_LEVEL 1 #define VERBOSE_LOG_LEVEL 1
#endif #endif
#define QUIET_LOG_LEVEL 4 #define QUIET_LOG_LEVEL 4
@@ -91,7 +91,6 @@ void mode(char* mode, int argc, char **argv);
#define MAX_SPEED_LINE \ #define MAX_SPEED_LINE \
"\t--" OPT_MAX_SPEED ",-m <bps>\tMaximum speed of the migration, in bytes/sec.\n" "\t--" OPT_MAX_SPEED ",-m <bps>\tMaximum speed of the migration, in bytes/sec.\n"
char * help_help_text; char *help_help_text;
#endif #endif

View File

@@ -8,55 +8,54 @@
* We intentionally ignore the reserved 128 bytes at the end of the * We intentionally ignore the reserved 128 bytes at the end of the
* request, since there's nothing we can do with them. * 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 ); memcpy(to->passwd, from->passwd, 8);
to->magic = be64toh( from->magic ); to->magic = be64toh(from->magic);
to->size = be64toh( from->size ); to->size = be64toh(from->size);
to->flags = be32toh( from->flags ); 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 ); memcpy(to->passwd, from->passwd, 8);
to->magic = htobe64( from->magic ); to->magic = htobe64(from->magic);
to->size = htobe64( from->size ); to->size = htobe64(from->size);
to->flags = htobe32( from->flags ); 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->magic = be32toh(from->magic);
to->flags = be16toh( from->flags ); to->flags = be16toh(from->flags);
to->type = be16toh( from->type ); to->type = be16toh(from->type);
to->handle.w = from->handle.w; to->handle.w = from->handle.w;
to->from = be64toh( from->from ); to->from = be64toh(from->from);
to->len = be32toh( from->len ); 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->magic = htobe32(from->magic);
to->flags = htobe16( from->flags ); to->flags = htobe16(from->flags);
to->type = htobe16( from->type ); to->type = htobe16(from->type);
to->handle.w = from->handle.w; to->handle.w = from->handle.w;
to->from = htobe64( from->from ); to->from = htobe64(from->from);
to->len = htobe32( from->len ); 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->magic = be32toh(from->magic);
to->error = be32toh( from->error ); to->error = be32toh(from->error);
to->handle.w = from->handle.w; 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->magic = htobe32(from->magic);
to->error = htobe32( from->error ); to->error = htobe32(from->error);
to->handle.w = from->handle.w; to->handle.w = from->handle.w;
} }

View File

@@ -29,8 +29,8 @@
#define FLAG_READ_ONLY (1 << 1) /* Device is read-only */ #define FLAG_READ_ONLY (1 << 1) /* Device is read-only */
#define FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ #define FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */
#define FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ #define FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
#define FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */ #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_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */
#define CMD_FLAG_NO_HOLE (1 << 1) #define CMD_FLAG_NO_HOLE (1 << 1)
#endif #endif
@@ -48,8 +48,8 @@
#include <inttypes.h> #include <inttypes.h>
typedef union nbd_handle_t { typedef union nbd_handle_t {
uint8_t b[8]; uint8_t b[8];
uint64_t w; uint64_t w;
} nbd_handle_t; } nbd_handle_t;
/* The _raw types are the types as they appear on the wire. Non-_raw /* 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. * for converting host to raw.
*/ */
struct nbd_init_raw { struct nbd_init_raw {
char passwd[8]; char passwd[8];
__be64 magic; __be64 magic;
__be64 size; __be64 size;
__be32 flags; __be32 flags;
char reserved[124]; char reserved[124];
}; };
struct nbd_request_raw { struct nbd_request_raw {
__be32 magic; __be32 magic;
__be16 flags; __be16 flags;
__be16 type; /* == READ || == WRITE || == FLUSH */ __be16 type; /* == READ || == WRITE || == FLUSH */
nbd_handle_t handle; nbd_handle_t handle;
__be64 from; __be64 from;
__be32 len; __be32 len;
} __attribute__((packed)); } __attribute__ ((packed));
struct nbd_reply_raw { struct nbd_reply_raw {
__be32 magic; __be32 magic;
__be32 error; /* 0 = ok, else error */ __be32 error; /* 0 = ok, else error */
nbd_handle_t handle; /* handle you got from request */ nbd_handle_t handle; /* handle you got from request */
}; };
struct nbd_init { struct nbd_init {
char passwd[8]; char passwd[8];
uint64_t magic; uint64_t magic;
uint64_t size; uint64_t size;
uint32_t flags; uint32_t flags;
char reserved[124]; char reserved[124];
}; };
struct nbd_request { struct nbd_request {
uint32_t magic; uint32_t magic;
uint16_t flags; uint16_t flags;
uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */ uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */
nbd_handle_t handle; nbd_handle_t handle;
uint64_t from; uint64_t from;
uint32_t len; uint32_t len;
} __attribute__((packed)); } __attribute__ ((packed));
struct nbd_reply { struct nbd_reply {
uint32_t magic; uint32_t magic;
uint32_t error; /* 0 = ok, else error */ uint32_t error; /* 0 = ok, else error */
nbd_handle_t handle; /* handle you got from request */ 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_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_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_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_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_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_reply(struct nbd_reply *from, struct nbd_reply_raw *to);
#endif #endif

View File

@@ -10,118 +10,116 @@ int atoi(const char *nptr);
) )
/* FIXME: should change this to return negative on error like everything else */ /* 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(out);
NULLCHECK( src ); NULLCHECK(src);
char temp[64]; char temp[64];
struct sockaddr_in *v4 = (struct sockaddr_in *) out; struct sockaddr_in *v4 = (struct sockaddr_in *) out;
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out; struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out;
/* allow user to start with [ and end with any other invalid char */ /* allow user to start with [ and end with any other invalid char */
{ {
int i=0, j=0; int i = 0, j = 0;
if (src[i] == '[') { i++; } if (src[i] == '[') {
for (; i<64 && IS_IP_VALID_CHAR(src[i]); i++) { i++;
temp[j++] = src[i];
}
temp[j] = 0;
} }
for (; i < 64 && IS_IP_VALID_CHAR(src[i]); i++) {
if (temp[0] == '0' && temp[1] == '\0') { temp[j++] = src[i];
v4->sin_family = AF_INET;
v4->sin_addr.s_addr = INADDR_ANY;
return 1;
} }
temp[j] = 0;
}
if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) { if (temp[0] == '0' && temp[1] == '\0') {
out->sa_family = AF_INET; v4->sin_family = AF_INET;
return 1; v4->sin_addr.s_addr = INADDR_ANY;
} return 1;
}
if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) { if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) {
out->sa_family = AF_INET6; out->sa_family = AF_INET;
return 1; 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] == '/' ) { if (address[0] == '/') {
un->sun_family = AF_UNIX; un->sun_family = AF_UNIX;
strncpy( un->sun_path, address, 108 ); /* FIXME: linux only */ strncpy(un->sun_path, address, 108); /* FIXME: linux only */
return 1; 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) int parse_acl(struct ip_and_mask (**out)[], int max, char **entries)
{ {
struct ip_and_mask* list; struct ip_and_mask *list;
int i; int i;
if (max == 0) { if (max == 0) {
*out = NULL; *out = NULL;
return 0; return 0;
} } else {
else { list = xmalloc(max * sizeof(struct ip_and_mask));
list = xmalloc(max * sizeof(struct ip_and_mask)); *out = (struct ip_and_mask(*)[]) list;
*out = (struct ip_and_mask (*)[])list; debug("acl alloc: %p", *out);
debug("acl alloc: %p", *out); }
}
for (i = 0; i < max; i++) { for (i = 0; i < max; i++) {
int j; int j;
struct ip_and_mask* outentry = &list[i]; struct ip_and_mask *outentry = &list[i];
# define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128) # define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128)
if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) { if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) {
return i; return i;
} }
for (j=0; entries[i][j] && entries[i][j] != '/'; j++) for (j = 0; entries[i][j] && entries[i][j] != '/'; j++); // increment j!
; // increment j!
if (entries[i][j] == '/') { if (entries[i][j] == '/') {
outentry->mask = atoi(entries[i]+j+1); outentry->mask = atoi(entries[i] + j + 1);
if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) { if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) {
return i; return i;
} }
} } else {
else { outentry->mask = MAX_MASK_BITS;
outentry->mask = MAX_MASK_BITS; }
}
# undef 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++) { for (i = 0; i < max; i++) {
debug("acl entry %d @ %p has mask %d", i, list[i], list[i].mask); 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 ); raw_port = atoi(s_port);
if ( raw_port < 0 || raw_port > 65535 ) { if (raw_port < 0 || raw_port > 65535) {
fatal( "Port number must be >= 0 and <= 65535" ); fatal("Port number must be >= 0 and <= 65535");
} }
out->sin_port = htobe16( raw_port ); out->sin_port = htobe16(raw_port);
} }

View File

@@ -8,22 +8,21 @@
#include <unistd.h> #include <unistd.h>
union mysockaddr { union mysockaddr {
unsigned short family; unsigned short family;
struct sockaddr generic; struct sockaddr generic;
struct sockaddr_in v4; struct sockaddr_in v4;
struct sockaddr_in6 v6; struct sockaddr_in6 v6;
struct sockaddr_un un; struct sockaddr_un un;
}; };
struct ip_and_mask { struct ip_and_mask {
union mysockaddr ip; union mysockaddr ip;
int mask; int mask;
}; };
int parse_ip_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_to_sockaddr(struct sockaddr *out, char *src);
int parse_acl(struct ip_and_mask (**out)[], int max, char **entries); 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 #endif

View File

@@ -8,214 +8,217 @@
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
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); int fd =
if( fd < 0 ){ socket(to->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_STREAM,
warn( "Couldn't create client socket"); 0);
return -1; if (fd < 0) {
} warn("Couldn't create client socket");
return -1;
}
if (NULL != from) { if (NULL != from) {
if ( 0 > bind( fd, from, sizeof(struct sockaddr_in6 ) ) ){ if (0 > bind(fd, from, sizeof(struct sockaddr_in6))) {
warn( SHOW_ERRNO( "bind() to source address failed" ) ); warn(SHOW_ERRNO("bind() to source address failed"));
if ( 0 > close( fd ) ) { /* Non-fatal leak */ if (0 > close(fd)) { /* Non-fatal leak */
warn( SHOW_ERRNO( "Failed to close fd %i", fd ) ); warn(SHOW_ERRNO("Failed to close fd %i", fd));
} }
return -1; return -1;
}
} }
}
if ( 0 > sock_try_connect( fd, to, sizeof( struct sockaddr_in6 ), 15 ) ) { if (0 > sock_try_connect(fd, to, sizeof(struct sockaddr_in6), 15)) {
warn( SHOW_ERRNO( "connect failed" ) ); warn(SHOW_ERRNO("connect failed"));
if ( 0 > close( fd ) ) { /* Non-fatal leak */ if (0 > close(fd)) { /* Non-fatal leak */
warn( SHOW_ERRNO( "Failed to close fd %i", fd ) ); warn(SHOW_ERRNO("Failed to close fd %i", fd));
}
return -1;
} }
return -1;
}
if ( sock_set_tcp_nodelay( fd, 1 ) == -1 ) { if (sock_set_tcp_nodelay(fd, 1) == -1) {
warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) ); 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 ) { if (strncmp(init_raw->passwd, INIT_PASSWD, 8) != 0) {
warn( "wrong passwd" ); warn("wrong passwd");
goto fail; goto fail;
} }
if ( be64toh( init_raw->magic ) != INIT_MAGIC ) { if (be64toh(init_raw->magic) != INIT_MAGIC) {
warn( "wrong magic (%x)", be64toh( init_raw->magic ) ); warn("wrong magic (%x)", be64toh(init_raw->magic));
goto fail; goto fail;
} }
if ( NULL != out_size ) { if (NULL != out_size) {
*out_size = be64toh( init_raw->size ); *out_size = be64toh(init_raw->size);
} }
if ( NULL != out_flags ) { if (NULL != out_flags) {
*out_flags = be32toh( init_raw->flags ); *out_flags = be32toh(init_raw->flags);
} }
return 1; return 1;
fail: 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 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) ) ) { memset(buf, 0, sizeof(struct nbd_init_raw)); // ensure reserved is 0s
warn( "Couldn't read init" ); nbd_h2r_init(&init, buf);
return 0;
}
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 ); if (0 > writeloop(fd, &init_raw, sizeof(init_raw))) {
init.magic = INIT_MAGIC; warn(SHOW_ERRNO("failed to write hello to socket"));
init.size = out_size; return 0;
init.flags = out_flags; }
return 1;
memset( buf, 0, sizeof( struct nbd_init_raw ) ); // ensure reserved is 0s
nbd_h2r_init( &init, buf );
return;
} }
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; request_raw->magic = htobe32(REQUEST_MAGIC);
nbd_hello_to_buf( &init_raw, out_size, out_flags ); request_raw->type = htobe16(type);
request_raw->flags = htobe16(flags);
if ( 0 > writeloop( fd, &init_raw, sizeof( init_raw ) ) ) { request_raw->handle.w =
warn( SHOW_ERRNO( "failed to write hello to socket" ) ); (((uint64_t) rand()) << 32) | ((uint64_t) rand());
return 0; request_raw->from = htobe64(from);
} request_raw->len = htobe32(len);
return 1;
} }
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); struct nbd_reply_raw reply_raw;
request_raw->type = htobe16(type);
request_raw->flags = htobe16(flags); ERROR_IF_NEGATIVE(readloop
request_raw->handle.w = (((uint64_t)rand()) << 32) | ((uint64_t)rand()); (fd, &reply_raw, sizeof(struct nbd_reply_raw)),
request_raw->from = htobe64(from); "Couldn't read reply");
request_raw->len = htobe32(len);
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)), FD_ZERO(&fds);
"Couldn't read reply"); 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) { FATAL_IF(-1 == selected, "Select failed");
error("Reply magic incorrect (%x)", reply->magic); ERROR_IF(0 == selected, "Timed out waiting for reply");
}
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" );
} }
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_request_raw request_raw;
struct nbd_reply reply; struct nbd_reply reply;
fill_request(&request_raw, REQUEST_READ, 0, from, len); fill_request(&request_raw, REQUEST_READ, 0, from, len);
FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
"Couldn't write request"); "Couldn't write request");
wait_for_data( fd, timeout_secs ); wait_for_data(fd, timeout_secs);
read_reply(fd, request_raw.handle.w, &reply); read_reply(fd, request_raw.handle.w, &reply);
if (out_buf) { if (out_buf) {
FATAL_IF_NEGATIVE(readloop(fd, out_buf, len), FATAL_IF_NEGATIVE(readloop(fd, out_buf, len), "Read failed");
"Read failed"); } else {
} FATAL_IF_NEGATIVE(splice_via_pipe_loop(fd, out_fd, len),
else { "Splice failed");
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_request_raw request_raw;
struct nbd_reply reply; struct nbd_reply reply;
fill_request(&request_raw, REQUEST_WRITE, 0, from, len); fill_request(&request_raw, REQUEST_WRITE, 0, from, len);
ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)), ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
"Couldn't write request"); "Couldn't write request");
if (in_buf) { if (in_buf) {
ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len), ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len), "Write failed");
"Write failed"); } else {
} ERROR_IF_NEGATIVE(splice_via_pipe_loop(in_fd, fd, len),
else { "Splice failed");
ERROR_IF_NEGATIVE( }
splice_via_pipe_loop(in_fd, fd, len),
"Splice failed"
);
}
wait_for_data( fd, timeout_secs ); wait_for_data(fd, timeout_secs);
read_reply(fd, request_raw.handle.w, &reply); read_reply(fd, request_raw.handle.w, &reply);
} }
int socket_nbd_disconnect( int fd ) int socket_nbd_disconnect(int fd)
{ {
int success = 1; int success = 1;
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
fill_request( &request_raw, REQUEST_DISCONNECT, 0, 0, 0 ); fill_request(&request_raw, REQUEST_DISCONNECT, 0, 0, 0);
/* FIXME: This shouldn't be a FATAL error. We should just drop /* FIXME: This shouldn't be a FATAL error. We should just drop
* the mirror without affecting the main server. * the mirror without affecting the main server.
*/ */
FATAL_IF_NEGATIVE( writeloop( fd, &request_raw, sizeof( request_raw ) ), FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
"Failed to write the disconnect request." ); "Failed to write the disconnect request.");
return success; return success;
} }
#define CHECK_RANGE(error_type) { \ #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(&params->connect_to.generic, &params->connect_from.generic); params->client =
FATAL_IF_NEGATIVE( params->client, "Couldn't connect." ); socket_connect(&params->connect_to.generic,
CHECK_RANGE("read"); &params->connect_from.generic);
socket_nbd_read(params->client, params->from, params->len, FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
params->data_fd, NULL, 10); CHECK_RANGE("read");
close(params->client); 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(&params->connect_to.generic, &params->connect_from.generic); params->client =
FATAL_IF_NEGATIVE( params->client, "Couldn't connect." ); socket_connect(&params->connect_to.generic,
CHECK_RANGE("write"); &params->connect_from.generic);
socket_nbd_write(params->client, params->from, params->len, FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
params->data_fd, NULL, 10); CHECK_RANGE("write");
close(params->client); socket_nbd_write(params->client, params->from, params->len,
params->data_fd, NULL, 10);
close(params->client);
} }

View File

@@ -6,18 +6,21 @@
#include <sys/socket.h> #include <sys/socket.h>
#include "nbdtypes.h" #include "nbdtypes.h"
int socket_connect(struct sockaddr* to, struct sockaddr* from); 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_read_hello(int fd, uint64_t * size, uint32_t * flags);
int socket_nbd_write_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_read(int fd, uint64_t from, uint32_t len, int out_fd,
void socket_nbd_write(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs); void *out_buf, int timeout_secs);
int socket_nbd_disconnect( int fd ); 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 /* as you can see, we're slowly accumulating code that should really be in an
* NBD library */ * NBD library */
void nbd_hello_to_buf( struct nbd_init_raw* buf, uint64_t out_size, uint32_t out_flags ); void nbd_hello_to_buf(struct nbd_init_raw *buf, uint64_t out_size,
int nbd_check_hello( struct nbd_init_raw* init_raw, uint64_t* out_size, uint32_t* out_flags ); uint32_t out_flags);
int nbd_check_hello(struct nbd_init_raw *init_raw, uint64_t * out_size,
uint32_t * out_flags);
#endif #endif

View File

@@ -4,64 +4,62 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/un.h> #include <sys/un.h>
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; char *response_text;
FILE * out; FILE *out;
int exit_status; int exit_status;
NULLCHECK( response ); NULLCHECK(response);
exit_status = atoi(response); exit_status = atoi(response);
response_text = strchr( response, ':' ); response_text = strchr(response, ':');
FATAL_IF_NULL( response_text, FATAL_IF_NULL(response_text,
"Error parsing server response: '%s'", response ); "Error parsing server response: '%s'", response);
out = exit_status > 0 ? stderr : stdout; out = exit_status > 0 ? stderr : stdout;
fprintf(out, "%s\n", response_text + 2); 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; char newline = 10;
int i; int i;
debug( "connecting to run remote command %s", command ); debug("connecting to run remote command %s", command);
int remote = socket(AF_UNIX, SOCK_STREAM, 0); int remote = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un address; struct sockaddr_un address;
char response[max_response]; 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; address.sun_family = AF_UNIX;
strncpy(address.sun_path, socket_name, sizeof(address.sun_path)); strncpy(address.sun_path, socket_name, sizeof(address.sun_path));
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(connect
connect(remote, (struct sockaddr*) &address, sizeof(address)), (remote, (struct sockaddr *) &address,
"Couldn't connect to %s", socket_name sizeof(address)), "Couldn't connect to %s",
); socket_name);
write(remote, command, strlen(command)); write(remote, command, strlen(command));
write(remote, &newline, 1); write(remote, &newline, 1);
for (i=0; i<argc; i++) { for (i = 0; i < argc; i++) {
if ( NULL != argv[i] ) { if (NULL != argv[i]) {
write(remote, argv[i], strlen(argv[i])); write(remote, argv[i], strlen(argv[i]));
}
write(remote, &newline, 1);
} }
write(remote, &newline, 1); write(remote, &newline, 1);
}
write(remote, &newline, 1);
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(read_until_newline(remote, response, max_response),
read_until_newline(remote, response, max_response), "Couldn't read response from %s", socket_name);
"Couldn't read response from %s", socket_name
);
print_response( response ); print_response(response);
exit(atoi(response)); exit(atoi(response));
} }

View File

@@ -29,13 +29,13 @@
#define ERR_MSG_WRITE "Couldn't write to a signaling pipe." #define ERR_MSG_WRITE "Couldn't write to a signaling pipe."
#define ERR_MSG_READ "Couldn't read from a signaling pipe." #define ERR_MSG_READ "Couldn't read from a signaling pipe."
void self_pipe_server_error( int err, char *msg ) void self_pipe_server_error(int err, char *msg)
{ {
char errbuf[1024] = {0}; char errbuf[1024] = { 0 };
strerror_r( err, errbuf, 1024 ); strerror_r(err, errbuf, 1024);
fatal( "%s\t%d (%s)", msg, err, errbuf ); fatal("%s\t%d (%s)", msg, err, errbuf);
} }
/** /**
@@ -47,33 +47,36 @@ void self_pipe_server_error( int err, char *msg )
* Remember to call self_pipe_destroy when you're done with the return * Remember to call self_pipe_destroy when you're done with the return
* value. * value.
*/ */
struct self_pipe * self_pipe_create(void) struct self_pipe *self_pipe_create(void)
{ {
struct self_pipe *sig = xmalloc( sizeof( struct self_pipe ) ); struct self_pipe *sig = xmalloc(sizeof(struct self_pipe));
int fds[2]; int fds[2];
if ( NULL == sig ) { return NULL; } if (NULL == sig) {
return NULL;
}
if ( pipe( fds ) ) { if (pipe(fds)) {
free( sig ); free(sig);
self_pipe_server_error( errno, ERR_MSG_PIPE ); self_pipe_server_error(errno, ERR_MSG_PIPE);
return NULL; return NULL;
} }
if ( fcntl( fds[0], F_SETFL, O_NONBLOCK ) || fcntl( fds[1], F_SETFL, O_NONBLOCK ) ) { if (fcntl(fds[0], F_SETFL, O_NONBLOCK)
int fcntl_err = errno; || fcntl(fds[1], F_SETFL, O_NONBLOCK)) {
while( close( fds[0] ) == -1 && errno == EINTR ); int fcntl_err = errno;
while( close( fds[1] ) == -1 && errno == EINTR ); while (close(fds[0]) == -1 && errno == EINTR);
free( sig ); while (close(fds[1]) == -1 && errno == EINTR);
self_pipe_server_error( fcntl_err, ERR_MSG_FCNTL ); free(sig);
self_pipe_server_error(fcntl_err, ERR_MSG_FCNTL);
return NULL; return NULL;
} }
sig->read_fd = fds[0]; sig->read_fd = fds[0];
sig->write_fd = fds[1]; sig->write_fd = fds[1];
return sig; 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 * Returns 1 on success. Can fail if weirdness happened to the write fd
* of the pipe in the self_pipe struct. * 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 ); NULLCHECK(sig);
FATAL_IF( 1 == sig->write_fd, "Shouldn't be writing to stdout" ); FATAL_IF(1 == sig->write_fd, "Shouldn't be writing to stdout");
FATAL_IF( 2 == sig->write_fd, "Shouldn't be writing to stderr" ); FATAL_IF(2 == sig->write_fd, "Shouldn't be writing to stderr");
int written = write( sig->write_fd, "X", 1 ); int written = write(sig->write_fd, "X", 1);
if ( written != 1 ) { if (written != 1) {
self_pipe_server_error( errno, ERR_MSG_WRITE ); self_pipe_server_error(errno, ERR_MSG_WRITE);
return 0; 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 * Returns the number of bytes read, which will be 1 on success and 0 if
* there was no signal. * 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 * Close the pipe and free the self_pipe. Do not try to use the
* self_pipe struct after calling this, the innards are mush. * 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->read_fd) == -1 && errno == EINTR);
while( close( sig->write_fd ) == -1 && errno == EINTR ); while (close(sig->write_fd) == -1 && errno == EINTR);
/* Just in case anyone *does* try to use this after free, /* Just in case anyone *does* try to use this after free,
* we should set the memory locations to an error value * we should set the memory locations to an error value
*/ */
sig->read_fd = -1; sig->read_fd = -1;
sig->write_fd = -1; sig->write_fd = -1;
free( sig ); free(sig);
return 1; 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 ); FD_SET(sig->read_fd, fds);
return 1; 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);
} }

View File

@@ -4,16 +4,16 @@
#include <sys/select.h> #include <sys/select.h>
struct self_pipe { struct self_pipe {
int read_fd; int read_fd;
int write_fd; int write_fd;
}; };
struct self_pipe * self_pipe_create(void); struct self_pipe *self_pipe_create(void);
int self_pipe_signal( struct self_pipe * sig ); int self_pipe_signal(struct self_pipe *sig);
int self_pipe_signal_clear( struct self_pipe *sig ); int self_pipe_signal_clear(struct self_pipe *sig);
int self_pipe_destroy( 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_set(struct self_pipe *sig, fd_set * fds);
int self_pipe_fd_isset( struct self_pipe *sig, fd_set *fds ); int self_pipe_fd_isset(struct self_pipe *sig, fd_set * fds);
#endif #endif

View File

@@ -9,279 +9,287 @@
#include "sockutil.h" #include "sockutil.h"
#include "util.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; struct sockaddr_un *un = (struct sockaddr_un *) sa;
size_t ret = 0; size_t ret = 0;
switch( sa->sa_family ) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
ret = sizeof( struct sockaddr_in ); ret = sizeof(struct sockaddr_in);
break; break;
case AF_INET6: case AF_INET6:
ret = sizeof( struct sockaddr_in6 ); ret = sizeof(struct sockaddr_in6);
break; break;
case AF_UNIX: case AF_UNIX:
ret = sizeof( un->sun_family ) + SUN_LEN( un ); ret = sizeof(un->sun_family) + SUN_LEN(un);
break; 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(sa);
NULLCHECK( dest ); NULLCHECK(dest);
struct sockaddr_in* in = ( struct sockaddr_in* ) sa; struct sockaddr_in *in = (struct sockaddr_in *) sa;
struct sockaddr_in6* in6 = ( struct sockaddr_in6* ) sa; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) sa;
struct sockaddr_un* un = ( struct sockaddr_un* ) sa; struct sockaddr_un *un = (struct sockaddr_un *) sa;
unsigned short real_port = ntohs( in->sin_port ); // common to in and in6 unsigned short real_port = ntohs(in->sin_port); // common to in and in6
const char* ret = NULL; const char *ret = NULL;
memset( dest, 0, len ); memset(dest, 0, len);
if ( sa->sa_family == AF_INET ) { if (sa->sa_family == AF_INET) {
ret = inet_ntop( AF_INET, &in->sin_addr, dest, len ); ret = inet_ntop(AF_INET, &in->sin_addr, dest, len);
} else if ( sa->sa_family == AF_INET6 ) { } else if (sa->sa_family == AF_INET6) {
ret = inet_ntop( AF_INET6, &in6->sin6_addr, dest, len ); ret = inet_ntop(AF_INET6, &in6->sin6_addr, dest, len);
} else if ( sa->sa_family == AF_UNIX ) { } else if (sa->sa_family == AF_UNIX) {
ret = strncpy( dest, un->sun_path, SUN_LEN( un ) ); ret = strncpy(dest, un->sun_path, SUN_LEN(un));
} }
if ( ret == NULL ) { if (ret == NULL) {
strncpy( dest, "???", len ); strncpy(dest, "???", len);
} }
if ( NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX ) { if (NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX) {
size_t size = strlen( dest ); size_t size = strlen(dest);
snprintf( dest + size, len - size, " port %d", real_port ); 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) || if (sock_set_keepalive(fd, 1) ||
sock_set_tcp_keepidle(fd, time) || sock_set_tcp_keepidle(fd, time) ||
sock_set_tcp_keepintvl(fd, intvl) || sock_set_tcp_keepintvl(fd, intvl) ||
sock_set_tcp_keepcnt(fd, probes)) { sock_set_tcp_keepcnt(fd, probes)) {
return -1; return -1;
} }
return 0; 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 */ /* 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 ) { if (flags == -1) {
return -1; return -1;
} }
if ( optval ) { if (optval) {
flags = flags | O_NONBLOCK; 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 { } 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; fd_set fds;
char s_address[256]; struct timeval tv = { wait, 0 };
int retry = 10; 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 { FD_ZERO(&fds);
bind_result = bind( fd, sa, sockaddr_size( sa ) ); FD_SET(fd, &fds);
if ( 0 == bind_result ) {
info( "Bound to %s", s_address );
break;
}
else {
warn( SHOW_ERRNO( "Couldn't bind to %s", s_address ) );
switch ( errno ) { do {
/* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF, result = connect(fd, to, addrlen);
* 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; if (result == -1) {
} switch (errno) {
case EINPROGRESS:
int sock_try_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) result = 0;
{ break; /* success */
int result; case EAGAIN:
case EINTR:
do { /* Try connect() again. This only breaks out of the switch,
result = select(nfds, readfds, writefds, exceptfds, timeout); * not the do...while loop. since result == -1, we go again.
if ( errno != EINTR ) { */
break; break;
} default:
warn(SHOW_ERRNO("Failed to connect()"));
} 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;
goto out; goto out;
}
} }
} while (result == -1);
if ( !FD_ISSET( fd, &fds ) ) { if (-1 == sock_try_select(FD_SETSIZE, NULL, &fds, NULL, &tv)) {
result = -1; warn(SHOW_ERRNO("failed to select() on non-blocking connect"));
errno = ETIMEDOUT; result = -1;
goto out; goto out;
} }
int scratch; if (!FD_ISSET(fd, &fds)) {
socklen_t s_size = sizeof( scratch ); result = -1;
if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size ) == -1 ) { errno = ETIMEDOUT;
result = -1; goto out;
warn( SHOW_ERRNO( "getsockopt() failed" ) ); }
goto out;
}
if ( scratch == EINPROGRESS ) { int scratch;
scratch = ETIMEDOUT; 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; if (scratch == EINPROGRESS) {
errno = scratch; scratch = ETIMEDOUT;
}
out: result = scratch ? -1 : 0;
if ( sock_set_nonblock( fd, 0 ) == -1 ) { errno = scratch;
warn( SHOW_ERRNO( "Failed to make socket blocking after connect()" ) );
return -1;
}
debug( "sock_try_connect: %i", result ); out:
return result; 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 { do {
result = close( fd ); result = close(fd);
if ( result == -1 ) { if (result == -1) {
if ( EINTR == errno ) { if (EINTR == errno) {
continue; /* retry EINTR */ continue; /* retry EINTR */
} else { } else {
warn( SHOW_ERRNO( "Failed to close() fd %i", fd ) ); warn(SHOW_ERRNO("Failed to close() fd %i", fd));
break; /* Other errors get reported */ break; /* Other errors get reported */
} }
} }
} while( 0 ); } while (0);
return result; return result;
} }

View File

@@ -7,15 +7,16 @@
#include <sys/select.h> #include <sys/select.h>
/* Returns the size of the sockaddr, or 0 on error */ /* 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 /* Convert a sockaddr into an address. Like inet_ntop, it returns dest if
* successful, NULL otherwise. In the latter case, dest will contain "???" * 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 */ /* 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 */ /* Set the SOL_KEEPALIVE otion */
int sock_set_keepalive(int fd, int optval); 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); int sock_set_nonblock(int fd, int optval);
/* Attempt to bind the fd to the sockaddr, retrying common transient failures */ /* 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 */ /* 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 */ /* 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 */ /* Try to call close(), retrying EINTR */
int sock_try_close( int fd ); int sock_try_close(int fd);
#endif #endif

View File

@@ -17,72 +17,75 @@ char *log_context = "";
void error_init(void) void error_init(void)
{ {
pthread_key_create(&cleanup_handler_key, free); pthread_key_create(&cleanup_handler_key, free);
} }
void error_handler(int fatal) void error_handler(int fatal)
{ {
DECLARE_ERROR_CONTEXT(context); DECLARE_ERROR_CONTEXT(context);
if (context) { if (context) {
longjmp(context->jmp, fatal ? 1 : 2 ); longjmp(context->jmp, fatal ? 1 : 2);
} } else {
else { if (fatal) {
if ( fatal ) { abort(); } abort();
else { pthread_exit((void*) 1); } } else {
pthread_exit((void *) 1);
} }
}
} }
void exit_err( const char *msg ) void exit_err(const char *msg)
{ {
fprintf( stderr, "%s\n", msg ); fprintf(stderr, "%s\n", msg);
exit( 1 ); 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); va_start(argptr, format);
vfprintf(stderr, format, argptr); vfprintf(stderr, format, argptr);
va_end(argptr); va_end(argptr);
} }
uint64_t monotonic_time_ms() uint64_t monotonic_time_ms()
{ {
struct timespec ts; struct timespec ts;
uint64_t seconds_ms, nanoseconds_ms; uint64_t seconds_ms, nanoseconds_ms;
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(clock_gettime(CLOCK_MONOTONIC, &ts),
clock_gettime(CLOCK_MONOTONIC, &ts), SHOW_ERRNO("clock_gettime failed")
SHOW_ERRNO( "clock_gettime failed" )
); );
seconds_ms = ts.tv_sec; seconds_ms = ts.tv_sec;
seconds_ms = seconds_ms * 1000; seconds_ms = seconds_ms * 1000;
nanoseconds_ms = ts.tv_nsec; nanoseconds_ms = ts.tv_nsec;
nanoseconds_ms = nanoseconds_ms / 1000000; 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); void *p = realloc(ptr, size);
FATAL_IF_NULL(p, "couldn't xrealloc %d bytes", ptr ? "realloc" : "malloc", size); FATAL_IF_NULL(p, "couldn't xrealloc %d bytes",
return p; ptr ? "realloc" : "malloc", size);
return p;
} }
void* xmalloc(size_t size) void *xmalloc(size_t size)
{ {
void* p = xrealloc(NULL, size); void *p = xrealloc(NULL, size);
memset(p, 0, size); memset(p, 0, size);
return p; return p;
} }

View File

@@ -10,10 +10,11 @@
#include <unistd.h> #include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
void* xrealloc(void* ptr, size_t size); void *xrealloc(void *ptr, size_t size);
void* xmalloc(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 */ /* set from 0 - 5 depending on what level of verbosity you want */
extern int log_level; extern int log_level;
@@ -25,15 +26,15 @@ void error_init(void);
extern char *log_context; 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 */ /* error_set_handler must be a macro not a function due to setjmp stack rules */
#include <setjmp.h> #include <setjmp.h>
struct error_handler_context { struct error_handler_context {
jmp_buf jmp; jmp_buf jmp;
cleanup_handler* handler; cleanup_handler *handler;
void* data; void *data;
}; };
#define DECLARE_ERROR_CONTEXT(name) \ #define DECLARE_ERROR_CONTEXT(name) \
@@ -87,7 +88,7 @@ extern pthread_key_t cleanup_handler_key;
void error_handler(int fatal); void error_handler(int fatal);
/* mylog a line at the given level (0 being most verbose) */ /* 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 */ /* Returns the current time, in milliseconds, from CLOCK_MONOTONIC */
uint64_t monotonic_time_ms(void); 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__ ) #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 #ifdef DEBUG
# define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__) #define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__)
#else #else
# define debug(msg, ...) /* no-op */ #define debug(msg, ...) /* no-op */
#endif #endif
/* informational message, not expected to be compiled out */ /* 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__ ); } #define WARN_IF_NEGATIVE( value, msg, ... ) if ( value < 0 ) { warn( msg, ##__VA_ARGS__ ); }
#endif #endif

View File

@@ -5,18 +5,17 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
int main(int argc, char** argv) int main(int argc, char **argv)
{ {
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
error_init(); error_init();
srand(time(NULL)); srand(time(NULL));
if (argc < 2) { if (argc < 2) {
exit_err( help_help_text ); exit_err(help_help_text);
} }
mode(argv[1], argc-1, argv+1); /* never returns */ mode(argv[1], argc - 1, argv + 1); /* never returns */
return 0; return 0;
} }

View File

@@ -8,164 +8,158 @@
static struct option proxy_options[] = { static struct option proxy_options[] = {
GETOPT_HELP, GETOPT_HELP,
GETOPT_ADDR, GETOPT_ADDR,
GETOPT_PORT, GETOPT_PORT,
GETOPT_CONNECT_ADDR, GETOPT_CONNECT_ADDR,
GETOPT_CONNECT_PORT, GETOPT_CONNECT_PORT,
GETOPT_BIND, GETOPT_BIND,
GETOPT_CACHE, GETOPT_CACHE,
GETOPT_QUIET, GETOPT_QUIET,
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE; static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE;
static char proxy_help_text[] = static char proxy_help_text[] =
"Usage: flexnbd-proxy <options>\n\n" "Usage: flexnbd-proxy <options>\n\n"
"Resiliently proxy an NBD connection between client and server\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" "We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n"
HELP_LINE HELP_LINE
"\t--" OPT_ADDR ",-l <ADDR>\tThe address we will bind to as a proxy.\n" "\t--" OPT_ADDR ",-l <ADDR>\tThe address we will bind to as a proxy.\n"
"\t--" OPT_PORT ",-p <PORT>\tThe port we will bind to as a proxy, if required.\n" "\t--" OPT_PORT
"\t--" OPT_CONNECT_ADDR ",-C <ADDR>\tAddress of the proxied server.\n" ",-p <PORT>\tThe port we will bind to as a proxy, if required.\n"
"\t--" OPT_CONNECT_PORT ",-P <PORT>\tPort of the proxied server.\n" "\t--" OPT_CONNECT_ADDR ",-C <ADDR>\tAddress of the proxied server.\n"
"\t--" OPT_BIND ",-b <ADDR>\tThe address we connect from, as a proxy.\n" "\t--" OPT_CONNECT_PORT ",-P <PORT>\tPort of the proxied server.\n"
"\t--" OPT_CACHE ",-c[=<CACHE-BYTES>]\tUse a RAM read cache of the given size.\n" "\t--" OPT_BIND
QUIET_LINE ",-b <ADDR>\tThe address we connect from, as a proxy.\n" "\t--"
VERBOSE_LINE; OPT_CACHE
",-c[=<CACHE-BYTES>]\tUse a RAM read cache of the given size.\n"
QUIET_LINE VERBOSE_LINE;
static char proxy_default_cache_size[] = "4096"; static char proxy_default_cache_size[] = "4096";
void read_proxy_param( void read_proxy_param(int c,
int c, char **downstream_addr,
char **downstream_addr, char **downstream_port,
char **downstream_port, char **upstream_addr,
char **upstream_addr, char **upstream_port,
char **upstream_port, char **bind_addr, char **cache_bytes)
char **bind_addr,
char **cache_bytes)
{ {
switch( c ) { switch (c) {
case 'h' : case 'h':
fprintf( stdout, "%s\n", proxy_help_text ); fprintf(stdout, "%s\n", proxy_help_text);
exit( 0 ); exit(0);
case 'l': case 'l':
*downstream_addr = optarg; *downstream_addr = optarg;
break; break;
case 'p': case 'p':
*downstream_port = optarg; *downstream_port = optarg;
break; break;
case 'C': case 'C':
*upstream_addr = optarg; *upstream_addr = optarg;
break; break;
case 'P': case 'P':
*upstream_port = optarg; *upstream_port = optarg;
break; break;
case 'b': case 'b':
*bind_addr = optarg; *bind_addr = optarg;
break; break;
case 'c': case 'c':
*cache_bytes = optarg ? optarg : proxy_default_cache_size; *cache_bytes = optarg ? optarg : proxy_default_cache_size;
break; break;
case 'q': case 'q':
log_level = QUIET_LOG_LEVEL; log_level = QUIET_LOG_LEVEL;
break; break;
case 'v': case 'v':
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( proxy_help_text ); exit_err(proxy_help_text);
break; break;
} }
} }
struct proxier * proxy = NULL; struct proxier *proxy = NULL;
void my_exit(int signum) void my_exit(int signum)
{ {
info( "Exit signalled (%i)", signum ); info("Exit signalled (%i)", signum);
if ( NULL != proxy ) { if (NULL != proxy) {
proxy_cleanup( proxy ); proxy_cleanup(proxy);
}; };
exit( 0 ); exit(0);
} }
int main( int argc, char *argv[] ) int main(int argc, char *argv[])
{ {
int c; int c;
char *downstream_addr = NULL; char *downstream_addr = NULL;
char *downstream_port = NULL; char *downstream_port = NULL;
char *upstream_addr = NULL; char *upstream_addr = NULL;
char *upstream_port = NULL; char *upstream_port = NULL;
char *bind_addr = NULL; char *bind_addr = NULL;
char *cache_bytes = NULL; char *cache_bytes = NULL;
int success; int success;
sigset_t mask; sigset_t mask;
struct sigaction exit_action; struct sigaction exit_action;
sigemptyset( &mask ); sigemptyset(&mask);
sigaddset( &mask, SIGTERM ); sigaddset(&mask, SIGTERM);
sigaddset( &mask, SIGQUIT ); sigaddset(&mask, SIGQUIT);
sigaddset( &mask, SIGINT ); sigaddset(&mask, SIGINT);
exit_action.sa_handler = my_exit; exit_action.sa_handler = my_exit;
exit_action.sa_mask = mask; exit_action.sa_mask = mask;
exit_action.sa_flags = 0; exit_action.sa_flags = 0;
srand(time(NULL)); srand(time(NULL));
while (1) { while (1) {
c = getopt_long( argc, argv, proxy_short_options, proxy_options, NULL ); c = getopt_long(argc, argv, proxy_short_options, proxy_options,
if ( -1 == c ) { break; } NULL);
read_proxy_param( c, if (-1 == c) {
&downstream_addr, break;
&downstream_port,
&upstream_addr,
&upstream_port,
&bind_addr,
&cache_bytes
);
} }
read_proxy_param(c,
&downstream_addr,
&downstream_port,
&upstream_addr,
&upstream_port, &bind_addr, &cache_bytes);
}
if ( NULL == downstream_addr ){ if (NULL == downstream_addr) {
fprintf( stderr, "--addr is required.\n" ); fprintf(stderr, "--addr is required.\n");
exit_err( proxy_help_text ); exit_err(proxy_help_text);
} else if ( NULL == upstream_addr || NULL == upstream_port ){ } else if (NULL == upstream_addr || NULL == upstream_port) {
fprintf( stderr, "both --conn-addr and --conn-port are required.\n" ); fprintf(stderr,
exit_err( proxy_help_text ); "both --conn-addr and --conn-port are required.\n");
} exit_err(proxy_help_text);
}
proxy = proxy_create( proxy = proxy_create(downstream_addr,
downstream_addr, downstream_port,
downstream_port, upstream_addr,
upstream_addr, upstream_port, bind_addr, cache_bytes);
upstream_port,
bind_addr,
cache_bytes
);
/* Set these *after* proxy has been assigned to */ /* Set these *after* proxy has been assigned to */
sigaction(SIGTERM, &exit_action, NULL); sigaction(SIGTERM, &exit_action, NULL);
sigaction(SIGQUIT, &exit_action, NULL); sigaction(SIGQUIT, &exit_action, NULL);
sigaction(SIGINT, &exit_action, NULL); sigaction(SIGINT, &exit_action, NULL);
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
if ( NULL != downstream_port ) { if (NULL != downstream_port) {
info( info("Proxying between %s %s (downstream) and %s %s (upstream)",
"Proxying between %s %s (downstream) and %s %s (upstream)", downstream_addr, downstream_port, upstream_addr,
downstream_addr, downstream_port, upstream_addr, upstream_port upstream_port);
); } else {
} else { info("Proxying between %s (downstream) and %s %s (upstream)",
info( downstream_addr, upstream_addr, upstream_port);
"Proxying between %s (downstream) and %s %s (upstream)", }
downstream_addr, upstream_addr, upstream_port
);
}
success = do_proxy( proxy ); success = do_proxy(proxy);
proxy_destroy( proxy ); proxy_destroy(proxy);
return success ? 0 : 1; return success ? 0 : 1;
} }

View File

@@ -2,67 +2,77 @@
#include "util.h" #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 ) ); struct prefetch *out = xmalloc(sizeof(struct prefetch));
NULLCHECK( out ); NULLCHECK(out);
out->buffer = xmalloc( size_bytes ); out->buffer = xmalloc(size_bytes);
NULLCHECK( out->buffer ); NULLCHECK(out->buffer);
out->size = size_bytes; out->size = size_bytes;
out->is_full = 0; out->is_full = 0;
out->from = 0; out->from = 0;
out->len = 0; out->len = 0;
return out; return out;
} }
void prefetch_destroy( struct prefetch *prefetch ) { void prefetch_destroy(struct prefetch *prefetch)
if( prefetch ) { {
free( prefetch->buffer ); if (prefetch) {
free( prefetch ); free(prefetch->buffer);
} free(prefetch);
}
} }
size_t prefetch_size( struct prefetch *prefetch){ size_t prefetch_size(struct prefetch *prefetch)
if ( prefetch ) { {
return prefetch->size; if (prefetch) {
} else { return prefetch->size;
return 0; } else {
} return 0;
}
} }
void prefetch_set_is_empty( struct prefetch *prefetch ){ void prefetch_set_is_empty(struct prefetch *prefetch)
prefetch_set_full( prefetch, 0 ); {
prefetch_set_full(prefetch, 0);
} }
void prefetch_set_is_full( struct prefetch *prefetch ){ void prefetch_set_is_full(struct prefetch *prefetch)
prefetch_set_full( prefetch, 1 ); {
prefetch_set_full(prefetch, 1);
} }
void prefetch_set_full( struct prefetch *prefetch, int val ){ void prefetch_set_full(struct prefetch *prefetch, int val)
if( prefetch ) { {
prefetch->is_full = val; if (prefetch) {
} prefetch->is_full = val;
}
} }
int prefetch_is_full( struct prefetch *prefetch ){ int prefetch_is_full(struct prefetch *prefetch)
if( prefetch ) { {
return prefetch->is_full; if (prefetch) {
} else { return prefetch->is_full;
return 0; } else {
} return 0;
}
} }
int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len ){ int prefetch_contains(struct prefetch *prefetch, uint64_t from,
NULLCHECK( prefetch ); uint32_t len)
return from >= prefetch->from && {
from + len <= prefetch->from + prefetch->len; NULLCHECK(prefetch);
return from >= prefetch->from &&
from + len <= prefetch->from + prefetch->len;
} }
char *prefetch_offset( struct prefetch *prefetch, uint64_t from ){ char *prefetch_offset(struct prefetch *prefetch, uint64_t from)
NULLCHECK( prefetch ); {
return prefetch->buffer + (from - prefetch->from); NULLCHECK(prefetch);
return prefetch->buffer + (from - prefetch->from);
} }

View File

@@ -7,27 +7,28 @@
#define PREFETCH_BUFSIZE 4096 #define PREFETCH_BUFSIZE 4096
struct prefetch { struct prefetch {
/* True if there is data in the buffer. */ /* True if there is data in the buffer. */
int is_full; int is_full;
/* The start point of the current content of buffer */ /* The start point of the current content of buffer */
uint64_t from; uint64_t from;
/* The length of the current content of buffer */ /* The length of the current content of buffer */
uint32_t len; uint32_t len;
/* The total size of the buffer, in bytes. */ /* The total size of the buffer, in bytes. */
size_t size; size_t size;
char *buffer; char *buffer;
}; };
struct prefetch* prefetch_create( size_t size_bytes ); struct prefetch *prefetch_create(size_t size_bytes);
void prefetch_destroy( struct prefetch *prefetch ); void prefetch_destroy(struct prefetch *prefetch);
size_t prefetch_size( struct prefetch *); size_t prefetch_size(struct prefetch *);
void prefetch_set_is_empty( struct prefetch *prefetch ); void prefetch_set_is_empty(struct prefetch *prefetch);
void prefetch_set_is_full( struct prefetch *prefetch ); void prefetch_set_is_full(struct prefetch *prefetch);
void prefetch_set_full( struct prefetch *prefetch, int val ); void prefetch_set_full(struct prefetch *prefetch, int val);
int prefetch_is_full( struct prefetch *prefetch ); int prefetch_is_full(struct prefetch *prefetch);
int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len ); int prefetch_contains(struct prefetch *prefetch, uint64_t from,
char *prefetch_offset( struct prefetch *prefetch, uint64_t from ); uint32_t len);
char *prefetch_offset(struct prefetch *prefetch, uint64_t from);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@
#include "self_pipe.h" #include "self_pipe.h"
#ifdef PREFETCH #ifdef PREFETCH
#include "prefetch.h" #include "prefetch.h"
#endif #endif
/** UPSTREAM_TIMEOUT /** UPSTREAM_TIMEOUT
@@ -21,80 +21,77 @@
struct proxier { struct proxier {
/** address/port to bind to */ /** address/port to bind to */
union mysockaddr listen_on; union mysockaddr listen_on;
/** address/port to connect to */ /** address/port to connect to */
union mysockaddr connect_to; union mysockaddr connect_to;
/** address to bind to when making outgoing connections */ /** address to bind to when making outgoing connections */
union mysockaddr connect_from; union mysockaddr connect_from;
int bind; /* Set to true if we should use it */ int bind; /* Set to true if we should use it */
/* The socket we listen() on and accept() against */ /* The socket we listen() on and accept() against */
int listen_fd; int listen_fd;
/* The socket returned by accept() that we receive requests from and send /* The socket returned by accept() that we receive requests from and send
* responses to * responses to
*/ */
int downstream_fd; int downstream_fd;
/* The socket returned by connect() that we send requests to and receive /* The socket returned by connect() that we send requests to and receive
* responses from * responses from
*/ */
int upstream_fd; int upstream_fd;
/* This is the size we advertise to the downstream server */ /* This is the size we advertise to the downstream server */
uint64_t upstream_size; uint64_t upstream_size;
/* These are the transmission flags sent as part of the handshake */ /* These are the transmission flags sent as part of the handshake */
uint32_t upstream_flags; uint32_t upstream_flags;
/* We transform the raw request header into here */ /* We transform the raw request header into here */
struct nbd_request req_hdr; struct nbd_request req_hdr;
/* We transform the raw reply header into here */ /* We transform the raw reply header into here */
struct nbd_reply rsp_hdr; struct nbd_reply rsp_hdr;
/* Used for our non-blocking negotiation with upstream. TODO: maybe use /* Used for our non-blocking negotiation with upstream. TODO: maybe use
* for downstream as well ( we currently overload rsp ) */ * for downstream as well ( we currently overload rsp ) */
struct iobuf init; struct iobuf init;
/* The current NBD request from downstream */ /* The current NBD request from downstream */
struct iobuf req; struct iobuf req;
/* The current NBD reply from upstream */ /* The current NBD reply from upstream */
struct iobuf rsp; struct iobuf rsp;
/* It's starting to feel like we need an object for a single proxy session. /* 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 * These two track how many requests we've sent so far, and whether the
* NBD_INIT code has been sent to the client yet. * NBD_INIT code has been sent to the client yet.
*/ */
uint64_t req_count; uint64_t req_count;
int hello_sent; int hello_sent;
/** These are only used if we pass --cache on the command line */ /** 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 /* While the in-flight request has been munged by prefetch, these two are
* set to true, and the original length of the request, respectively */ * set to true, and the original length of the request, respectively */
int is_prefetch_req; int is_prefetch_req;
uint32_t prefetch_req_orig_len; uint32_t prefetch_req_orig_len;
/* And here, we actually store the prefetched data once it's returned */ /* And here, we actually store the prefetched data once it's returned */
struct prefetch *prefetch; struct prefetch *prefetch;
/** */ /** */
}; };
struct proxier* proxy_create( struct proxier *proxy_create(char *s_downstream_address,
char* s_downstream_address, char *s_downstream_port,
char* s_downstream_port, char *s_upstream_address,
char* s_upstream_address, char *s_upstream_port,
char* s_upstream_port, char *s_upstream_bind, char *s_cache_bytes);
char* s_upstream_bind, int do_proxy(struct proxier *proxy);
char* s_cache_bytes); void proxy_cleanup(struct proxier *proxy);
int do_proxy( struct proxier* proxy ); void proxy_destroy(struct proxier *proxy);
void proxy_cleanup( struct proxier* proxy );
void proxy_destroy( struct proxier* proxy );
#endif #endif

View File

@@ -6,103 +6,104 @@
#include "acl.h" #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 = (struct acl *) xmalloc(sizeof(struct acl));
acl->len = parse_acl( &acl->entries, len, lines ); acl->len = parse_acl(&acl->entries, len, lines);
acl->default_deny = default_deny; acl->default_deny = default_deny;
return acl; 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 /** 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. * 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++) { for (i = 0; i < list_length; i++) {
struct ip_and_mask *entry = &(*list)[i]; struct ip_and_mask *entry = &(*list)[i];
int testbits; int testbits;
unsigned char *raw_address1 = NULL, *raw_address2 = NULL; 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) { if (test->generic.sa_family != entry->ip.family) {
continue; 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");
} }
return 0; if (test->generic.sa_family == AF_INET) {
} debug("it's an AF_INET");
raw_address1 = (unsigned char *) &test->v4.sin_addr;
int acl_includes( struct acl * acl, union mysockaddr * addr ) raw_address2 = (unsigned char *) &entry->ip.v4.sin_addr;
{ } else if (test->generic.sa_family == AF_INET6) {
NULLCHECK( acl ); debug("it's an AF_INET6");
raw_address1 = (unsigned char *) &test->v6.sin6_addr;
if ( 0 == acl->len ) { raw_address2 = (unsigned char *) &entry->ip.v6.sin6_addr;
return !( acl->default_deny ); } 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 ); NULLCHECK(acl);
return acl->default_deny;
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 ); NULLCHECK(acl);
acl->len = 0; return acl->default_deny;
acl->entries = NULL;
free( acl );
} }
void acl_destroy(struct acl *acl)
{
free(acl->entries);
acl->len = 0;
acl->entries = NULL;
free(acl);
}

View File

@@ -4,9 +4,9 @@
#include "parse.h" #include "parse.h"
struct acl { struct acl {
int len; int len;
int default_deny; int default_deny;
struct ip_and_mask (*entries)[]; struct ip_and_mask (*entries)[];
}; };
/** Allocate a new acl structure, parsing the given lines to sockaddr /** 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 * default_deny controls the behaviour of an empty list: if true, all
* requests will be denied. If true, all requests will be accepted. * 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. /** Check to see whether an address is allowed by an acl.
* See acl_create for how the default_deny setting affects this. * 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 */ /** 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. /** Free the acl structure and the internal acl entries table.
*/ */
void acl_destroy( struct acl * ); void acl_destroy(struct acl *);
#endif #endif

View File

@@ -12,8 +12,8 @@
* poking at the bits directly without using these * poking at the bits directly without using these
* accessors/macros * accessors/macros
*/ */
typedef uint64_t bitfield_word_t; typedef uint64_t bitfield_word_t;
typedef bitfield_word_t * bitfield_p; typedef bitfield_word_t *bitfield_p;
#define BITFIELD_WORD_SIZE sizeof(bitfield_word_t) #define BITFIELD_WORD_SIZE sizeof(bitfield_word_t)
#define BITS_PER_WORD (BITFIELD_WORD_SIZE * 8) #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) ((_bytes + (BITFIELD_WORD_SIZE-1)) / BITFIELD_WORD_SIZE)
/** Return the bit value ''idx'' in array ''b'' */ /** Return the bit value ''idx'' in array ''b'' */
static inline int bit_get(bitfield_p b, uint64_t idx) { static inline int bit_get(bitfield_p b, uint64_t idx)
return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD-1))) & 1; {
return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD - 1))) & 1;
} }
/** Return 1 if the bit at ''idx'' in array ''b'' is set */ /** Return 1 if the bit at ''idx'' in array ''b'' is set */
static inline int bit_is_set(bitfield_p b, uint64_t idx) { static inline int bit_is_set(bitfield_p b, uint64_t idx)
return bit_get(b, idx); {
return bit_get(b, idx);
} }
/** Return 1 if the bit at ''idx'' in array ''b'' is clear */ /** Return 1 if the bit at ''idx'' in array ''b'' is clear */
static inline int bit_is_clear(bitfield_p b, uint64_t idx) { static inline int bit_is_clear(bitfield_p b, uint64_t idx)
return !bit_get(b, idx); {
return !bit_get(b, idx);
} }
/** Tests whether the bit at ''idx'' in array ''b'' has value ''value'' */ /** 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) { static inline int bit_has_value(bitfield_p b, uint64_t idx, int value)
return bit_get(b, idx) == !!value; {
return bit_get(b, idx) == ! !value;
} }
/** Sets the bit ''idx'' in array ''b'' */ /** Sets the bit ''idx'' in array ''b'' */
static inline void bit_set(bitfield_p b, uint64_t idx) { static inline void bit_set(bitfield_p b, uint64_t idx)
BIT_WORD(b, idx) |= BIT_MASK(idx); {
BIT_WORD(b, idx) |= BIT_MASK(idx);
} }
/** Clears the bit ''idx'' in array ''b'' */ /** Clears the bit ''idx'' in array ''b'' */
static inline void bit_clear(bitfield_p b, uint64_t idx) { static inline void bit_clear(bitfield_p b, uint64_t idx)
BIT_WORD(b, idx) &= ~BIT_MASK(idx); {
BIT_WORD(b, idx) &= ~BIT_MASK(idx);
} }
/** Sets ''len'' bits in array ''b'' starting at offset ''from'' */ /** 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) static inline void bit_set_range(bitfield_p b, uint64_t from, uint64_t len)
{ {
for ( ; (from % BITS_PER_WORD) != 0 && len > 0 ; len-- ) { for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) {
bit_set( b, from++ ); bit_set(b, from++);
} }
if (len >= BITS_PER_WORD) { if (len >= BITS_PER_WORD) {
memset(&BIT_WORD(b, from), 0xff, len / 8 ); memset(&BIT_WORD(b, from), 0xff, len / 8);
from += len; from += len;
len = len % BITS_PER_WORD; len = len % BITS_PER_WORD;
from -= len; from -= len;
} }
for ( ; len > 0 ; len-- ) { for (; len > 0; len--) {
bit_set( b, from++ ); bit_set(b, from++);
} }
} }
/** Clears ''len'' bits in array ''b'' starting at offset ''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-- ) { for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) {
bit_clear( b, from++ ); bit_clear(b, from++);
} }
if (len >= BITS_PER_WORD) { if (len >= BITS_PER_WORD) {
memset(&BIT_WORD(b, from), 0, len / 8 ); memset(&BIT_WORD(b, from), 0, len / 8);
from += len; from += len;
len = len % BITS_PER_WORD; len = len % BITS_PER_WORD;
from -= len; from -= len;
} }
for ( ; len > 0 ; len-- ) { for (; len > 0; len--) {
bit_clear( b, from++ ); bit_clear(b, from++);
} }
} }
/** Counts the number of contiguous bits in array ''b'', starting at ''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 * 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. * 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) { static inline uint64_t bit_run_count(bitfield_p b, uint64_t from,
uint64_t count = 0; uint64_t len, int *run_is_set)
int first_value = bit_get(b, from); {
bitfield_word_t word_match = first_value ? -1 : 0; 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 ) { if (run_is_set != NULL) {
*run_is_set = first_value; *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--) { for (; len >= BITS_PER_WORD; len -= BITS_PER_WORD) {
if (bit_has_value(b, from + count, first_value)) { if (BIT_WORD(b, from + count) == word_match) {
count++; count += BITS_PER_WORD;
} else { } else {
return count; break;
}
} }
}
for ( ; len >= BITS_PER_WORD ; len -= BITS_PER_WORD ) { for (; len > 0; len--) {
if (BIT_WORD(b, from + count) == word_match) { if (bit_has_value(b, from + count, first_value)) {
count += BITS_PER_WORD; count++;
} else {
break;
}
} }
}
for ( ; len > 0; len-- ) { return count;
if ( bit_has_value(b, from + count, first_value) ) {
count++;
}
}
return count;
} }
enum bitset_stream_events { enum bitset_stream_events {
BITSET_STREAM_UNSET = 0, BITSET_STREAM_UNSET = 0,
BITSET_STREAM_SET = 1, BITSET_STREAM_SET = 1,
BITSET_STREAM_ON = 2, BITSET_STREAM_ON = 2,
BITSET_STREAM_OFF = 3 BITSET_STREAM_OFF = 3
}; };
#define BITSET_STREAM_EVENTS_ENUM_SIZE 4 #define BITSET_STREAM_EVENTS_ENUM_SIZE 4
struct bitset_stream_entry { struct bitset_stream_entry {
enum bitset_stream_events event; enum bitset_stream_events event;
uint64_t from; uint64_t from;
uint64_t len; uint64_t len;
}; };
/** Limit the stream size to 1MB for now. /** 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 ) ) #define BITSET_STREAM_SIZE ( ( 1024 * 1024 ) / sizeof( struct bitset_stream_entry ) )
struct bitset_stream { struct bitset_stream {
struct bitset_stream_entry entries[BITSET_STREAM_SIZE]; struct bitset_stream_entry entries[BITSET_STREAM_SIZE];
int in; int in;
int out; int out;
int size; int size;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond_not_full; pthread_cond_t cond_not_full;
pthread_cond_t cond_not_empty; pthread_cond_t cond_not_empty;
uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE]; uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE];
}; };
@@ -169,47 +184,49 @@ struct bitset_stream {
* written reliably by multiple threads. * written reliably by multiple threads.
*/ */
struct bitset { struct bitset {
pthread_mutex_t lock; pthread_mutex_t lock;
uint64_t size; uint64_t size;
int resolution; int resolution;
struct bitset_stream *stream; struct bitset_stream *stream;
int stream_enabled; int stream_enabled;
bitfield_word_t bits[]; bitfield_word_t bits[];
}; };
/** Allocate a bitset for a file of the given size, and chunks of the /** Allocate a bitset for a file of the given size, and chunks of the
* given resolution. * 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 // calculate a size to allocate that is a multiple of the size of the
// bitfield word // bitfield word
size_t bitfield_size = size_t bitfield_size =
BIT_WORDS_FOR_SIZE((( size + resolution - 1 ) / resolution)) * sizeof( bitfield_word_t ); BIT_WORDS_FOR_SIZE(((size + resolution -
struct bitset *bitset = xmalloc(sizeof( struct bitset ) + ( bitfield_size / 8 ) ); 1) / resolution)) * sizeof(bitfield_word_t);
struct bitset *bitset =
xmalloc(sizeof(struct bitset) + (bitfield_size / 8));
bitset->size = size; bitset->size = size;
bitset->resolution = resolution; bitset->resolution = resolution;
/* don't actually need to call pthread_mutex_destroy '*/ /* don't actually need to call pthread_mutex_destroy ' */
pthread_mutex_init(&bitset->lock, NULL); pthread_mutex_init(&bitset->lock, NULL);
bitset->stream = xmalloc( sizeof( struct bitset_stream ) ); bitset->stream = xmalloc(sizeof(struct bitset_stream));
pthread_mutex_init( &bitset->stream->mutex, NULL ); pthread_mutex_init(&bitset->stream->mutex, NULL);
/* Technically don't need to call pthread_cond_destroy either */ /* 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_full, NULL);
pthread_cond_init( &bitset->stream->cond_not_empty, 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 ); free(set->stream);
set->stream = NULL; set->stream = NULL;
free( set ); free(set);
} }
#define INT_FIRST_AND_LAST \ #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") FATAL_IF_NEGATIVE(pthread_mutex_unlock(&set->lock), "Error unlocking bitset")
static inline void bitset_stream_enqueue( static inline void bitset_stream_enqueue(struct bitset *set,
struct bitset * set, enum bitset_stream_events event,
enum bitset_stream_events event, uint64_t from, uint64_t len)
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 ) { while (stream->size == BITSET_STREAM_SIZE) {
pthread_cond_wait( &stream->cond_not_full, &stream->mutex ); pthread_cond_wait(&stream->cond_not_full, &stream->mutex);
} }
stream->entries[stream->in].event = event; stream->entries[stream->in].event = event;
stream->entries[stream->in].from = from; stream->entries[stream->in].from = from;
stream->entries[stream->in].len = len; stream->entries[stream->in].len = len;
stream->queued_bytes[event] += len; stream->queued_bytes[event] += len;
stream->size++; stream->size++;
stream->in++; stream->in++;
stream->in %= BITSET_STREAM_SIZE; stream->in %= BITSET_STREAM_SIZE;
pthread_mutex_unlock( & stream->mutex ); pthread_mutex_unlock(&stream->mutex);
pthread_cond_signal( &stream->cond_not_empty ); pthread_cond_signal(&stream->cond_not_empty);
return; return;
} }
static inline void bitset_stream_dequeue( static inline void bitset_stream_dequeue(struct bitset *set,
struct bitset * set, struct bitset_stream_entry *out)
struct bitset_stream_entry * out
)
{ {
struct bitset_stream * stream = set->stream; struct bitset_stream *stream = set->stream;
struct bitset_stream_entry * dequeued; struct bitset_stream_entry *dequeued;
pthread_mutex_lock( &stream->mutex ); pthread_mutex_lock(&stream->mutex);
while ( stream->size == 0 ) { while (stream->size == 0) {
pthread_cond_wait( &stream->cond_not_empty, &stream->mutex ); pthread_cond_wait(&stream->cond_not_empty, &stream->mutex);
} }
dequeued = &stream->entries[stream->out]; dequeued = &stream->entries[stream->out];
if ( out != NULL ) { if (out != NULL) {
out->event = dequeued->event; out->event = dequeued->event;
out->from = dequeued->from; out->from = dequeued->from;
out->len = dequeued->len; out->len = dequeued->len;
} }
stream->queued_bytes[dequeued->event] -= dequeued->len; stream->queued_bytes[dequeued->event] -= dequeued->len;
stream->size--; stream->size--;
stream->out++; stream->out++;
stream->out %= BITSET_STREAM_SIZE; stream->out %= BITSET_STREAM_SIZE;
pthread_mutex_unlock( &stream->mutex ); pthread_mutex_unlock(&stream->mutex);
pthread_cond_signal( &stream->cond_not_full ); 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 ); pthread_mutex_lock(&set->stream->mutex);
size = set->stream->size; size = set->stream->size;
pthread_mutex_unlock( &set->stream->mutex ); pthread_mutex_unlock(&set->stream->mutex);
return size; return size;
} }
static inline uint64_t bitset_stream_queued_bytes( static inline uint64_t bitset_stream_queued_bytes(struct bitset *set,
struct bitset * set, enum bitset_stream_events
enum bitset_stream_events event event)
)
{ {
uint64_t total; uint64_t total;
pthread_mutex_lock( &set->stream->mutex ); pthread_mutex_lock(&set->stream->mutex);
total = set->stream->queued_bytes[event]; total = set->stream->queued_bytes[event];
pthread_mutex_unlock( &set->stream->mutex ); 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; BITSET_LOCK;
set->stream_enabled = 1; set->stream_enabled = 1;
bitset_stream_enqueue( set, BITSET_STREAM_ON, 0, set->size ); bitset_stream_enqueue(set, BITSET_STREAM_ON, 0, set->size);
BITSET_UNLOCK; BITSET_UNLOCK;
} }
static inline void bitset_disable_stream( struct bitset * set ) static inline void bitset_disable_stream(struct bitset *set)
{ {
BITSET_LOCK; BITSET_LOCK;
bitset_stream_enqueue( set, BITSET_STREAM_OFF, 0, set->size ); bitset_stream_enqueue(set, BITSET_STREAM_OFF, 0, set->size);
set->stream_enabled = 0; set->stream_enabled = 0;
BITSET_UNLOCK; BITSET_UNLOCK;
} }
/** Set the bits in a bitset which correspond to the given bytes in the larger /** Set the bits in a bitset which correspond to the given bytes in the larger
* file. * file.
*/ */
static inline void bitset_set_range( static inline void bitset_set_range(struct bitset *set,
struct bitset * set, uint64_t from, uint64_t len)
uint64_t from,
uint64_t len)
{ {
INT_FIRST_AND_LAST; INT_FIRST_AND_LAST;
BITSET_LOCK; BITSET_LOCK;
bit_set_range(set->bits, first, bitlen); bit_set_range(set->bits, first, bitlen);
if ( set->stream_enabled ) { if (set->stream_enabled) {
bitset_stream_enqueue( set, BITSET_STREAM_SET, from, len ); bitset_stream_enqueue(set, BITSET_STREAM_SET, from, len);
} }
BITSET_UNLOCK; BITSET_UNLOCK;
} }
/** Set every bit in the bitset. */ /** 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 /** Clear the bits in a bitset which correspond to the given bytes in the
* larger file. * larger file.
*/ */
static inline void bitset_clear_range( static inline void bitset_clear_range(struct bitset *set,
struct bitset * set, uint64_t from, uint64_t len)
uint64_t from,
uint64_t len)
{ {
INT_FIRST_AND_LAST; INT_FIRST_AND_LAST;
BITSET_LOCK; BITSET_LOCK;
bit_clear_range(set->bits, first, bitlen); bit_clear_range(set->bits, first, bitlen);
if ( set->stream_enabled ) { if (set->stream_enabled) {
bitset_stream_enqueue( set, BITSET_STREAM_UNSET, from, len ); bitset_stream_enqueue(set, BITSET_STREAM_UNSET, from, len);
} }
BITSET_UNLOCK; BITSET_UNLOCK;
} }
/** Clear every bit in the bitset. */ /** 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 /** As per bitset_run_count but also tells you whether the run it found was set
* or unset, atomically. * or unset, atomically.
*/ */
static inline uint64_t bitset_run_count_ex( static inline uint64_t bitset_run_count_ex(struct bitset *set,
struct bitset * set, uint64_t from,
uint64_t from, uint64_t len, int *run_is_set)
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. */ /* Clip our requests to the end of the bitset, avoiding uint underflow. */
if ( from > set->size ) { if (from > set->size) {
return 0; return 0;
} }
len = ( len + from ) > set->size ? ( set->size - from ) : len; len = (len + from) > set->size ? (set->size - from) : len;
INT_FIRST_AND_LAST; INT_FIRST_AND_LAST;
BITSET_LOCK; BITSET_LOCK;
run = bit_run_count(set->bits, first, bitlen, run_is_set) * set->resolution; run =
run -= (from % set->resolution); bit_run_count(set->bits, first, bitlen,
BITSET_UNLOCK; 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 /** Counts the number of contiguous bytes that are represented as a run in
* the bit field. * the bit field.
*/ */
static inline uint64_t bitset_run_count( static inline uint64_t bitset_run_count(struct bitset *set,
struct bitset * set, uint64_t from, uint64_t len)
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. /** 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. /** 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 #endif

File diff suppressed because it is too large Load Diff

View File

@@ -19,41 +19,40 @@
struct client { struct client {
/* When we call pthread_join, if the thread is already dead /* When we call pthread_join, if the thread is already dead
* we can get an ESRCH. Since we have no other way to tell * 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 * if that ESRCH is from a dead thread or a thread that never
* existed, we use a `stopped` flag to indicate a thread which * existed, we use a `stopped` flag to indicate a thread which
* did exist, but went away. Only check this after a * did exist, but went away. Only check this after a
* pthread_join call. * pthread_join call.
*/ */
int stopped; int stopped;
int socket; int socket;
int fileno; int fileno;
char* mapped; 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? */ /* Have we seen a REQUEST_DISCONNECT message? */
int disconnect; int disconnect;
/* kill the whole server if a request has been outstanding too long, /* kill the whole server if a request has been outstanding too long,
* assuming use_killswitch is set in serve * assuming use_killswitch is set in serve
*/ */
timer_t killswitch; 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); void *client_serve(void *client_uncast);
struct client * client_create( struct server * serve, int socket ); struct client *client_create(struct server *serve, int socket);
void client_destroy( struct client * client ); void client_destroy(struct client *client);
void client_signal_stop( struct client * client ); void client_signal_stop(struct client *client);
#endif #endif

View File

@@ -44,590 +44,570 @@
#include <unistd.h> #include <unistd.h>
struct control * control_create( struct control *control_create(struct flexnbd *flexnbd, const char *csn)
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->flexnbd = flexnbd;
control->socket_name = csn; control->socket_name = csn;
control->open_signal = self_pipe_create(); control->open_signal = self_pipe_create();
control->close_signal = self_pipe_create(); control->close_signal = self_pipe_create();
control->mirror_state_mbox = mbox_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 ); NULLCHECK(control);
self_pipe_signal( control->close_signal ); 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 ); mbox_destroy(control->mirror_state_mbox);
self_pipe_destroy( control->close_signal ); self_pipe_destroy(control->close_signal);
self_pipe_destroy( control->open_signal ); self_pipe_destroy(control->open_signal);
free( control ); free(control);
} }
struct control_client * control_client_create( struct control_client *control_client_create(struct flexnbd *flexnbd,
struct flexnbd * flexnbd, int client_fd,
int client_fd , struct mbox *state_mbox)
struct mbox * state_mbox )
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
struct control_client * control_client = struct control_client *control_client =
xmalloc( sizeof( struct control_client ) ); xmalloc(sizeof(struct control_client));
control_client->socket = client_fd; control_client->socket = client_fd;
control_client->flexnbd = flexnbd; control_client->flexnbd = flexnbd;
control_client->mirror_state_mbox = state_mbox; control_client->mirror_state_mbox = state_mbox;
return control_client; return control_client;
} }
void control_client_destroy( struct control_client * client ) void control_client_destroy(struct control_client *client)
{ {
NULLCHECK( client ); NULLCHECK(client);
free( 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);
NULLCHECK( control->flexnbd ); NULLCHECK(control->flexnbd);
struct control_client * control_client = struct control_client *control_client =
control_client_create( control_client_create(control->flexnbd,
control->flexnbd, client_fd,
client_fd , control->mirror_state_mbox);
control->mirror_state_mbox);
/* We intentionally don't spawn a thread for the client here. /* We intentionally don't spawn a thread for the client here.
* This is to avoid having more than one thread potentially * This is to avoid having more than one thread potentially
* waiting on the migration commit status. * waiting on the migration commit status.
*/ */
control_respond( control_client ); control_respond(control_client);
} }
void control_accept_client( struct control * control ) void control_accept_client(struct control *control)
{ {
int client_fd; int client_fd;
union mysockaddr client_address; union mysockaddr client_address;
socklen_t addrlen = sizeof( union mysockaddr ); socklen_t addrlen = sizeof(union mysockaddr);
client_fd = accept( control->control_fd, &client_address.generic, &addrlen ); client_fd =
FATAL_IF( -1 == client_fd, "control accept failed" ); 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_ZERO(&fds);
FD_SET( control->control_fd, &fds ); FD_SET(control->control_fd, &fds);
self_pipe_fd_set( control->close_signal, &fds ); self_pipe_fd_set(control->close_signal, &fds);
debug("Control thread selecting"); debug("Control thread selecting");
FATAL_UNLESS( 0 < select( FD_SETSIZE, &fds, NULL, NULL, NULL ), FATAL_UNLESS(0 < select(FD_SETSIZE, &fds, NULL, NULL, NULL),
"Control select failed." ); "Control select failed.");
if ( self_pipe_fd_isset( control->close_signal, &fds ) ){ if (self_pipe_fd_isset(control->close_signal, &fds)) {
return 0; return 0;
} }
if ( FD_ISSET( control->control_fd, &fds ) ) { if (FD_ISSET(control->control_fd, &fds)) {
control_accept_client( control ); control_accept_client(control);
} }
return 1; 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; struct sockaddr_un bind_address;
int control_fd; int control_fd;
if (!socket_name) { if (!socket_name) {
fatal( "Tried to open a control socket without a socket name" ); fatal("Tried to open a control socket without a socket name");
} }
control_fd = socket(AF_UNIX, SOCK_STREAM, 0); control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
FATAL_IF_NEGATIVE(control_fd , FATAL_IF_NEGATIVE(control_fd, "Couldn't create control socket");
"Couldn't create control socket");
memset(&bind_address, 0, sizeof(struct sockaddr_un)); memset(&bind_address, 0, sizeof(struct sockaddr_un));
bind_address.sun_family = AF_UNIX; bind_address.sun_family = AF_UNIX;
strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1); 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( FATAL_IF_NEGATIVE(bind
bind(control_fd , &bind_address, sizeof(bind_address)), (control_fd, &bind_address, sizeof(bind_address)),
"Couldn't bind control socket to %s: %s", "Couldn't bind control socket to %s: %s",
socket_name, strerror( errno ) socket_name, strerror(errno)
); );
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(listen(control_fd, 5),
listen(control_fd , 5), "Couldn't listen on control socket");
"Couldn't listen on control socket" return control_fd;
);
return control_fd;
} }
void control_listen(struct control* control) void control_listen(struct control *control)
{ {
NULLCHECK( control ); NULLCHECK(control);
control->control_fd = open_control_socket( control->socket_name ); 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_set fds;
FD_ZERO( &fds ); FD_ZERO(&fds);
self_pipe_fd_set( control->open_signal, &fds ); self_pipe_fd_set(control->open_signal, &fds);
FATAL_IF_NEGATIVE( select( FD_SETSIZE, &fds, NULL, NULL, NULL ), FATAL_IF_NEGATIVE(select(FD_SETSIZE, &fds, NULL, NULL, NULL),
"select() failed" ); "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_wait_for_open_signal(control);
control_listen( control ); control_listen(control);
while( control_accept( control ) ); while (control_accept(control));
} }
void control_cleanup( void control_cleanup(struct control *control,
struct control * control, int fatal __attribute__ ((unused)))
int fatal __attribute__((unused)) )
{ {
NULLCHECK( control ); NULLCHECK(control);
unlink( control->socket_name ); unlink(control->socket_name);
close( control->control_fd ); close(control->control_fd);
} }
void * control_runner( void * control_uncast ) void *control_runner(void *control_uncast)
{ {
debug("Control thread"); debug("Control thread");
NULLCHECK( control_uncast ); NULLCHECK(control_uncast);
struct control * control = (struct control *)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 ); control_cleanup(control, 0);
pthread_exit( NULL ); pthread_exit(NULL);
} }
#define write_socket(msg) write(client_fd, (msg "\n"), strlen((msg))+1) #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) { switch (mirror_state) {
case MS_INIT: case MS_INIT:
case MS_UNKNOWN: case MS_UNKNOWN:
write_socket( "1: Mirror failed to initialise" ); write_socket("1: Mirror failed to initialise");
fatal( "Impossible mirror state: %d", mirror_state ); fatal("Impossible mirror state: %d", mirror_state);
case MS_FAIL_CONNECT: case MS_FAIL_CONNECT:
write_socket( "1: Mirror failed to connect"); write_socket("1: Mirror failed to connect");
break; break;
case MS_FAIL_REJECTED: case MS_FAIL_REJECTED:
write_socket( "1: Mirror was rejected" ); write_socket("1: Mirror was rejected");
break; break;
case MS_FAIL_NO_HELLO: case MS_FAIL_NO_HELLO:
write_socket( "1: Remote server failed to respond"); write_socket("1: Remote server failed to respond");
break; break;
case MS_FAIL_SIZE_MISMATCH: case MS_FAIL_SIZE_MISMATCH:
write_socket( "1: Remote size does not match local size" ); write_socket("1: Remote size does not match local size");
break; break;
case MS_ABANDONED: case MS_ABANDONED:
write_socket( "1: Mirroring abandoned" ); write_socket("1: Mirroring abandoned");
break; break;
case MS_GO: case MS_GO:
case MS_DONE: /* Yes, I know we know better, but it's simpler this way */ case MS_DONE: /* Yes, I know we know better, but it's simpler this way */
write_socket( "0: Mirror started" ); write_socket("0: Mirror started");
break; break;
default: default:
fatal( "Unhandled mirror state: %d", mirror_state ); fatal("Unhandled mirror state: %d", mirror_state);
} }
} }
#undef write_socket #undef write_socket
/* Call this in the thread where you want to receive the mirror state */ /* Call this in the thread where you want to receive the mirror state */
enum mirror_state control_client_mirror_wait( enum mirror_state control_client_mirror_wait(struct control_client *client)
struct control_client* client)
{ {
NULLCHECK( client ); NULLCHECK(client);
NULLCHECK( client->mirror_state_mbox ); NULLCHECK(client->mirror_state_mbox);
struct mbox * mbox = client->mirror_state_mbox; struct mbox *mbox = client->mirror_state_mbox;
enum mirror_state mirror_state; enum mirror_state mirror_state;
enum mirror_state * contents; enum mirror_state *contents;
contents = (enum mirror_state*)mbox_receive( mbox ); contents = (enum mirror_state *) mbox_receive(mbox);
NULLCHECK( contents ); 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) #define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1)
/** Command parser to start mirror process from socket input */ /** 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; struct flexnbd *flexnbd = client->flexnbd;
union mysockaddr *connect_to = xmalloc( sizeof( union mysockaddr ) ); union mysockaddr *connect_to = xmalloc(sizeof(union mysockaddr));
union mysockaddr *connect_from = NULL; union mysockaddr *connect_from = NULL;
uint64_t max_Bps = UINT64_MAX; uint64_t max_Bps = UINT64_MAX;
int action_at_finish; int action_at_finish;
int raw_port; int raw_port;
if (linesc < 2) { if (linesc < 2) {
write_socket("1: mirror takes at least two parameters"); write_socket("1: mirror takes at least two parameters");
return -1; 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"); server_unlock_start_mirror(serve);
return -1;
}
raw_port = atoi(lines[1]); /* Do this outside the lock to minimise the length of time the
if (raw_port < 0 || raw_port > 65535) { * sighandler can block the serve thread
write_socket("1: bad IP port number"); */
return -1; if (serve->mirror_super) {
} FATAL_IF(0 != pthread_create(&serve->mirror_super->thread,
connect_to->v4.sin_port = htobe16(raw_port); NULL,
mirror_super_runner,
serve),
"Failed to create mirror thread");
action_at_finish = ACTION_EXIT; debug("Control thread mirror super waiting");
if (linesc > 2) { enum mirror_state state = control_client_mirror_wait(client);
if (strcmp("exit", lines[2]) == 0) { debug("Control thread writing response");
action_at_finish = ACTION_EXIT; control_write_mirror_response(state, client->socket);
} }
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) { debug("Control thread going away.");
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) { return 0;
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;
} }
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);
NULLCHECK( client->flexnbd ); NULLCHECK(client->flexnbd);
struct server* serve = flexnbd_server( client->flexnbd ); struct server *serve = flexnbd_server(client->flexnbd);
uint64_t max_Bps; uint64_t max_Bps;
if ( !serve->mirror_super ) { if (!serve->mirror_super) {
write_socket( "1: Not currently mirroring" ); write_socket("1: Not currently mirroring");
return -1; return -1;
} }
if ( linesc != 1 ) { if (linesc != 1) {
write_socket( "1: Bad format" ); write_socket("1: Bad format");
return -1; return -1;
} }
errno = 0; errno = 0;
max_Bps = strtoull( lines[0], NULL, 10 ); max_Bps = strtoull(lines[0], NULL, 10);
if ( errno == ERANGE ) { if (errno == ERANGE) {
write_socket( "1: max_bps out of range" ); write_socket("1: max_bps out of range");
return -1; return -1;
} else if ( errno != 0 ) { } else if (errno != 0) {
write_socket( "1: max_bps couldn't be parsed" ); write_socket("1: max_bps couldn't be parsed");
return -1; return -1;
} }
serve->mirror->max_bytes_per_second = max_Bps; serve->mirror->max_bytes_per_second = max_Bps;
write_socket( "0: updated" ); write_socket("0: updated");
return 0; return 0;
} }
#undef write_socket #undef write_socket
/** Command parser to alter access control list from socket input */ /** 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);
NULLCHECK( client->flexnbd ); NULLCHECK(client->flexnbd);
struct flexnbd * flexnbd = client->flexnbd; struct flexnbd *flexnbd = client->flexnbd;
int default_deny = flexnbd_default_deny( flexnbd ); int default_deny = flexnbd_default_deny(flexnbd);
struct acl * new_acl = acl_create( linesc, lines, default_deny ); struct acl *new_acl = acl_create(linesc, lines, default_deny);
if (new_acl->len != linesc) { if (new_acl->len != linesc) {
warn("Bad ACL spec: %s", lines[new_acl->len] ); warn("Bad ACL spec: %s", lines[new_acl->len]);
write(client->socket, "1: bad spec: ", 13); write(client->socket, "1: bad spec: ", 13);
write(client->socket, lines[new_acl->len], write(client->socket, lines[new_acl->len],
strlen(lines[new_acl->len])); strlen(lines[new_acl->len]));
write(client->socket, "\n", 1); write(client->socket, "\n", 1);
acl_destroy( new_acl ); acl_destroy(new_acl);
} } else {
else { flexnbd_replace_acl(flexnbd, new_acl);
flexnbd_replace_acl( flexnbd, new_acl ); info("ACL set");
info("ACL set"); write(client->socket, "0: updated\n", 11);
write( client->socket, "0: updated\n", 11); }
}
return 0; return 0;
} }
int control_break( int control_break(struct control_client *client,
struct control_client* client, int linesc __attribute__ ((unused)),
int linesc __attribute__ ((unused)), char **lines __attribute__ ((unused))
char** lines __attribute__((unused)) )
)
{ {
NULLCHECK( client ); NULLCHECK(client);
NULLCHECK( client->flexnbd ); NULLCHECK(client->flexnbd);
int result = 0; int result = 0;
struct flexnbd* flexnbd = client->flexnbd; struct flexnbd *flexnbd = client->flexnbd;
struct server * serve = flexnbd_server( flexnbd ); struct server *serve = flexnbd_server(flexnbd);
server_lock_start_mirror( serve ); server_lock_start_mirror(serve);
{ {
if ( server_is_mirroring( serve ) ) { if (server_is_mirroring(serve)) {
info( "Signaling to abandon mirror" ); info("Signaling to abandon mirror");
server_abandon_mirror( serve ); server_abandon_mirror(serve);
debug( "Abandon signaled" ); debug("Abandon signaled");
if ( server_is_closed( serve ) ) { if (server_is_closed(serve)) {
info( "Mirror completed while canceling" ); info("Mirror completed while canceling");
write( client->socket, write(client->socket, "1: mirror completed\n", 20);
"1: mirror completed\n", 20 ); } else {
} info("Mirror successfully stopped.");
else { write(client->socket, "0: mirror stopped\n", 18);
info( "Mirror successfully stopped." ); result = 1;
write( client->socket, }
"0: mirror stopped\n", 18 );
result = 1;
}
} else { } else {
warn( "Not mirroring." ); warn("Not mirroring.");
write( client->socket, "1: not mirroring\n", 17 ); 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 */ /** FIXME: add some useful statistics */
int control_status( int control_status(struct control_client *client,
struct control_client* client, int linesc __attribute__ ((unused)),
int linesc __attribute__ ((unused)), char **lines __attribute__ ((unused))
char** lines __attribute__((unused)) )
)
{ {
NULLCHECK( client ); NULLCHECK(client);
NULLCHECK( client->flexnbd ); NULLCHECK(client->flexnbd);
struct status * status = flexnbd_status_create( client->flexnbd ); struct status *status = flexnbd_status_create(client->flexnbd);
write( client->socket, "0: ", 3 ); write(client->socket, "0: ", 3);
status_write( status, client->socket ); status_write(status, client->socket);
status_destroy( status ); status_destroy(status);
return 0; return 0;
} }
void control_client_cleanup(struct control_client* client, void control_client_cleanup(struct control_client *client,
int fatal __attribute__ ((unused)) ) int fatal __attribute__ ((unused)))
{ {
if (client->socket) { close(client->socket); } if (client->socket) {
close(client->socket);
}
/* This is wrongness */ /* This is wrongness */
if ( server_acl_locked( client->flexnbd->serve ) ) { server_unlock_acl( client->flexnbd->serve ); } 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 */ /** 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; int i, linesc;
linesc = read_lines_until_blankline(client->socket, 256, &lines); linesc = read_lines_until_blankline(client->socket, 256, &lines);
if (linesc < 1) if (linesc < 1) {
{ write(client->socket, "9: missing command\n", 19);
write(client->socket, "9: missing command\n", 19); /* ignore failure */
/* 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) { } else if (strcmp(lines[0], "mirror") == 0) {
info("acl command received" ); info("mirror command received");
if (control_acl(client, linesc-1, lines+1) < 0) { if (control_mirror(client, linesc - 1, lines + 1) < 0) {
debug("acl command failed"); debug("mirror command failed");
}
} }
else if (strcmp(lines[0], "mirror") == 0) { } else if (strcmp(lines[0], "break") == 0) {
info("mirror command received" ); info("break command received");
if (control_mirror(client, linesc-1, lines+1) < 0) { if (control_break(client, linesc - 1, lines + 1) < 0) {
debug("mirror command failed"); debug("break command failed");
}
} }
else if (strcmp(lines[0], "break") == 0) { } else if (strcmp(lines[0], "status") == 0) {
info( "break command received" ); info("status command received");
if ( control_break( client, linesc-1, lines+1) < 0) { if (control_status(client, linesc - 1, lines + 1) < 0) {
debug( "break command failed" ); debug("status command failed");
}
} }
else if (strcmp(lines[0], "status") == 0) { } else if (strcmp(lines[0], "mirror_max_bps") == 0) {
info("status command received" ); info("mirror_max_bps command received");
if (control_status(client, linesc-1, lines+1) < 0) { if (control_mirror_max_bps(client, linesc - 1, lines + 1) < 0) {
debug("status command failed"); debug("mirror_max_bps 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 {
write(client->socket, "10: unknown command\n", 23);
}
for (i=0; i<linesc; i++) { for (i = 0; i < linesc; i++) {
free(lines[i]); free(lines[i]);
} }
free(lines); free(lines);
control_client_cleanup(client, 0); control_client_cleanup(client, 0);
debug("control command handled" ); debug("control command handled");
} }

View File

@@ -13,47 +13,46 @@ struct server;
#include "mbox.h" #include "mbox.h"
struct control { struct control {
struct flexnbd * flexnbd; struct flexnbd *flexnbd;
int control_fd; int control_fd;
const char * socket_name; const char *socket_name;
pthread_t thread; pthread_t thread;
struct self_pipe * open_signal; struct self_pipe *open_signal;
struct self_pipe * close_signal; struct self_pipe *close_signal;
/* This is owned by the control object, and used by a /* This is owned by the control object, and used by a
* mirror_super to communicate the state of a mirror attempt as * mirror_super to communicate the state of a mirror attempt as
* early as feasible. It can't be owned by the mirror_super * early as feasible. It can't be owned by the mirror_super
* object because the mirror_super object can be freed at any * object because the mirror_super object can be freed at any
* time (including while the control_client is waiting on it), * time (including while the control_client is waiting on it),
* whereas the control object lasts for the lifetime of the * whereas the control object lasts for the lifetime of the
* process (and we can only have a mirror thread if the control * process (and we can only have a mirror thread if the control
* thread has started it). * thread has started it).
*/ */
struct mbox * mirror_state_mbox; struct mbox *mirror_state_mbox;
}; };
struct control_client{ struct control_client {
int socket; int socket;
struct flexnbd * flexnbd; struct flexnbd *flexnbd;
/* Passed in on creation. We know it's all right to do this /* Passed in on creation. We know it's all right to do this
* because we know there's only ever one control_client. * because we know there's only ever one control_client.
*/ */
struct mbox * mirror_state_mbox; struct mbox *mirror_state_mbox;
}; };
struct control * control_create( struct control *control_create(struct flexnbd *,
struct flexnbd *, const char *control_socket_name);
const char * control_socket_name ); void control_signal_close(struct control *);
void control_signal_close( struct control * ); void control_destroy(struct control *);
void control_destroy( struct control * );
void * control_runner( void * ); void *control_runner(void *);
void accept_control_connection(struct server* params, int client_fd, union mysockaddr* client_address); void accept_control_connection(struct server *params, int client_fd,
void serve_open_control_socket(struct server* params); union mysockaddr *client_address);
void serve_open_control_socket(struct server *params);
#endif #endif

View File

@@ -43,223 +43,206 @@
int flexnbd_build_signal_fd(void) int flexnbd_build_signal_fd(void)
{ {
sigset_t mask; sigset_t mask;
int sfd; int sfd;
sigemptyset( &mask ); sigemptyset(&mask);
sigaddset( &mask, SIGTERM ); sigaddset(&mask, SIGTERM);
sigaddset( &mask, SIGQUIT ); sigaddset(&mask, SIGQUIT);
sigaddset( &mask, SIGINT ); sigaddset(&mask, SIGINT);
FATAL_UNLESS( 0 == pthread_sigmask( SIG_BLOCK, &mask, NULL ), FATAL_UNLESS(0 == pthread_sigmask(SIG_BLOCK, &mask, NULL),
"Signal blocking failed" ); "Signal blocking failed");
sfd = signalfd( -1, &mask, 0 ); sfd = signalfd(-1, &mask, 0);
FATAL_IF( -1 == sfd, "Failed to get a signal fd" ); FATAL_IF(-1 == sfd, "Failed to get a signal fd");
return sfd; return sfd;
} }
void flexnbd_create_shared( void flexnbd_create_shared(struct flexnbd *flexnbd,
struct flexnbd * flexnbd, const char *s_ctrl_sock)
const char * s_ctrl_sock)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
if ( s_ctrl_sock ){ if (s_ctrl_sock) {
flexnbd->control = flexnbd->control = control_create(flexnbd, s_ctrl_sock);
control_create( flexnbd, s_ctrl_sock ); } else {
} flexnbd->control = NULL;
else { }
flexnbd->control = NULL;
}
flexnbd->signal_fd = flexnbd_build_signal_fd(); flexnbd->signal_fd = flexnbd_build_signal_fd();
} }
struct flexnbd * flexnbd_create_serving( struct flexnbd *flexnbd_create_serving(char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_file,
char* s_file, char *s_ctrl_sock,
char* s_ctrl_sock, int default_deny,
int default_deny, int acl_entries,
int acl_entries, char **s_acl_entries,
char** s_acl_entries, int max_nbd_clients,
int max_nbd_clients, int use_killswitch)
int use_killswitch)
{ {
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) ); struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
flexnbd->serve = server_create( flexnbd->serve = server_create(flexnbd,
flexnbd, s_ip_address,
s_ip_address, s_port,
s_port, s_file,
s_file, default_deny,
default_deny, acl_entries,
acl_entries, s_acl_entries,
s_acl_entries, max_nbd_clients, use_killswitch, 1);
max_nbd_clients, flexnbd_create_shared(flexnbd, s_ctrl_sock);
use_killswitch,
1);
flexnbd_create_shared( flexnbd, s_ctrl_sock );
// Beats installing one handler per client instance // Beats installing one handler per client instance
if ( use_killswitch ) { if (use_killswitch) {
struct sigaction act = { struct sigaction act = {
.sa_sigaction = client_killswitch_hit, .sa_sigaction = client_killswitch_hit,
.sa_flags = SA_RESTART | SA_SIGINFO .sa_flags = SA_RESTART | SA_SIGINFO
}; };
FATAL_UNLESS( FATAL_UNLESS(0 == sigaction(CLIENT_KILLSWITCH_SIGNAL, &act, NULL),
0 == sigaction( CLIENT_KILLSWITCH_SIGNAL, &act, NULL ), "Installing client killswitch signal failed");
"Installing client killswitch signal failed" }
);
}
return flexnbd; return flexnbd;
} }
struct flexnbd * flexnbd_create_listening( struct flexnbd *flexnbd_create_listening(char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_file,
char* s_file, char *s_ctrl_sock,
char* s_ctrl_sock, int default_deny,
int default_deny, int acl_entries,
int acl_entries, char **s_acl_entries)
char** s_acl_entries )
{ {
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) ); struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
flexnbd->serve = server_create( flexnbd->serve = server_create(flexnbd,
flexnbd, s_ip_address,
s_ip_address, s_port,
s_port, s_file,
s_file, default_deny,
default_deny, acl_entries, s_acl_entries, 1, 0, 0);
acl_entries, flexnbd_create_shared(flexnbd, s_ctrl_sock);
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 // listen can't use killswitch, as mirror may pause on sending things
// for a very long time. // 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);
NULLCHECK( flexnbd->control ); NULLCHECK(flexnbd->control);
pthread_t * control_thread = &flexnbd->control->thread; pthread_t *control_thread = &flexnbd->control->thread;
FATAL_UNLESS( 0 == pthread_create( FATAL_UNLESS(0 == pthread_create(control_thread,
control_thread, NULL,
NULL, control_runner,
control_runner, flexnbd->control),
flexnbd->control ), "Couldn't create the control thread");
"Couldn't create the control thread" );
} }
void flexnbd_stop_control( struct flexnbd * flexnbd ) void flexnbd_stop_control(struct flexnbd *flexnbd)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
NULLCHECK( flexnbd->control ); NULLCHECK(flexnbd->control);
control_signal_close( flexnbd->control ); control_signal_close(flexnbd->control);
pthread_t tid = flexnbd->control->thread; pthread_t tid = flexnbd->control->thread;
FATAL_UNLESS( 0 == pthread_join( tid, NULL ), FATAL_UNLESS(0 == pthread_join(tid, NULL),
"Failed joining the control thread" ); "Failed joining the control thread");
debug( "Control thread %p pthread_join returned", tid ); debug("Control thread %p pthread_join returned", tid);
} }
int flexnbd_signal_fd( struct flexnbd * flexnbd ) int flexnbd_signal_fd(struct flexnbd *flexnbd)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
return flexnbd->signal_fd; return flexnbd->signal_fd;
} }
void flexnbd_destroy( struct flexnbd * flexnbd ) void flexnbd_destroy(struct flexnbd *flexnbd)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
if ( flexnbd->control ) { if (flexnbd->control) {
control_destroy( flexnbd->control ); control_destroy(flexnbd->control);
} }
close( flexnbd->signal_fd ); close(flexnbd->signal_fd);
free( flexnbd ); free(flexnbd);
} }
struct server * flexnbd_server( struct flexnbd * flexnbd ) struct server *flexnbd_server(struct flexnbd *flexnbd)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
return flexnbd->serve; 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 ); NULLCHECK(flexnbd);
server_replace_acl( flexnbd_server(flexnbd), acl ); 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 ); NULLCHECK(flexnbd);
struct status * status; struct status *status;
status = status_create( flexnbd_server( flexnbd ) ); status = status_create(flexnbd_server(flexnbd));
return status; return status;
} }
void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve ) void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
flexnbd->serve = serve; flexnbd->serve = serve;
} }
/* Get the default_deny of the current server object. */ /* 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 ); NULLCHECK(flexnbd);
return server_default_deny( flexnbd->serve ); return server_default_deny(flexnbd->serve);
} }
void make_writable( const char * filename ) void make_writable(const char *filename)
{ {
NULLCHECK( filename ); NULLCHECK(filename);
FATAL_IF_NEGATIVE( chmod( filename, S_IWUSR ), FATAL_IF_NEGATIVE(chmod(filename, S_IWUSR),
"Couldn't chmod %s: %s", "Couldn't chmod %s: %s", filename, strerror(errno));
filename,
strerror( errno ) );
} }
int flexnbd_serve( struct flexnbd * flexnbd ) int flexnbd_serve(struct flexnbd *flexnbd)
{ {
NULLCHECK( flexnbd ); NULLCHECK(flexnbd);
int success; int success;
struct self_pipe * open_signal = NULL; struct self_pipe *open_signal = NULL;
if ( flexnbd->control ){ if (flexnbd->control) {
debug( "Spawning control thread" ); debug("Spawning control thread");
flexnbd_spawn_control( flexnbd ); flexnbd_spawn_control(flexnbd);
open_signal = flexnbd->control->open_signal; open_signal = flexnbd->control->open_signal;
} }
success = do_serve( flexnbd->serve, open_signal ); success = do_serve(flexnbd->serve, open_signal);
debug("do_serve success is %d", success ); debug("do_serve success is %d", success);
if ( flexnbd->control ) { if (flexnbd->control) {
debug( "Stopping control thread" ); debug("Stopping control thread");
flexnbd_stop_control( flexnbd ); flexnbd_stop_control(flexnbd);
debug("Control thread stopped"); debug("Control thread stopped");
} }
return success; return success;
} }

View File

@@ -13,54 +13,51 @@
/* Carries the "globals". */ /* Carries the "globals". */
struct flexnbd { struct flexnbd {
/* Our serve pointer should never be dereferenced outside a /* Our serve pointer should never be dereferenced outside a
* flexnbd_switch_lock/unlock pair. * flexnbd_switch_lock/unlock pair.
*/ */
struct server * serve; struct server *serve;
/* We only have a control object if a control socket name was /* We only have a control object if a control socket name was
* passed on the command line. * passed on the command line.
*/ */
struct control * control; struct control *control;
/* File descriptor for a signalfd(2) signal stream. */ /* File descriptor for a signalfd(2) signal stream. */
int signal_fd; int signal_fd;
}; };
struct flexnbd * flexnbd_create(void); struct flexnbd *flexnbd_create(void);
struct flexnbd * flexnbd_create_serving( struct flexnbd *flexnbd_create_serving(char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_file,
char* s_file, char *s_ctrl_sock,
char* s_ctrl_sock, int default_deny,
int default_deny, int acl_entries,
int acl_entries, char **s_acl_entries,
char** s_acl_entries, int max_nbd_clients,
int max_nbd_clients, int use_killswitch);
int use_killswitch);
struct flexnbd * flexnbd_create_listening( struct flexnbd *flexnbd_create_listening(char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_file,
char* s_file, char *s_ctrl_sock,
char* s_ctrl_sock, int default_deny,
int default_deny, int acl_entries,
int acl_entries, char **s_acl_entries);
char** s_acl_entries );
void flexnbd_destroy( struct flexnbd * ); void flexnbd_destroy(struct flexnbd *);
enum mirror_state; enum mirror_state;
enum mirror_state flexnbd_get_mirror_state( struct flexnbd * ); enum mirror_state flexnbd_get_mirror_state(struct flexnbd *);
int flexnbd_default_deny( struct flexnbd * ); int flexnbd_default_deny(struct flexnbd *);
void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve ); void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve);
int flexnbd_signal_fd( struct flexnbd * flexnbd ); int flexnbd_signal_fd(struct flexnbd *flexnbd);
int flexnbd_serve( struct flexnbd * flexnbd ); int flexnbd_serve(struct flexnbd *flexnbd);
int flexnbd_proxy( struct flexnbd * flexnbd ); int flexnbd_proxy(struct flexnbd *flexnbd);
struct server * flexnbd_server( struct flexnbd * flexnbd ); struct server *flexnbd_server(struct flexnbd *flexnbd);
void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl ); void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl);
struct status * flexnbd_status_create( struct flexnbd * flexnbd ); struct status *flexnbd_status_create(struct flexnbd *flexnbd);
#endif #endif

View File

@@ -4,72 +4,70 @@
#include <pthread.h> #include <pthread.h>
struct flexthread_mutex * flexthread_mutex_create(void) struct flexthread_mutex *flexthread_mutex_create(void)
{ {
struct flexthread_mutex * ftm = struct flexthread_mutex *ftm =
xmalloc( sizeof( struct flexthread_mutex ) ); xmalloc(sizeof(struct flexthread_mutex));
FATAL_UNLESS( 0 == pthread_mutex_init( &ftm->mutex, NULL ), FATAL_UNLESS(0 == pthread_mutex_init(&ftm->mutex, NULL),
"Mutex initialisation failed" ); "Mutex initialisation failed");
return ftm; 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 ) ) { if (flexthread_mutex_held(ftm)) {
flexthread_mutex_unlock( ftm ); flexthread_mutex_unlock(ftm);
} } else if ((pthread_t) NULL != ftm->holder) {
else if ( (pthread_t)NULL != ftm->holder ) { /* This "should never happen": if we can try to destroy
/* This "should never happen": if we can try to destroy * a mutex currently held by another thread, there's a
* a mutex currently held by another thread, there's a * logic bug somewhere. I know the test here is racy,
* logic bug somewhere. I know the test here is racy, * but there's not a lot we can do about it at this
* but there's not a lot we can do about it at this * point.
* point. */
*/ fatal("Attempted to destroy a flexthread_mutex"
fatal( "Attempted to destroy a flexthread_mutex"\ " held by another thread!");
" held by another thread!" ); }
}
FATAL_UNLESS( 0 == pthread_mutex_destroy( &ftm->mutex ), FATAL_UNLESS(0 == pthread_mutex_destroy(&ftm->mutex),
"Mutex destroy failed" ); "Mutex destroy failed");
free( ftm ); 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 ); int failure = pthread_mutex_lock(&ftm->mutex);
if ( 0 == failure ) { if (0 == failure) {
ftm->holder = pthread_self(); 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; pthread_t orig = ftm->holder;
ftm->holder = (pthread_t)NULL; ftm->holder = (pthread_t) NULL;
int failure = pthread_mutex_unlock( &ftm->mutex ); int failure = pthread_mutex_unlock(&ftm->mutex);
if ( 0 != failure ) { if (0 != failure) {
ftm->holder = orig; ftm->holder = orig;
} }
return failure; return failure;
} }
int flexthread_mutex_held( struct flexthread_mutex * ftm ) int flexthread_mutex_held(struct flexthread_mutex *ftm)
{ {
NULLCHECK( ftm ); NULLCHECK(ftm);
return pthread_self() == ftm->holder; return pthread_self() == ftm->holder;
} }

View File

@@ -15,15 +15,15 @@
*/ */
struct flexthread_mutex { struct flexthread_mutex {
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_t holder; pthread_t holder;
}; };
struct flexthread_mutex * flexthread_mutex_create(void); struct flexthread_mutex *flexthread_mutex_create(void);
void flexthread_mutex_destroy( struct flexthread_mutex * ); void flexthread_mutex_destroy(struct flexthread_mutex *);
int flexthread_mutex_lock( struct flexthread_mutex * ); int flexthread_mutex_lock(struct flexthread_mutex *);
int flexthread_mutex_unlock( struct flexthread_mutex * ); int flexthread_mutex_unlock(struct flexthread_mutex *);
int flexthread_mutex_held( struct flexthread_mutex * ); int flexthread_mutex_held(struct flexthread_mutex *);
#endif #endif

View File

@@ -3,75 +3,75 @@
#include <pthread.h> #include <pthread.h>
struct mbox * mbox_create( void ) struct mbox *mbox_create(void)
{ {
struct mbox * mbox = xmalloc( sizeof( struct mbox ) ); struct mbox *mbox = xmalloc(sizeof(struct mbox));
FATAL_UNLESS( 0 == pthread_cond_init( &mbox->filled_cond, NULL ), FATAL_UNLESS(0 == pthread_cond_init(&mbox->filled_cond, NULL),
"Failed to initialise a condition variable" ); "Failed to initialise a condition variable");
FATAL_UNLESS( 0 == pthread_cond_init( &mbox->emptied_cond, NULL ), FATAL_UNLESS(0 == pthread_cond_init(&mbox->emptied_cond, NULL),
"Failed to initialise a condition variable" ); "Failed to initialise a condition variable");
FATAL_UNLESS( 0 == pthread_mutex_init( &mbox->mutex, NULL ), FATAL_UNLESS(0 == pthread_mutex_init(&mbox->mutex, NULL),
"Failed to initialise a mutex" ); "Failed to initialise a mutex");
return mbox; return mbox;
} }
void mbox_post( struct mbox * mbox, void * contents ) void mbox_post(struct mbox *mbox, void *contents)
{ {
pthread_mutex_lock( &mbox->mutex ); pthread_mutex_lock(&mbox->mutex);
{ {
if (mbox->full){ if (mbox->full) {
pthread_cond_wait( &mbox->emptied_cond, &mbox->mutex ); pthread_cond_wait(&mbox->emptied_cond, &mbox->mutex);
}
mbox->contents = contents;
mbox->full = 1;
while( 0 != pthread_cond_signal( &mbox->filled_cond ) );
} }
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 ); NULLCHECK(mbox);
void * result; void *result;
pthread_mutex_lock( &mbox->mutex ); pthread_mutex_lock(&mbox->mutex);
{ {
if ( !mbox->full ) { if (!mbox->full) {
pthread_cond_wait( &mbox->filled_cond, &mbox->mutex ); 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_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->emptied_cond));
while( 0 != pthread_cond_destroy( &mbox->filled_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);
} }

View File

@@ -14,42 +14,42 @@
struct mbox { struct mbox {
void * contents; void *contents;
/** Marker to tell us if there's content in the box. /** Marker to tell us if there's content in the box.
* Keeping this separate allows us to use NULL for the contents. * 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 /** This gets signaled by mbox_post, and waited on by
* mbox_receive */ * mbox_receive */
pthread_cond_t filled_cond; pthread_cond_t filled_cond;
/** This is signaled by mbox_receive, and waited on by mbox_post */ /** This is signaled by mbox_receive, and waited on by mbox_post */
pthread_cond_t emptied_cond; pthread_cond_t emptied_cond;
pthread_mutex_t mutex; pthread_mutex_t mutex;
}; };
/* Create an mbox. */ /* Create an mbox. */
struct mbox * mbox_create(void); struct mbox *mbox_create(void);
/* Put something in the mbox, blocking if it's already full. /* Put something in the mbox, blocking if it's already full.
* That something can be NULL if you want. * 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. */ /* 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. /* 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. */ /* 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. */ /* Free the mbox and destroy the associated pthread bits. */
void mbox_destroy( struct mbox *); void mbox_destroy(struct mbox *);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -58,65 +58,65 @@ enum mirror_state;
#define MS_REQUEST_LIMIT_SECS_F 60.0 #define MS_REQUEST_LIMIT_SECS_F 60.0
enum mirror_finish_action { enum mirror_finish_action {
ACTION_EXIT, ACTION_EXIT,
ACTION_UNLINK, ACTION_UNLINK,
ACTION_NOTHING ACTION_NOTHING
}; };
enum mirror_state { enum mirror_state {
MS_UNKNOWN, MS_UNKNOWN,
MS_INIT, MS_INIT,
MS_GO, MS_GO,
MS_ABANDONED, MS_ABANDONED,
MS_DONE, MS_DONE,
MS_FAIL_CONNECT, MS_FAIL_CONNECT,
MS_FAIL_REJECTED, MS_FAIL_REJECTED,
MS_FAIL_NO_HELLO, MS_FAIL_NO_HELLO,
MS_FAIL_SIZE_MISMATCH MS_FAIL_SIZE_MISMATCH
}; };
struct mirror { struct mirror {
pthread_t thread; pthread_t thread;
/* Signal to this then join the thread if you want to abandon mirroring */ /* Signal to this then join the thread if you want to abandon mirroring */
struct self_pipe * abandon_signal; struct self_pipe *abandon_signal;
union mysockaddr * connect_to; union mysockaddr *connect_to;
union mysockaddr * connect_from; union mysockaddr *connect_from;
int client; int client;
const char * filename; const char *filename;
/* Limiter, used to restrict migration speed Only dirty bytes (those going /* Limiter, used to restrict migration speed Only dirty bytes (those going
* over the network) are considered */ * over the network) are considered */
uint64_t max_bytes_per_second; 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 */ /* We need to send every byte at least once; we do so by */
uint64_t offset; uint64_t offset;
enum mirror_state commit_state; enum mirror_state commit_state;
/* commit_signal is sent immediately after attempting to connect /* commit_signal is sent immediately after attempting to connect
* and checking the remote size, whether successful or not. * and checking the remote size, whether successful or not.
*/ */
struct mbox * commit_signal; struct mbox *commit_signal;
/* The time (from monotonic_time_ms()) the migration was started. Can be /* The time (from monotonic_time_ms()) the migration was started. Can be
* used to calculate bps, etc. */ * used to calculate bps, etc. */
uint64_t migration_started; uint64_t migration_started;
/* Running count of all bytes we've transferred */ /* Running count of all bytes we've transferred */
uint64_t all_dirty; uint64_t all_dirty;
}; };
struct mirror_super { struct mirror_super {
struct mirror * mirror; struct mirror *mirror;
pthread_t thread; pthread_t thread;
struct mbox * state_mbox; struct mbox *state_mbox;
}; };
@@ -127,15 +127,13 @@ struct mirror_super {
struct server; struct server;
struct flexnbd; struct flexnbd;
struct mirror_super * mirror_super_create( struct mirror_super *mirror_super_create(const char *filename,
const char * filename, union mysockaddr *connect_to,
union mysockaddr * connect_to, union mysockaddr *connect_from,
union mysockaddr * connect_from, uint64_t max_Bps,
uint64_t max_Bps, enum mirror_finish_action
enum mirror_finish_action action_at_finish, action_at_finish,
struct mbox * state_mbox struct mbox *state_mbox);
); void *mirror_super_runner(void *serve_uncast);
void * mirror_super_runner( void * serve_uncast );
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,20 +3,20 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> /* for sig_atomic_t */ #include <signal.h> /* for sig_atomic_t */
#include "flexnbd.h" #include "flexnbd.h"
#include "parse.h" #include "parse.h"
#include "acl.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 { struct client_tbl_entry {
pthread_t thread; pthread_t thread;
union mysockaddr address; union mysockaddr address;
struct client * client; struct client *client;
}; };
@@ -25,146 +25,143 @@ struct client_tbl_entry {
#define CLIENT_KEEPALIVE_INTVL 10 #define CLIENT_KEEPALIVE_INTVL 10
#define CLIENT_KEEPALIVE_PROBES 3 #define CLIENT_KEEPALIVE_PROBES 3
struct server { struct server {
/* The flexnbd wrapper this server is attached to */ /* The flexnbd wrapper this server is attached to */
struct flexnbd * flexnbd; struct flexnbd *flexnbd;
/** address/port to bind to */ /** address/port to bind to */
union mysockaddr bind_to; union mysockaddr bind_to;
/** (static) file name to serve */ /** (static) file name to serve */
char* filename; char *filename;
/** TCP backlog for listen() */ /** TCP backlog for listen() */
int tcp_backlog; int tcp_backlog;
/** (static) file name of UNIX control socket (or NULL if none) */ /** (static) file name of UNIX control socket (or NULL if none) */
char* control_socket_name; char *control_socket_name;
/** size of file */ /** size of file */
uint64_t size; uint64_t size;
/** to interrupt accept loop and clients, write() to close_signal[1] */ /** to interrupt accept loop and clients, write() to close_signal[1] */
struct self_pipe * close_signal; struct self_pipe *close_signal;
/** access control list */ /** access control list */
struct acl * acl; struct acl *acl;
/** acl_updated_signal will be signalled after the acl struct /** acl_updated_signal will be signalled after the acl struct
* has been replaced * has been replaced
*/ */
struct self_pipe * acl_updated_signal; struct self_pipe *acl_updated_signal;
/* Claimed around any updates to the ACL. */ /* Claimed around any updates to the ACL. */
struct flexthread_mutex * l_acl; struct flexthread_mutex *l_acl;
/* Claimed around starting a mirror so that it doesn't race with /* Claimed around starting a mirror so that it doesn't race with
* shutting down on a SIGTERM. */ * shutting down on a SIGTERM. */
struct flexthread_mutex * l_start_mirror; struct flexthread_mutex *l_start_mirror;
struct mirror* mirror; struct mirror *mirror;
struct mirror_super * mirror_super; struct mirror_super *mirror_super;
/* This is used to stop the mirror from starting after we /* This is used to stop the mirror from starting after we
* receive a SIGTERM */ * receive a SIGTERM */
int mirror_can_start; int mirror_can_start;
int server_fd; int server_fd;
int control_fd; int control_fd;
/* the allocation_map keeps track of which blocks in the backing file /* the allocation_map keeps track of which blocks in the backing file
* have been allocated, or part-allocated on disc, with unallocated * have been allocated, or part-allocated on disc, with unallocated
* blocks presumed to contain zeroes (i.e. represented as sparse files * blocks presumed to contain zeroes (i.e. represented as sparse files
* by the filesystem). We can use this information when receiving * by the filesystem). We can use this information when receiving
* incoming writes, and avoid writing zeroes to unallocated sections * incoming writes, and avoid writing zeroes to unallocated sections
* of the file which would needlessly increase disc usage. This * of the file which would needlessly increase disc usage. This
* bitmap will start at all-zeroes for an empty file, and tend towards * 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 * 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 * blocks can never become unallocated again, as is the case with ext3
* at least). * at least).
*/ */
struct bitset * allocation_map; struct bitset *allocation_map;
/* when starting up, this thread builds the allocation_map */ /* when starting up, this thread builds the allocation_map */
pthread_t allocation_map_builder_thread; pthread_t allocation_map_builder_thread;
/* when the thread has finished, it sets this to 1 */ /* when the thread has finished, it sets this to 1 */
volatile sig_atomic_t allocation_map_built; volatile sig_atomic_t allocation_map_built;
volatile sig_atomic_t allocation_map_not_built; volatile sig_atomic_t allocation_map_not_built;
int max_nbd_clients; int max_nbd_clients;
struct client_tbl_entry *nbd_client; struct client_tbl_entry *nbd_client;
/** Should clients use the killswitch? */ /** Should clients use the killswitch? */
int use_killswitch; int use_killswitch;
/** If this isn't set, newly accepted clients will be closed immediately */ /** 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 /* Marker for whether this server has control over the data in
* the file, or if we're waiting to receive it from an inbound * the file, or if we're waiting to receive it from an inbound
* migration which hasn't yet finished. * migration which hasn't yet finished.
* *
* It's the value which controls the exit status of a serve or * It's the value which controls the exit status of a serve or
* listen process. * listen process.
*/ */
int success; int success;
}; };
struct server * server_create( struct server *server_create(struct flexnbd *flexnbd,
struct flexnbd * flexnbd, char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_file,
char* s_file, int default_deny,
int default_deny, int acl_entries,
int acl_entries, char **s_acl_entries,
char** s_acl_entries, int max_nbd_clients,
int max_nbd_clients, int use_killswitch, int success);
int use_killswitch, void server_destroy(struct server *);
int success ); int server_is_closed(struct server *serve);
void server_destroy( struct server * ); void serve_signal_close(struct server *serve);
int server_is_closed(struct server* serve); void serve_wait_for_close(struct server *serve);
void serve_signal_close( struct server *serve ); void server_replace_acl(struct server *serve, struct acl *acl);
void serve_wait_for_close( struct server * serve ); void server_control_arrived(struct server *serve);
void server_replace_acl( struct server *serve, struct acl * acl); int server_is_in_control(struct server *serve);
void server_control_arrived( struct server *serve ); int server_default_deny(struct server *serve);
int server_is_in_control( struct server *serve ); int server_acl_locked(struct server *serve);
int server_default_deny( struct server * serve ); void server_lock_acl(struct server *serve);
int server_acl_locked( struct server * serve ); void server_unlock_acl(struct server *serve);
void server_lock_acl( struct server *serve ); void server_lock_start_mirror(struct server *serve);
void server_unlock_acl( struct server *serve ); void server_unlock_start_mirror(struct server *serve);
void server_lock_start_mirror( struct server *serve ); int server_is_mirroring(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_bytes_remaining(struct server *serve);
uint64_t server_mirror_eta( struct server * serve ); uint64_t server_mirror_eta(struct server *serve);
uint64_t server_mirror_bps( struct server * serve ); uint64_t server_mirror_bps(struct server *serve);
void server_abandon_mirror( struct server * serve ); void server_abandon_mirror(struct server *serve);
void server_prevent_mirror_start( struct server *serve ); void server_prevent_mirror_start(struct server *serve);
void server_allow_mirror_start( struct server *serve ); void server_allow_mirror_start(struct server *serve);
int server_mirror_can_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 /* These three functions are used by mirror around the final pass, to close
* existing clients and prevent new ones from being around * existing clients and prevent new ones from being around
*/ */
void server_forbid_new_clients( struct server *serve ); void server_forbid_new_clients(struct server *serve);
void server_close_clients( struct server *serve ); void server_close_clients(struct server *serve);
void server_join_clients( struct server *serve ); void server_join_clients(struct server *serve);
void server_allow_new_clients( struct server *serve ); void server_allow_new_clients(struct server *serve);
/* Returns a count (ish) of the number of currently-running client threads */ /* 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 { struct mode_readwrite_params {
union mysockaddr connect_to; union mysockaddr connect_to;
union mysockaddr connect_from; union mysockaddr connect_from;
uint64_t from; uint64_t from;
uint32_t len; uint32_t len;
int data_fd; int data_fd;
int client; int client;
}; };
#endif #endif

View File

@@ -2,41 +2,44 @@
#include "serve.h" #include "serve.h"
#include "util.h" #include "util.h"
struct status * status_create( struct server * serve ) struct status *status_create(struct server *serve)
{ {
NULLCHECK( serve ); NULLCHECK(serve);
struct status * status; struct status *status;
status = xmalloc( sizeof( struct status ) ); status = xmalloc(sizeof(struct status));
status->pid = getpid(); status->pid = getpid();
status->size = serve->size; status->size = serve->size;
status->has_control = serve->success; status->has_control = serve->success;
status->clients_allowed = serve->allow_new_clients; status->clients_allowed = serve->allow_new_clients;
status->num_clients = server_count_clients( serve ); status->num_clients = server_count_clients(serve);
server_lock_start_mirror( serve ); server_lock_start_mirror(serve);
status->is_mirroring = NULL != serve->mirror; status->is_mirroring = NULL != serve->mirror;
if ( status->is_mirroring ) { if (status->is_mirroring) {
status->migration_duration = monotonic_time_ms(); status->migration_duration = monotonic_time_ms();
if ( ( serve->mirror->migration_started ) < status->migration_duration ) { if ((serve->mirror->migration_started) <
status->migration_duration -= serve->mirror->migration_started; status->migration_duration) {
} else { status->migration_duration -= serve->mirror->migration_started;
status->migration_duration = 0; } 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 );
} }
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 ) \ #define PRINT_UINT64( var ) \
do{dprintf( fd, #var "=%"PRIu64" ", status->var );}while(0) 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_INT(pid);
PRINT_UINT64( size ); PRINT_UINT64(size);
PRINT_BOOL( is_mirroring ); PRINT_BOOL(is_mirroring);
PRINT_BOOL( clients_allowed ); PRINT_BOOL(clients_allowed);
PRINT_INT( num_clients ); PRINT_INT(num_clients);
PRINT_BOOL( has_control ); PRINT_BOOL(has_control);
if ( status->is_mirroring ) { if (status->is_mirroring) {
PRINT_UINT64( migration_speed ); PRINT_UINT64(migration_speed);
PRINT_UINT64( migration_duration ); PRINT_UINT64(migration_duration);
PRINT_UINT64( migration_seconds_left ); PRINT_UINT64(migration_seconds_left);
PRINT_UINT64( migration_bytes_left ); PRINT_UINT64(migration_bytes_left);
if ( status->migration_speed_limit < UINT64_MAX ) { if (status->migration_speed_limit < UINT64_MAX) {
PRINT_UINT64( migration_speed_limit ); PRINT_UINT64(migration_speed_limit);
}; };
} }
dprintf(fd, "\n"); dprintf(fd, "\n");
return 1; return 1;
} }
void status_destroy( struct status * status ) void status_destroy(struct status *status)
{ {
NULLCHECK( status ); NULLCHECK(status);
free( status ); free(status);
} }

View File

@@ -75,30 +75,29 @@
#include <unistd.h> #include <unistd.h>
struct status { struct status {
pid_t pid; pid_t pid;
uint64_t size; uint64_t size;
int has_control; int has_control;
int clients_allowed; int clients_allowed;
int num_clients; int num_clients;
int is_mirroring; int is_mirroring;
uint64_t migration_duration; uint64_t migration_duration;
uint64_t migration_speed; uint64_t migration_speed;
uint64_t migration_speed_limit; uint64_t migration_speed_limit;
uint64_t migration_seconds_left; uint64_t migration_seconds_left;
uint64_t migration_bytes_left; uint64_t migration_bytes_left;
}; };
/** Create a status object for the given server. */ /** 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 */ /** 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 */ /** Free the status object */
void status_destroy( struct status * ); void status_destroy(struct status *);
#endif #endif

View File

@@ -4,226 +4,221 @@
#include "acl.h" #include "acl.h"
#include "util.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_if(NULL == acl, "No acl alloced.");
fail_unless( 0 == acl->len, "Incorrect length" ); fail_unless(0 == acl->len, "Incorrect length");
} }
END_TEST
END_TEST START_TEST(test_parses_single_line)
START_TEST( test_parses_single_line )
{ {
char *lines[] = {"127.0.0.1"}; char *lines[] = { "127.0.0.1" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
fail_unless( 1 == acl->len, "Incorrect length." ); fail_unless(1 == acl->len, "Incorrect length.");
fail_if( NULL == acl->entries, "No entries present." ); 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"}; char *lines[] = { "127.0.0.1", "::1" };
struct acl * acl = acl_create( 2, lines, 0 ); struct acl *acl = acl_create(2, lines, 0);
union mysockaddr e0, e1; union mysockaddr e0, e1;
parse_ip_to_sockaddr( &e0.generic, lines[0] ); parse_ip_to_sockaddr(&e0.generic, lines[0]);
parse_ip_to_sockaddr( &e1.generic, lines[1] ); 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; struct ip_and_mask *entry;
entry = &(*acl->entries)[0]; entry = &(*acl->entries)[0];
fail_unless(entry->ip.family == e0.family, "entry 0 has wrong family!"); fail_unless(entry->ip.family == e0.family,
entry = &(*acl->entries)[1]; "entry 0 has wrong family!");
fail_unless(entry->ip.family == e1.family, "entry 1 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"}; char *lines[] = { "127.0.0.1" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
acl_destroy( acl ); acl_destroy(acl);
} }
END_TEST
END_TEST START_TEST(test_includes_single_address)
START_TEST( test_includes_single_address )
{ {
char *lines[] = {"127.0.0.1"}; char *lines[] = { "127.0.0.1" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
union mysockaddr x; 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 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"}; char *lines[] = { "127.0.0.1/24" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
union mysockaddr x; union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.0" ); parse_ip_to_sockaddr(&x.generic, "127.0.0.0");
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
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");
parse_ip_to_sockaddr( &x.generic, "127.0.0.255" ); parse_ip_to_sockaddr(&x.generic, "127.0.0.255");
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
} }
END_TEST 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"}; char *lines[] = { "fe80::/10" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
union mysockaddr x; union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "fe80::1" ); parse_ip_to_sockaddr(&x.generic, "fe80::1");
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
parse_ip_to_sockaddr( &x.generic, "fe80::2" ); parse_ip_to_sockaddr(&x.generic, "fe80::2");
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
parse_ip_to_sockaddr( &x.generic, "fe80:ffff:ffff::ffff" ); parse_ip_to_sockaddr(&x.generic, "fe80:ffff:ffff::ffff");
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" ); fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
} }
END_TEST 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"}; char *lines[] = { "127.0.0.1", "::1" };
struct acl * acl = acl_create( 2, lines, 0 ); struct acl *acl = acl_create(2, lines, 0);
union mysockaddr e0; union mysockaddr e0;
union mysockaddr e1; union mysockaddr e1;
parse_ip_to_sockaddr( &e0.generic, "127.0.0.1" ); parse_ip_to_sockaddr(&e0.generic, "127.0.0.1");
parse_ip_to_sockaddr( &e1.generic, "::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, &e0),
fail_unless( acl_includes( acl, &e1 ), "Included address 1 wasn't covered" ); "Included address 0 wasn't covered");
fail_unless(acl_includes(acl, &e1),
"Included address 1 wasn't covered");
} }
END_TEST
END_TEST START_TEST(test_doesnt_include_other_address)
START_TEST( test_doesnt_include_other_address )
{ {
char *lines[] = {"127.0.0.1"}; char *lines[] = { "127.0.0.1" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
union mysockaddr x; union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" ); parse_ip_to_sockaddr(&x.generic, "127.0.0.2");
fail_if( acl_includes( acl, &x ), "Excluded address was covered." ); fail_if(acl_includes(acl, &x), "Excluded address was covered.");
} }
END_TEST 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"}; char *lines[] = { "127.0.0.1/32" };
struct acl * acl = acl_create( 1, lines, 0 ); struct acl *acl = acl_create(1, lines, 0);
union mysockaddr x; union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" ); parse_ip_to_sockaddr(&x.generic, "127.0.0.2");
fail_if( acl_includes( acl, &x ), "Excluded address was covered." ); fail_if(acl_includes(acl, &x), "Excluded address was covered.");
} }
END_TEST 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"}; char *lines[] = { "127.0.0.1", "::1" };
struct acl * acl = acl_create( 2, lines, 0 ); struct acl *acl = acl_create(2, lines, 0);
union mysockaddr e0; union mysockaddr e0;
union mysockaddr e1; union mysockaddr e1;
parse_ip_to_sockaddr( &e0.generic, "127.0.0.2" ); parse_ip_to_sockaddr(&e0.generic, "127.0.0.2");
parse_ip_to_sockaddr( &e1.generic, "::2" ); parse_ip_to_sockaddr(&e1.generic, "::2");
fail_if( acl_includes( acl, &e0 ), "Excluded address 0 was covered." ); 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, &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 ); struct acl *acl = acl_create(0, NULL, 1);
union mysockaddr x; 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
END_TEST START_TEST(test_default_accept_rejects)
START_TEST( test_default_accept_rejects )
{ {
struct acl * acl = acl_create( 0, NULL, 0 ); struct acl *acl = acl_create(0, NULL, 0);
union mysockaddr x; 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
END_TEST Suite * acl_suite(void)
Suite* acl_suite(void)
{ {
Suite *s = suite_create("acl"); Suite *s = suite_create("acl");
TCase *tc_create = tcase_create("create"); TCase *tc_create = tcase_create("create");
TCase *tc_includes = tcase_create("includes"); TCase *tc_includes = tcase_create("includes");
TCase *tc_destroy = tcase_create("destroy"); TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_null_acl); tcase_add_test(tc_create, test_null_acl);
tcase_add_test(tc_create, test_parses_single_line); tcase_add_test(tc_create, test_parses_single_line);
tcase_add_test(tc_includes, test_parses_multiple_lines); 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);
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv4); tcase_add_test(tc_includes,
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv6); 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);
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_netmask_specified); tcase_add_test(tc_includes,
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_multiple_entries_exist); 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_deny_rejects);
tcase_add_test(tc_includes, test_default_accept_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_create);
suite_add_tcase(s, tc_includes); suite_add_tcase(s, tc_includes);
suite_add_tcase(s, tc_destroy); suite_add_tcase(s, tc_destroy);
return s; return s;
} }
int main(void) int main(void)
{ {
#ifdef DEBUG #ifdef DEBUG
log_level = 0; log_level = 0;
#else #else
log_level = 2; log_level = 2;
#endif #endif
int number_failed; int number_failed;
Suite *s = acl_suite(); Suite *s = acl_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
log_level = 0; log_level = 0;
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,492 +9,473 @@
START_TEST(test_bit_set) START_TEST(test_bit_set)
{ {
uint64_t num = 0; uint64_t num = 0;
bitfield_p bits = (bitfield_p) &num; bitfield_p bits = (bitfield_p) & num;
#define TEST_BIT_SET(bit, newvalue) \ #define TEST_BIT_SET(bit, newvalue) \
bit_set(bits, (bit)); \ bit_set(bits, (bit)); \
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue)); fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
TEST_BIT_SET(0, 1); TEST_BIT_SET(0, 1);
TEST_BIT_SET(1, 3); TEST_BIT_SET(1, 3);
TEST_BIT_SET(2, 7); TEST_BIT_SET(2, 7);
TEST_BIT_SET(7, 0x87); TEST_BIT_SET(7, 0x87);
TEST_BIT_SET(63, 0x8000000000000087); TEST_BIT_SET(63, 0x8000000000000087);
} }
END_TEST
START_TEST(test_bit_clear) END_TEST START_TEST(test_bit_clear)
{ {
uint64_t num = 0xffffffffffffffff; uint64_t num = 0xffffffffffffffff;
bitfield_p bits = (bitfield_p) &num; bitfield_p bits = (bitfield_p) & num;
#define TEST_BIT_CLEAR(bit, newvalue) \ #define TEST_BIT_CLEAR(bit, newvalue) \
bit_clear(bits, (bit)); \ bit_clear(bits, (bit)); \
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue)); fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
TEST_BIT_CLEAR(0, 0xfffffffffffffffe); TEST_BIT_CLEAR(0, 0xfffffffffffffffe);
TEST_BIT_CLEAR(1, 0xfffffffffffffffc); TEST_BIT_CLEAR(1, 0xfffffffffffffffc);
TEST_BIT_CLEAR(2, 0xfffffffffffffff8); TEST_BIT_CLEAR(2, 0xfffffffffffffff8);
TEST_BIT_CLEAR(7, 0xffffffffffffff78); TEST_BIT_CLEAR(7, 0xffffffffffffff78);
TEST_BIT_CLEAR(63,0x7fffffffffffff78); TEST_BIT_CLEAR(63, 0x7fffffffffffff78);
} }
END_TEST
START_TEST(test_bit_tests) END_TEST START_TEST(test_bit_tests)
{ {
uint64_t num = 0x5555555555555555; uint64_t num = 0x5555555555555555;
bitfield_p bits = (bitfield_p) &num; bitfield_p bits = (bitfield_p) & num;
fail_unless(bit_has_value(bits, 0, 1), "bit_has_value 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, 1, 0), "bit_has_value malfunction");
fail_unless(bit_has_value(bits, 63, 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_set(bits, 0), "bit_is_set malfunction");
fail_unless(bit_is_clear(bits, 1), "bit_is_clear 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_set(bits, 62), "bit_is_set malfunction");
fail_unless(bit_is_clear(bits, 63), "bit_is_clear 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)]; bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)];
uint64_t *longs = (uint64_t *) buffer; uint64_t *longs = (uint64_t *) buffer;
uint64_t i; uint64_t i;
memset(buffer, 0, 4160); memset(buffer, 0, 4160);
for (i=0; i<64; i++) { for (i = 0; i < 64; i++) {
bit_set_range(buffer, i*64, i); bit_set_range(buffer, i * 64, i);
fail_unless( fail_unless(longs[i] == (1ULL << i) - 1,
longs[i] == (1ULL<<i)-1, "longs[%ld] = %lx SHOULD BE %lx",
"longs[%ld] = %lx SHOULD BE %lx", i, longs[i], (1ULL << i) - 1);
i, longs[i], (1ULL<<i)-1
);
fail_unless(longs[i+1] == 0, "bit_set_range overshot at i=%d", i); fail_unless(longs[i + 1] == 0, "bit_set_range overshot at i=%d",
} i);
}
for (i=0; i<64; i++) { for (i = 0; i < 64; i++) {
bit_clear_range(buffer, i*64, i); bit_clear_range(buffer, i * 64, i);
fail_unless(longs[i] == 0, "bit_clear_range didn't work at i=%d", i); fail_unless(longs[i] == 0, "bit_clear_range didn't work at i=%d",
} i);
}
} }
END_TEST
START_TEST(test_bit_runs) END_TEST START_TEST(test_bit_runs)
{ {
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(256)]; bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(256)];
int i, ptr=0, runs[] = { int i, ptr = 0, runs[] = {
56,97,22,12,83,1,45,80,85,51,64,40,63,67,75,64,94,81,79,62 56, 97, 22, 12, 83, 1, 45, 80, 85, 51, 64, 40, 63, 67, 75, 64, 94,
}; 81, 79, 62
};
memset(buffer,0,256); memset(buffer, 0, 256);
for (i=0; i < 20; i += 2) { for (i = 0; i < 20; i += 2) {
ptr += runs[i]; ptr += runs[i];
bit_set_range(buffer, ptr, runs[i+1]); bit_set_range(buffer, ptr, runs[i + 1]);
ptr += runs[i+1]; ptr += runs[i + 1];
} }
ptr = 0; ptr = 0;
for (i=0; i < 20; i += 1) { for (i = 0; i < 20; i += 1) {
int run = bit_run_count(buffer, ptr, 2048-ptr, NULL); int run = bit_run_count(buffer, ptr, 2048 - ptr, NULL);
fail_unless( fail_unless(run == runs[i],
run == runs[i], "run %d should have been %d, was %d", i, runs[i], run);
"run %d should have been %d, was %d", ptr += runs[i];
i, runs[i], run }
);
ptr += runs[i];
}
} }
END_TEST
START_TEST(test_bitset) END_TEST START_TEST(test_bitset)
{ {
struct bitset * map; struct bitset *map;
uint64_t *num; uint64_t *num;
map = bitset_alloc(6400, 100); map = bitset_alloc(6400, 100);
num = (uint64_t*) map->bits; num = (uint64_t *) map->bits;
bitset_set_range(map,0,50); bitset_set_range(map, 0, 50);
ck_assert_int_eq(1, *num); ck_assert_int_eq(1, *num);
bitset_set_range(map,99,1); bitset_set_range(map, 99, 1);
ck_assert_int_eq(1, *num); ck_assert_int_eq(1, *num);
bitset_set_range(map,100,1); bitset_set_range(map, 100, 1);
ck_assert_int_eq(3, *num); ck_assert_int_eq(3, *num);
bitset_set_range(map,0,800); bitset_set_range(map, 0, 800);
ck_assert_int_eq(255, *num); ck_assert_int_eq(255, *num);
bitset_set_range(map,1499,2); bitset_set_range(map, 1499, 2);
ck_assert_int_eq(0xc0ff, *num); ck_assert_int_eq(0xc0ff, *num);
bitset_clear_range(map,1499,2); bitset_clear_range(map, 1499, 2);
ck_assert_int_eq(255, *num); ck_assert_int_eq(255, *num);
*num = 0; *num = 0;
bitset_set_range(map, 1499, 2); bitset_set_range(map, 1499, 2);
bitset_clear_range(map, 1300, 200); bitset_clear_range(map, 1300, 200);
ck_assert_int_eq(0x8000, *num); ck_assert_int_eq(0x8000, *num);
*num = 0; *num = 0;
bitset_set_range(map, 0, 6400); bitset_set_range(map, 0, 6400);
ck_assert_int_eq(0xffffffffffffffff, *num); ck_assert_int_eq(0xffffffffffffffff, *num);
bitset_clear_range(map, 3200, 400); bitset_clear_range(map, 3200, 400);
ck_assert_int_eq(0xfffffff0ffffffff, *num); ck_assert_int_eq(0xfffffff0ffffffff, *num);
} }
END_TEST
END_TEST START_TEST(test_bitset_set)
START_TEST( test_bitset_set )
{ {
struct bitset * map; struct bitset *map;
uint64_t run; uint64_t run;
map = bitset_alloc(64, 1); map = bitset_alloc(64, 1);
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
bitset_set( map ); bitset_set(map);
assert_bitset_is( map, 0xffffffffffffffff ); assert_bitset_is(map, 0xffffffffffffffff);
bitset_free( map ); bitset_free(map);
map = bitset_alloc( 6400, 100 ); map = bitset_alloc(6400, 100);
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
bitset_set( map ); bitset_set(map);
assert_bitset_is( map, 0xffffffffffffffff ); assert_bitset_is(map, 0xffffffffffffffff);
bitset_free( map ); bitset_free(map);
// Now do something large and representative // Now do something large and representative
map = bitset_alloc( 53687091200, 4096 ); map = bitset_alloc(53687091200, 4096);
bitset_set( map ); bitset_set(map);
run = bitset_run_count( map, 0, 53687091200 ); run = bitset_run_count(map, 0, 53687091200);
ck_assert_int_eq( run, 53687091200 ); ck_assert_int_eq(run, 53687091200);
bitset_free( map ); bitset_free(map);
} }
END_TEST
END_TEST START_TEST(test_bitset_clear)
START_TEST( test_bitset_clear )
{ {
struct bitset * map; struct bitset *map;
uint64_t *num; uint64_t *num;
uint64_t run; uint64_t run;
map = bitset_alloc(64, 1); map = bitset_alloc(64, 1);
num = (uint64_t*) map->bits; num = (uint64_t *) map->bits;
ck_assert_int_eq( 0x0000000000000000, *num ); ck_assert_int_eq(0x0000000000000000, *num);
bitset_set( map ); bitset_set(map);
bitset_clear( map ); bitset_clear(map);
ck_assert_int_eq( 0x0000000000000000, *num ); ck_assert_int_eq(0x0000000000000000, *num);
bitset_free( map ); bitset_free(map);
// Now do something large and representative // Now do something large and representative
map = bitset_alloc( 53687091200, 4096 ); map = bitset_alloc(53687091200, 4096);
bitset_set( map ); bitset_set(map);
bitset_clear( map ); bitset_clear(map);
run = bitset_run_count( map, 0, 53687091200 ); run = bitset_run_count(map, 0, 53687091200);
ck_assert_int_eq( run, 53687091200 ); ck_assert_int_eq(run, 53687091200);
bitset_free( map ); 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 ); struct bitset *map = bitset_alloc(64, 1);
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
bitset_set_range( map, 8, 8 ); bitset_set_range(map, 8, 8);
assert_bitset_is( map, 0x000000000000ff00 ); assert_bitset_is(map, 0x000000000000ff00);
bitset_clear( map ); bitset_clear(map);
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
bitset_set_range( map, 0, 0 ); bitset_set_range(map, 0, 0);
assert_bitset_is( map, 0x0000000000000000 ); 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 ); struct bitset *map = bitset_alloc(64, 1);
bitset_set( map ); bitset_set(map);
assert_bitset_is( map, 0xffffffffffffffff ); assert_bitset_is(map, 0xffffffffffffffff);
bitset_clear_range( map, 8, 8 ); bitset_clear_range(map, 8, 8);
assert_bitset_is( map, 0xffffffffffff00ff ); assert_bitset_is(map, 0xffffffffffff00ff);
bitset_set( map ); bitset_set(map);
assert_bitset_is( map, 0xffffffffffffffff ); assert_bitset_is(map, 0xffffffffffffffff);
bitset_clear_range( map, 0, 0 ); bitset_clear_range(map, 0, 0);
assert_bitset_is( map, 0xffffffffffffffff ); 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 ); struct bitset *map = bitset_alloc(64, 1);
uint64_t run; uint64_t run;
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
run = bitset_run_count( map, 0, 64 ); run = bitset_run_count(map, 0, 64);
ck_assert_int_eq( 64, run ); ck_assert_int_eq(64, run);
bitset_set_range( map, 0, 32 ); bitset_set_range(map, 0, 32);
assert_bitset_is( map, 0x00000000ffffffff ); assert_bitset_is(map, 0x00000000ffffffff);
run = bitset_run_count( map, 0, 64 ); run = bitset_run_count(map, 0, 64);
ck_assert_int_eq( 32, run ); ck_assert_int_eq(32, run);
run = bitset_run_count( map, 0, 16 ); run = bitset_run_count(map, 0, 16);
ck_assert_int_eq( 16, run ); ck_assert_int_eq(16, run);
run = bitset_run_count( map, 16, 64 ); run = bitset_run_count(map, 16, 64);
ck_assert_int_eq( 16, run ); ck_assert_int_eq(16, run);
run = bitset_run_count( map, 31, 64 ); run = bitset_run_count(map, 31, 64);
ck_assert_int_eq( 1, run ); ck_assert_int_eq(1, run);
run = bitset_run_count( map, 32, 64 ); run = bitset_run_count(map, 32, 64);
ck_assert_int_eq( 32, run ); ck_assert_int_eq(32, run);
run = bitset_run_count( map, 32, 32 ); run = bitset_run_count(map, 32, 32);
ck_assert_int_eq( 32, run ); ck_assert_int_eq(32, run);
run = bitset_run_count( map, 32, 16 ); run = bitset_run_count(map, 32, 16);
ck_assert_int_eq( 16, run ); ck_assert_int_eq(16, run);
bitset_free( map ); bitset_free(map);
map = bitset_alloc( 6400, 100 ); map = bitset_alloc(6400, 100);
assert_bitset_is( map, 0x0000000000000000 ); assert_bitset_is(map, 0x0000000000000000);
run = bitset_run_count( map, 0, 6400 ); run = bitset_run_count(map, 0, 6400);
ck_assert_int_eq( 6400, run ); 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 ); run = bitset_run_count(map, 0, 6400);
ck_assert_int_eq( 3200, run ); ck_assert_int_eq(3200, run);
run = bitset_run_count( map, 1, 6400 ); run = bitset_run_count(map, 1, 6400);
ck_assert_int_eq( 3199, run ); ck_assert_int_eq(3199, run);
run = bitset_run_count( map, 3200, 6400 ); run = bitset_run_count(map, 3200, 6400);
ck_assert_int_eq( 3200, run ); ck_assert_int_eq(3200, run);
run = bitset_run_count( map, 6500, 6400 ); run = bitset_run_count(map, 6500, 6400);
ck_assert_int_eq( 0, run ); ck_assert_int_eq(0, run);
bitset_free( map ); bitset_free(map);
// Now do something large and representative // Now do something large and representative
map = bitset_alloc( 53687091200, 4096 ); map = bitset_alloc(53687091200, 4096);
bitset_set( map ); bitset_set(map);
run = bitset_run_count( map, 0, 53687091200 ); run = bitset_run_count(map, 0, 53687091200);
ck_assert_int_eq( run, 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 ); struct bitset *map = bitset_alloc(64, 1);
bitset_set_range( map, 0, 64 ); bitset_set_range(map, 0, 64);
ck_assert_int_eq( 0, bitset_stream_size( map ) ); ck_assert_int_eq(0, bitset_stream_size(map));
bitset_free( 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 ); struct bitset *map = bitset_alloc(64, 1);
bitset_clear_range( map, 0, 64 ); bitset_clear_range(map, 0, 64);
ck_assert_int_eq( 0, bitset_stream_size( map ) ); ck_assert_int_eq(0, bitset_stream_size(map));
bitset_free( 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 *map = bitset_alloc(64, 1);
struct bitset_stream_entry result; struct bitset_stream_entry result;
memset( &result, 0, sizeof( 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(BITSET_STREAM_ON, result.event);
ck_assert_int_eq( 0, result.from ); ck_assert_int_eq(0, result.from);
ck_assert_int_eq( 64, result.len ); 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 *map = bitset_alloc(64, 1);
struct bitset_stream_entry result; struct bitset_stream_entry result;
memset( &result, 0, sizeof( result ) ); memset(&result, 0, sizeof(result));
bitset_enable_stream( map ); bitset_enable_stream(map);
bitset_disable_stream( map ); bitset_disable_stream(map);
ck_assert_int_eq( 0, map->stream_enabled ); ck_assert_int_eq(0, map->stream_enabled);
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, NULL); // ON
bitset_stream_dequeue( map, &result ); // OFF bitset_stream_dequeue(map, &result); // OFF
ck_assert_int_eq( BITSET_STREAM_OFF, result.event ); ck_assert_int_eq(BITSET_STREAM_OFF, result.event);
ck_assert_int_eq( 0, result.from ); ck_assert_int_eq(0, result.from);
ck_assert_int_eq( 64, result.len ); 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 *map = bitset_alloc(64, 1);
struct bitset_stream_entry result; struct bitset_stream_entry result;
memset( &result, 0, sizeof( result ) ); memset(&result, 0, sizeof(result));
bitset_enable_stream( map ); bitset_enable_stream(map);
bitset_set_range( map, 0, 32 ); 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, NULL); // ON
bitset_stream_dequeue( map, &result ); // SET bitset_stream_dequeue(map, &result); // SET
ck_assert_int_eq( BITSET_STREAM_SET, result.event ); ck_assert_int_eq(BITSET_STREAM_SET, result.event);
ck_assert_int_eq( 0, result.from ); ck_assert_int_eq(0, result.from);
ck_assert_int_eq( 32, result.len ); 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 *map = bitset_alloc(64, 1);
struct bitset_stream_entry result; struct bitset_stream_entry result;
memset( &result, 0, sizeof( result ) ); memset(&result, 0, sizeof(result));
bitset_enable_stream( map ); bitset_enable_stream(map);
bitset_clear_range( map, 0, 32 ); bitset_clear_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, NULL); // ON
bitset_stream_dequeue( map, &result ); // UNSET bitset_stream_dequeue(map, &result); // UNSET
ck_assert_int_eq( BITSET_STREAM_UNSET, result.event ); ck_assert_int_eq(BITSET_STREAM_UNSET, result.event);
ck_assert_int_eq( 0, result.from ); ck_assert_int_eq(0, result.from);
ck_assert_int_eq( 32, result.len ); 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 ); struct bitset *map = bitset_alloc(64, 1);
bitset_enable_stream( map ); bitset_enable_stream(map);
bitset_set_range( map, 0, 32 ); bitset_set_range(map, 0, 32);
bitset_set_range( map, 16, 32 ); bitset_set_range(map, 16, 32);
bitset_set_range( map, 7, 16 ); bitset_set_range(map, 7, 16);
bitset_clear_range( map, 0, 32 ); bitset_clear_range(map, 0, 32);
bitset_clear_range( map, 16, 32 ); bitset_clear_range(map, 16, 32);
bitset_clear_range( map, 48, 16 ); bitset_clear_range(map, 48, 16);
bitset_disable_stream( map ); 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 ); struct bitset *map = bitset_alloc(64, 1);
bitset_enable_stream( map ); bitset_enable_stream(map);
bitset_set_range( map, 0, 32 ); bitset_set_range(map, 0, 32);
bitset_set_range( map, 16, 32 ); bitset_set_range(map, 16, 32);
bitset_set_range( map, 7, 16 ); bitset_set_range(map, 7, 16);
bitset_clear_range( map, 0, 32 ); bitset_clear_range(map, 0, 32);
bitset_clear_range( map, 16, 32 ); bitset_clear_range(map, 16, 32);
bitset_clear_range( map, 48, 16 ); bitset_clear_range(map, 48, 16);
bitset_clear_range( map, 0, 2 ); bitset_clear_range(map, 0, 2);
bitset_disable_stream( map ); bitset_disable_stream(map);
ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_ON ) ); ck_assert_int_eq(64,
ck_assert_int_eq( 80, bitset_stream_queued_bytes( map, BITSET_STREAM_SET ) ); bitset_stream_queued_bytes(map, BITSET_STREAM_ON));
ck_assert_int_eq( 82, bitset_stream_queued_bytes( map, BITSET_STREAM_UNSET ) ); ck_assert_int_eq(80,
ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_OFF ) ); bitset_stream_queued_bytes(map, BITSET_STREAM_SET));
bitset_free( map ); 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 *tc_bit = tcase_create("bit");
tcase_add_test(tc_bit, test_bit_set); tcase_add_test(tc_bit, test_bit_set);
tcase_add_test(tc_bit, test_bit_clear); tcase_add_test(tc_bit, test_bit_clear);
tcase_add_test(tc_bit, test_bit_tests); tcase_add_test(tc_bit, test_bit_tests);
tcase_add_test(tc_bit, test_bit_ranges); tcase_add_test(tc_bit, test_bit_ranges);
tcase_add_test(tc_bit, test_bit_runs); tcase_add_test(tc_bit, test_bit_runs);
suite_add_tcase(s, tc_bit); suite_add_tcase(s, tc_bit);
TCase *tc_bitset = tcase_create("bitset"); TCase *tc_bitset = tcase_create("bitset");
tcase_add_test(tc_bitset, test_bitset); tcase_add_test(tc_bitset, test_bitset);
tcase_add_test(tc_bitset, test_bitset_set); tcase_add_test(tc_bitset, test_bitset_set);
tcase_add_test(tc_bitset, test_bitset_clear); tcase_add_test(tc_bitset, test_bitset_clear);
tcase_add_test(tc_bitset, test_bitset_run_count); 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_set_range);
tcase_add_test(tc_bitset, test_bitset_clear_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_set_range_doesnt_push_to_stream);
tcase_add_test(tc_bitset, test_bitset_clear_range_doesnt_push_to_stream); tcase_add_test(tc_bitset,
suite_add_tcase(s, 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 *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_enable_stream);
tcase_add_test(tc_bitset_stream, test_bitset_disable_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_set_range);
tcase_add_test(tc_bitset_stream, test_bitset_stream_with_clear_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_size);
tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes); tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes);
suite_add_tcase(s, tc_bitset_stream); suite_add_tcase(s, tc_bitset_stream);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = bitset_suite(); Suite *s = bitset_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,114 +9,104 @@
#include <unistd.h> #include <unistd.h>
struct server fake_server = {0}; struct server fake_server = { 0 };
#define FAKE_SERVER &fake_server #define FAKE_SERVER &fake_server
#define FAKE_SOCKET (42) #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
END_TEST START_TEST(test_assigns_server)
START_TEST( test_assigns_server )
{ {
struct client * c; struct client *c;
/* can't predict the storage size so we can't allocate one on /* can't predict the storage size so we can't allocate one on
* the stack * the stack
*/ */
c = client_create( FAKE_SERVER, FAKE_SOCKET ); 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
END_TEST START_TEST(test_opens_stop_signal)
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 ), fail_unless(1 == self_pipe_signal_clear(c->stop_signal),
"No signal was sent." ); "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 ); struct client *c = client_create(FAKE_SERVER, FAKE_SOCKET);
int read_fd = c->stop_signal->read_fd; int read_fd = c->stop_signal->read_fd;
int write_fd = c->stop_signal->write_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(read_fd), "Stop signal wasn't destroyed.");
fail_unless( fd_is_closed( write_fd ), "Stop signal wasn't destroyed." ); fail_unless(fd_is_closed(write_fd), "Stop signal wasn't destroyed.");
} }
END_TEST
END_TEST START_TEST(test_read_request_quits_on_stop_signal)
START_TEST( test_read_request_quits_on_stop_signal )
{ {
int fds[2]; int fds[2];
struct nbd_request nbdr; struct nbd_request nbdr;
pipe( fds ); pipe(fds);
struct client *c = client_create( FAKE_SERVER, fds[0] ); struct client *c = client_create(FAKE_SERVER, fds[0]);
client_signal_stop( c ); client_signal_stop(c);
int client_serve_request( struct client *); int client_serve_request(struct client *);
fail_unless( 1 == client_serve_request( c ), "Didn't quit on stop." ); fail_unless(1 == client_serve_request(c), "Didn't quit on stop.");
close( fds[0] ); close(fds[0]);
close( fds[1] ); close(fds[1]);
} }
END_TEST
END_TEST Suite * client_suite(void)
Suite *client_suite(void)
{ {
Suite *s = suite_create("client"); Suite *s = suite_create("client");
TCase *tc_create = tcase_create("create"); TCase *tc_create = tcase_create("create");
TCase *tc_signal = tcase_create("signal"); TCase *tc_signal = tcase_create("signal");
TCase *tc_destroy = tcase_create("destroy"); TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_assigns_socket); tcase_add_test(tc_create, test_assigns_socket);
tcase_add_test(tc_create, test_assigns_server); tcase_add_test(tc_create, test_assigns_server);
tcase_add_test(tc_signal, test_opens_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_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_create);
suite_add_tcase(s, tc_signal); suite_add_tcase(s, tc_signal);
suite_add_tcase(s, tc_destroy); suite_add_tcase(s, tc_destroy);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = client_suite(); Suite *s = client_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,39 +4,36 @@
#include <check.h> #include <check.h>
START_TEST( test_assigns_sock_name ) START_TEST(test_assigns_sock_name)
{ {
struct flexnbd flexnbd = {0}; struct flexnbd flexnbd = { 0 };
char csn[] = "foobar"; 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
END_TEST Suite * control_suite(void)
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); tcase_add_test(tc_create, test_assigns_sock_name);
suite_add_tcase( s, tc_create ); suite_add_tcase(s, tc_create);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = control_suite(); Suite *s = control_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -3,42 +3,38 @@
#include <check.h> #include <check.h>
START_TEST( test_listening_assigns_sock ) START_TEST(test_listening_assigns_sock)
{ {
struct flexnbd * flexnbd = flexnbd_create_listening( struct flexnbd *flexnbd = flexnbd_create_listening("127.0.0.1",
"127.0.0.1", "4777",
"4777", "fakefile",
"fakefile", "fakesock",
"fakesock", 0,
0, 0,
0, NULL);
NULL ); fail_if(NULL == flexnbd->control->socket_name, "No socket was copied");
fail_if( NULL == flexnbd->control->socket_name, "No socket was copied" );
} }
END_TEST
END_TEST Suite * flexnbd_suite(void)
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); tcase_add_test(tc_create, test_listening_assigns_sock);
suite_add_tcase( s, tc_create ); suite_add_tcase(s, tc_create);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = flexnbd_suite(); Suite *s = flexnbd_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,59 +4,57 @@
#include <check.h> #include <check.h>
START_TEST( test_mutex_create ) START_TEST(test_mutex_create)
{ {
struct flexthread_mutex * ftm = flexthread_mutex_create(); struct flexthread_mutex *ftm = flexthread_mutex_create();
NULLCHECK( ftm ); NULLCHECK(ftm);
flexthread_mutex_destroy( ftm ); flexthread_mutex_destroy(ftm);
} }
END_TEST
END_TEST START_TEST(test_mutex_lock)
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" ); fail_if(flexthread_mutex_held(ftm),
flexthread_mutex_lock( ftm ); "Flexthread_mutex is held before lock");
fail_unless( flexthread_mutex_held( ftm ), "Flexthread_mutex is not held inside lock" ); flexthread_mutex_lock(ftm);
flexthread_mutex_unlock( ftm ); fail_unless(flexthread_mutex_held(ftm),
fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held after unlock" ); "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
END_TEST Suite * flexthread_suite(void)
Suite* flexthread_suite(void)
{ {
Suite *s = suite_create("flexthread"); Suite *s = suite_create("flexthread");
TCase *tc_create = tcase_create("create"); TCase *tc_create = tcase_create("create");
TCase *tc_destroy = tcase_create("destroy"); TCase *tc_destroy = tcase_create("destroy");
tcase_add_test( tc_create, test_mutex_create ); tcase_add_test(tc_create, test_mutex_create);
tcase_add_test( tc_create, test_mutex_lock ); tcase_add_test(tc_create, test_mutex_lock);
suite_add_tcase(s, tc_create); suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_destroy); suite_add_tcase(s, tc_destroy);
return s; return s;
} }
int main(void) int main(void)
{ {
#ifdef DEBUG #ifdef DEBUG
log_level = 0; log_level = 0;
#else #else
log_level = 2; log_level = 2;
#endif #endif
int number_failed; int number_failed;
Suite *s = flexthread_suite(); Suite *s = flexthread_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
log_level = 0; log_level = 0;
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -2,133 +2,125 @@
#include <check.h> #include <check.h>
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 fds[2];
int nread; int nread;
char buf[5] = {0}; char buf[5] = { 0 };
pipe(fds); pipe(fds);
write( fds[1], "1234\n", 5 ); write(fds[1], "1234\n", 5);
nread = read_until_newline( fds[0], buf, 5 ); nread = read_until_newline(fds[0], buf, 5);
ck_assert_int_eq( 5, nread ); ck_assert_int_eq(5, nread);
} }
END_TEST
END_TEST START_TEST(test_read_until_newline_inserts_null)
START_TEST( test_read_until_newline_inserts_null )
{ {
int fds[2]; int fds[2];
int nread; int nread;
char buf[5] = {0}; char buf[5] = { 0 };
pipe(fds); pipe(fds);
write( fds[1], "1234\n", 5 ); write(fds[1], "1234\n", 5);
nread = read_until_newline( fds[0], buf, 5 ); nread = read_until_newline(fds[0], buf, 5);
ck_assert_int_eq( '\0', buf[4] ); ck_assert_int_eq('\0', buf[4]);
} }
END_TEST
END_TEST START_TEST(test_read_empty_line_inserts_null)
START_TEST( test_read_empty_line_inserts_null )
{ {
int fds[2]; int fds[2];
int nread; int nread;
char buf[5] = {0}; char buf[5] = { 0 };
pipe(fds); pipe(fds);
write( fds[1], "\n", 1 ); write(fds[1], "\n", 1);
nread = read_until_newline( fds[0], buf, 1 ); nread = read_until_newline(fds[0], buf, 1);
ck_assert_int_eq( '\0', buf[0] ); ck_assert_int_eq('\0', buf[0]);
ck_assert_int_eq( 1, nread ); ck_assert_int_eq(1, nread);
} }
END_TEST
END_TEST START_TEST(test_read_eof_returns_err)
START_TEST( test_read_eof_returns_err )
{ {
int fds[2]; int fds[2];
int nread; int nread;
char buf[5] = {0}; char buf[5] = { 0 };
pipe( fds ); pipe(fds);
close( fds[1] ); close(fds[1]);
nread = read_until_newline( fds[0], buf, 5 ); nread = read_until_newline(fds[0], buf, 5);
ck_assert_int_eq( -1, nread ); ck_assert_int_eq(-1, nread);
} }
END_TEST
END_TEST START_TEST(test_read_eof_fills_line)
START_TEST( test_read_eof_fills_line )
{ {
int fds[2]; int fds[2];
int nread; int nread;
char buf[5] = {0}; char buf[5] = { 0 };
pipe(fds); pipe(fds);
write( fds[1], "1234", 4 ); write(fds[1], "1234", 4);
close( fds[1] ); close(fds[1]);
nread = read_until_newline( fds[0], buf, 5 ); nread = read_until_newline(fds[0], buf, 5);
ck_assert_int_eq( -1, nread ); ck_assert_int_eq(-1, nread);
ck_assert_int_eq( '4', buf[3] ); ck_assert_int_eq('4', buf[3]);
} }
END_TEST
END_TEST START_TEST(test_read_lines_until_blankline)
START_TEST( test_read_lines_until_blankline )
{ {
char **lines = NULL; char **lines = NULL;
int fds[2]; int fds[2];
int nlines; int nlines;
pipe( fds ); 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
END_TEST Suite * ioutil_suite(void)
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_until_newline = tcase_create("read_until_newline");
TCase *tc_read_lines_until_blankline = tcase_create("read_lines_until_blankline"); 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,
tcase_add_test(tc_read_until_newline, test_read_until_newline_inserts_null); test_read_until_newline_returns_line_length_plus_null);
tcase_add_test(tc_read_until_newline, test_read_empty_line_inserts_null); tcase_add_test(tc_read_until_newline,
tcase_add_test(tc_read_until_newline, test_read_eof_returns_err); test_read_until_newline_inserts_null);
tcase_add_test(tc_read_until_newline, test_read_eof_fills_line ); 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_until_newline);
suite_add_tcase(s, tc_read_lines_until_blankline); suite_add_tcase(s, tc_read_lines_until_blankline);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = ioutil_suite(); Suite *s = ioutil_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,83 +4,76 @@
#include <pthread.h> #include <pthread.h>
#include <check.h> #include <check.h>
START_TEST( test_allocs_cvar ) START_TEST(test_allocs_cvar)
{ {
struct mbox * mbox = mbox_create(); struct mbox *mbox = mbox_create();
fail_if( NULL == mbox, "Nothing allocated" ); fail_if(NULL == mbox, "Nothing allocated");
pthread_cond_t cond_zero; pthread_cond_t cond_zero;
/* A freshly inited pthread_cond_t is set to {0} */ /* A freshly inited pthread_cond_t is set to {0} */
memset( &cond_zero, 'X', sizeof( cond_zero ) ); memset(&cond_zero, 'X', sizeof(cond_zero));
fail_if( memcmp( &cond_zero, &mbox->filled_cond, sizeof( cond_zero ) ) == 0 , fail_if(memcmp(&cond_zero, &mbox->filled_cond, sizeof(cond_zero)) == 0,
"Condition variable not allocated" ); "Condition variable not allocated");
fail_if( memcmp( &cond_zero, &mbox->emptied_cond, sizeof( cond_zero ) ) == 0 , fail_if(memcmp(&cond_zero, &mbox->emptied_cond, sizeof(cond_zero)) ==
"Condition variable not allocated" ); 0, "Condition variable not allocated");
} }
END_TEST
END_TEST START_TEST(test_post_stores_value)
START_TEST( test_post_stores_value )
{ {
struct mbox * mbox = mbox_create(); struct mbox *mbox = mbox_create();
void * deadbeef = (void *)0xDEADBEEF; void *deadbeef = (void *) 0xDEADBEEF;
mbox_post( mbox, deadbeef ); mbox_post(mbox, deadbeef);
fail_unless( deadbeef == mbox_contents( mbox ), fail_unless(deadbeef == mbox_contents(mbox),
"Contents were not posted" ); "Contents were not posted");
} }
END_TEST
END_TEST void *mbox_receive_runner(void *mbox_uncast)
void * mbox_receive_runner( void * mbox_uncast )
{ {
struct mbox * mbox = (struct mbox *)mbox_uncast; struct mbox *mbox = (struct mbox *) mbox_uncast;
void * contents = NULL; void *contents = NULL;
contents = mbox_receive( mbox ); contents = mbox_receive(mbox);
return contents; return contents;
} }
START_TEST( test_receive_blocks_until_post ) START_TEST(test_receive_blocks_until_post)
{ {
struct mbox * mbox = mbox_create(); struct mbox *mbox = mbox_create();
pthread_t receiver; pthread_t receiver;
pthread_create( &receiver, NULL, mbox_receive_runner, mbox ); pthread_create(&receiver, NULL, mbox_receive_runner, mbox);
void * deadbeef = (void *)0xDEADBEEF; void *deadbeef = (void *) 0xDEADBEEF;
void * retval =NULL; void *retval = NULL;
usleep(10000); usleep(10000);
fail_unless( EBUSY == pthread_tryjoin_np( receiver, &retval ), fail_unless(EBUSY == pthread_tryjoin_np(receiver, &retval),
"Receiver thread wasn't blocked"); "Receiver thread wasn't blocked");
mbox_post( mbox, deadbeef ); mbox_post(mbox, deadbeef);
fail_unless( 0 == pthread_join( receiver, &retval ), fail_unless(0 == pthread_join(receiver, &retval),
"Failed to join the receiver thread" ); "Failed to join the receiver thread");
fail_unless( retval == deadbeef, fail_unless(retval == deadbeef, "Return value was wrong");
"Return value was wrong" );
} }
END_TEST
END_TEST Suite * mbox_suite(void)
Suite* mbox_suite(void)
{ {
Suite *s = suite_create("mbox"); Suite *s = suite_create("mbox");
TCase *tc_create = tcase_create("create"); TCase *tc_create = tcase_create("create");
TCase *tc_post = tcase_create("post"); 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_post_stores_value);
tcase_add_test( tc_post, test_receive_blocks_until_post); tcase_add_test(tc_post, test_receive_blocks_until_post);
suite_add_tcase(s, tc_create); suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_post); suite_add_tcase(s, tc_post);
return s; return s;
} }
@@ -88,17 +81,16 @@ Suite* mbox_suite(void)
int main(void) int main(void)
{ {
#ifdef DEBUG #ifdef DEBUG
log_level = 0; log_level = 0;
#else #else
log_level = 2; log_level = 2;
#endif #endif
int number_failed; int number_failed;
Suite *s = mbox_suite(); Suite *s = mbox_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
log_level = 0; log_level = 0;
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,257 +4,246 @@
START_TEST(test_init_passwd) START_TEST(test_init_passwd)
{ {
struct nbd_init_raw init_raw; struct nbd_init_raw init_raw;
struct nbd_init init; struct nbd_init init;
memcpy( init_raw.passwd, INIT_PASSWD, 8 ); memcpy(init_raw.passwd, INIT_PASSWD, 8);
nbd_r2h_init( &init_raw, &init ); nbd_r2h_init(&init_raw, &init);
memset( init_raw.passwd, 0, 8 ); memset(init_raw.passwd, 0, 8);
nbd_h2r_init( &init, &init_raw ); nbd_h2r_init(&init, &init_raw);
fail_unless( memcmp( init.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied." ); fail_unless(memcmp(init.passwd, INIT_PASSWD, 8) == 0,
fail_unless( memcmp( init_raw.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied back." ); "The password was not copied.");
fail_unless(memcmp(init_raw.passwd, INIT_PASSWD, 8) == 0,
"The password was not copied back.");
} }
END_TEST
END_TEST START_TEST(test_init_magic)
START_TEST(test_init_magic)
{ {
struct nbd_init_raw init_raw; struct nbd_init_raw init_raw;
struct nbd_init init; struct nbd_init init;
init_raw.magic = 12345; init_raw.magic = 12345;
nbd_r2h_init( &init_raw, &init ); nbd_r2h_init(&init_raw, &init);
fail_unless( be64toh( 12345 ) == init.magic, "Magic was not converted." ); fail_unless(be64toh(12345) == init.magic, "Magic was not converted.");
init.magic = 67890; init.magic = 67890;
nbd_h2r_init( &init, &init_raw ); nbd_h2r_init(&init, &init_raw);
fail_unless( htobe64( 67890 ) == init_raw.magic, "Magic was not converted back." ); fail_unless(htobe64(67890) == init_raw.magic,
"Magic was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_init_size)
START_TEST(test_init_size)
{ {
struct nbd_init_raw init_raw; struct nbd_init_raw init_raw;
struct nbd_init init; struct nbd_init init;
init_raw.size = 12345; init_raw.size = 12345;
nbd_r2h_init( &init_raw, &init ); nbd_r2h_init(&init_raw, &init);
fail_unless( be64toh( 12345 ) == init.size, "Size was not converted." ); fail_unless(be64toh(12345) == init.size, "Size was not converted.");
init.size = 67890; init.size = 67890;
nbd_h2r_init( &init, &init_raw ); nbd_h2r_init(&init, &init_raw);
fail_unless( htobe64( 67890 ) == init_raw.size, "Size was not converted back." ); fail_unless(htobe64(67890) == init_raw.size,
"Size was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_request_magic)
START_TEST(test_request_magic )
{ {
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
request_raw.magic = 12345; request_raw.magic = 12345;
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( be32toh( 12345 ) == request.magic, "Magic was not converted." ); fail_unless(be32toh(12345) == request.magic,
"Magic was not converted.");
request.magic = 67890; request.magic = 67890;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( htobe32( 67890 ) == request_raw.magic, "Magic was not converted back." ); 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_raw request_raw;
struct nbd_request request; struct nbd_request request;
request_raw.type = 123; request_raw.type = 123;
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( be16toh( 123 ) == request.type, "Type was not converted." ); fail_unless(be16toh(123) == request.type, "Type was not converted.");
request.type = 234; request.type = 234;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( htobe16( 234 ) == request_raw.type, "Type was not converted back." ); fail_unless(htobe16(234) == request_raw.type,
"Type was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_request_flags)
START_TEST(test_request_flags)
{ {
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
request_raw.flags = 123; request_raw.flags = 123;
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( be16toh( 123 ) == request.flags, "Flags were not converted." ); fail_unless(be16toh(123) == request.flags,
"Flags were not converted.");
request.flags = 234; request.flags = 234;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( htobe16( 234 ) == request_raw.flags, "Flags were not converted back." ); fail_unless(htobe16(234) == request_raw.flags,
"Flags were not converted back.");
} }
END_TEST
END_TEST START_TEST(test_request_handle)
START_TEST(test_request_handle)
{ {
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
memcpy( request_raw.handle.b, "MYHANDLE", 8 ); memcpy(request_raw.handle.b, "MYHANDLE", 8);
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
request_raw.handle.w = 0; request_raw.handle.w = 0;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( memcmp( request.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." ); fail_unless(memcmp(request.handle.b, "MYHANDLE", 8) == 0,
fail_unless( memcmp( request_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." ); "The handle was not copied.");
fail_unless(memcmp(request_raw.handle.b, "MYHANDLE", 8) == 0,
"The handle was not copied back.");
} }
END_TEST
END_TEST START_TEST(test_request_from)
START_TEST(test_request_from )
{ {
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
request_raw.from = 12345; request_raw.from = 12345;
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( be64toh( 12345 ) == request.from, "From was not converted." ); fail_unless(be64toh(12345) == request.from, "From was not converted.");
request.from = 67890; request.from = 67890;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( htobe64( 67890 ) == request_raw.from, "From was not converted back." ); fail_unless(htobe64(67890) == request_raw.from,
"From was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_request_len)
START_TEST(test_request_len )
{ {
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
request_raw.len = 12345; request_raw.len = 12345;
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( be32toh( 12345 ) == request.len, "Type was not converted." ); fail_unless(be32toh(12345) == request.len, "Type was not converted.");
request.len = 67890; request.len = 67890;
nbd_h2r_request( &request, &request_raw ); nbd_h2r_request(&request, &request_raw);
fail_unless( htobe32( 67890 ) == request_raw.len, "Type was not converted back." ); fail_unless(htobe32(67890) == request_raw.len,
"Type was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_reply_magic)
START_TEST(test_reply_magic )
{ {
struct nbd_reply_raw reply_raw; struct nbd_reply_raw reply_raw;
struct nbd_reply reply; struct nbd_reply reply;
reply_raw.magic = 12345; reply_raw.magic = 12345;
nbd_r2h_reply( &reply_raw, &reply ); nbd_r2h_reply(&reply_raw, &reply);
fail_unless( be32toh( 12345 ) == reply.magic, "Magic was not converted." ); fail_unless(be32toh(12345) == reply.magic, "Magic was not converted.");
reply.magic = 67890; reply.magic = 67890;
nbd_h2r_reply( &reply, &reply_raw ); nbd_h2r_reply(&reply, &reply_raw);
fail_unless( htobe32( 67890 ) == reply_raw.magic, "Magic was not converted back." ); fail_unless(htobe32(67890) == reply_raw.magic,
"Magic was not converted back.");
} }
END_TEST
END_TEST START_TEST(test_reply_error)
START_TEST(test_reply_error )
{ {
struct nbd_reply_raw reply_raw; struct nbd_reply_raw reply_raw;
struct nbd_reply reply; struct nbd_reply reply;
reply_raw.error = 12345; reply_raw.error = 12345;
nbd_r2h_reply( &reply_raw, &reply ); nbd_r2h_reply(&reply_raw, &reply);
fail_unless( be32toh( 12345 ) == reply.error, "Error was not converted." ); fail_unless(be32toh(12345) == reply.error, "Error was not converted.");
reply.error = 67890; reply.error = 67890;
nbd_h2r_reply( &reply, &reply_raw ); nbd_h2r_reply(&reply, &reply_raw);
fail_unless( htobe32( 67890 ) == reply_raw.error, "Error was not converted back." ); 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_raw reply_raw;
struct nbd_reply reply; struct nbd_reply reply;
memcpy( reply_raw.handle.b, "MYHANDLE", 8 ); memcpy(reply_raw.handle.b, "MYHANDLE", 8);
nbd_r2h_reply( &reply_raw, &reply ); nbd_r2h_reply(&reply_raw, &reply);
reply_raw.handle.w = 0; reply_raw.handle.w = 0;
nbd_h2r_reply( &reply, &reply_raw ); nbd_h2r_reply(&reply, &reply_raw);
fail_unless( memcmp( reply.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." ); fail_unless(memcmp(reply.handle.b, "MYHANDLE", 8) == 0,
fail_unless( memcmp( reply_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." ); "The handle was not copied.");
fail_unless(memcmp(reply_raw.handle.b, "MYHANDLE", 8) == 0,
"The handle was not copied back.");
} }
END_TEST
END_TEST START_TEST(test_convert_from)
START_TEST( test_convert_from )
{ {
/* Check that we can correctly pull numbers out of an /* Check that we can correctly pull numbers out of an
* nbd_request_raw */ * nbd_request_raw */
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
struct nbd_request request; struct nbd_request request;
uint64_t target = 0x8000000000000000; uint64_t target = 0x8000000000000000;
/* this is stored big-endian */ /* this is stored big-endian */
request_raw.from = htobe64(target); request_raw.from = htobe64(target);
/* We expect this to convert big-endian to the host format */ /* We expect this to convert big-endian to the host format */
nbd_r2h_request( &request_raw, &request ); nbd_r2h_request(&request_raw, &request);
fail_unless( target == request.from, "from was wrong" ); fail_unless(target == request.from, "from was wrong");
} }
END_TEST
Suite *nbdtypes_suite(void) END_TEST Suite * nbdtypes_suite(void)
{ {
Suite *s = suite_create( "nbdtypes" ); Suite *s = suite_create("nbdtypes");
TCase *tc_init = tcase_create( "nbd_init" ); TCase *tc_init = tcase_create("nbd_init");
TCase *tc_request = tcase_create( "nbd_request" ); TCase *tc_request = tcase_create("nbd_request");
TCase *tc_reply = tcase_create( "nbd_reply" ); TCase *tc_reply = tcase_create("nbd_reply");
tcase_add_test( tc_init, test_init_passwd ); tcase_add_test(tc_init, test_init_passwd);
tcase_add_test( tc_init, test_init_magic ); tcase_add_test(tc_init, test_init_magic);
tcase_add_test( tc_init, test_init_size ); tcase_add_test(tc_init, test_init_size);
tcase_add_test( tc_request, test_request_magic ); tcase_add_test(tc_request, test_request_magic);
tcase_add_test( tc_request, test_request_type ); tcase_add_test(tc_request, test_request_type);
tcase_add_test( tc_request, test_request_handle ); tcase_add_test(tc_request, test_request_handle);
tcase_add_test( tc_request, test_request_from ); tcase_add_test(tc_request, test_request_from);
tcase_add_test( tc_request, test_request_len ); tcase_add_test(tc_request, test_request_len);
tcase_add_test( tc_request, test_convert_from ); tcase_add_test(tc_request, test_convert_from);
tcase_add_test( tc_reply, test_reply_magic ); tcase_add_test(tc_reply, test_reply_magic);
tcase_add_test( tc_reply, test_reply_error ); tcase_add_test(tc_reply, test_reply_error);
tcase_add_test( tc_reply, test_reply_handle ); tcase_add_test(tc_reply, test_reply_handle);
suite_add_tcase( s, tc_init ); suite_add_tcase(s, tc_init);
suite_add_tcase( s, tc_request ); suite_add_tcase(s, tc_request);
suite_add_tcase( s, tc_reply ); suite_add_tcase(s, tc_reply);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = nbdtypes_suite(); Suite *s = nbdtypes_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -3,45 +3,41 @@
#include <check.h> #include <check.h>
START_TEST( test_can_parse_ip_address_twice ) START_TEST(test_can_parse_ip_address_twice)
{ {
char ip_address[] = "127.0.0.1"; char ip_address[] = "127.0.0.1";
struct sockaddr saddr; 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
END_TEST Suite * parse_suite(void)
Suite* parse_suite(void)
{ {
Suite *s = suite_create("parse"); Suite *s = suite_create("parse");
TCase *tc_create = tcase_create("ip_to_sockaddr"); 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 #ifdef DEBUG
# define LOG_LEVEL 0 #define LOG_LEVEL 0
#else #else
# define LOG_LEVEL 2 #define LOG_LEVEL 2
#endif #endif
int main(void) int main(void)
{ {
log_level = LOG_LEVEL; log_level = LOG_LEVEL;
int number_failed; int number_failed;
Suite *s = parse_suite(); Suite *s = parse_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -21,173 +21,169 @@
int fd_read_request( int, struct nbd_request_raw *); int fd_read_request(int, struct nbd_request_raw *);
int fd_write_reply( int, uint64_t, int ); int fd_write_reply(int, uint64_t, int);
int marker; int marker;
void error_marker(void * unused __attribute__((unused)), void error_marker(void *unused __attribute__ ((unused)),
int fatal __attribute__((unused))) int fatal __attribute__ ((unused)))
{ {
marker = 1; marker = 1;
return; return;
} }
struct respond { struct respond {
int sock_fds[2]; // server end int sock_fds[2]; // server end
int do_fail; int do_fail;
pthread_t thread_id; pthread_t thread_id;
pthread_attr_t thread_attr; pthread_attr_t thread_attr;
struct nbd_request received; struct nbd_request received;
}; };
void * responder( void *respond_uncast ) void *responder(void *respond_uncast)
{ {
struct respond * resp = (struct respond *) respond_uncast; struct respond *resp = (struct respond *) respond_uncast;
int sock_fd = resp->sock_fds[1]; int sock_fd = resp->sock_fds[1];
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
uint64_t wrong_handle = 0x80; uint64_t wrong_handle = 0x80;
if( fd_read_request( sock_fd, &request_raw ) == -1){ if (fd_read_request(sock_fd, &request_raw) == -1) {
fprintf(stderr, "Problem with fd_read_request\n"); 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 { } else {
nbd_r2h_request( &request_raw, &resp->received); fd_write_reply(sock_fd, resp->received.handle.w, 0);
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 );
} }
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 ) ); struct respond *respond =
socketpair( PF_UNIX, SOCK_STREAM, 0, respond->sock_fds ); (struct respond *) calloc(1, sizeof(struct respond));
respond->do_fail = do_fail; socketpair(PF_UNIX, SOCK_STREAM, 0, respond->sock_fds);
respond->do_fail = do_fail;
pthread_attr_init( &respond->thread_attr ); pthread_attr_init(&respond->thread_attr);
pthread_create( &respond->thread_id, &respond->thread_attr, responder, respond ); pthread_create(&respond->thread_id, &respond->thread_attr, responder,
respond);
return respond; return respond;
} }
void respond_destroy( struct respond * 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)))
{ {
DECLARE_ERROR_CONTEXT( error_context ); NULLCHECK(respond);
error_set_handler( (cleanup_handler *)error_marker, error_context );
struct respond * respond = respond_create( 1 ); pthread_join(respond->thread_id, NULL);
int devnull = open("/dev/null", O_WRONLY); pthread_attr_destroy(&respond->thread_attr);
char outbuf[8] = {0};
socket_nbd_read( respond->sock_fds[0], 0, 8, devnull, outbuf, 1 ); close(respond->sock_fds[0]);
close(respond->sock_fds[1]);
return NULL; 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(); error_init();
pthread_t reader_thread; pthread_t reader_thread;
log_level=5; log_level = 5;
marker = 0; marker = 0;
pthread_create( &reader_thread, NULL, reader, NULL ); pthread_create(&reader_thread, NULL, reader, NULL);
FATAL_UNLESS( 0 == pthread_join( reader_thread, NULL ), FATAL_UNLESS(0 == pthread_join(reader_thread, NULL),
"pthread_join failed"); "pthread_join failed");
log_level=2; log_level = 2;
fail_unless( marker == 1, "Error handler wasn't called" ); fail_unless(marker == 1, "Error handler wasn't called");
} }
END_TEST
END_TEST START_TEST(test_accepts_matched_handle)
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); int devnull = open("/dev/null", O_WRONLY);
char outbuf[8] = {0}; 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
END_TEST START_TEST(test_disconnect_doesnt_read_reply)
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
END_TEST Suite * readwrite_suite(void)
Suite* readwrite_suite(void)
{ {
Suite *s = suite_create("readwrite"); Suite *s = suite_create("readwrite");
TCase *tc_transfer = tcase_create("entrust"); TCase *tc_transfer = tcase_create("entrust");
TCase *tc_disconnect = tcase_create("disconnect"); TCase *tc_disconnect = tcase_create("disconnect");
tcase_add_test(tc_transfer, test_rejects_mismatched_handle); tcase_add_test(tc_transfer, test_rejects_mismatched_handle);
tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0); tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0);
/* This test is a little funny. We respond with a dodgy handle /* This test is a little funny. We respond with a dodgy handle
* and check that this *doesn't* cause a message rejection, * and check that this *doesn't* cause a message rejection,
* because we want to know that the sender won't even try to * because we want to know that the sender won't even try to
* read the response. * read the response.
*/ */
tcase_add_exit_test( tc_disconnect, test_disconnect_doesnt_read_reply,0 ); tcase_add_exit_test(tc_disconnect, test_disconnect_doesnt_read_reply,
0);
suite_add_tcase(s, tc_transfer); suite_add_tcase(s, tc_transfer);
suite_add_tcase(s, tc_disconnect); suite_add_tcase(s, tc_disconnect);
return s; return s;
} }
#ifdef DEBUG #ifdef DEBUG
# define LOG_LEVEL 0 #define LOG_LEVEL 0
#else #else
# define LOG_LEVEL 2 #define LOG_LEVEL 2
#endif #endif
int main(void) int main(void)
{ {
log_level = LOG_LEVEL; log_level = LOG_LEVEL;
int number_failed; int number_failed;
Suite *s = readwrite_suite(); Suite *s = readwrite_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
log_level = 0; log_level = 0;
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,190 +9,180 @@
#include "self_pipe.h" #include "self_pipe.h"
START_TEST( test_opens_pipe ) START_TEST(test_opens_pipe)
{ {
struct self_pipe* sig; struct self_pipe *sig;
char buf[] = " "; char buf[] = " ";
sig = self_pipe_create(); sig = self_pipe_create();
write( sig->write_fd, "1", 1 ); write(sig->write_fd, "1", 1);
read( sig->read_fd, buf, 1 ); read(sig->read_fd, buf, 1);
fail_unless( buf[0] == '1', "Pipe does not seem to be open;" ); fail_unless(buf[0] == '1', "Pipe does not seem to be open;");
self_pipe_destroy( sig ); 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;
} }
pthread_t start_signal_thread( struct self_pipe *sig ) END_TEST void *signal_thread(void *thing)
{ {
pthread_attr_t attr; struct self_pipe *sig = (struct self_pipe *) thing;
pthread_t thread_id; usleep(100000);
self_pipe_signal(sig);
return NULL;
}
pthread_attr_init( &attr ); pthread_t start_signal_thread(struct self_pipe * sig)
pthread_create( &thread_id, &attr, signal_thread, sig ); {
pthread_attr_destroy( &attr ); 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; struct self_pipe *sig;
fd_set fds; fd_set fds;
pthread_t signal_thread_id; pthread_t signal_thread_id;
sig = self_pipe_create(); sig = self_pipe_create();
FD_ZERO( &fds ); FD_ZERO(&fds);
self_pipe_fd_set( sig, &fds ); self_pipe_fd_set(sig, &fds);
signal_thread_id = start_signal_thread( sig ); signal_thread_id = start_signal_thread(sig);
if ( select( FD_SETSIZE, &fds, NULL, NULL, NULL ) == -1 ) { if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) == -1) {
fail( strerror(errno) ); 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 ); break;
default:
fail_unless( self_pipe_fd_isset( sig, &fds ), "Signalled pipe was not FD_ISSET." ); fail("The read fd wasn't closed, and had data in it.");
pthread_join( signal_thread_id, NULL ); break;
}
self_pipe_destroy( sig );
} }
END_TEST
END_TEST START_TEST(test_destroy_closes_write_pipe)
START_TEST( test_clear_returns_immediately )
{ {
struct self_pipe *sig; struct self_pipe *sig;
sig = self_pipe_create(); ssize_t write_len;
fail_unless( 0 == self_pipe_signal_clear( sig ), "Wrong clear result." ); int orig_write_fd;
}
END_TEST
sig = self_pipe_create();
orig_write_fd = sig->write_fd;
self_pipe_destroy(sig);
START_TEST( test_destroy_closes_read_pipe ) while ((write_len = write(orig_write_fd, "", 0)) == -1
{ && errno == EINTR);
struct self_pipe* sig;
ssize_t read_len;
int orig_read_fd;
sig = self_pipe_create(); switch (write_len) {
orig_read_fd = sig->read_fd; case 0:
self_pipe_destroy( sig ); fail("The write fd wasn't closed.");
break;
while( (read_len = read( orig_read_fd, "", 0 )) == -1 && errno == EINTR ); case -1:
switch (errno) {
switch( read_len ) { case EPIPE:
case 0: case EBADF:
fail("The read fd wasn't closed." ); /* This is what we want */
break; break;
case -1: case EAGAIN:
switch(errno) { fail("The write fd wasn't closed.");
case EBADF: break;
/* This is what we want */ default:
break; fail(strerror(errno));
case EAGAIN: break;
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;
} }
} break;
END_TEST default:
/* To get here, the write(_,_,0) would have to
* write some bytes.
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.
*/ */
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 main(void)
{ {
int number_failed; int number_failed;
Suite *s = self_pipe_suite(); Suite *s = self_pipe_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -15,9 +15,9 @@
#include <fcntl.h> #include <fcntl.h>
#ifdef DEBUG #ifdef DEBUG
# define LOG_LEVEL 0 #define LOG_LEVEL 0
#else #else
# define LOG_LEVEL 2 #define LOG_LEVEL 2
#endif #endif
@@ -28,237 +28,245 @@
#define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0) #define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0)
#define myfail_unless( tst, msg ) myfail_if( !(tst), msg ) #define myfail_unless( tst, msg ) myfail_if( !(tst), msg )
char * dummy_file; char *dummy_file;
char *make_tmpfile(void) char *make_tmpfile(void)
{ {
FILE *fp; FILE *fp;
char *fn_buf; char *fn_buf;
char leader[] = "/tmp/check_serve"; char leader[] = "/tmp/check_serve";
fn_buf = (char *)malloc( 1024 ); fn_buf = (char *) malloc(1024);
strncpy( fn_buf, leader, sizeof( leader ) - 1); strncpy(fn_buf, leader, sizeof(leader) - 1);
snprintf( &fn_buf[sizeof( leader ) - 1], 10, "%d", getpid() ); snprintf(&fn_buf[sizeof(leader) - 1], 10, "%d", getpid());
fp = fopen( fn_buf, "w" ); fp = fopen(fn_buf, "w");
fwrite( fn_buf, 1024, 1, fp ); fwrite(fn_buf, 1024, 1, fp);
fclose( 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 ); } if (dummy_file) {
free( dummy_file ); unlink(dummy_file);
dummy_file = NULL; }
free(dummy_file);
dummy_file = NULL;
} }
START_TEST( test_replaces_acl ) START_TEST(test_replaces_acl)
{ {
struct flexnbd flexnbd; struct flexnbd flexnbd;
flexnbd.signal_fd = -1; flexnbd.signal_fd = -1;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); struct server *s =
struct acl * new_acl = acl_create( 0, NULL, 0 ); 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." ); myfail_unless(s->acl == new_acl, "ACL wasn't replaced.");
server_destroy( s ); server_destroy(s);
} }
END_TEST
END_TEST START_TEST(test_signals_acl_updated)
START_TEST( test_signals_acl_updated )
{ {
struct flexnbd flexnbd; struct flexnbd flexnbd;
flexnbd.signal_fd = -1; flexnbd.signal_fd = -1;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 ); struct server *s =
struct acl * new_acl = acl_create( 0, NULL, 0 ); 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 ), myfail_unless(1 == self_pipe_signal_clear(s->acl_updated_signal),
"No signal sent." ); "No signal sent.");
server_destroy( s ); server_destroy(s);
} }
END_TEST
END_TEST int connect_client(char *addr, int actual_port, char *source_addr)
int connect_client( char *addr, int actual_port, char *source_addr )
{ {
int client_fd = -1; int client_fd = -1;
struct addrinfo hint; struct addrinfo hint;
struct addrinfo *ailist, *aip; struct addrinfo *ailist, *aip;
memset( &hint, '\0', sizeof( struct addrinfo ) ); memset(&hint, '\0', sizeof(struct addrinfo));
hint.ai_socktype = SOCK_STREAM; 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; int connected = 0;
for( aip = ailist; aip; aip = aip->ai_next ) { for (aip = ailist; aip; aip = aip->ai_next) {
((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port ); ((struct sockaddr_in *) aip->ai_addr)->sin_port =
client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol ); htons(actual_port);
client_fd =
socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
if (source_addr) { if (source_addr) {
struct sockaddr src; struct sockaddr src;
if( !parse_ip_to_sockaddr(&src, source_addr)) { if (!parse_ip_to_sockaddr(&src, source_addr)) {
close(client_fd); close(client_fd);
continue; continue;
} }
bind(client_fd, &src, sizeof(struct sockaddr_in6)); 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 );
} }
myfail_unless( connected, "Didn't connect." ); if (client_fd == -1) {
return client_fd; 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 /* These are "internal" functions we need for the following test. We
* shouldn't need them but there's no other way at the moment. */ * shouldn't need them but there's no other way at the moment. */
void serve_open_server_socket( struct server * ); void serve_open_server_socket(struct server *);
int server_port( struct server * ); int server_port(struct server *);
void server_accept( struct server * ); void server_accept(struct server *);
int fd_is_closed( int ); int fd_is_closed(int);
void server_close_clients( struct server * ); 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 /* This is the wrong way round. Rather than pulling the thread
* and socket out of the server structure, we should be testing * and socket out of the server structure, we should be testing
* a client socket. * a client socket.
*/ */
struct flexnbd flexnbd; struct flexnbd flexnbd;
flexnbd.signal_fd = -1; 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 =
struct acl * new_acl = acl_create( 0, NULL, 1 ); server_create(&flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL,
struct client * c; 1, 0, 1);
struct client_tbl_entry * entry; struct acl *new_acl = acl_create(0, NULL, 1);
struct client *c;
struct client_tbl_entry *entry;
int actual_port; int actual_port;
int client_fd; int client_fd;
int server_fd; int server_fd;
serve_open_server_socket( s ); serve_open_server_socket(s);
actual_port = server_port( s ); actual_port = server_port(s);
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" ); client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1");
server_accept( s ); server_accept(s);
entry = &s->nbd_client[0]; entry = &s->nbd_client[0];
c = entry->client; c = entry->client;
/* At this point there should be an entry in the nbd_clients /* At this point there should be an entry in the nbd_clients
* table and a background thread to run the client loop * table and a background thread to run the client loop
*/ */
myfail_if( entry->thread == 0, "No client thread was started." ); myfail_if(entry->thread == 0, "No client thread was started.");
server_fd = c->socket; server_fd = c->socket;
myfail_if( fd_is_closed(server_fd), myfail_if(fd_is_closed(server_fd),
"Sanity check failed - client socket wasn't open." ); "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 */ /* accept again, so that we can react to the acl replacement signal */
server_accept( s ); server_accept(s);
/* Fail if we time out here */ /* Fail if we time out here */
while( !fd_is_closed( server_fd ) ); while (!fd_is_closed(server_fd));
close( client_fd ); close(client_fd);
server_close_clients( s ); server_close_clients(s);
server_destroy( s ); server_destroy(s);
} }
END_TEST
END_TEST START_TEST(test_acl_update_leaves_good_client)
START_TEST( test_acl_update_leaves_good_client )
{ {
struct flexnbd flexnbd; struct flexnbd flexnbd;
flexnbd.signal_fd = -1; 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"}; char *lines[] = { "127.0.0.1" };
struct acl * new_acl = acl_create( 1, lines, 1 ); struct acl *new_acl = acl_create(1, lines, 1);
struct client * c; struct client *c;
struct client_tbl_entry * entry; struct client_tbl_entry *entry;
int actual_port; int actual_port;
int client_fd; int client_fd;
int server_fd; int server_fd;
serve_open_server_socket( s ); serve_open_server_socket(s);
actual_port = server_port( s ); actual_port = server_port(s);
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" ); client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1");
server_accept( s ); server_accept(s);
entry = &s->nbd_client[0]; entry = &s->nbd_client[0];
c = entry->client; c = entry->client;
/* At this point there should be an entry in the nbd_clients /* At this point there should be an entry in the nbd_clients
* table and a background thread to run the client loop * table and a background thread to run the client loop
*/ */
myfail_if( entry->thread == 0, "No client thread was started." ); myfail_if(entry->thread == 0, "No client thread was started.");
server_fd = c->socket; server_fd = c->socket;
myfail_if( fd_is_closed(server_fd), myfail_if(fd_is_closed(server_fd),
"Sanity check failed - client socket wasn't open." ); "Sanity check failed - client socket wasn't open.");
server_replace_acl( s, new_acl ); server_replace_acl(s, new_acl);
server_accept( s ); server_accept(s);
myfail_if( self_pipe_signal_clear( c->stop_signal ), myfail_if(self_pipe_signal_clear(c->stop_signal),
"Client was told to stop." ); "Client was told to stop.");
close( client_fd ); close(client_fd);
server_close_clients( s ); server_close_clients(s);
server_destroy( s ); server_destroy(s);
} }
END_TEST
END_TEST Suite * serve_suite(void)
Suite* serve_suite(void)
{ {
Suite *s = suite_create("serve"); Suite *s = suite_create("serve");
TCase *tc_acl_update = tcase_create("acl_update"); 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_replaces_acl);
tcase_add_test(tc_acl_update, test_signals_acl_updated); 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_closes_bad_client,
tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, 0); 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) int main(void)
{ {
log_level = LOG_LEVEL; log_level = LOG_LEVEL;
error_init(); error_init();
int number_failed; int number_failed;
Suite *s = serve_suite(); Suite *s = serve_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -6,110 +6,112 @@
#include <check.h> #include <check.h>
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 sa;
struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
char testbuf[128]; char testbuf[128];
const char* result; const char *result;
v4->sin_family = AF_INET; v4->sin_family = AF_INET;
v4->sin_port = htons( 4777 ); v4->sin_port = htons(4777);
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
result = sockaddr_address_string( &sa, &testbuf[0], 128 ); result = sockaddr_address_string(&sa, &testbuf[0], 128);
ck_assert( result != NULL ); 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 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_raw;
struct sockaddr_in6* v6 = &v6_raw; struct sockaddr_in6 *v6 = &v6_raw;
struct sockaddr* sa = (struct sockaddr*) &v6_raw; struct sockaddr *sa = (struct sockaddr *) &v6_raw;
char testbuf[128]; char testbuf[128];
const char* result; const char *result;
v6->sin6_family = AF_INET6; v6->sin6_family = AF_INET6;
v6->sin6_port = htons( 4777 ); v6->sin6_port = htons(4777);
ck_assert_int_eq( 1, inet_pton( AF_INET6, "fe80::1", &v6->sin6_addr )); ck_assert_int_eq(1, inet_pton(AF_INET6, "fe80::1", &v6->sin6_addr));
result = sockaddr_address_string( sa, &testbuf[0], 128 ); result = sockaddr_address_string(sa, &testbuf[0], 128);
ck_assert( result != NULL ); 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 */ /* 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 sa;
struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
char testbuf[128]; char testbuf[128];
const char* result; const char *result;
v4->sin_family = AF_UNSPEC; v4->sin_family = AF_UNSPEC;
v4->sin_port = htons( 4777 ); v4->sin_port = htons(4777);
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
result = sockaddr_address_string( &sa, &testbuf[0], 128 ); result = sockaddr_address_string(&sa, &testbuf[0], 128);
ck_assert( result == NULL ); 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 */ /* 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 sa;
struct sockaddr_in* v4 = (struct sockaddr_in*) &sa; struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
char testbuf[128]; char testbuf[128];
const char* result; const char *result;
memset( testbuf, 0, 128 ); memset(testbuf, 0, 128);
v4->sin_family = AF_INET; v4->sin_family = AF_INET;
v4->sin_port = htons( 4777 ); v4->sin_port = htons(4777);
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr )); ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
memset( &testbuf, 0, 128 ); memset(&testbuf, 0, 128);
result = sockaddr_address_string( &sa, &testbuf[0], 2 ); result = sockaddr_address_string(&sa, &testbuf[0], 2);
ck_assert( result == NULL ); 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,
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_inet6_converts_to_string); test_sockaddr_address_string_af_inet_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,
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_doesnt_overflow_short_buffer); test_sockaddr_address_string_af_inet6_converts_to_string);
suite_add_tcase(s, tc_sockaddr_address_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 main(void)
{ {
int number_failed; int number_failed;
Suite *s = sockutil_suite(); Suite *s = sockutil_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -6,366 +6,331 @@
#include <check.h> #include <check.h>
struct server* mock_server(void) struct server *mock_server(void)
{ {
struct server* out = xmalloc( sizeof( struct server ) ); struct server *out = xmalloc(sizeof(struct server));
out->l_start_mirror = flexthread_mutex_create(); out->l_start_mirror = flexthread_mutex_create();
out->nbd_client = xmalloc( sizeof( struct client_tbl_entry ) * 4 ); out->nbd_client = xmalloc(sizeof(struct client_tbl_entry) * 4);
out->max_nbd_clients = 4; out->max_nbd_clients = 4;
out->size = 65536; 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(); struct server *out = mock_server();
out->mirror = xmalloc( sizeof( struct mirror ) ); out->mirror = xmalloc(sizeof(struct mirror));
out->mirror_super = xmalloc( sizeof( struct mirror_super ) ); out->mirror_super = xmalloc(sizeof(struct mirror_super));
return out; return out;
} }
void destroy_mock_server( struct server* serve ) void destroy_mock_server(struct server *serve)
{ {
if ( NULL != serve->mirror ) { if (NULL != serve->mirror) {
free( serve->mirror ); free(serve->mirror);
} }
if ( NULL != serve->mirror_super ) { if (NULL != serve->mirror_super) {
free( 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 ); bitset_free(serve->allocation_map);
free( serve->nbd_client ); free(serve->nbd_client);
free( serve ); free(serve);
} }
START_TEST( test_status_create ) START_TEST(test_status_create)
{ {
struct server * server = mock_server(); struct server *server = mock_server();
struct status * status = status_create( server ); struct status *status = status_create(server);
fail_if( NULL == status, "Status wasn't allocated" ); fail_if(NULL == status, "Status wasn't allocated");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); 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(); struct server *server = mock_server();
server->success = 1; 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" ); fail_unless(status->has_control == 1, "has_control wasn't copied");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); destroy_mock_server(server);
} }
END_TEST
END_TEST START_TEST(test_gets_is_mirroring)
START_TEST( test_gets_is_mirroring )
{ {
struct server * server = mock_server(); struct server *server = mock_server();
struct status * status = status_create( server ); struct status *status = status_create(server);
fail_if( status->is_mirroring, "is_mirroring was set" ); fail_if(status->is_mirroring, "is_mirroring was set");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); destroy_mock_server(server);
server = mock_mirroring_server(); server = mock_mirroring_server();
status = status_create( server ); status = status_create(server);
fail_unless( status->is_mirroring, "is_mirroring wasn't set" ); fail_unless(status->is_mirroring, "is_mirroring wasn't set");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); 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 server *server = mock_server();
struct status * status = status_create( server ); struct status *status = status_create(server);
fail_if( status->clients_allowed, "clients_allowed was set" ); fail_if(status->clients_allowed, "clients_allowed was set");
status_destroy( status ); status_destroy(status);
server->allow_new_clients = 1; server->allow_new_clients = 1;
status = status_create( server ); status = status_create(server);
fail_unless( status->clients_allowed, "clients_allowed was not set" ); fail_unless(status->clients_allowed, "clients_allowed was not set");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); destroy_mock_server(server);
} }
END_TEST
START_TEST( test_gets_pid ) END_TEST START_TEST(test_gets_pid)
{ {
struct server * server = mock_server(); struct server *server = mock_server();
struct status * status = status_create( 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 ); status_destroy(status);
destroy_mock_server( server ); destroy_mock_server(server);
} }
END_TEST
START_TEST( test_gets_size ) END_TEST START_TEST(test_gets_size)
{ {
struct server * server = mock_server(); struct server *server = mock_server();
server->size = 1024; 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 ); status_destroy(status);
destroy_mock_server( server ); 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(); struct server *server = mock_mirroring_server();
server->mirror->all_dirty = 16384; server->mirror->all_dirty = 16384;
server->mirror->max_bytes_per_second = 32768; server->mirror->max_bytes_per_second = 32768;
server->mirror->offset = 0; server->mirror->offset = 0;
/* we have a bit of a time dependency here */ /* we have a bit of a time dependency here */
server->mirror->migration_started = monotonic_time_ms(); server->mirror->migration_started = monotonic_time_ms();
struct status * status = status_create( server ); struct status *status = status_create(server);
fail_unless ( fail_unless(0 == status->migration_duration ||
0 == status->migration_duration ||
1 == status->migration_duration || 1 == status->migration_duration ||
2 == status->migration_duration, 2 == status->migration_duration,
"migration_duration is unreasonable!" "migration_duration is unreasonable!");
);
fail_unless( fail_unless(16384 / (status->migration_duration + 1) ==
16384 / ( status->migration_duration + 1 ) == status->migration_speed, status->migration_speed,
"migration_speed not calculated correctly" "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 // ( size / current_bps ) + 1 happens to be 3 for this test
fail_unless( 3 == status->migration_seconds_left, "migration_seconds_left not gathered" ); fail_unless(3 == status->migration_seconds_left,
"migration_seconds_left not gathered");
status_destroy( status ); status_destroy(status);
destroy_mock_server( server ); destroy_mock_server(server);
} }
END_TEST END_TEST
#define RENDER_TEST_SETUP \ #define RENDER_TEST_SETUP \
struct status status; \ struct status status; \
int fds[2]; \ int fds[2]; \
pipe( fds ); pipe( fds );
void fail_unless_rendered(int fd, char *fragment)
void fail_unless_rendered( int fd, char *fragment )
{ {
char buf[1024] = {0}; char buf[1024] = { 0 };
char emsg[1024] = {0}; char emsg[1024] = { 0 };
char *found = NULL; 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" ); fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read");
found = strstr( buf, fragment ); found = strstr(buf, fragment);
fail_if( NULL == found, emsg ); 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 buf[1024] = { 0 };
char emsg[1024] = {0}; char emsg[1024] = { 0 };
char *found = NULL; 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" ); fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read");
found = strstr( buf, fragment ); found = strstr(buf, fragment);
fail_unless( NULL == found, emsg ); 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.has_control = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "has_control=true" ); 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
END_TEST START_TEST(test_renders_is_mirroring)
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.is_mirroring = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "is_mirroring=true" ); 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.clients_allowed = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "clients_allowed=true" ); 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.num_clients = 4000;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "num_clients=0" ); 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
END_TEST START_TEST(test_renders_pid)
START_TEST( test_renders_pid )
{ {
RENDER_TEST_SETUP RENDER_TEST_SETUP status.pid = 42;
status_write(&status, fds[1]);
status.pid = 42; fail_unless_rendered(fds[0], "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 RENDER_TEST_SETUP status.size = ((uint64_t) 1 << 33);
status_write(&status, fds[1]);
status.size = ( (uint64_t)1 << 33 ); fail_unless_rendered(fds[0], "size=8589934592");
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_write(&status, fds[1]);
status.migration_duration = 8; fail_if_rendered(fds[0], "migration_duration");
status.migration_speed = 40000000;
status.migration_speed_limit = 40000001;
status.migration_seconds_left = 1;
status.migration_bytes_left = 5000;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_duration" ); fail_if_rendered(fds[0], "migration_speed");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_speed" ); fail_if_rendered(fds[0], "migration_speed_limit");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_speed_limit" ); fail_if_rendered(fds[0], "migration_seconds_left");
status_write( &status, fds[1] ); status.is_mirroring = 1;
fail_if_rendered( fds[0], "migration_seconds_left" );
status.is_mirroring = 1; status_write(&status, fds[1]);
fail_unless_rendered(fds[0], "migration_duration=8");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_duration=8" ); fail_unless_rendered(fds[0], "migration_speed=40000000");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_speed=40000000" ); fail_unless_rendered(fds[0], "migration_speed_limit=40000001");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_speed_limit=40000001" ); fail_unless_rendered(fds[0], "migration_seconds_left=1");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_seconds_left=1" ); fail_unless_rendered(fds[0], "migration_bytes_left=5000");
status_write( &status, fds[1] ); status.migration_speed_limit = UINT64_MAX;
fail_unless_rendered( fds[0], "migration_bytes_left=5000" );
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
END_TEST Suite * status_suite(void)
Suite *status_suite(void)
{ {
Suite *s = suite_create("status"); Suite *s = suite_create("status");
TCase *tc_create = tcase_create("create"); TCase *tc_create = tcase_create("create");
TCase *tc_render = tcase_create("render"); TCase *tc_render = tcase_create("render");
tcase_add_test(tc_create, test_status_create); tcase_add_test(tc_create, test_status_create);
tcase_add_test(tc_create, test_gets_has_control); 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_is_mirroring);
tcase_add_test(tc_create, test_gets_clients_allowed); tcase_add_test(tc_create, test_gets_clients_allowed);
tcase_add_test(tc_create, test_gets_pid); tcase_add_test(tc_create, test_gets_pid);
tcase_add_test(tc_create, test_gets_size); tcase_add_test(tc_create, test_gets_size);
tcase_add_test(tc_create, test_gets_migration_statistics); 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_has_control);
tcase_add_test(tc_render, test_renders_is_mirroring); 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_clients_allowed);
tcase_add_test(tc_render, test_renders_num_clients); tcase_add_test(tc_render, test_renders_num_clients);
tcase_add_test(tc_render, test_renders_pid); tcase_add_test(tc_render, test_renders_pid);
tcase_add_test(tc_render, test_renders_size); tcase_add_test(tc_render, test_renders_size);
tcase_add_test(tc_render, test_renders_migration_statistics); tcase_add_test(tc_render, test_renders_migration_statistics);
suite_add_tcase(s, tc_create); suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_render); suite_add_tcase(s, tc_render);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = status_suite(); Suite *s = status_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,165 +9,156 @@
struct cleanup_bucket { struct cleanup_bucket {
struct self_pipe *called_signal; struct self_pipe *called_signal;
}; };
struct cleanup_bucket bkt; struct cleanup_bucket bkt;
void bucket_init(void){ void bucket_init(void)
if ( bkt.called_signal ) { {
self_pipe_destroy( bkt.called_signal ); if (bkt.called_signal) {
} self_pipe_destroy(bkt.called_signal);
bkt.called_signal = self_pipe_create(); }
bkt.called_signal = self_pipe_create();
} }
void setup(void) void setup(void)
{ {
bkt.called_signal = NULL; bkt.called_signal = NULL;
} }
int handler_called(void) 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){ if (NULL != foo) {
self_pipe_signal( foo->called_signal ); self_pipe_signal(foo->called_signal);
} }
} }
void trigger_fatal(void) void trigger_fatal(void)
{ {
error_init(); error_init();
error_set_handler( (cleanup_handler*) dummy_cleanup, &bkt ); 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_init();
error_set_handler( (cleanup_handler *) dummy_cleanup, &bkt); error_set_handler((cleanup_handler *) dummy_cleanup, &bkt);
log_level = 4; log_level = 4;
error("Expected error"); 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 ) { if (pid == 0) {
trigger_fatal(); trigger_fatal();
/* If we get here, just block so the test timeout fails /* If we get here, just block so the test timeout fails
* us */ * us */
sleep(10); sleep(10);
} } else {
else { int kidret, kidstatus, result;
int kidret, kidstatus, result; result = waitpid(pid, &kidret, 0);
result = waitpid( pid, &kidret, 0 ); fail_if(result < 0, "Wait failed.");
fail_if( result < 0, "Wait failed." ); fail_unless(WIFSIGNALED(kidret), "Process didn't exit via signal");
fail_unless( WIFSIGNALED( kidret ), "Process didn't exit via signal" ); kidstatus = WTERMSIG(kidret);
kidstatus = WTERMSIG( kidret ); ck_assert_int_eq(kidstatus, SIGABRT);
ck_assert_int_eq( kidstatus, SIGABRT ); }
}
} }
END_TEST
END_TEST void *error_thread(void *nothing __attribute__ ((unused)))
void * error_thread( void *nothing __attribute__((unused)) )
{ {
trigger_error(); trigger_error();
return NULL; return NULL;
} }
START_TEST( test_error_doesnt_kill_process ) START_TEST(test_error_doesnt_kill_process)
{ {
bucket_init(); bucket_init();
pthread_attr_t attr; pthread_attr_t attr;
pthread_t tid; pthread_t tid;
pthread_attr_init( &attr ); pthread_attr_init(&attr);
pthread_create( &tid, &attr, error_thread, NULL ); pthread_create(&tid, &attr, error_thread, NULL);
pthread_join( tid, NULL ); pthread_join(tid, NULL);
} }
END_TEST
END_TEST START_TEST(test_error_calls_handler)
START_TEST( test_error_calls_handler )
{ {
bucket_init(); bucket_init();
pthread_attr_t attr; pthread_attr_t attr;
pthread_t tid; pthread_t tid;
pthread_attr_init( &attr ); pthread_attr_init(&attr);
pthread_create( &tid, &attr, error_thread, NULL ); pthread_create(&tid, &attr, error_thread, NULL);
pthread_join( tid, NULL ); pthread_join(tid, NULL);
fail_unless( handler_called(), "Handler wasn't called." ); fail_unless(handler_called(), "Handler wasn't called.");
} }
END_TEST
END_TEST START_TEST(test_fatal_doesnt_call_handler)
START_TEST( test_fatal_doesnt_call_handler )
{ {
bucket_init(); bucket_init();
pid_t kidpid; pid_t kidpid;
kidpid = fork(); kidpid = fork();
if ( kidpid == 0 ) { if (kidpid == 0) {
trigger_fatal(); trigger_fatal();
} } else {
else { int kidstatus;
int kidstatus; int result = waitpid(kidpid, &kidstatus, 0);
int result = waitpid( kidpid, &kidstatus, 0 ); fail_if(result < 0, "Wait failed");
fail_if( result < 0, "Wait failed" ); fail_if(handler_called(), "Handler was called.");
fail_if( handler_called(), "Handler was called."); }
}
} }
END_TEST
END_TEST Suite * util_suite(void)
Suite* util_suite(void)
{ {
Suite *s = suite_create("util"); Suite *s = suite_create("util");
TCase *tc_process = tcase_create("process"); TCase *tc_process = tcase_create("process");
TCase *tc_handler = tcase_create("handler"); 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_fatal_kills_process);
tcase_add_test(tc_process, test_error_doesnt_kill_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_error_calls_handler);
tcase_add_test(tc_handler, test_fatal_doesnt_call_handler); tcase_add_test(tc_handler, test_fatal_doesnt_call_handler);
suite_add_tcase(s, tc_process); suite_add_tcase(s, tc_process);
suite_add_tcase(s, tc_handler); suite_add_tcase(s, tc_handler);
return s; return s;
} }
int main(void) int main(void)
{ {
int number_failed; int number_failed;
Suite *s = util_suite(); Suite *s = util_suite();
SRunner *sr = srunner_create(s); SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL); srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr); number_failed = srunner_ntests_failed(sr);
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }