Merge branch 'fix-formatting' into 'develop'

Formatted all code using `indent`

See merge request open-source/flexnbd-c!47
This commit is contained in:
James Carter
2018-02-20 11:42:25 +00:00
59 changed files with 7627 additions and 7648 deletions

24
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,24 @@
# Contribution guide
The code is formatted using the K&R style of "indent".
```
indent -kr <files go here>
```
The C unit tests have also been indented in the same way, but manually adjsted
such that the functions follow the normal libcheck layout.
```c
START_TEST( ... ) {
}
END TEST
```
Indent tends to mangle the `END_TEST` macro, so that will need adjusting if
`indent` is run over the test files again.

View File

@@ -13,10 +13,10 @@
#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;
@@ -25,32 +25,31 @@ int build_allocation_map(struct bitset * allocation_map, int fd)
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_flags = FIEMAP_FLAG_SYNC;
fiemap->fm_extent_count = max_extents; fiemap->fm_extent_count = max_extents;
fiemap->fm_mapped_extents = 0; fiemap->fm_mapped_extents = 0;
if ( ioctl( fd, FS_IOC_FIEMAP, fiemap ) < 0 ) { if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
debug( "Couldn't get fiemap, returning no allocation_map" ); debug("Couldn't get fiemap, returning no allocation_map");
return 0; /* it's up to the caller to free the map */ return 0; /* it's up to the caller to free the map */
} } else {
else { for (unsigned int i = 0; i < fiemap->fm_mapped_extents; i++) {
for ( unsigned int i = 0; i < fiemap->fm_mapped_extents; i++ ) { bitset_set_range(allocation_map,
bitset_set_range( allocation_map,
fiemap->fm_extents[i].fe_logical, fiemap->fm_extents[i].fe_logical,
fiemap->fm_extents[i].fe_length ); fiemap->fm_extents[i].fe_length);
} }
@@ -58,12 +57,10 @@ int build_allocation_map(struct bitset * allocation_map, int fd)
* if we've actually hit max_offsets. * if we've actually hit max_offsets.
*/ */
if (fiemap->fm_mapped_extents > 0) { if (fiemap->fm_mapped_extents > 0) {
struct fiemap_extent *last = &fiemap->fm_extents[ struct fiemap_extent *last =
fiemap->fm_mapped_extents-1 &fiemap->fm_extents[fiemap->fm_mapped_extents - 1];
];
offset = last->fe_logical + last->fe_length; offset = last->fe_logical + last->fe_length;
} } else {
else {
offset += fiemap->fm_length; offset += fiemap->fm_length;
} }
} }
@@ -74,7 +71,8 @@ int build_allocation_map(struct bitset * allocation_map, int fd)
} }
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.
@@ -85,7 +83,7 @@ int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **
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);
@@ -101,7 +99,7 @@ int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **
/* If discs are not in multiples of 512, then odd things happen, /* If discs are not in multiples of 512, then odd things happen,
* resulting in reads/writes past the ends of files. * resulting in reads/writes past the ends of files.
*/ */
if ( size != (size & (~0x1ff))) { if (size != (size & (~0x1ff))) {
warn("file does not fit into 512-byte sectors; the end of the file will be ignored."); warn("file does not fit into 512-byte sectors; the end of the file will be ignored.");
size &= ~0x1ff; size &= ~0x1ff;
} }
@@ -111,15 +109,15 @@ int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **
} }
if (out_map) { if (out_map) {
*out_map = mmap64(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, *out_map = mmap64(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
*out_fd, 0); *out_fd, 0);
if (((long) *out_map) == -1) { if (((long) *out_map) == -1) {
warn("mmap64() failed"); warn("mmap64() failed");
return -1; return -1;
} }
debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd, *out_map); debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd,
} *out_map);
else { } else {
debug("opened %s size %ld on fd %d", filename, size, *out_fd); debug("opened %s size %ld on fd %d", filename, size, *out_fd);
} }
@@ -129,11 +127,11 @@ int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **
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
@@ -145,17 +143,18 @@ int writeloop(int filedes, const void *buffer, size_t size)
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",
readden);
return -1; return -1;
} }
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
@@ -165,15 +164,17 @@ int readloop(int filedes, void *buffer, size_t size)
return 0; 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; sent += result;
@@ -184,21 +185,22 @@ int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count)
} }
#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 =
splice(fd_in, off_in, fd_out, off_out, len, flags);
if (result < 0) { if (result < 0) {
//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);
if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK) ) { if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK)) {
return spliced; return spliced;
} } else {
else {
return -1; return -1;
} }
} else { } else {
@@ -214,21 +216,27 @@ 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) { while (spliced < len) {
ssize_t run = len-spliced; ssize_t run = len - spliced;
ssize_t s2, s1 = spliceloop(fd_in, NULL, pipefd[1], NULL, run, SPLICE_F_NONBLOCK); ssize_t s2, s1 =
spliceloop(fd_in, NULL, pipefd[1], NULL, run,
SPLICE_F_NONBLOCK);
/*if (run > 65535) /*if (run > 65535)
run = 65535;*/ run = 65535; */
if (s1 < 0) { break; } if (s1 < 0) {
break;
}
s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0); s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0);
if (s2 < 0) { break; } if (s2 < 0) {
break;
}
spliced += s2; spliced += s2;
} }
close(pipefd[0]); close(pipefd[0]);
@@ -244,29 +252,31 @@ 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) {
return -1;
}
if (buf[cur] == 10) { if (buf[cur] == 10) {
buf[cur] = '\0'; buf[cur] = '\0';
break; 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);
@@ -275,8 +285,10 @@ int read_lines_until_blankline(int fd, int max_line_length, char ***lines)
* -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 = xrealloc(*lines, (lines_count + 1) * sizeof(char *));
(*lines)[lines_count] = strdup(line); (*lines)[lines_count] = strdup(line);
if ((*lines)[lines_count][0] == 0) { if ((*lines)[lines_count][0] == 0) {
return lines_count; return lines_count;
@@ -286,10 +298,10 @@ int read_lines_until_blankline(int fd, int max_line_length, char ***lines)
} }
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;
} }
@@ -297,38 +309,39 @@ int fd_is_closed( int fd_in )
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 { } else {
debug( SHOW_ERRNO( "read() returned 0 bytes" ) ); debug(SHOW_ERRNO("read() returned 0 bytes"));
count = 0; count = 0;
} }
} }
@@ -336,22 +349,23 @@ ssize_t iobuf_read(int fd, struct iobuf *iobuf, size_t default_size )
return count; return count;
} }
ssize_t iobuf_write( int fd, struct iobuf *iobuf ) ssize_t iobuf_write(int fd, struct iobuf * iobuf)
{ {
size_t left = iobuf->size - iobuf->needle; size_t left = iobuf->size - iobuf->needle;
ssize_t count; ssize_t count;
debug( "Writing %"PRIu32" of %"PRIu32" bytes to fd %i", left, iobuf->size, fd ); debug("Writing %" PRIu32 " of %" PRIu32 " bytes to fd %i", left,
count = write( fd, iobuf->buf + iobuf->needle, left ); iobuf->size, fd);
count = write(fd, iobuf->buf + iobuf->needle, left);
if ( count >= 0 ) { if (count >= 0) {
iobuf->needle += count; iobuf->needle += count;
debug( "write() returned %"PRIu32" bytes", count ); debug("write() returned %" PRIu32 " bytes", count);
} else { } else {
if ( io_errno_permanent() ) { if (io_errno_permanent()) {
warn( SHOW_ERRNO( "write() failed on fd %i", fd ) ); warn(SHOW_ERRNO("write() failed on fd %i", fd));
} else { } else {
debug( SHOW_ERRNO( "write() returned 0 bytes" ) ); debug(SHOW_ERRNO("write() returned 0 bytes"));
count = 0; count = 0;
} }
} }

View File

@@ -8,8 +8,8 @@ struct iobuf {
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 */
@@ -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

@@ -72,7 +72,7 @@ struct nbd_request_raw {
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;
@@ -95,7 +95,7 @@ struct nbd_request {
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;
@@ -103,13 +103,12 @@ struct nbd_reply {
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,10 +10,10 @@ 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;
@@ -21,9 +21,11 @@ int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
/* 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++;
}
for (; i < 64 && IS_IP_VALID_CHAR(src[i]); i++) {
temp[j++] = src[i]; temp[j++] = src[i];
} }
temp[j] = 0; temp[j] = 0;
@@ -49,62 +51,59 @@ int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
} }
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);
} }
@@ -112,16 +111,15 @@ 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)
{ {
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

@@ -20,10 +20,9 @@ struct ip_and_mask {
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,122 +8,131 @@
#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);
if (fd < 0) {
warn("Couldn't create client socket");
return -1; 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; return 0;
} }
int socket_nbd_read_hello( int fd, uint64_t* out_size, uint32_t* out_flags ) int socket_nbd_read_hello(int fd, uint64_t * out_size,
uint32_t * out_flags)
{ {
struct nbd_init_raw init_raw; struct nbd_init_raw init_raw;
if ( 0 > readloop( fd, &init_raw, sizeof(init_raw) ) ) { if (0 > readloop(fd, &init_raw, sizeof(init_raw))) {
warn( "Couldn't read init" ); warn("Couldn't read init");
return 0; return 0;
} }
return nbd_check_hello( &init_raw, out_size, out_flags ); return nbd_check_hello(&init_raw, out_size, out_flags);
} }
void nbd_hello_to_buf( struct nbd_init_raw *buf, off64_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 init; struct nbd_init init;
memcpy( &init.passwd, INIT_PASSWD, 8 ); memcpy(&init.passwd, INIT_PASSWD, 8);
init.magic = INIT_MAGIC; init.magic = INIT_MAGIC;
init.size = out_size; init.size = out_size;
init.flags = out_flags; init.flags = out_flags;
memset( buf, 0, sizeof( struct nbd_init_raw ) ); // ensure reserved is 0s memset(buf, 0, sizeof(struct nbd_init_raw)); // ensure reserved is 0s
nbd_h2r_init( &init, buf ); nbd_h2r_init(&init, buf);
return; return;
} }
int socket_nbd_write_hello( int fd, 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_raw init_raw; struct nbd_init_raw init_raw;
nbd_hello_to_buf( &init_raw, out_size, out_flags ); nbd_hello_to_buf(&init_raw, out_size, out_flags);
if ( 0 > writeloop( fd, &init_raw, sizeof( init_raw ) ) ) { if (0 > writeloop(fd, &init_raw, sizeof(init_raw))) {
warn( SHOW_ERRNO( "failed to write hello to socket" ) ); warn(SHOW_ERRNO("failed to write hello to socket"));
return 0; return 0;
} }
return 1; return 1;
} }
void fill_request(struct nbd_request_raw *request_raw, uint16_t type, uint16_t flags, uint64_t from, uint32_t len) void fill_request(struct nbd_request_raw *request_raw, uint16_t type,
uint16_t flags, uint64_t from, uint32_t len)
{ {
request_raw->magic = htobe32(REQUEST_MAGIC); request_raw->magic = htobe32(REQUEST_MAGIC);
request_raw->type = htobe16(type); request_raw->type = htobe16(type);
request_raw->flags = htobe16(flags); request_raw->flags = htobe16(flags);
request_raw->handle.w = (((uint64_t)rand()) << 32) | ((uint64_t)rand()); request_raw->handle.w =
(((uint64_t) rand()) << 32) | ((uint64_t) rand());
request_raw->from = htobe64(from); request_raw->from = htobe64(from);
request_raw->len = htobe32(len); request_raw->len = htobe32(len);
} }
void read_reply(int fd, uint64_t request_raw_handle, struct nbd_reply *reply) void read_reply(int fd, uint64_t request_raw_handle,
struct nbd_reply *reply)
{ {
struct nbd_reply_raw reply_raw; struct nbd_reply_raw reply_raw;
ERROR_IF_NEGATIVE(readloop(fd, &reply_raw, sizeof(struct nbd_reply_raw)), ERROR_IF_NEGATIVE(readloop
(fd, &reply_raw, sizeof(struct nbd_reply_raw)),
"Couldn't read reply"); "Couldn't read reply");
nbd_r2h_reply( &reply_raw, reply ); nbd_r2h_reply(&reply_raw, reply);
if (reply->magic != REPLY_MAGIC) { if (reply->magic != REPLY_MAGIC) {
error("Reply magic incorrect (%x)", reply->magic); error("Reply magic incorrect (%x)", reply->magic);
@@ -136,25 +145,26 @@ void read_reply(int fd, uint64_t request_raw_handle, struct nbd_reply *reply)
} }
} }
void wait_for_data( int fd, int timeout_secs ) void wait_for_data(int fd, int timeout_secs)
{ {
fd_set fds; fd_set fds;
struct timeval tv = { timeout_secs, 0 }; struct timeval tv = { timeout_secs, 0 };
int selected; int selected;
FD_ZERO( &fds ); FD_ZERO(&fds);
FD_SET( fd, &fds ); FD_SET(fd, &fds);
selected = sock_try_select( selected =
FD_SETSIZE, &fds, NULL, NULL, timeout_secs >=0 ? &tv : NULL sock_try_select(FD_SETSIZE, &fds, NULL, NULL,
); timeout_secs >= 0 ? &tv : NULL);
FATAL_IF( -1 == selected, "Select failed" ); FATAL_IF(-1 == selected, "Select failed");
ERROR_IF( 0 == selected, "Timed out waiting for reply" ); 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;
@@ -164,22 +174,19 @@ void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, void* out_
"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;
@@ -189,32 +196,28 @@ void socket_nbd_write(int fd, uint64_t from, uint32_t len, int in_fd, void* in_b
"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;
} }
@@ -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,
&params->connect_from.generic);
FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
CHECK_RANGE("read"); CHECK_RANGE("read");
socket_nbd_read(params->client, params->from, params->len, socket_nbd_read(params->client, params->from, params->len,
params->data_fd, NULL, 10); params->data_fd, NULL, 10);
close(params->client); 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,
&params->connect_from.generic);
FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
CHECK_RANGE("write"); CHECK_RANGE("write");
socket_nbd_write(params->client, params->from, params->len, socket_nbd_write(params->client, params->from, params->len,
params->data_fd, NULL, 10); params->data_fd, NULL, 10);
close(params->client); 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,31 +4,32 @@
#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];
@@ -40,28 +41,25 @@ void do_remote_command(char* command, char* socket_name, int argc, char** argv)
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,25 +47,28 @@ 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) {
if ( pipe( fds ) ) {
free( sig );
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 (pipe(fds)) {
free(sig);
self_pipe_server_error(errno, ERR_MSG_PIPE);
return NULL;
}
if (fcntl(fds[0], F_SETFL, O_NONBLOCK)
|| fcntl(fds[1], F_SETFL, O_NONBLOCK)) {
int fcntl_err = errno; int fcntl_err = errno;
while( close( fds[0] ) == -1 && errno == EINTR ); while (close(fds[0]) == -1 && errno == EINTR);
while( close( fds[1] ) == -1 && errno == EINTR ); while (close(fds[1]) == -1 && errno == EINTR);
free( sig ); free(sig);
self_pipe_server_error( fcntl_err, ERR_MSG_FCNTL ); self_pipe_server_error(fcntl_err, ERR_MSG_FCNTL);
return NULL; return NULL;
} }
@@ -83,15 +86,15 @@ 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;
} }
@@ -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,12 +121,12 @@ 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
@@ -131,17 +134,17 @@ int self_pipe_destroy( struct self_pipe * sig )
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

@@ -9,11 +9,11 @@ struct self_pipe {
}; };
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,66 +9,68 @@
#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) ||
@@ -79,72 +81,76 @@ int sock_set_keepalive_params( int fd, int time, int intvl, int probes)
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 { } else {
flags = flags & (~O_NONBLOCK); flags = flags & (~O_NONBLOCK);
} }
return fcntl( fd, F_SETFL, flags ); return fcntl(fd, F_SETFL, flags);
} }
int sock_try_bind( int fd, const struct sockaddr* sa ) int sock_try_bind(int fd, const struct sockaddr *sa)
{ {
int bind_result; int bind_result;
char s_address[256]; char s_address[256];
int retry = 10; int retry = 10;
sockaddr_address_string( sa, &s_address[0], 256 ); sockaddr_address_string(sa, &s_address[0], 256);
do { do {
bind_result = bind( fd, sa, sockaddr_size( sa ) ); bind_result = bind(fd, sa, sockaddr_size(sa));
if ( 0 == bind_result ) { if (0 == bind_result) {
info( "Bound to %s", s_address ); info("Bound to %s", s_address);
break; break;
} } else {
else { warn(SHOW_ERRNO("Couldn't bind to %s", s_address));
warn( SHOW_ERRNO( "Couldn't bind to %s", s_address ) );
switch ( errno ) { switch (errno) {
/* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF, /* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF,
* EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, * EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT,
* ENOMEM, ENOTDIR, EROFS * ENOMEM, ENOTDIR, EROFS
@@ -159,58 +165,61 @@ int sock_try_bind( int fd, const struct sockaddr* sa )
case EADDRNOTAVAIL: case EADDRNOTAVAIL:
retry--; retry--;
if (retry) { if (retry) {
debug( "retrying" ); debug("retrying");
sleep( 1 ); sleep(1);
} }
continue; continue;
case EADDRINUSE: case EADDRINUSE:
warn( "%s in use, giving up.", s_address ); warn("%s in use, giving up.", s_address);
retry = 0; retry = 0;
break; break;
default: default:
warn( "giving up" ); warn("giving up");
retry = 0; retry = 0;
} }
} }
} while ( retry ); } while (retry);
return bind_result; return bind_result;
} }
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)
{ {
int result; int result;
do { do {
result = select(nfds, readfds, writefds, exceptfds, timeout); result = select(nfds, readfds, writefds, exceptfds, timeout);
if ( errno != EINTR ) { if (errno != EINTR) {
break; break;
} }
} while ( result == -1 ); } while (result == -1);
return result; return result;
} }
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)
{ {
fd_set fds; fd_set fds;
struct timeval tv = { wait, 0 }; struct timeval tv = { wait, 0 };
int result = 0; int result = 0;
if ( sock_set_nonblock( fd, 1 ) == -1 ) { if (sock_set_nonblock(fd, 1) == -1) {
warn( SHOW_ERRNO( "Failed to set socket non-blocking for connect()" ) ); warn(SHOW_ERRNO
return connect( fd, to, addrlen ); ("Failed to set socket non-blocking for connect()"));
return connect(fd, to, addrlen);
} }
FD_ZERO( &fds ); FD_ZERO(&fds);
FD_SET( fd, &fds ); FD_SET(fd, &fds);
do { do {
result = connect( fd, to, addrlen ); result = connect(fd, to, addrlen);
if ( result == -1 ) { if (result == -1) {
switch( errno ) { switch (errno) {
case EINPROGRESS: case EINPROGRESS:
result = 0; result = 0;
break; /* success */ break; /* success */
@@ -221,67 +230,66 @@ int sock_try_connect( int fd, struct sockaddr* to, socklen_t addrlen, int wait )
*/ */
break; break;
default: default:
warn( SHOW_ERRNO( "Failed to connect()" ) ); warn(SHOW_ERRNO("Failed to connect()"));
goto out; goto out;
} }
} }
} while ( result == -1 ); } while (result == -1);
if ( -1 == sock_try_select( FD_SETSIZE, NULL, &fds, NULL, &tv) ) { if (-1 == sock_try_select(FD_SETSIZE, NULL, &fds, NULL, &tv)) {
warn( SHOW_ERRNO( "failed to select() on non-blocking connect" ) ); warn(SHOW_ERRNO("failed to select() on non-blocking connect"));
result = -1; result = -1;
goto out; goto out;
} }
if ( !FD_ISSET( fd, &fds ) ) { if (!FD_ISSET(fd, &fds)) {
result = -1; result = -1;
errno = ETIMEDOUT; errno = ETIMEDOUT;
goto out; goto out;
} }
int scratch; int scratch;
socklen_t s_size = sizeof( scratch ); socklen_t s_size = sizeof(scratch);
if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size ) == -1 ) { if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size) == -1) {
result = -1; result = -1;
warn( SHOW_ERRNO( "getsockopt() failed" ) ); warn(SHOW_ERRNO("getsockopt() failed"));
goto out; goto out;
} }
if ( scratch == EINPROGRESS ) { if (scratch == EINPROGRESS) {
scratch = ETIMEDOUT; scratch = ETIMEDOUT;
} }
result = scratch ? -1 : 0; result = scratch ? -1 : 0;
errno = scratch; errno = scratch;
out: out:
if ( sock_set_nonblock( fd, 0 ) == -1 ) { if (sock_set_nonblock(fd, 0) == -1) {
warn( SHOW_ERRNO( "Failed to make socket blocking after connect()" ) ); warn(SHOW_ERRNO("Failed to make socket blocking after connect()"));
return -1; return -1;
} }
debug( "sock_try_connect: %i", result ); debug("sock_try_connect: %i", result);
return 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

@@ -25,25 +25,29 @@ 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 {
if (fatal) {
abort();
} else {
pthread_exit((void *) 1);
} }
else {
if ( fatal ) { abort(); }
else { pthread_exit((void*) 1); }
} }
} }
void exit_err( const char *msg ) void exit_err(const char *msg)
{ {
fprintf( stderr, "%s\n", msg ); 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;
@@ -57,9 +61,8 @@ 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;
@@ -72,17 +75,17 @@ uint64_t monotonic_time_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",
ptr ? "realloc" : "malloc", size);
return p; 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,7 +5,7 @@
#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();
@@ -13,10 +13,9 @@ int main(int argc, char** argv)
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

@@ -19,6 +19,7 @@ static struct option proxy_options[] = {
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"
@@ -26,29 +27,29 @@ static char proxy_help_text[] =
"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
",-p <PORT>\tThe port we will bind to as a proxy, if required.\n"
"\t--" OPT_CONNECT_ADDR ",-C <ADDR>\tAddress of the proxied server.\n" "\t--" OPT_CONNECT_ADDR ",-C <ADDR>\tAddress of the proxied server.\n"
"\t--" OPT_CONNECT_PORT ",-P <PORT>\tPort of the proxied server.\n" "\t--" OPT_CONNECT_PORT ",-P <PORT>\tPort of the proxied server.\n"
"\t--" OPT_BIND ",-b <ADDR>\tThe address we connect from, as a proxy.\n" "\t--" OPT_BIND
"\t--" OPT_CACHE ",-c[=<CACHE-BYTES>]\tUse a RAM read cache of the given size.\n" ",-b <ADDR>\tThe address we connect from, as a proxy.\n" "\t--"
QUIET_LINE OPT_CACHE
VERBOSE_LINE; ",-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 **bind_addr, char **cache_bytes)
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;
@@ -74,23 +75,23 @@ void read_proxy_param(
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;
@@ -104,10 +105,10 @@ int main( int argc, char *argv[] )
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;
@@ -116,34 +117,31 @@ int main( int argc, char *argv[] )
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) {
break;
}
read_proxy_param(c,
&downstream_addr, &downstream_addr,
&downstream_port, &downstream_port,
&upstream_addr, &upstream_addr,
&upstream_port, &upstream_port, &bind_addr, &cache_bytes);
&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, upstream_port, bind_addr, cache_bytes);
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);
@@ -151,21 +149,17 @@ int main( int argc, char *argv[] )
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( info("Proxying between %s (downstream) and %s %s (upstream)",
"Proxying between %s (downstream) and %s %s (upstream)", downstream_addr, upstream_addr, upstream_port);
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,13 +2,14 @@
#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;
@@ -19,50 +20,59 @@ struct prefetch* prefetch_create( size_t size_bytes ){
} }
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 ) { {
if (prefetch) {
return prefetch->size; return prefetch->size;
} else { } else {
return 0; 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 ) { {
if (prefetch) {
prefetch->is_full = val; prefetch->is_full = val;
} }
} }
int prefetch_is_full( struct prefetch *prefetch ){ int prefetch_is_full(struct prefetch *prefetch)
if( prefetch ) { {
if (prefetch) {
return prefetch->is_full; return prefetch->is_full;
} else { } else {
return 0; 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)
{
NULLCHECK(prefetch);
return from >= prefetch->from && return from >= prefetch->from &&
from + len <= prefetch->from + prefetch->len; 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 ); {
NULLCHECK(prefetch);
return prefetch->buffer + (from - prefetch->from); return prefetch->buffer + (from - prefetch->from);
} }

View File

@@ -20,14 +20,15 @@ struct prefetch {
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
@@ -85,16 +85,13 @@ struct proxier {
/** */ /** */
}; };
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,34 +6,37 @@
#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;
@@ -41,28 +44,28 @@ static int is_included_in_acl(int list_length, struct ip_and_mask (*list)[], uni
if (test->generic.sa_family == AF_INET) { if (test->generic.sa_family == AF_INET) {
debug("it's an AF_INET"); debug("it's an AF_INET");
raw_address1 = (unsigned char*) &test->v4.sin_addr; raw_address1 = (unsigned char *) &test->v4.sin_addr;
raw_address2 = (unsigned char*) &entry->ip.v4.sin_addr; raw_address2 = (unsigned char *) &entry->ip.v4.sin_addr;
} } else if (test->generic.sa_family == AF_INET6) {
else if (test->generic.sa_family == AF_INET6) {
debug("it's an AF_INET6"); debug("it's an AF_INET6");
raw_address1 = (unsigned char*) &test->v6.sin6_addr; raw_address1 = (unsigned char *) &test->v6.sin6_addr;
raw_address2 = (unsigned char*) &entry->ip.v6.sin6_addr; raw_address2 = (unsigned char *) &entry->ip.v6.sin6_addr;
} } else {
else { fatal("Can't check an ACL for this address type.");
fatal( "Can't check an ACL for this address type." );
} }
debug("testbits=%d", entry->mask); debug("testbits=%d", entry->mask);
for (testbits = entry->mask; testbits > 0; testbits -= 8) { for (testbits = entry->mask; testbits > 0; testbits -= 8) {
debug("testbits=%d, c1=%02x, c2=%02x", testbits, raw_address1[0], raw_address2[0]); debug("testbits=%d, c1=%02x, c2=%02x", testbits,
raw_address1[0], raw_address2[0]);
if (testbits >= 8) { if (testbits >= 8) {
if (raw_address1[0] != raw_address2[0]) { goto no_match; } if (raw_address1[0] != raw_address2[0]) {
goto no_match;
} }
else { } else {
if ((raw_address1[0] & testmasks[testbits%8]) != if ((raw_address1[0] & testmasks[testbits % 8]) !=
(raw_address2[0] & testmasks[testbits%8]) ) { (raw_address2[0] & testmasks[testbits % 8])) {
goto no_match; goto no_match;
} }
} }
@@ -73,36 +76,34 @@ static int is_included_in_acl(int list_length, struct ip_and_mask (*list)[], uni
return 1; return 1;
no_match: ; no_match:;
debug("no match"); debug("no match");
} }
return 0; return 0;
} }
int acl_includes( struct acl * acl, union mysockaddr * addr ) int acl_includes(struct acl *acl, union mysockaddr *addr)
{ {
NULLCHECK( acl ); NULLCHECK(acl);
if ( 0 == acl->len ) { if (0 == acl->len) {
return !( acl->default_deny ); return !(acl->default_deny);
} } else {
else { return is_included_in_acl(acl->len, acl->entries, addr);
return is_included_in_acl( acl->len, acl->entries, addr );
} }
} }
int acl_default_deny( struct acl * acl ) int acl_default_deny(struct acl *acl)
{ {
NULLCHECK( acl ); NULLCHECK(acl);
return acl->default_deny; return acl->default_deny;
} }
void acl_destroy( struct acl * acl ) void acl_destroy(struct acl *acl)
{ {
free( acl->entries ); free(acl->entries);
acl->len = 0; acl->len = 0;
acl->entries = NULL; acl->entries = NULL;
free( acl ); free(acl);
} }

View File

@@ -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

@@ -13,7 +13,7 @@
* 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,64 +30,77 @@ 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++);
} }
} }
@@ -96,16 +109,18 @@ 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 len, int *run_is_set)
{
uint64_t count = 0; uint64_t count = 0;
int first_value = bit_get(b, from); int first_value = bit_get(b, from);
bitfield_word_t word_match = first_value ? -1 : 0; 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--) { for (; ((from + count) % BITS_PER_WORD) != 0 && len > 0; len--) {
if (bit_has_value(b, from + count, first_value)) { if (bit_has_value(b, from + count, first_value)) {
count++; count++;
} else { } else {
@@ -113,7 +128,7 @@ static inline uint64_t bit_run_count(bitfield_p b, uint64_t from, uint64_t len,
} }
} }
for ( ; len >= BITS_PER_WORD ; len -= BITS_PER_WORD ) { for (; len >= BITS_PER_WORD; len -= BITS_PER_WORD) {
if (BIT_WORD(b, from + count) == word_match) { if (BIT_WORD(b, from + count) == word_match) {
count += BITS_PER_WORD; count += BITS_PER_WORD;
} else { } else {
@@ -121,8 +136,8 @@ static inline uint64_t bit_run_count(bitfield_p b, uint64_t from, uint64_t len,
} }
} }
for ( ; len > 0; len-- ) { for (; len > 0; len--) {
if ( bit_has_value(b, from + count, first_value) ) { if (bit_has_value(b, from + count, first_value)) {
count++; count++;
} }
} }
@@ -180,36 +195,38 @@ struct bitset {
/** 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,19 +241,16 @@ 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 from, uint64_t len)
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;
@@ -248,29 +262,27 @@ static inline void bitset_stream_enqueue(
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;
@@ -281,49 +293,48 @@ static inline void bitset_stream_dequeue(
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;
} }
@@ -331,17 +342,15 @@ static inline void bitset_disable_stream( struct bitset * set )
/** 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;
@@ -349,7 +358,7 @@ static inline void bitset_set_range(
/** 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);
} }
@@ -357,17 +366,15 @@ static inline void bitset_set( struct bitset * set )
/** 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;
@@ -375,7 +382,7 @@ static inline void bitset_clear_range(
/** 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);
} }
@@ -383,25 +390,24 @@ static inline void bitset_clear( struct bitset * set )
/** 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, uint64_t len, int *run_is_set)
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 =
bit_run_count(set->bits, first, bitlen,
run_is_set) * set->resolution;
run -= (from % set->resolution); run -= (from % set->resolution);
BITSET_UNLOCK; BITSET_UNLOCK;
@@ -411,28 +417,25 @@ static inline uint64_t bitset_run_count_ex(
/** 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

View File

@@ -18,20 +18,22 @@
// When this signal is invoked, we call shutdown() on the client fd, which // When this signal is invoked, we call shutdown() on the client fd, which
// results in the thread being wound up // results in the thread being wound up
void client_killswitch_hit(int signal __attribute__ ((unused)), siginfo_t *info, void *ptr __attribute__ ((unused))) void client_killswitch_hit(int signal
__attribute__ ((unused)), siginfo_t * info,
void *ptr __attribute__ ((unused)))
{ {
int fd = info->si_value.sival_int; int fd = info->si_value.sival_int;
warn( "Killswitch for fd %i activated, calling shutdown on socket", fd ); warn("Killswitch for fd %i activated, calling shutdown on socket", fd);
FATAL_IF( FATAL_IF(-1 == shutdown(fd, SHUT_RDWR),
-1 == shutdown( fd, SHUT_RDWR ), SHOW_ERRNO
SHOW_ERRNO( "Failed to shutdown() the socket, killing the server" ) ("Failed to shutdown() the socket, killing the server")
); );
} }
struct client *client_create( struct server *serve, int socket ) struct client *client_create(struct server *serve, int socket)
{ {
NULLCHECK( serve ); NULLCHECK(serve);
struct client *c; struct client *c;
struct sigevent evp = { struct sigevent evp = {
@@ -46,44 +48,44 @@ struct client *client_create( struct server *serve, int socket )
*/ */
evp.sigev_value.sival_int = socket; evp.sigev_value.sival_int = socket;
c = xmalloc( sizeof( struct client ) ); c = xmalloc(sizeof(struct client));
c->stopped = 0; c->stopped = 0;
c->socket = socket; c->socket = socket;
c->serve = serve; c->serve = serve;
c->stop_signal = self_pipe_create(); c->stop_signal = self_pipe_create();
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(timer_create
timer_create( CLOCK_MONOTONIC, &evp, &(c->killswitch) ), (CLOCK_MONOTONIC, &evp, &(c->killswitch)),
SHOW_ERRNO( "Failed to create killswitch timer" ) SHOW_ERRNO("Failed to create killswitch timer")
); );
debug( "Alloced client %p with socket %d", c, socket ); debug("Alloced client %p with socket %d", c, socket);
return c; return c;
} }
void client_signal_stop( struct client *c) void client_signal_stop(struct client *c)
{ {
NULLCHECK( c); NULLCHECK(c);
debug("client %p: signal stop (%d, %d)", c,c->stop_signal->read_fd, c->stop_signal->write_fd ); debug("client %p: signal stop (%d, %d)", c, c->stop_signal->read_fd,
self_pipe_signal( c->stop_signal ); c->stop_signal->write_fd);
self_pipe_signal(c->stop_signal);
} }
void client_destroy( struct client *client ) void client_destroy(struct client *client)
{ {
NULLCHECK( client ); NULLCHECK(client);
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(timer_delete(client->killswitch),
timer_delete( client->killswitch ), SHOW_ERRNO("Couldn't delete killswitch")
SHOW_ERRNO( "Couldn't delete killswitch" )
); );
debug( "Destroying stop signal for client %p", client ); debug("Destroying stop signal for client %p", client);
self_pipe_destroy( client->stop_signal ); self_pipe_destroy(client->stop_signal);
debug( "Freeing client %p", client ); debug("Freeing client %p", client);
free( client ); free(client);
} }
@@ -100,13 +102,13 @@ void client_destroy( struct client *client )
* allocated, we can proceed as normal and make one call to writeloop. * allocated, we can proceed as normal and make one call to writeloop.
* *
*/ */
void write_not_zeroes(struct client* client, uint64_t from, uint64_t len) void write_not_zeroes(struct client *client, uint64_t from, uint64_t len)
{ {
NULLCHECK( client ); NULLCHECK(client);
NULLCHECK( client->serve ); NULLCHECK(client->serve);
NULLCHECK( client->serve->allocation_map ); NULLCHECK(client->serve->allocation_map);
struct bitset * map = client->serve->allocation_map; struct bitset *map = client->serve->allocation_map;
while (len > 0) { while (len > 0) {
/* so we have to calculate how much of our input to consider /* so we have to calculate how much of our input to consider
@@ -119,7 +121,8 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len)
uint64_t run = bitset_run_count(map, from, len); uint64_t run = bitset_run_count(map, from, len);
debug("write_not_zeroes: from=%ld, len=%d, run=%d", from, len, run); debug("write_not_zeroes: from=%ld, len=%d, run=%d", from, len,
run);
if (run > len) { if (run > len) {
run = len; run = len;
@@ -143,7 +146,7 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len)
} }
*/ */
#define DO_READ(dst, len) ERROR_IF_NEGATIVE( \ #define DO_READ(dst, len) ERROR_IF_NEGATIVE( \
readloop( \ readloop( \
client->socket, \ client->socket, \
(dst), \ (dst), \
@@ -161,11 +164,10 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len)
* sake of the event stream - the actual bytes have changed, and we * sake of the event stream - the actual bytes have changed, and we
* are interested in that fact. * are interested in that fact.
*/ */
bitset_set_range( map, from, run ); bitset_set_range(map, from, run);
len -= run; len -= run;
from += run; from += run;
} } else {
else {
char zerobuffer[block_allocation_resolution]; char zerobuffer[block_allocation_resolution];
/* not allocated, read in block_allocation_resoution */ /* not allocated, read in block_allocation_resoution */
while (run > 0) { while (run > 0) {
@@ -183,10 +185,11 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len)
*/ */
int all_zeros = (zerobuffer[0] == 0) && int all_zeros = (zerobuffer[0] == 0) &&
(0 == memcmp( zerobuffer, zerobuffer+1, blockrun-1 )); (0 ==
memcmp(zerobuffer, zerobuffer + 1, blockrun - 1));
if ( !all_zeros ) { if (!all_zeros) {
memcpy(client->mapped+from, zerobuffer, blockrun); memcpy(client->mapped + from, zerobuffer, blockrun);
bitset_set_range(map, from, blockrun); bitset_set_range(map, from, blockrun);
/* at this point we could choose to /* at this point we could choose to
* short-cut the rest of the write for * short-cut the rest of the write for
@@ -209,7 +212,7 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len)
} }
int fd_read_request( int fd, struct nbd_request_raw *out_request) int fd_read_request(int fd, struct nbd_request_raw *out_request)
{ {
return readloop(fd, out_request, sizeof(struct nbd_request_raw)); return readloop(fd, out_request, sizeof(struct nbd_request_raw));
} }
@@ -217,26 +220,25 @@ int fd_read_request( int fd, struct nbd_request_raw *out_request)
/* Returns 1 if *request was filled with a valid request which we should /* Returns 1 if *request was filled with a valid request which we should
* try to honour. 0 otherwise. */ * try to honour. 0 otherwise. */
int client_read_request( struct client * client , struct nbd_request *out_request, int * disconnected ) int client_read_request(struct client *client,
struct nbd_request *out_request, int *disconnected)
{ {
NULLCHECK( client ); NULLCHECK(client);
NULLCHECK( out_request ); NULLCHECK(out_request);
struct nbd_request_raw request_raw; struct nbd_request_raw request_raw;
if (fd_read_request(client->socket, &request_raw) == -1) { if (fd_read_request(client->socket, &request_raw) == -1) {
*disconnected = 1; *disconnected = 1;
switch( errno ){ switch (errno) {
case 0: case 0:
warn( "EOF while reading request" ); warn("EOF while reading request");
return 0; return 0;
case ECONNRESET: case ECONNRESET:
warn( "Connection reset while" warn("Connection reset while" " reading request");
" reading request" );
return 0; return 0;
case ETIMEDOUT: case ETIMEDOUT:
warn( "Connection timed out while" warn("Connection timed out while" " reading request");
" reading request" );
return 0; return 0;
default: default:
/* FIXME: I've seen this happen, but I /* FIXME: I've seen this happen, but I
@@ -246,17 +248,15 @@ int client_read_request( struct client * client , struct nbd_request *out_reques
* again. It should *probably* be an * again. It should *probably* be an
* error() call, but I want to be sure. * error() call, but I want to be sure.
* */ * */
fatal("Error reading request: %d, %s", fatal("Error reading request: %d, %s", errno, strerror(errno));
errno,
strerror( errno ));
} }
} }
nbd_r2h_request( &request_raw, out_request ); nbd_r2h_request(&request_raw, out_request);
return 1; return 1;
} }
int fd_write_reply( int fd, uint64_t handle, int error ) int fd_write_reply(int fd, uint64_t handle, int error)
{ {
struct nbd_reply reply; struct nbd_reply reply;
struct nbd_reply_raw reply_raw; struct nbd_reply_raw reply_raw;
@@ -265,22 +265,22 @@ int fd_write_reply( int fd, uint64_t handle, int error )
reply.error = error; reply.error = error;
reply.handle.w = handle; reply.handle.w = handle;
nbd_h2r_reply( &reply, &reply_raw ); nbd_h2r_reply(&reply, &reply_raw);
debug( "Replying with handle=0x%08X, error=%"PRIu32, handle, error ); debug("Replying with handle=0x%08X, error=%" PRIu32, handle, error);
if( -1 == writeloop( fd, &reply_raw, sizeof( reply_raw ) ) ) { if (-1 == writeloop(fd, &reply_raw, sizeof(reply_raw))) {
switch( errno ) { switch (errno) {
case ECONNRESET: case ECONNRESET:
error( "Connection reset while writing reply" ); error("Connection reset while writing reply");
break; break;
case EBADF: case EBADF:
fatal( "Tried to write to an invalid file descriptor" ); fatal("Tried to write to an invalid file descriptor");
break; break;
case EPIPE: case EPIPE:
error( "Remote end closed" ); error("Remote end closed");
break; break;
default: default:
fatal( "Unhandled error while writing: %d", errno ); fatal("Unhandled error while writing: %d", errno);
} }
} }
@@ -293,32 +293,32 @@ int fd_write_reply( int fd, uint64_t handle, int error )
* Returns 1; we don't check for errors on the write. * Returns 1; we don't check for errors on the write.
* TODO: Check for errors on the write. * TODO: Check for errors on the write.
*/ */
int client_write_reply( struct client * client, struct nbd_request *request, int error ) int client_write_reply(struct client *client, struct nbd_request *request,
int error)
{ {
return fd_write_reply( client->socket, request->handle.w, error); return fd_write_reply(client->socket, request->handle.w, error);
} }
void client_write_init( struct client * client, uint64_t size ) void client_write_init(struct client *client, uint64_t size)
{ {
struct nbd_init init = {{0}}; struct nbd_init init = { {0} };
struct nbd_init_raw init_raw = {{0}}; struct nbd_init_raw init_raw = { {0} };
memcpy( init.passwd, INIT_PASSWD, sizeof( init.passwd ) ); memcpy(init.passwd, INIT_PASSWD, sizeof(init.passwd));
init.magic = INIT_MAGIC; init.magic = INIT_MAGIC;
init.size = size; init.size = size;
/* As more features are implemented, this is the place to advertise /* As more features are implemented, this is the place to advertise
* them. * them.
*/ */
init.flags = FLAG_HAS_FLAGS | FLAG_SEND_FLUSH | FLAG_SEND_FUA; init.flags = FLAG_HAS_FLAGS | FLAG_SEND_FLUSH | FLAG_SEND_FUA;
memset( init.reserved, 0, 124 ); memset(init.reserved, 0, 124);
nbd_h2r_init( &init, &init_raw ); nbd_h2r_init(&init, &init_raw);
ERROR_IF_NEGATIVE( ERROR_IF_NEGATIVE(writeloop
writeloop(client->socket, &init_raw, sizeof(init_raw)), (client->socket, &init_raw, sizeof(init_raw)),
"Couldn't send hello" "Couldn't send hello");
);
} }
@@ -326,35 +326,27 @@ void client_write_init( struct client * client, uint64_t size )
* client sends a write we can't honour - we need to get rid of the * client sends a write we can't honour - we need to get rid of the
* bytes they've already written before we can look for another request. * bytes they've already written before we can look for another request.
*/ */
void client_flush( struct client * client, size_t len ) void client_flush(struct client *client, size_t len)
{ {
int devnull = open("/dev/null", O_WRONLY); int devnull = open("/dev/null", O_WRONLY);
FATAL_IF_NEGATIVE( devnull, FATAL_IF_NEGATIVE(devnull,
"Couldn't open /dev/null: %s", strerror(errno)); "Couldn't open /dev/null: %s", strerror(errno));
int pipes[2]; int pipes[2];
pipe( pipes ); pipe(pipes);
const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE; const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE;
size_t spliced = 0; size_t spliced = 0;
while ( spliced < len ) { while (spliced < len) {
ssize_t received = splice( ssize_t received = splice(client->socket, NULL,
client->socket, NULL,
pipes[1], NULL, pipes[1], NULL,
len-spliced, flags ); len - spliced, flags);
FATAL_IF_NEGATIVE( received, FATAL_IF_NEGATIVE(received, "splice error: %s", strerror(errno));
"splice error: %s",
strerror(errno));
ssize_t junked = 0; ssize_t junked = 0;
while( junked < received ) { while (junked < received) {
ssize_t junk; ssize_t junk;
junk = splice( junk = splice(pipes[0], NULL, devnull, NULL, received, flags);
pipes[0], NULL, FATAL_IF_NEGATIVE(junk, "splice error: %s", strerror(errno));
devnull, NULL,
received, flags );
FATAL_IF_NEGATIVE( junk,
"splice error: %s",
strerror(errno));
junked += junk; junked += junk;
} }
spliced += received; spliced += received;
@@ -362,7 +354,7 @@ void client_flush( struct client * client, size_t len )
debug("Flushed %d bytes", len); debug("Flushed %d bytes", len);
close( devnull ); close(devnull);
} }
@@ -371,8 +363,8 @@ void client_flush( struct client * client, size_t len )
* request_err is set to 0 if the client sent a bad request, in which * request_err is set to 0 if the client sent a bad request, in which
* case we drop the connection. * case we drop the connection.
*/ */
int client_request_needs_reply( struct client * client, int client_request_needs_reply(struct client *client,
struct nbd_request request ) struct nbd_request request)
{ {
/* The client is stupid, but don't take down the whole server as a result. /* The client is stupid, but don't take down the whole server as a result.
* We send a reply before disconnecting so that at least some indication of * We send a reply before disconnecting so that at least some indication of
@@ -381,34 +373,31 @@ int client_request_needs_reply( struct client * client,
*/ */
if (request.magic != REQUEST_MAGIC) { if (request.magic != REQUEST_MAGIC) {
warn("Bad magic 0x%08X from client", request.magic); warn("Bad magic 0x%08X from client", request.magic);
client_write_reply( client, &request, EBADMSG ); client_write_reply(client, &request, EBADMSG);
client->disconnect = 1; // no need to flush client->disconnect = 1; // no need to flush
return 0; return 0;
} }
debug( debug("request type=%" PRIu16 ", flags=%" PRIu16 ", from=%" PRIu64
"request type=%"PRIu16", flags=%"PRIu16", from=%"PRIu64", len=%"PRIu32", handle=0x%08X", ", len=%" PRIu32 ", handle=0x%08X", request.type, request.flags,
request.type, request.flags, request.from, request.len, request.handle request.from, request.len, request.handle);
);
/* check it's not out of range. NBD protocol requires ENOSPC to be /* check it's not out of range. NBD protocol requires ENOSPC to be
* returned in this instance * returned in this instance
*/ */
if ( request.from+request.len > client->serve->size) { if (request.from + request.len > client->serve->size) {
warn("write request %"PRIu64"+%"PRIu32" out of range", warn("write request %" PRIu64 "+%" PRIu32 " out of range",
request.from, request.len request.from, request.len);
); if (request.type == REQUEST_WRITE) {
if ( request.type == REQUEST_WRITE ) { client_flush(client, request.len);
client_flush( client, request.len );
} }
client_write_reply( client, &request, ENOSPC ); client_write_reply(client, &request, ENOSPC);
client->disconnect = 0; client->disconnect = 0;
return 0; return 0;
} }
switch (request.type) switch (request.type) {
{
case REQUEST_READ: case REQUEST_READ:
break; break;
case REQUEST_WRITE: case REQUEST_WRITE:
@@ -423,7 +412,7 @@ int client_request_needs_reply( struct client * client,
/* NBD prototcol says servers SHOULD return EINVAL to unknown /* NBD prototcol says servers SHOULD return EINVAL to unknown
* commands */ * commands */
warn("Unknown request 0x%08X", request.type); warn("Unknown request 0x%08X", request.type);
client_write_reply( client, &request, EINVAL ); client_write_reply(client, &request, EINVAL);
client->disconnect = 0; client->disconnect = 0;
return 0; return 0;
} }
@@ -431,100 +420,98 @@ int client_request_needs_reply( struct client * client,
} }
void client_reply_to_read( struct client* client, struct nbd_request request ) void client_reply_to_read(struct client *client,
struct nbd_request request)
{ {
off64_t offset; off64_t offset;
debug("request read %ld+%d", request.from, request.len); debug("request read %ld+%d", request.from, request.len);
sock_set_tcp_cork( client->socket, 1 ); sock_set_tcp_cork(client->socket, 1);
client_write_reply( client, &request, 0 ); client_write_reply(client, &request, 0);
offset = request.from; offset = request.from;
/* If we get cut off partway through this sendfile, we don't /* If we get cut off partway through this sendfile, we don't
* want to kill the server. This should be an error. * want to kill the server. This should be an error.
*/ */
ERROR_IF_NEGATIVE( ERROR_IF_NEGATIVE(sendfileloop(client->socket,
sendfileloop(
client->socket,
client->fileno, client->fileno,
&offset, &offset,
request.len), request.len),
"sendfile failed from=%ld, len=%d", "sendfile failed from=%ld, len=%d",
offset, offset, request.len);
request.len);
sock_set_tcp_cork( client->socket, 0 ); sock_set_tcp_cork(client->socket, 0);
} }
void client_reply_to_write( struct client* client, struct nbd_request request ) void client_reply_to_write(struct client *client,
struct nbd_request request)
{ {
debug("request write from=%"PRIu64", len=%"PRIu32", handle=0x%08X", request.from, request.len, request.handle); debug("request write from=%" PRIu64 ", len=%" PRIu32 ", handle=0x%08X",
request.from, request.len, request.handle);
if (client->serve->allocation_map_built) { if (client->serve->allocation_map_built) {
write_not_zeroes( client, request.from, request.len ); write_not_zeroes(client, request.from, request.len);
} } else {
else {
debug("No allocation map, writing directly."); debug("No allocation map, writing directly.");
/* If we get cut off partway through reading this data: /* If we get cut off partway through reading this data:
* */ * */
ERROR_IF_NEGATIVE( ERROR_IF_NEGATIVE(readloop(client->socket,
readloop( client->socket,
client->mapped + request.from, client->mapped + request.from,
request.len), request.len),
"reading write data failed from=%ld, len=%d", "reading write data failed from=%ld, len=%d",
request.from, request.from, request.len);
request.len
);
/* the allocation_map is shared between client threads, and may be /* the allocation_map is shared between client threads, and may be
* being built. We need to reflect the write in it, as it may be in * being built. We need to reflect the write in it, as it may be in
* a position the builder has already gone over. * a position the builder has already gone over.
*/ */
bitset_set_range(client->serve->allocation_map, request.from, request.len); bitset_set_range(client->serve->allocation_map, request.from,
request.len);
} }
// Only flush if FUA is set // Only flush if FUA is set
if (request.flags & CMD_FLAG_FUA) if (request.flags & CMD_FLAG_FUA) {
{
/* multiple of page size */ /* multiple of page size */
uint64_t from_rounded = request.from & (~(sysconf(_SC_PAGE_SIZE)-1)); uint64_t from_rounded =
request.from & (~(sysconf(_SC_PAGE_SIZE) - 1));
uint64_t len_rounded = request.len + (request.from - from_rounded); uint64_t len_rounded = request.len + (request.from - from_rounded);
debug("Calling msync from=%"PRIu64", len=%"PRIu64"",from_rounded, len_rounded); debug("Calling msync from=%" PRIu64 ", len=%" PRIu64 "",
from_rounded, len_rounded);
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(msync(client->mapped + from_rounded,
msync( client->mapped + from_rounded,
len_rounded, len_rounded,
MS_SYNC | MS_INVALIDATE), MS_SYNC | MS_INVALIDATE),
"msync failed %ld %ld", request.from, request.len "msync failed %ld %ld", request.from,
); request.len);
} }
client_write_reply( client, &request, 0); client_write_reply(client, &request, 0);
} }
void client_reply_to_flush( struct client* client, struct nbd_request request ) void client_reply_to_flush(struct client *client,
struct nbd_request request)
{ {
debug("request flush from=%"PRIu64", len=%"PRIu32", handle=0x%08X", request.from, request.len, request.handle); debug("request flush from=%" PRIu64 ", len=%" PRIu32 ", handle=0x%08X",
request.from, request.len, request.handle);
ERROR_IF_NEGATIVE( ERROR_IF_NEGATIVE(msync
msync(client->mapped, client->mapped_size, MS_SYNC | MS_INVALIDATE), (client->mapped, client->mapped_size,
"flush failed" MS_SYNC | MS_INVALIDATE), "flush failed");
);
client_write_reply( client, &request, 0); client_write_reply(client, &request, 0);
} }
void client_reply( struct client* client, struct nbd_request request ) void client_reply(struct client *client, struct nbd_request request)
{ {
switch (request.type) { switch (request.type) {
case REQUEST_READ: case REQUEST_READ:
client_reply_to_read( client, request ); client_reply_to_read(client, request);
break; break;
case REQUEST_WRITE: case REQUEST_WRITE:
client_reply_to_write( client, request ); client_reply_to_write(client, request);
break; break;
case REQUEST_FLUSH: case REQUEST_FLUSH:
client_reply_to_flush( client, request ); client_reply_to_flush(client, request);
break; break;
} }
} }
@@ -533,52 +520,50 @@ void client_reply( struct client* client, struct nbd_request request )
/* Starts a timer that will kill the whole process if disarm is not called /* Starts a timer that will kill the whole process if disarm is not called
* within a timeout (see CLIENT_HANDLE_TIMEOUT). * within a timeout (see CLIENT_HANDLE_TIMEOUT).
*/ */
void client_arm_killswitch( struct client* client ) void client_arm_killswitch(struct client *client)
{ {
struct itimerspec its = { struct itimerspec its = {
.it_value = { .tv_nsec = 0, .tv_sec = CLIENT_HANDLER_TIMEOUT }, .it_value = {.tv_nsec = 0,.tv_sec = CLIENT_HANDLER_TIMEOUT},
.it_interval = { .tv_nsec = 0, .tv_sec = 0 } .it_interval = {.tv_nsec = 0,.tv_sec = 0}
}; };
if ( !client->serve->use_killswitch ) { if (!client->serve->use_killswitch) {
return; return;
} }
debug( "Arming killswitch" ); debug("Arming killswitch");
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(timer_settime(client->killswitch, 0, &its, NULL),
timer_settime( client->killswitch, 0, &its, NULL ), SHOW_ERRNO("Failed to arm killswitch")
SHOW_ERRNO( "Failed to arm killswitch" )
); );
return; return;
} }
void client_disarm_killswitch( struct client* client ) void client_disarm_killswitch(struct client *client)
{ {
struct itimerspec its = { struct itimerspec its = {
.it_value = { .tv_nsec = 0, .tv_sec = 0 }, .it_value = {.tv_nsec = 0,.tv_sec = 0},
.it_interval = { .tv_nsec = 0, .tv_sec = 0 } .it_interval = {.tv_nsec = 0,.tv_sec = 0}
}; };
if ( !client->serve->use_killswitch ) { if (!client->serve->use_killswitch) {
return; return;
} }
debug( "Disarming killswitch" ); debug("Disarming killswitch");
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(timer_settime(client->killswitch, 0, &its, NULL),
timer_settime( client->killswitch, 0, &its, NULL ), SHOW_ERRNO("Failed to disarm killswitch")
SHOW_ERRNO( "Failed to disarm killswitch" )
); );
return; return;
} }
/* Returns 0 if we should continue trying to serve requests */ /* Returns 0 if we should continue trying to serve requests */
int client_serve_request(struct client* client) int client_serve_request(struct client *client)
{ {
struct nbd_request request = {0}; struct nbd_request request = { 0 };
int stop = 1; int stop = 1;
int disconnected = 0; int disconnected = 0;
fd_set rfds, efds; fd_set rfds, efds;
@@ -592,28 +577,29 @@ int client_serve_request(struct client* client)
* non-blocking. * non-blocking.
*/ */
FD_ZERO( &rfds ); FD_ZERO(&rfds);
FD_SET( client->socket, &rfds ); FD_SET(client->socket, &rfds);
self_pipe_fd_set( client->stop_signal, &rfds ); self_pipe_fd_set(client->stop_signal, &rfds);
FD_ZERO( &efds ); FD_ZERO(&efds);
FD_SET( client->socket, &efds ); FD_SET(client->socket, &efds);
fd_count = sock_try_select( FD_SETSIZE, &rfds, NULL, &efds, NULL ); fd_count = sock_try_select(FD_SETSIZE, &rfds, NULL, &efds, NULL);
if ( fd_count == 0 ) { if (fd_count == 0) {
/* This "can't ever happen" */ /* This "can't ever happen" */
fatal( "No FDs selected, and no timeout!" ); fatal("No FDs selected, and no timeout!");
} else if (fd_count < 0) {
fatal("Select failed");
} }
else if ( fd_count < 0 ) { fatal( "Select failed" ); }
if ( self_pipe_fd_isset( client->stop_signal, &rfds ) ){ if (self_pipe_fd_isset(client->stop_signal, &rfds)) {
debug("Client received stop signal."); debug("Client received stop signal.");
return 1; // Don't try to serve more requests return 1; // Don't try to serve more requests
} }
if ( FD_ISSET( client->socket, &efds ) ) { if (FD_ISSET(client->socket, &efds)) {
debug( "Client connection closed" ); debug("Client connection closed");
return 1; return 1;
} }
@@ -630,51 +616,51 @@ int client_serve_request(struct client* client)
* a single byte, and then wait. * a single byte, and then wait.
* *
*/ */
client_arm_killswitch( client ); client_arm_killswitch(client);
if ( !client_read_request( client, &request, &disconnected ) ) { if (!client_read_request(client, &request, &disconnected)) {
client_disarm_killswitch( client ); client_disarm_killswitch(client);
return stop; return stop;
} }
if ( disconnected ) { if (disconnected) {
client_disarm_killswitch( client ); client_disarm_killswitch(client);
return stop; return stop;
} }
if ( !client_request_needs_reply( client, request ) ) { if (!client_request_needs_reply(client, request)) {
client_disarm_killswitch( client ); client_disarm_killswitch(client);
return client->disconnect; return client->disconnect;
} }
{ {
if ( !server_is_closed( client->serve ) ) { if (!server_is_closed(client->serve)) {
client_reply( client, request ); client_reply(client, request);
stop = 0; stop = 0;
} }
} }
client_disarm_killswitch( client ); client_disarm_killswitch(client);
return stop; return stop;
} }
void client_send_hello(struct client* client) void client_send_hello(struct client *client)
{ {
client_write_init( client, client->serve->size ); client_write_init(client, client->serve->size);
} }
void client_cleanup(struct client* client, void client_cleanup(struct client *client,
int fatal __attribute__ ((unused)) ) int fatal __attribute__ ((unused)))
{ {
info("client cleanup for client %p", client); info("client cleanup for client %p", client);
/* If the thread hits an error, we need to ensure this is off */ /* If the thread hits an error, we need to ensure this is off */
client_disarm_killswitch( client ); client_disarm_killswitch(client);
if (client->socket) { if (client->socket) {
FATAL_IF_NEGATIVE( close(client->socket), FATAL_IF_NEGATIVE(close(client->socket),
"Error closing client socket %d", "Error closing client socket %d",
client->socket ); client->socket);
debug("Closed client socket fd %d", client->socket); debug("Closed client socket fd %d", client->socket);
client->socket = -1; client->socket = -1;
} }
@@ -682,58 +668,57 @@ void client_cleanup(struct client* client,
munmap(client->mapped, client->serve->size); munmap(client->mapped, client->serve->size);
} }
if (client->fileno) { if (client->fileno) {
FATAL_IF_NEGATIVE( close(client->fileno), FATAL_IF_NEGATIVE(close(client->fileno),
"Error closing file %d", "Error closing file %d", client->fileno);
client->fileno ); debug("Closed client file fd %d", client->fileno);
debug("Closed client file fd %d", client->fileno );
client->fileno = -1; client->fileno = -1;
} }
if ( server_acl_locked( client->serve ) ) { server_unlock_acl( client->serve ); } if (server_acl_locked(client->serve)) {
server_unlock_acl(client->serve);
}
} }
void* client_serve(void* client_uncast) void *client_serve(void *client_uncast)
{ {
struct client* client = (struct client*) client_uncast; struct client *client = (struct client *) client_uncast;
error_set_handler((cleanup_handler*) client_cleanup, client); error_set_handler((cleanup_handler *) client_cleanup, client);
info("client: mmaping file"); info("client: mmaping file");
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(open_and_mmap(client->serve->filename,
open_and_mmap(
client->serve->filename,
&client->fileno, &client->fileno,
&client->mapped_size, &client->mapped_size,
(void**) &client->mapped (void **) &client->mapped),
), "Couldn't open/mmap file %s: %s",
"Couldn't open/mmap file %s: %s", client->serve->filename, strerror( errno ) client->serve->filename, strerror(errno)
); );
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(madvise
madvise( client->mapped, client->serve->size, MADV_RANDOM ), (client->mapped, client->serve->size, MADV_RANDOM),
SHOW_ERRNO( "Failed to madvise() %s", client->serve->filename ) SHOW_ERRNO("Failed to madvise() %s",
client->serve->filename)
); );
debug( "Opened client file fd %d", client->fileno); debug("Opened client file fd %d", client->fileno);
debug("client: sending hello"); debug("client: sending hello");
client_send_hello(client); client_send_hello(client);
debug("client: serving requests"); debug("client: serving requests");
while (client_serve_request(client) == 0) while (client_serve_request(client) == 0);
;
debug("client: stopped serving requests"); debug("client: stopped serving requests");
client->stopped = 1; client->stopped = 1;
if ( client->disconnect ){ if (client->disconnect) {
debug("client: control arrived" ); debug("client: control arrived");
server_control_arrived( client->serve ); server_control_arrived(client->serve);
} }
debug("Cleaning client %p up normally in thread %p", client, pthread_self()); debug("Cleaning client %p up normally in thread %p", client,
pthread_self());
client_cleanup(client, 0); client_cleanup(client, 0);
debug("Client thread done" ); debug("Client thread done");
return NULL; return NULL;
} }

View File

@@ -30,13 +30,13 @@ struct client {
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;
@@ -48,12 +48,11 @@ struct client {
}; };
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,13 +44,11 @@
#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;
@@ -62,33 +60,32 @@ struct control * control_create(
} }
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;
@@ -98,226 +95,224 @@ struct control_client * control_client_create(
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;
@@ -345,21 +340,18 @@ int control_mirror(struct control_client* client, int linesc, char** lines)
if (linesc > 2) { if (linesc > 2) {
if (strcmp("exit", lines[2]) == 0) { if (strcmp("exit", lines[2]) == 0) {
action_at_finish = ACTION_EXIT; action_at_finish = ACTION_EXIT;
} } else if (strcmp("unlink", lines[2]) == 0) {
else if (strcmp( "unlink", lines[2]) == 0 ) {
action_at_finish = ACTION_UNLINK; action_at_finish = ACTION_UNLINK;
} } else if (strcmp("nothing", lines[2]) == 0) {
else if (strcmp("nothing", lines[2]) == 0) {
action_at_finish = ACTION_NOTHING; action_at_finish = ACTION_NOTHING;
} } else {
else {
write_socket("1: action must be 'exit' or 'nothing'"); write_socket("1: action must be 'exit' or 'nothing'");
return -1; return -1;
} }
} }
if (linesc > 3) { if (linesc > 3) {
connect_from = xmalloc( sizeof( union mysockaddr ) ); connect_from = xmalloc(sizeof(union mysockaddr));
if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) { if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) {
write_socket("1: bad bind address"); write_socket("1: bad bind address");
return -1; return -1;
@@ -368,12 +360,12 @@ int control_mirror(struct control_client* client, int linesc, char** lines)
if (linesc > 4) { if (linesc > 4) {
errno = 0; errno = 0;
max_Bps = strtoull( lines[4], NULL, 10 ); max_Bps = strtoull(lines[4], 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;
} }
} }
@@ -384,88 +376,85 @@ int control_mirror(struct control_client* client, int linesc, char** lines)
return -1; return -1;
} }
struct server * serve = flexnbd_server(flexnbd); struct server *serve = flexnbd_server(flexnbd);
server_lock_start_mirror( serve ); server_lock_start_mirror(serve);
{ {
if ( server_mirror_can_start( serve ) ) { if (server_mirror_can_start(serve)) {
serve->mirror_super = mirror_super_create( serve->mirror_super = mirror_super_create(serve->filename,
serve->filename,
connect_to, connect_to,
connect_from, connect_from,
max_Bps , max_Bps,
action_at_finish, action_at_finish,
client->mirror_state_mbox ); client->
mirror_state_mbox);
serve->mirror = serve->mirror_super->mirror; serve->mirror = serve->mirror_super->mirror;
server_prevent_mirror_start( serve ); server_prevent_mirror_start(serve);
} else { } else {
if ( serve->mirror_super ) { if (serve->mirror_super) {
warn( "Tried to start a second mirror run" ); warn("Tried to start a second mirror run");
write_socket( "1: mirror already running" ); write_socket("1: mirror already running");
} else { } else {
warn( "Cannot start mirroring, shutting down" ); warn("Cannot start mirroring, shutting down");
write_socket( "1: shutting down" ); write_socket("1: shutting down");
} }
} }
} }
server_unlock_start_mirror( serve ); server_unlock_start_mirror(serve);
/* Do this outside the lock to minimise the length of time the /* Do this outside the lock to minimise the length of time the
* sighandler can block the serve thread * sighandler can block the serve thread
*/ */
if ( serve->mirror_super ) { if (serve->mirror_super) {
FATAL_IF( 0 != pthread_create( FATAL_IF(0 != pthread_create(&serve->mirror_super->thread,
&serve->mirror_super->thread,
NULL, NULL,
mirror_super_runner, mirror_super_runner,
serve serve),
), "Failed to create mirror thread");
"Failed to create mirror thread"
);
debug("Control thread mirror super waiting"); debug("Control thread mirror super waiting");
enum mirror_state state = enum mirror_state state = control_client_mirror_wait(client);
control_client_mirror_wait( client );
debug("Control thread writing response"); debug("Control thread writing response");
control_write_mirror_response( state, client->socket ); control_write_mirror_response(state, client->socket);
} }
debug( "Control thread going away." ); debug("Control thread going away.");
return 0; return 0;
} }
int control_mirror_max_bps( struct control_client* client, int linesc, char** lines ) int control_mirror_max_bps(struct control_client *client, int linesc,
char **lines)
{ {
NULLCHECK( client ); NULLCHECK(client);
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;
} }
@@ -473,161 +462,152 @@ int control_mirror_max_bps( struct control_client* client, int linesc, char** li
#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." );
write( client->socket,
"0: mirror stopped\n", 18 );
result = 1; 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) {
else if (strcmp(lines[0], "acl") == 0) { info("acl command received");
info("acl command received" ); if (control_acl(client, linesc - 1, lines + 1) < 0) {
if (control_acl(client, linesc-1, lines+1) < 0) {
debug("acl command failed"); debug("acl command failed");
} }
} } else if (strcmp(lines[0], "mirror") == 0) {
else if (strcmp(lines[0], "mirror") == 0) { info("mirror command received");
info("mirror command received" ); if (control_mirror(client, linesc - 1, lines + 1) < 0) {
if (control_mirror(client, linesc-1, lines+1) < 0) {
debug("mirror command failed"); debug("mirror command failed");
} }
} else if (strcmp(lines[0], "break") == 0) {
info("break command received");
if (control_break(client, linesc - 1, lines + 1) < 0) {
debug("break command failed");
} }
else if (strcmp(lines[0], "break") == 0) { } 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" );
}
}
else if (strcmp(lines[0], "status") == 0) {
info("status command received" );
if (control_status(client, linesc-1, lines+1) < 0) {
debug("status command failed"); debug("status command failed");
} }
} else if ( strcmp( lines[0], "mirror_max_bps" ) == 0 ) { } else if (strcmp(lines[0], "mirror_max_bps") == 0) {
info( "mirror_max_bps command received" ); info("mirror_max_bps command received");
if( control_mirror_max_bps( client, linesc-1, lines+1 ) < 0 ) { if (control_mirror_max_bps(client, linesc - 1, lines + 1) < 0) {
debug( "mirror_max_bps command failed" ); debug("mirror_max_bps command failed");
} }
} } else {
else {
write(client->socket, "10: unknown command\n", 23); 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,14 +13,14 @@ 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
@@ -31,29 +31,28 @@ struct control {
* 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

@@ -46,31 +46,28 @@ 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 {
}
else {
flexnbd->control = NULL; flexnbd->control = NULL;
} }
@@ -78,67 +75,57 @@ void flexnbd_create_shared(
} }
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, max_nbd_clients, use_killswitch, 1);
use_killswitch, flexnbd_create_shared(flexnbd, s_ctrl_sock);
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, acl_entries, s_acl_entries, 1, 0, 0);
s_acl_entries, flexnbd_create_shared(flexnbd, s_ctrl_sock);
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.
@@ -146,120 +133,116 @@ struct flexnbd * flexnbd_create_listening(
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

@@ -16,51 +16,48 @@ 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,48 +4,47 @@
#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();
} }
@@ -53,23 +52,22 @@ int flexthread_mutex_lock( struct flexthread_mutex * ftm )
} }
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

@@ -19,11 +19,11 @@ struct flexthread_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->contents = contents;
mbox->full = 1; mbox->full = 1;
while( 0 != pthread_cond_signal( &mbox->filled_cond ) ); while (0 != pthread_cond_signal(&mbox->filled_cond));
} }
pthread_mutex_unlock( &mbox->mutex ); 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; mbox->full = 0;
result = mbox->contents; result = mbox->contents;
mbox->contents = NULL; mbox->contents = NULL;
while( 0 != pthread_cond_signal( &mbox->emptied_cond)); while (0 != pthread_cond_signal(&mbox->emptied_cond));
} }
pthread_mutex_unlock( &mbox->mutex ); pthread_mutex_unlock(&mbox->mutex);
return result; 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,7 +14,7 @@
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.
@@ -31,25 +31,25 @@ struct mbox {
/* 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

@@ -79,12 +79,12 @@ 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 */
@@ -102,7 +102,7 @@ struct mirror {
/* 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. */
@@ -114,9 +114,9 @@ struct mirror {
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 action_at_finish, enum mirror_finish_action
struct mbox * state_mbox action_at_finish,
); struct mbox *state_mbox);
void * mirror_super_runner( void * serve_uncast ); void *mirror_super_runner(void *serve_uncast);
#endif #endif

View File

@@ -19,6 +19,7 @@ static struct option serve_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char serve_short_options[] = "hl:p:f:s:dk" SOPT_QUIET SOPT_VERBOSE; static char serve_short_options[] = "hl:p:f:s:dk" SOPT_QUIET SOPT_VERBOSE;
static char serve_help_text[] = static char serve_help_text[] =
"Usage: flexnbd " CMD_SERVE " <options> [<acl address>*]\n\n" "Usage: flexnbd " CMD_SERVE " <options> [<acl address>*]\n\n"
@@ -28,10 +29,9 @@ static char serve_help_text[] =
"\t--" OPT_PORT ",-p <PORT>\tThe port to serve on.\n" "\t--" OPT_PORT ",-p <PORT>\tThe port to serve on.\n"
"\t--" OPT_FILE ",-f <FILE>\tThe file to serve.\n" "\t--" OPT_FILE ",-f <FILE>\tThe file to serve.\n"
"\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n"
"\t--" OPT_KILLSWITCH",-k \tKill the server if a request takes 120 seconds.\n" "\t--" OPT_KILLSWITCH
SOCK_LINE ",-k \tKill the server if a request takes 120 seconds.\n" SOCK_LINE
VERBOSE_LINE VERBOSE_LINE QUIET_LINE;
QUIET_LINE;
static struct option listen_options[] = { static struct option listen_options[] = {
@@ -45,6 +45,7 @@ static struct option listen_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char listen_short_options[] = "hl:p:f:s:d" SOPT_QUIET SOPT_VERBOSE; static char listen_short_options[] = "hl:p:f:s:d" SOPT_QUIET SOPT_VERBOSE;
static char listen_help_text[] = static char listen_help_text[] =
"Usage: flexnbd " CMD_LISTEN " <options> [<acl_address>*]\n\n" "Usage: flexnbd " CMD_LISTEN " <options> [<acl_address>*]\n\n"
@@ -54,9 +55,7 @@ static char listen_help_text[] =
"\t--" OPT_PORT ",-p <PORT>\tThe port to listen on.\n" "\t--" OPT_PORT ",-p <PORT>\tThe port to listen on.\n"
"\t--" OPT_FILE ",-f <FILE>\tThe file to serve.\n" "\t--" OPT_FILE ",-f <FILE>\tThe file to serve.\n"
"\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n" "\t--" OPT_DENY ",-d\tDeny connections by default unless in ACL.\n"
SOCK_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE;
VERBOSE_LINE
QUIET_LINE;
static struct option read_options[] = { static struct option read_options[] = {
GETOPT_HELP, GETOPT_HELP,
@@ -69,6 +68,7 @@ static struct option read_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char read_short_options[] = "hl:p:F:S:b:" SOPT_QUIET SOPT_VERBOSE; static char read_short_options[] = "hl:p:F:S:b:" SOPT_QUIET SOPT_VERBOSE;
static char read_help_text[] = static char read_help_text[] =
"Usage: flexnbd " CMD_READ " <options>\n\n" "Usage: flexnbd " CMD_READ " <options>\n\n"
@@ -78,24 +78,20 @@ static char read_help_text[] =
"\t--" OPT_PORT ",-p <PORT>\tThe port to read from.\n" "\t--" OPT_PORT ",-p <PORT>\tThe port to read from.\n"
"\t--" OPT_FROM ",-F <OFFSET>\tByte offset to read from.\n" "\t--" OPT_FROM ",-F <OFFSET>\tByte offset to read from.\n"
"\t--" OPT_SIZE ",-S <SIZE>\tBytes to read.\n" "\t--" OPT_SIZE ",-S <SIZE>\tBytes to read.\n"
BIND_LINE BIND_LINE VERBOSE_LINE QUIET_LINE;
VERBOSE_LINE
QUIET_LINE;
static struct option *write_options = read_options; static struct option *write_options = read_options;
static char *write_short_options = read_short_options; static char *write_short_options = read_short_options;
static char write_help_text[] = static char write_help_text[] =
"Usage: flexnbd " CMD_WRITE" <options>\n\n" "Usage: flexnbd " CMD_WRITE " <options>\n\n"
"Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n" "Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n"
HELP_LINE HELP_LINE
"\t--" OPT_ADDR ",-l <ADDR>\tThe address to write to.\n" "\t--" OPT_ADDR ",-l <ADDR>\tThe address to write to.\n"
"\t--" OPT_PORT ",-p <PORT>\tThe port to write to.\n" "\t--" OPT_PORT ",-p <PORT>\tThe port to write to.\n"
"\t--" OPT_FROM ",-F <OFFSET>\tByte offset to write from.\n" "\t--" OPT_FROM ",-F <OFFSET>\tByte offset to write from.\n"
"\t--" OPT_SIZE ",-S <SIZE>\tBytes to write.\n" "\t--" OPT_SIZE ",-S <SIZE>\tBytes to write.\n"
BIND_LINE BIND_LINE VERBOSE_LINE QUIET_LINE;
VERBOSE_LINE
QUIET_LINE;
static struct option acl_options[] = { static struct option acl_options[] = {
GETOPT_HELP, GETOPT_HELP,
@@ -104,14 +100,12 @@ static struct option acl_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char acl_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char acl_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE;
static char acl_help_text[] = static char acl_help_text[] =
"Usage: flexnbd " CMD_ACL " <options> [<acl address>+]\n\n" "Usage: flexnbd " CMD_ACL " <options> [<acl address>+]\n\n"
"Set the access control list for a server with control socket SOCK.\n\n" "Set the access control list for a server with control socket SOCK.\n\n"
HELP_LINE HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE;
SOCK_LINE
VERBOSE_LINE
QUIET_LINE;
static struct option mirror_speed_options[] = { static struct option mirror_speed_options[] = {
GETOPT_HELP, GETOPT_HELP,
@@ -121,15 +115,12 @@ static struct option mirror_speed_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char mirror_speed_short_options[] = "hs:m:" SOPT_QUIET SOPT_VERBOSE; static char mirror_speed_short_options[] = "hs:m:" SOPT_QUIET SOPT_VERBOSE;
static char mirror_speed_help_text[] = static char mirror_speed_help_text[] =
"Usage: flexnbd " CMD_MIRROR_SPEED " <options>\n\n" "Usage: flexnbd " CMD_MIRROR_SPEED " <options>\n\n"
"Set the maximum speed of a migration from a mirring server listening on SOCK.\n\n" "Set the maximum speed of a migration from a mirring server listening on SOCK.\n\n"
HELP_LINE HELP_LINE SOCK_LINE MAX_SPEED_LINE VERBOSE_LINE QUIET_LINE;
SOCK_LINE
MAX_SPEED_LINE
VERBOSE_LINE
QUIET_LINE;
static struct option mirror_options[] = { static struct option mirror_options[] = {
GETOPT_HELP, GETOPT_HELP,
@@ -142,6 +133,7 @@ static struct option mirror_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char mirror_short_options[] = "hs:l:p:ub:" SOPT_QUIET SOPT_VERBOSE; static char mirror_short_options[] = "hs:l:p:ub:" SOPT_QUIET SOPT_VERBOSE;
static char mirror_help_text[] = static char mirror_help_text[] =
"Usage: flexnbd " CMD_MIRROR " <options>\n\n" "Usage: flexnbd " CMD_MIRROR " <options>\n\n"
@@ -151,9 +143,7 @@ static char mirror_help_text[] =
"\t--" OPT_PORT ",-p <PORT>\tThe port to mirror to.\n" "\t--" OPT_PORT ",-p <PORT>\tThe port to mirror to.\n"
SOCK_LINE SOCK_LINE
"\t--" OPT_UNLINK ",-u\tUnlink the local file when done.\n" "\t--" OPT_UNLINK ",-u\tUnlink the local file when done.\n"
BIND_LINE BIND_LINE VERBOSE_LINE QUIET_LINE;
VERBOSE_LINE
QUIET_LINE;
static struct option break_options[] = { static struct option break_options[] = {
GETOPT_HELP, GETOPT_HELP,
@@ -162,14 +152,12 @@ static struct option break_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char break_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char break_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE;
static char break_help_text[] = static char break_help_text[] =
"Usage: flexnbd " CMD_BREAK " <options>\n\n" "Usage: flexnbd " CMD_BREAK " <options>\n\n"
"Stop mirroring from the server with control socket SOCK.\n\n" "Stop mirroring from the server with control socket SOCK.\n\n"
HELP_LINE HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE;
SOCK_LINE
VERBOSE_LINE
QUIET_LINE;
static struct option status_options[] = { static struct option status_options[] = {
@@ -179,14 +167,12 @@ static struct option status_options[] = {
GETOPT_VERBOSE, GETOPT_VERBOSE,
{0} {0}
}; };
static char status_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE; static char status_short_options[] = "hs:" SOPT_QUIET SOPT_VERBOSE;
static char status_help_text[] = static char status_help_text[] =
"Usage: flexnbd " CMD_STATUS " <options>\n\n" "Usage: flexnbd " CMD_STATUS " <options>\n\n"
"Get the status for a server with control socket SOCK.\n\n" "Get the status for a server with control socket SOCK.\n\n"
HELP_LINE HELP_LINE SOCK_LINE VERBOSE_LINE QUIET_LINE;
SOCK_LINE
VERBOSE_LINE
QUIET_LINE;
char help_help_text_arr[] = char help_help_text_arr[] =
"Usage: flexnbd <cmd> [cmd options]\n\n" "Usage: flexnbd <cmd> [cmd options]\n\n"
@@ -200,26 +186,26 @@ char help_help_text_arr[] =
"\tflexnbd mirror-speed\n" "\tflexnbd mirror-speed\n"
"\tflexnbd break\n" "\tflexnbd break\n"
"\tflexnbd status\n" "\tflexnbd status\n"
"\tflexnbd help\n\n" "\tflexnbd help\n\n" "See flexnbd help <cmd> for further info\n";
"See flexnbd help <cmd> for further info\n";
/* Slightly odd array/pointer pair to stop the compiler from complaining /* Slightly odd array/pointer pair to stop the compiler from complaining
* about symbol sizes * about symbol sizes
*/ */
char * help_help_text = help_help_text_arr; char *help_help_text = help_help_text_arr;
void do_read(struct mode_readwrite_params* params); void do_read(struct mode_readwrite_params *params);
void do_write(struct mode_readwrite_params* params); void do_write(struct mode_readwrite_params *params);
void do_remote_command(char* command, char* mode, int argc, char** argv); void do_remote_command(char *command, char *mode, int argc, char **argv);
void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char **sock, int *default_deny, int *use_killswitch ) void read_serve_param(int c, char **ip_addr, char **ip_port, char **file,
char **sock, int *default_deny, int *use_killswitch)
{ {
switch(c){ switch (c) {
case 'h': case 'h':
fprintf(stdout, "%s\n", serve_help_text ); fprintf(stdout, "%s\n", serve_help_text);
exit( 0 ); exit(0);
case 'l': case 'l':
*ip_addr = optarg; *ip_addr = optarg;
break; break;
@@ -245,22 +231,20 @@ void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char
*use_killswitch = 1; *use_killswitch = 1;
break; break;
default: default:
exit_err( serve_help_text ); exit_err(serve_help_text);
break; break;
} }
} }
void read_listen_param( int c, void read_listen_param(int c,
char **ip_addr, char **ip_addr,
char **ip_port, char **ip_port,
char **file, char **file, char **sock, int *default_deny)
char **sock,
int *default_deny )
{ {
switch(c){ switch (c) {
case 'h': case 'h':
fprintf(stdout, "%s\n", listen_help_text ); fprintf(stdout, "%s\n", listen_help_text);
exit(0); exit(0);
case 'l': case 'l':
*ip_addr = optarg; *ip_addr = optarg;
@@ -284,17 +268,19 @@ void read_listen_param( int c,
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( listen_help_text ); exit_err(listen_help_text);
break; break;
} }
} }
void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **bind_addr, char **from, char **size, char *err_text ) void read_readwrite_param(int c, char **ip_addr, char **ip_port,
char **bind_addr, char **from, char **size,
char *err_text)
{ {
switch(c){ switch (c) {
case 'h': case 'h':
fprintf(stdout, "%s\n", err_text ); fprintf(stdout, "%s\n", err_text);
exit( 0 ); exit(0);
case 'l': case 'l':
*ip_addr = optarg; *ip_addr = optarg;
break; break;
@@ -317,17 +303,17 @@ void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **bind_ad
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( err_text ); exit_err(err_text);
break; break;
} }
} }
void read_sock_param( int c, char **sock, char *help_text ) void read_sock_param(int c, char **sock, char *help_text)
{ {
switch(c){ switch (c) {
case 'h': case 'h':
fprintf( stdout, "%s\n", help_text ); fprintf(stdout, "%s\n", help_text);
exit( 0 ); exit(0);
case 's': case 's':
*sock = optarg; *sock = optarg;
break; break;
@@ -338,26 +324,22 @@ void read_sock_param( int c, char **sock, char *help_text )
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( help_text ); exit_err(help_text);
break; break;
} }
} }
void read_acl_param( int c, char **sock ) void read_acl_param(int c, char **sock)
{ {
read_sock_param( c, sock, acl_help_text ); read_sock_param(c, sock, acl_help_text);
} }
void read_mirror_speed_param( void read_mirror_speed_param(int c, char **sock, char **max_speed)
int c,
char **sock,
char **max_speed
)
{ {
switch( c ) { switch (c) {
case 'h': case 'h':
fprintf( stdout, "%s\n", mirror_speed_help_text ); fprintf(stdout, "%s\n", mirror_speed_help_text);
exit( 0 ); exit(0);
case 's': case 's':
*sock = optarg; *sock = optarg;
break; break;
@@ -371,24 +353,21 @@ void read_mirror_speed_param(
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( mirror_speed_help_text ); exit_err(mirror_speed_help_text);
break; break;
} }
} }
void read_mirror_param( void read_mirror_param(int c,
int c,
char **sock, char **sock,
char **ip_addr, char **ip_addr,
char **ip_port, char **ip_port, int *unlink, char **bind_addr)
int *unlink,
char **bind_addr )
{ {
switch( c ){ switch (c) {
case 'h': case 'h':
fprintf( stdout, "%s\n", mirror_help_text ); fprintf(stdout, "%s\n", mirror_help_text);
exit( 0 ); exit(0);
case 's': case 's':
*sock = optarg; *sock = optarg;
break; break;
@@ -411,17 +390,17 @@ void read_mirror_param(
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( mirror_help_text ); exit_err(mirror_help_text);
break; break;
} }
} }
void read_break_param( int c, char **sock ) void read_break_param(int c, char **sock)
{ {
switch( c ) { switch (c) {
case 'h': case 'h':
fprintf( stdout, "%s\n", break_help_text ); fprintf(stdout, "%s\n", break_help_text);
exit( 0 ); exit(0);
case 's': case 's':
*sock = optarg; *sock = optarg;
break; break;
@@ -432,18 +411,18 @@ void read_break_param( int c, char **sock )
log_level = VERBOSE_LOG_LEVEL; log_level = VERBOSE_LOG_LEVEL;
break; break;
default: default:
exit_err( break_help_text ); exit_err(break_help_text);
break; break;
} }
} }
void read_status_param( int c, char **sock ) void read_status_param(int c, char **sock)
{ {
read_sock_param( c, sock, status_help_text ); read_sock_param(c, sock, status_help_text);
} }
int mode_serve( int argc, char *argv[] ) int mode_serve(int argc, char *argv[])
{ {
int c; int c;
char *ip_addr = NULL; char *ip_addr = NULL;
@@ -456,35 +435,44 @@ int mode_serve( int argc, char *argv[] )
int success; int success;
struct flexnbd * flexnbd; struct flexnbd *flexnbd;
while (1) { while (1) {
c = getopt_long(argc, argv, serve_short_options, serve_options, NULL); c = getopt_long(argc, argv, serve_short_options, serve_options,
if ( c == -1 ) { break; } NULL);
if (c == -1) {
read_serve_param( c, &ip_addr, &ip_port, &file, &sock, &default_deny, &use_killswitch ); break;
} }
if ( NULL == ip_addr || NULL == ip_port ) { read_serve_param(c, &ip_addr, &ip_port, &file, &sock,
&default_deny, &use_killswitch);
}
if (NULL == ip_addr || NULL == ip_port) {
err = 1; err = 1;
fprintf( stderr, "both --addr and --port are required.\n" ); fprintf(stderr, "both --addr and --port are required.\n");
} }
if ( NULL == file ) { if (NULL == file) {
err = 1; err = 1;
fprintf( stderr, "--file is required\n" ); fprintf(stderr, "--file is required\n");
}
if (err) {
exit_err(serve_help_text);
} }
if ( err ) { exit_err( serve_help_text ); }
flexnbd = flexnbd_create_serving( ip_addr, ip_port, file, sock, default_deny, argc - optind, argv + optind, MAX_NBD_CLIENTS, use_killswitch ); flexnbd =
info( "Serving file %s", file ); flexnbd_create_serving(ip_addr, ip_port, file, sock, default_deny,
success = flexnbd_serve( flexnbd ); argc - optind, argv + optind,
flexnbd_destroy( flexnbd ); MAX_NBD_CLIENTS, use_killswitch);
info("Serving file %s", file);
success = flexnbd_serve(flexnbd);
flexnbd_destroy(flexnbd);
return success ? 0 : 1; return success ? 0 : 1;
} }
int mode_listen( int argc, char *argv[] ) int mode_listen(int argc, char *argv[])
{ {
int c; int c;
char *ip_addr = NULL; char *ip_addr = NULL;
@@ -496,36 +484,39 @@ int mode_listen( int argc, char *argv[] )
int success; int success;
struct flexnbd * flexnbd; struct flexnbd *flexnbd;
while (1) { while (1) {
c = getopt_long(argc, argv, listen_short_options, listen_options, NULL); c = getopt_long(argc, argv, listen_short_options, listen_options,
if ( c == -1 ) { break; } NULL);
if (c == -1) {
read_listen_param( c, &ip_addr, &ip_port, break;
&file, &sock, &default_deny );
} }
if ( NULL == ip_addr || NULL == ip_port ) { read_listen_param(c, &ip_addr, &ip_port,
&file, &sock, &default_deny);
}
if (NULL == ip_addr || NULL == ip_port) {
err = 1; err = 1;
fprintf( stderr, "both --addr and --port are required.\n" ); fprintf(stderr, "both --addr and --port are required.\n");
} }
if ( NULL == file ) { if (NULL == file) {
err = 1; err = 1;
fprintf( stderr, "--file is required\n" ); fprintf(stderr, "--file is required\n");
}
if (err) {
exit_err(listen_help_text);
} }
if ( err ) { exit_err( listen_help_text ); }
flexnbd = flexnbd_create_listening( flexnbd = flexnbd_create_listening(ip_addr,
ip_addr,
ip_port, ip_port,
file, file,
sock, sock,
default_deny, default_deny,
argc - optind, argc - optind, argv + optind);
argv + optind); success = flexnbd_serve(flexnbd);
success = flexnbd_serve( flexnbd ); flexnbd_destroy(flexnbd);
flexnbd_destroy( flexnbd );
return success ? 0 : 1; return success ? 0 : 1;
} }
@@ -545,67 +536,60 @@ int mode_listen( int argc, char *argv[] )
* char *s_length, * char *s_length,
* char *s_filename ) * char *s_filename )
*/ */
void params_readwrite( void params_readwrite(int write_not_read,
int write_not_read, struct mode_readwrite_params *out,
struct mode_readwrite_params* out, char *s_ip_address,
char* s_ip_address, char *s_port,
char* s_port, char *s_bind_address,
char* s_bind_address, char *s_from, char *s_length_or_filename)
char* s_from,
char* s_length_or_filename
)
{ {
FATAL_IF_NULL(s_ip_address, "No IP address supplied"); FATAL_IF_NULL(s_ip_address, "No IP address supplied");
FATAL_IF_NULL(s_port, "No port number supplied"); FATAL_IF_NULL(s_port, "No port number supplied");
FATAL_IF_NULL(s_from, "No from supplied"); FATAL_IF_NULL(s_from, "No from supplied");
FATAL_IF_NULL(s_length_or_filename, "No length supplied"); FATAL_IF_NULL(s_length_or_filename, "No length supplied");
FATAL_IF_ZERO( FATAL_IF_ZERO(parse_ip_to_sockaddr
parse_ip_to_sockaddr(&out->connect_to.generic, s_ip_address), (&out->connect_to.generic, s_ip_address),
"Couldn't parse connection address '%s'", "Couldn't parse connection address '%s'", s_ip_address);
s_ip_address
);
if (s_bind_address != NULL && if (s_bind_address != NULL &&
parse_ip_to_sockaddr(&out->connect_from.generic, s_bind_address) == 0) { parse_ip_to_sockaddr(&out->connect_from.generic,
s_bind_address) == 0) {
fatal("Couldn't parse bind address '%s'", s_bind_address); fatal("Couldn't parse bind address '%s'", s_bind_address);
} }
parse_port( s_port, &out->connect_to.v4 ); parse_port(s_port, &out->connect_to.v4);
long signed_from = atol(s_from); long signed_from = atol(s_from);
FATAL_IF_NEGATIVE( signed_from, FATAL_IF_NEGATIVE(signed_from,
"Can't read from a negative offset %d.", signed_from); "Can't read from a negative offset %d.",
signed_from);
out->from = signed_from; out->from = signed_from;
if (write_not_read) { if (write_not_read) {
if (s_length_or_filename[0]-48 < 10) { if (s_length_or_filename[0] - 48 < 10) {
out->len = atol(s_length_or_filename); out->len = atol(s_length_or_filename);
out->data_fd = 0; out->data_fd = 0;
} } else {
else { out->data_fd = open(s_length_or_filename, O_RDONLY);
out->data_fd = open(
s_length_or_filename, O_RDONLY);
FATAL_IF_NEGATIVE(out->data_fd, FATAL_IF_NEGATIVE(out->data_fd,
"Couldn't open %s", s_length_or_filename); "Couldn't open %s", s_length_or_filename);
off64_t signed_len = lseek64(out->data_fd, 0, SEEK_END); off64_t signed_len = lseek64(out->data_fd, 0, SEEK_END);
FATAL_IF_NEGATIVE(signed_len, FATAL_IF_NEGATIVE(signed_len,
"Couldn't find length of %s", s_length_or_filename); "Couldn't find length of %s",
s_length_or_filename);
out->len = signed_len; out->len = signed_len;
FATAL_IF_NEGATIVE( FATAL_IF_NEGATIVE(lseek64(out->data_fd, 0, SEEK_SET),
lseek64(out->data_fd, 0, SEEK_SET), "Couldn't rewind %s", s_length_or_filename);
"Couldn't rewind %s", s_length_or_filename
);
} }
} } else {
else {
out->len = atol(s_length_or_filename); out->len = atol(s_length_or_filename);
out->data_fd = 1; out->data_fd = 1;
} }
} }
int mode_read( int argc, char *argv[] ) int mode_read(int argc, char *argv[])
{ {
int c; int c;
char *ip_addr = NULL; char *ip_addr = NULL;
@@ -617,31 +601,38 @@ int mode_read( int argc, char *argv[] )
struct mode_readwrite_params readwrite; struct mode_readwrite_params readwrite;
while (1){ while (1) {
c = getopt_long(argc, argv, read_short_options, read_options, NULL); c = getopt_long(argc, argv, read_short_options, read_options,
NULL);
if ( c == -1 ) { break; } if (c == -1) {
break;
read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size, read_help_text );
} }
if ( NULL == ip_addr || NULL == ip_port ) { read_readwrite_param(c, &ip_addr, &ip_port, &bind_addr, &from,
&size, read_help_text);
}
if (NULL == ip_addr || NULL == ip_port) {
err = 1; err = 1;
fprintf( stderr, "both --addr and --port are required.\n" ); fprintf(stderr, "both --addr and --port are required.\n");
} }
if ( NULL == from || NULL == size ) { if (NULL == from || NULL == size) {
err = 1; err = 1;
fprintf( stderr, "both --from and --size are required.\n" ); fprintf(stderr, "both --from and --size are required.\n");
}
if (err) {
exit_err(read_help_text);
} }
if ( err ) { exit_err( read_help_text ); }
memset( &readwrite, 0, sizeof( readwrite ) ); memset(&readwrite, 0, sizeof(readwrite));
params_readwrite( 0, &readwrite, ip_addr, ip_port, bind_addr, from, size ); params_readwrite(0, &readwrite, ip_addr, ip_port, bind_addr, from,
do_read( &readwrite ); size);
do_read(&readwrite);
return 0; return 0;
} }
int mode_write( int argc, char *argv[] ) int mode_write(int argc, char *argv[])
{ {
int c; int c;
char *ip_addr = NULL; char *ip_addr = NULL;
@@ -653,232 +644,246 @@ int mode_write( int argc, char *argv[] )
struct mode_readwrite_params readwrite; struct mode_readwrite_params readwrite;
while (1){ while (1) {
c = getopt_long(argc, argv, write_short_options, write_options, NULL); c = getopt_long(argc, argv, write_short_options, write_options,
if ( c == -1 ) { break; } NULL);
if (c == -1) {
read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size, write_help_text ); break;
} }
if ( NULL == ip_addr || NULL == ip_port ) { read_readwrite_param(c, &ip_addr, &ip_port, &bind_addr, &from,
&size, write_help_text);
}
if (NULL == ip_addr || NULL == ip_port) {
err = 1; err = 1;
fprintf( stderr, "both --addr and --port are required.\n" ); fprintf(stderr, "both --addr and --port are required.\n");
} }
if ( NULL == from || NULL == size ) { if (NULL == from || NULL == size) {
err = 1; err = 1;
fprintf( stderr, "both --from and --size are required.\n" ); fprintf(stderr, "both --from and --size are required.\n");
}
if (err) {
exit_err(write_help_text);
} }
if ( err ) { exit_err( write_help_text ); }
memset( &readwrite, 0, sizeof( readwrite ) ); memset(&readwrite, 0, sizeof(readwrite));
params_readwrite( 1, &readwrite, ip_addr, ip_port, bind_addr, from, size ); params_readwrite(1, &readwrite, ip_addr, ip_port, bind_addr, from,
do_write( &readwrite ); size);
do_write(&readwrite);
return 0; return 0;
} }
int mode_acl( int argc, char *argv[] ) int mode_acl(int argc, char *argv[])
{ {
int c; int c;
char *sock = NULL; char *sock = NULL;
while (1) { while (1) {
c = getopt_long( argc, argv, acl_short_options, acl_options, NULL ); c = getopt_long(argc, argv, acl_short_options, acl_options, NULL);
if ( c == -1 ) { break; } if (c == -1) {
read_acl_param( c, &sock ); break;
}
read_acl_param(c, &sock);
} }
if ( NULL == sock ){ if (NULL == sock) {
fprintf( stderr, "--sock is required.\n" ); fprintf(stderr, "--sock is required.\n");
exit_err( acl_help_text ); exit_err(acl_help_text);
} }
/* Don't use the CMD_ACL macro here, "acl" is the remote command /* Don't use the CMD_ACL macro here, "acl" is the remote command
* name, not the cli option * name, not the cli option
*/ */
do_remote_command( "acl", sock, argc - optind, argv + optind ); do_remote_command("acl", sock, argc - optind, argv + optind);
return 0; return 0;
} }
int mode_mirror_speed( int argc, char *argv[] ) int mode_mirror_speed(int argc, char *argv[])
{ {
int c; int c;
char *sock = NULL; char *sock = NULL;
char *speed = NULL; char *speed = NULL;
while( 1 ) { while (1) {
c = getopt_long( argc, argv, mirror_speed_short_options, mirror_speed_options, NULL ); c = getopt_long(argc, argv, mirror_speed_short_options,
if ( -1 == c ) { break; } mirror_speed_options, NULL);
read_mirror_speed_param( c, &sock, &speed ); if (-1 == c) {
break;
}
read_mirror_speed_param(c, &sock, &speed);
} }
if ( NULL == sock ) { if (NULL == sock) {
fprintf( stderr, "--sock is required.\n" ); fprintf(stderr, "--sock is required.\n");
exit_err( mirror_speed_help_text ); exit_err(mirror_speed_help_text);
} }
if ( NULL == speed ) { if (NULL == speed) {
fprintf( stderr, "--max-speed is required.\n"); fprintf(stderr, "--max-speed is required.\n");
exit_err( mirror_speed_help_text ); exit_err(mirror_speed_help_text);
} }
do_remote_command( "mirror_max_bps", sock, 1, &speed ); do_remote_command("mirror_max_bps", sock, 1, &speed);
return 0; return 0;
} }
int mode_mirror( int argc, char *argv[] ) int mode_mirror(int argc, char *argv[])
{ {
int c; int c;
char *sock = NULL; char *sock = NULL;
char *remote_argv[4] = {0}; char *remote_argv[4] = { 0 };
int err = 0; int err = 0;
int unlink = 0; int unlink = 0;
remote_argv[2] = "exit"; remote_argv[2] = "exit";
while (1) { while (1) {
c = getopt_long( argc, argv, mirror_short_options, mirror_options, NULL); c = getopt_long(argc, argv, mirror_short_options, mirror_options,
if ( -1 == c ) { break; } NULL);
read_mirror_param( c, if (-1 == c) {
break;
}
read_mirror_param(c,
&sock, &sock,
&remote_argv[0], &remote_argv[0],
&remote_argv[1], &remote_argv[1], &unlink, &remote_argv[3]);
&unlink,
&remote_argv[3] );
} }
if ( NULL == sock ){ if (NULL == sock) {
fprintf( stderr, "--sock is required.\n" ); fprintf(stderr, "--sock is required.\n");
err = 1; err = 1;
} }
if ( NULL == remote_argv[0] || NULL == remote_argv[1] ) { if (NULL == remote_argv[0] || NULL == remote_argv[1]) {
fprintf( stderr, "both --addr and --port are required.\n"); fprintf(stderr, "both --addr and --port are required.\n");
err = 1; err = 1;
} }
if ( err ) { exit_err( mirror_help_text ); } if (err) {
if ( unlink ) { remote_argv[2] = "unlink"; } exit_err(mirror_help_text);
}
if (unlink) {
remote_argv[2] = "unlink";
}
if (remote_argv[3] == NULL) { if (remote_argv[3] == NULL) {
do_remote_command( "mirror", sock, 3, remote_argv ); do_remote_command("mirror", sock, 3, remote_argv);
} } else {
else { do_remote_command("mirror", sock, 4, remote_argv);
do_remote_command( "mirror", sock, 4, remote_argv );
} }
return 0; return 0;
} }
int mode_break( int argc, char *argv[] ) int mode_break(int argc, char *argv[])
{ {
int c; int c;
char *sock = NULL; char *sock = NULL;
while (1) { while (1) {
c = getopt_long( argc, argv, break_short_options, break_options, NULL ); c = getopt_long(argc, argv, break_short_options, break_options,
if ( -1 == c ) { break; } NULL);
read_break_param( c, &sock ); if (-1 == c) {
break;
}
read_break_param(c, &sock);
} }
if ( NULL == sock ){ if (NULL == sock) {
fprintf( stderr, "--sock is required.\n" ); fprintf(stderr, "--sock is required.\n");
exit_err( break_help_text ); exit_err(break_help_text);
} }
do_remote_command( "break", sock, argc - optind, argv + optind ); do_remote_command("break", sock, argc - optind, argv + optind);
return 0; return 0;
} }
int mode_status( int argc, char *argv[] ) int mode_status(int argc, char *argv[])
{ {
int c; int c;
char *sock = NULL; char *sock = NULL;
while (1) { while (1) {
c = getopt_long( argc, argv, status_short_options, status_options, NULL ); c = getopt_long(argc, argv, status_short_options, status_options,
if ( -1 == c ) { break; } NULL);
read_status_param( c, &sock ); if (-1 == c) {
break;
}
read_status_param(c, &sock);
} }
if ( NULL == sock ){ if (NULL == sock) {
fprintf( stderr, "--sock is required.\n" ); fprintf(stderr, "--sock is required.\n");
exit_err( status_help_text ); exit_err(status_help_text);
} }
do_remote_command( "status", sock, argc - optind, argv + optind ); do_remote_command("status", sock, argc - optind, argv + optind);
return 0; return 0;
} }
int mode_help( int argc, char *argv[] ) int mode_help(int argc, char *argv[])
{ {
char *cmd; char *cmd;
char *help_text = NULL; char *help_text = NULL;
if ( argc < 1 ){ if (argc < 1) {
help_text = help_help_text; help_text = help_help_text;
} else { } else {
cmd = argv[0]; cmd = argv[0];
if (IS_CMD( CMD_SERVE, cmd ) ) { if (IS_CMD(CMD_SERVE, cmd)) {
help_text = serve_help_text; help_text = serve_help_text;
} else if ( IS_CMD( CMD_LISTEN, cmd ) ) { } else if (IS_CMD(CMD_LISTEN, cmd)) {
help_text = listen_help_text; help_text = listen_help_text;
} else if ( IS_CMD( CMD_READ, cmd ) ) { } else if (IS_CMD(CMD_READ, cmd)) {
help_text = read_help_text; help_text = read_help_text;
} else if ( IS_CMD( CMD_WRITE, cmd ) ) { } else if (IS_CMD(CMD_WRITE, cmd)) {
help_text = write_help_text; help_text = write_help_text;
} else if ( IS_CMD( CMD_ACL, cmd ) ) { } else if (IS_CMD(CMD_ACL, cmd)) {
help_text = acl_help_text; help_text = acl_help_text;
} else if ( IS_CMD( CMD_MIRROR, cmd ) ) { } else if (IS_CMD(CMD_MIRROR, cmd)) {
help_text = mirror_help_text; help_text = mirror_help_text;
} else if ( IS_CMD( CMD_STATUS, cmd ) ) { } else if (IS_CMD(CMD_STATUS, cmd)) {
help_text = status_help_text; help_text = status_help_text;
} else { exit_err( help_help_text ); } } else {
exit_err(help_help_text);
}
} }
fprintf( stdout, "%s\n", help_text ); fprintf(stdout, "%s\n", help_text);
return 0; return 0;
} }
void mode(char* mode, int argc, char **argv) void mode(char *mode, int argc, char **argv)
{ {
if ( IS_CMD( CMD_SERVE, mode ) ) { if (IS_CMD(CMD_SERVE, mode)) {
exit( mode_serve( argc, argv ) ); exit(mode_serve(argc, argv));
} } else if (IS_CMD(CMD_LISTEN, mode)) {
else if ( IS_CMD( CMD_LISTEN, mode ) ) { exit(mode_listen(argc, argv));
exit( mode_listen( argc, argv ) ); } else if (IS_CMD(CMD_READ, mode)) {
} mode_read(argc, argv);
else if ( IS_CMD( CMD_READ, mode ) ) { } else if (IS_CMD(CMD_WRITE, mode)) {
mode_read( argc, argv ); mode_write(argc, argv);
} } else if (IS_CMD(CMD_ACL, mode)) {
else if ( IS_CMD( CMD_WRITE, mode ) ) { mode_acl(argc, argv);
mode_write( argc, argv ); } else if (IS_CMD(CMD_MIRROR_SPEED, mode)) {
} mode_mirror_speed(argc, argv);
else if ( IS_CMD( CMD_ACL, mode ) ) { } else if (IS_CMD(CMD_MIRROR, mode)) {
mode_acl( argc, argv ); mode_mirror(argc, argv);
} else if ( IS_CMD ( CMD_MIRROR_SPEED, mode ) ) { } else if (IS_CMD(CMD_BREAK, mode)) {
mode_mirror_speed( argc, argv ); mode_break(argc, argv);
} } else if (IS_CMD(CMD_STATUS, mode)) {
else if ( IS_CMD( CMD_MIRROR, mode ) ) { mode_status(argc, argv);
mode_mirror( argc, argv ); } else if (IS_CMD(CMD_HELP, mode)) {
} mode_help(argc - 1, argv + 1);
else if ( IS_CMD( CMD_BREAK, mode ) ) { } else {
mode_break( argc, argv ); mode_help(argc - 1, argv + 1);
} exit(1);
else if ( IS_CMD( CMD_STATUS, mode ) ) {
mode_status( argc, argv );
}
else if ( IS_CMD( CMD_HELP, mode ) ) {
mode_help( argc-1, argv+1 );
}
else {
mode_help( argc-1, argv+1 );
exit( 1 );
} }
exit(0); exit(0);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -10,13 +10,13 @@
#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;
}; };
@@ -26,38 +26,38 @@ struct client_tbl_entry {
#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;
@@ -76,7 +76,7 @@ struct server {
* 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;
@@ -103,56 +103,54 @@ struct server {
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 use_killswitch, int success);
int success ); void server_destroy(struct server *);
void server_destroy( struct server * ); int server_is_closed(struct server *serve);
int server_is_closed(struct server* serve); void serve_signal_close(struct server *serve);
void serve_signal_close( struct server *serve ); void serve_wait_for_close(struct server *serve);
void serve_wait_for_close( struct server * serve ); void server_replace_acl(struct server *serve, struct acl *acl);
void server_replace_acl( struct server *serve, struct acl * acl); void server_control_arrived(struct server *serve);
void server_control_arrived( struct server *serve ); int server_is_in_control(struct server *serve);
int server_is_in_control( struct server *serve ); int server_default_deny(struct server *serve);
int server_default_deny( struct server * serve ); int server_acl_locked(struct server *serve);
int server_acl_locked( struct server * serve ); void server_lock_acl(struct server *serve);
void server_lock_acl( struct server *serve ); void server_unlock_acl(struct server *serve);
void server_unlock_acl( struct server *serve ); void server_lock_start_mirror(struct server *serve);
void server_lock_start_mirror( struct server *serve ); void server_unlock_start_mirror(struct server *serve);
void server_unlock_start_mirror( struct server *serve ); int server_is_mirroring(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;
@@ -167,4 +165,3 @@ struct mode_readwrite_params {
#endif #endif

View File

@@ -2,39 +2,42 @@
#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) {
status->migration_duration -= serve->mirror->migration_started; status->migration_duration -= serve->mirror->migration_started;
} else { } else {
status->migration_duration = 0; status->migration_duration = 0;
} }
status->migration_duration /= 1000; status->migration_duration /= 1000;
status->migration_speed = server_mirror_bps( serve ); status->migration_speed = server_mirror_bps(serve);
status->migration_speed_limit = serve->mirror->max_bytes_per_second; status->migration_speed_limit =
serve->mirror->max_bytes_per_second;
status->migration_seconds_left = server_mirror_eta( serve ); status->migration_seconds_left = server_mirror_eta(serve);
status->migration_bytes_left = server_mirror_bytes_remaining( serve ); status->migration_bytes_left =
server_mirror_bytes_remaining(serve);
} }
server_unlock_start_mirror( serve ); server_unlock_start_mirror(serve);
return status; return status;
@@ -48,22 +51,22 @@ 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);
}; };
} }
@@ -72,9 +75,8 @@ int status_write( struct status * status, int fd )
} }
void status_destroy( struct status * status ) void status_destroy(struct status *status)
{ {
NULLCHECK( status ); NULLCHECK(status);
free( status ); free(status);
} }

View File

@@ -90,15 +90,14 @@ struct status {
}; };
/** 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,179 +4,178 @@
#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 END_TEST
START_TEST( test_parses_multiple_lines ) 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 0 has wrong family!");
entry = &(*acl->entries)[1]; entry = &(*acl->entries)[1];
fail_unless(entry->ip.family == e1.family, "entry 1 has wrong family!"); fail_unless(entry->ip.family == e1.family,
"entry 1 has wrong family!");
} }
END_TEST END_TEST
START_TEST( test_destroy_doesnt_crash ) 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 END_TEST
START_TEST( test_default_deny_rejects ) 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");
@@ -189,14 +188,19 @@ Suite* acl_suite(void)
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);
@@ -226,4 +230,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -10,7 +10,7 @@
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)); \
@@ -27,7 +27,7 @@ END_TEST
START_TEST(test_bit_clear) 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)); \
@@ -37,14 +37,14 @@ START_TEST(test_bit_clear)
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 END_TEST
START_TEST(test_bit_tests) 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");
@@ -64,20 +64,20 @@ START_TEST(test_bit_ranges)
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 END_TEST
@@ -85,27 +85,25 @@ END_TEST
START_TEST(test_bit_runs) 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",
i, runs[i], run
);
ptr += runs[i]; ptr += runs[i];
} }
} }
@@ -113,23 +111,23 @@ END_TEST
START_TEST(test_bitset) 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;
@@ -145,313 +143,315 @@ START_TEST(test_bitset)
} }
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 END_TEST
START_TEST( test_bitset_set_range ) 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 END_TEST
START_TEST( test_bitset_clear_range ) 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 END_TEST
START_TEST( test_bitset_run_count ) 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 END_TEST
START_TEST( test_bitset_set_range_doesnt_push_to_stream ) 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 END_TEST
START_TEST( test_bitset_clear_range_doesnt_push_to_stream ) 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 END_TEST
START_TEST(test_bitset_enable_stream) 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 END_TEST
START_TEST(test_bitset_disable_stream) 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 END_TEST
START_TEST(test_bitset_stream_with_set_range) 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 END_TEST
START_TEST(test_bitset_stream_with_clear_range) 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 END_TEST
START_TEST(test_bitset_stream_size) 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 END_TEST
START_TEST(test_bitset_stream_queued_bytes) 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 END_TEST
Suite* bitset_suite(void) Suite * bitset_suite(void)
{ {
Suite *s = suite_create("bitset"); Suite *s = suite_create("bitset");
@@ -471,7 +471,8 @@ Suite* bitset_suite(void)
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,
test_bitset_clear_range_doesnt_push_to_stream);
suite_add_tcase(s, tc_bitset); suite_add_tcase(s, tc_bitset);
@@ -497,4 +498,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,83 +9,79 @@
#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");
@@ -99,7 +95,7 @@ Suite *client_suite(void)
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);
@@ -119,4 +115,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,26 +4,25 @@
#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;
} }
@@ -39,4 +38,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -3,29 +3,27 @@
#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;
} }
@@ -41,4 +39,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,38 +4,39 @@
#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);
@@ -59,4 +60,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -2,117 +2,116 @@
#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 );
close( fds[1] );
nread = read_until_newline( fds[0], buf, 5 );
ck_assert_int_eq( -1, nread );
}
END_TEST
START_TEST( test_read_eof_fills_line )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe(fds); pipe(fds);
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] );
} }
END_TEST END_TEST
START_TEST(test_read_eof_fills_line)
{
int fds[2];
int nread;
char buf[5] = { 0 };
pipe(fds);
START_TEST( test_read_lines_until_blankline ) write(fds[1], "1234", 4);
close(fds[1]);
nread = read_until_newline(fds[0], buf, 5);
ck_assert_int_eq(-1, nread);
ck_assert_int_eq('4', buf[3]);
}
END_TEST
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,
test_read_until_newline_inserts_null);
tcase_add_test(tc_read_until_newline,
test_read_empty_line_inserts_null);
tcase_add_test(tc_read_until_newline, test_read_eof_returns_err); tcase_add_test(tc_read_until_newline, test_read_eof_returns_err);
tcase_add_test(tc_read_until_newline, test_read_eof_fills_line ); 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);
@@ -131,4 +130,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -4,69 +4,65 @@
#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");
@@ -74,8 +70,8 @@ Suite* mbox_suite(void)
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);
@@ -101,4 +97,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -7,62 +7,65 @@ 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 END_TEST
@@ -72,113 +75,112 @@ START_TEST(test_request_type)
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 END_TEST
@@ -187,19 +189,20 @@ 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 */
@@ -212,36 +215,36 @@ START_TEST( test_convert_from )
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 END_TEST
Suite *nbdtypes_suite(void) 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_flags ); tcase_add_test(tc_request, test_request_flags);
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;
@@ -258,4 +261,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -3,19 +3,17 @@
#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");
@@ -28,9 +26,9 @@ Suite* parse_suite(void)
} }
#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)
@@ -44,4 +42,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -21,13 +21,13 @@
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;
@@ -41,113 +41,112 @@ struct respond {
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 { } else {
nbd_r2h_request( &request_raw, &resp->received); nbd_r2h_request(&request_raw, &resp->received);
if (resp->do_fail){ if (resp->do_fail) {
fd_write_reply( sock_fd, wrong_handle, 0 ); fd_write_reply(sock_fd, wrong_handle, 0);
} else {
fd_write_reply(sock_fd, resp->received.handle.w, 0);
} }
else { write(sock_fd, "12345678", 8);
fd_write_reply( sock_fd, resp->received.handle.w, 0 );
}
write( sock_fd, "12345678", 8 );
} }
return NULL; 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));
socketpair(PF_UNIX, SOCK_STREAM, 0, respond->sock_fds);
respond->do_fail = do_fail; 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 ); {
NULLCHECK(respond);
pthread_join( respond->thread_id, NULL ); pthread_join(respond->thread_id, NULL);
pthread_attr_destroy( &respond->thread_attr ); pthread_attr_destroy(&respond->thread_attr);
close( respond->sock_fds[0] ); close(respond->sock_fds[0]);
close( respond->sock_fds[1] ); close(respond->sock_fds[1]);
free( respond ); free(respond);
} }
void * reader( void * nothing __attribute__((unused))) void *reader(void *nothing __attribute__ ((unused)))
{ {
DECLARE_ERROR_CONTEXT( error_context ); DECLARE_ERROR_CONTEXT(error_context);
error_set_handler( (cleanup_handler *)error_marker, error_context ); error_set_handler((cleanup_handler *) error_marker, error_context);
struct respond * respond = respond_create( 1 ); struct respond *respond = respond_create(1);
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);
return NULL; return NULL;
} }
START_TEST( test_rejects_mismatched_handle ) 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");
@@ -162,7 +161,8 @@ Suite* readwrite_suite(void)
* 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);
@@ -173,9 +173,9 @@ Suite* readwrite_suite(void)
#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)
@@ -190,4 +190,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -9,141 +9,139 @@
#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 END_TEST
void *signal_thread(void *thing)
void * signal_thread( void * thing )
{ {
struct self_pipe *sig = (struct self_pipe *)thing; struct self_pipe *sig = (struct self_pipe *) thing;
usleep( 100000 ); usleep(100000);
self_pipe_signal( sig ); self_pipe_signal(sig);
return NULL; return NULL;
} }
pthread_t start_signal_thread( struct self_pipe *sig ) pthread_t start_signal_thread(struct self_pipe * sig)
{ {
pthread_attr_t attr; pthread_attr_t attr;
pthread_t thread_id; pthread_t thread_id;
pthread_attr_init( &attr ); pthread_attr_init(&attr);
pthread_create( &thread_id, &attr, signal_thread, sig ); pthread_create(&thread_id, &attr, signal_thread, sig);
pthread_attr_destroy( &attr ); pthread_attr_destroy(&attr);
return thread_id; 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 ); self_pipe_signal_clear(sig);
fail_unless( self_pipe_fd_isset( sig, &fds ), "Signalled pipe was not FD_ISSET." ); fail_unless(self_pipe_fd_isset(sig, &fds),
pthread_join( signal_thread_id, NULL ); "Signalled pipe was not FD_ISSET.");
pthread_join(signal_thread_id, NULL);
self_pipe_destroy( sig ); self_pipe_destroy(sig);
} }
END_TEST END_TEST
START_TEST(test_clear_returns_immediately)
START_TEST( test_clear_returns_immediately )
{ {
struct self_pipe *sig; struct self_pipe *sig;
sig = self_pipe_create(); sig = self_pipe_create();
fail_unless( 0 == self_pipe_signal_clear( sig ), "Wrong clear result." ); fail_unless(0 == self_pipe_signal_clear(sig), "Wrong clear result.");
} }
END_TEST END_TEST
START_TEST(test_destroy_closes_read_pipe)
START_TEST( test_destroy_closes_read_pipe )
{ {
struct self_pipe* sig; struct self_pipe *sig;
ssize_t read_len; ssize_t read_len;
int orig_read_fd; int orig_read_fd;
sig = self_pipe_create(); sig = self_pipe_create();
orig_read_fd = sig->read_fd; orig_read_fd = sig->read_fd;
self_pipe_destroy( sig ); self_pipe_destroy(sig);
while( (read_len = read( orig_read_fd, "", 0 )) == -1 && errno == EINTR ); while ((read_len = read(orig_read_fd, "", 0)) == -1 && errno == EINTR);
switch( read_len ) { switch (read_len) {
case 0: case 0:
fail("The read fd wasn't closed." ); fail("The read fd wasn't closed.");
break; break;
case -1: case -1:
switch(errno) { switch (errno) {
case EBADF: case EBADF:
/* This is what we want */ /* This is what we want */
break; break;
case EAGAIN: case EAGAIN:
fail( "The read fd wasn't closed." ); fail("The read fd wasn't closed.");
break; break;
default: default:
fail( strerror( errno ) ); fail(strerror(errno));
break; break;
} }
break; break;
default: default:
fail( "The read fd wasn't closed, and had data in it." ); fail("The read fd wasn't closed, and had data in it.");
break; break;
} }
} }
END_TEST END_TEST
START_TEST(test_destroy_closes_write_pipe)
START_TEST( test_destroy_closes_write_pipe )
{ {
struct self_pipe * sig; struct self_pipe *sig;
ssize_t write_len; ssize_t write_len;
int orig_write_fd; int orig_write_fd;
sig = self_pipe_create(); sig = self_pipe_create();
orig_write_fd = sig->write_fd; orig_write_fd = sig->write_fd;
self_pipe_destroy( sig ); self_pipe_destroy(sig);
while ( ( write_len = write( orig_write_fd, "", 0 ) ) == -1 && errno == EINTR ); while ((write_len = write(orig_write_fd, "", 0)) == -1
&& errno == EINTR);
switch( write_len ) { switch (write_len) {
case 0: case 0:
fail( "The write fd wasn't closed." ); fail("The write fd wasn't closed.");
break; break;
case -1: case -1:
switch( errno ) { switch (errno) {
case EPIPE: case EPIPE:
case EBADF: case EBADF:
/* This is what we want */ /* This is what we want */
break; break;
case EAGAIN: case EAGAIN:
fail("The write fd wasn't closed." ); fail("The write fd wasn't closed.");
break; break;
default: default:
fail( strerror( errno ) ); fail(strerror(errno));
break; break;
} }
break; break;
@@ -151,16 +149,14 @@ START_TEST( test_destroy_closes_write_pipe )
/* To get here, the write(_,_,0) would have to /* To get here, the write(_,_,0) would have to
* write some bytes. * write some bytes.
*/ */
fail( "The write fd wasn't closed, and something REALLY WEIRD is going on." ); fail("The write fd wasn't closed, and something REALLY WEIRD is going on.");
break; break;
} }
} }
END_TEST END_TEST
Suite * self_pipe_suite(void)
Suite *self_pipe_suite(void)
{ {
Suite *s = suite_create("self_pipe"); Suite *s = suite_create("self_pipe");
@@ -169,10 +165,10 @@ Suite *self_pipe_suite(void)
TCase *tc_destroy = tcase_create("destroy"); TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_opens_pipe); tcase_add_test(tc_create, test_opens_pipe);
tcase_add_test(tc_signal, test_signals ); tcase_add_test(tc_signal, test_signals);
tcase_add_test(tc_signal, test_clear_returns_immediately ); 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_read_pipe);
tcase_add_test(tc_destroy, test_destroy_closes_write_pipe ); tcase_add_test(tc_destroy, test_destroy_closes_write_pipe);
/* We don't test that destroy free()'s the self_pipe pointer because /* We don't test that destroy free()'s the self_pipe pointer because
* that'll be caught by valgrind. * that'll be caught by valgrind.
*/ */
@@ -195,4 +191,3 @@ int main(void)
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,7 +28,7 @@
#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)
{ {
@@ -36,62 +36,66 @@ char *make_tmpfile(void)
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);
}
free(dummy_file);
dummy_file = NULL; 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;
@@ -101,46 +105,51 @@ int connect_client( char *addr, int actual_port, char *source_addr )
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 (client_fd == -1) {
if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) { continue;
}
if (connect(client_fd, aip->ai_addr, aip->ai_addrlen) == 0) {
connected = 1; connected = 1;
break; break;
} }
close( client_fd ); close(client_fd);
} }
myfail_unless( connected, "Didn't connect." ); myfail_unless(connected, "Didn't connect.");
return client_fd; 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
@@ -148,101 +157,105 @@ START_TEST( test_acl_update_closes_bad_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 =
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);
@@ -261,4 +274,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -6,96 +6,100 @@
#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 END_TEST
Suite *sockutil_suite(void) 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);
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); suite_add_tcase(s, tc_sockaddr_address_string);
return s; return s;
@@ -112,4 +116,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -6,134 +6,133 @@
#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 END_TEST
START_TEST( test_gets_has_control ) 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 END_TEST
START_TEST( test_gets_clients_allowed ) 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 END_TEST
START_TEST( test_gets_pid ) 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 END_TEST
START_TEST( test_gets_size ) 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 END_TEST
START_TEST( test_gets_migration_statistics ) 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;
@@ -141,194 +140,174 @@ START_TEST( test_gets_migration_statistics )
/* 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]);
status.has_control = 1; fail_unless_rendered(fds[0], "has_control=true");
status_write( &status, fds[1] );
fail_unless_rendered( fds[0], "has_control=true" );
status.has_control = 0; status.has_control = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "has_control=false" ); 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]);
status.is_mirroring = 1; fail_unless_rendered(fds[0], "is_mirroring=true");
status_write( &status, fds[1] );
fail_unless_rendered( fds[0], "is_mirroring=true" );
status.is_mirroring = 0; status.is_mirroring = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "is_mirroring=false" ); fail_unless_rendered(fds[0], "is_mirroring=false");
} }
END_TEST END_TEST
START_TEST( test_renders_clients_allowed ) START_TEST(test_renders_clients_allowed)
{ {
RENDER_TEST_SETUP RENDER_TEST_SETUP status.clients_allowed = 1;
status_write(&status, fds[1]);
status.clients_allowed = 1; fail_unless_rendered(fds[0], "clients_allowed=true");
status_write( &status, fds[1] );
fail_unless_rendered( fds[0], "clients_allowed=true" );
status.clients_allowed = 0; status.clients_allowed = 0;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "clients_allowed=false" ); fail_unless_rendered(fds[0], "clients_allowed=false");
} }
END_TEST END_TEST
START_TEST( test_renders_num_clients ) START_TEST(test_renders_num_clients)
{ {
RENDER_TEST_SETUP RENDER_TEST_SETUP status.num_clients = 0;
status_write(&status, fds[1]);
status.num_clients = 0; fail_unless_rendered(fds[0], "num_clients=0");
status_write( &status, fds[1] );
fail_unless_rendered( fds[0], "num_clients=0" );
status.num_clients = 4000; status.num_clients = 4000;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "num_clients=4000" ); 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 END_TEST
START_TEST( test_renders_size ) 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 END_TEST
START_TEST( test_renders_migration_statistics ) START_TEST(test_renders_migration_statistics)
{ {
RENDER_TEST_SETUP RENDER_TEST_SETUP status.is_mirroring = 0;
status.is_mirroring = 0;
status.migration_duration = 8; status.migration_duration = 8;
status.migration_speed = 40000000; status.migration_speed = 40000000;
status.migration_speed_limit = 40000001; status.migration_speed_limit = 40000001;
status.migration_seconds_left = 1; status.migration_seconds_left = 1;
status.migration_bytes_left = 5000; 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_duration");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_speed" ); fail_if_rendered(fds[0], "migration_speed");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_speed_limit" ); fail_if_rendered(fds[0], "migration_speed_limit");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_seconds_left" ); fail_if_rendered(fds[0], "migration_seconds_left");
status.is_mirroring = 1; status.is_mirroring = 1;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_duration=8" ); fail_unless_rendered(fds[0], "migration_duration=8");
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=40000000");
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_speed_limit=40000001");
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_seconds_left=1");
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_unless_rendered( fds[0], "migration_bytes_left=5000" ); fail_unless_rendered(fds[0], "migration_bytes_left=5000");
status.migration_speed_limit = UINT64_MAX; status.migration_speed_limit = UINT64_MAX;
status_write( &status, fds[1] ); status_write(&status, fds[1]);
fail_if_rendered( fds[0], "migration_speed_limit" ); 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");
@@ -368,4 +347,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }

View File

@@ -14,9 +14,10 @@ struct cleanup_bucket {
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();
} }
@@ -28,13 +29,14 @@ void setup(void)
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);
} }
} }
@@ -42,116 +44,110 @@ void dummy_cleanup( struct cleanup_bucket * foo, int fatal __attribute__((unused
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);
@@ -170,4 +166,3 @@ int main(void)
srunner_free(sr); srunner_free(sr);
return (number_failed == 0) ? 0 : 1; return (number_failed == 0) ? 0 : 1;
} }