Formatted all code using indent
This commit is contained in:
3
CONTRIBUTING.md
Normal file
3
CONTRIBUTING.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Contribution guide
|
||||
|
||||
The code is formatted using the K&R style of "indent".
|
@@ -13,228 +13,236 @@
|
||||
#include "ioutil.h"
|
||||
|
||||
|
||||
int build_allocation_map(struct bitset * allocation_map, int fd)
|
||||
int build_allocation_map(struct bitset *allocation_map, int fd)
|
||||
{
|
||||
/* break blocking ioctls down */
|
||||
const unsigned long max_length = 100*1024*1024;
|
||||
const unsigned int max_extents = 1000;
|
||||
/* break blocking ioctls down */
|
||||
const unsigned long max_length = 100 * 1024 * 1024;
|
||||
const unsigned int max_extents = 1000;
|
||||
|
||||
unsigned long offset = 0;
|
||||
unsigned long offset = 0;
|
||||
|
||||
struct {
|
||||
struct fiemap fiemap;
|
||||
struct fiemap_extent extents[max_extents];
|
||||
} fiemap_static;
|
||||
struct fiemap* fiemap = (struct fiemap*) &fiemap_static;
|
||||
struct {
|
||||
struct fiemap fiemap;
|
||||
struct fiemap_extent extents[max_extents];
|
||||
} fiemap_static;
|
||||
struct fiemap *fiemap = (struct fiemap *) &fiemap_static;
|
||||
|
||||
memset(&fiemap_static, 0, sizeof(fiemap_static));
|
||||
memset(&fiemap_static, 0, sizeof(fiemap_static));
|
||||
|
||||
for (offset = 0; offset < allocation_map->size; ) {
|
||||
for (offset = 0; offset < allocation_map->size;) {
|
||||
|
||||
fiemap->fm_start = offset;
|
||||
fiemap->fm_start = offset;
|
||||
|
||||
fiemap->fm_length = max_length;
|
||||
if ( offset + max_length > allocation_map->size ) {
|
||||
fiemap->fm_length = allocation_map->size-offset;
|
||||
}
|
||||
|
||||
fiemap->fm_flags = FIEMAP_FLAG_SYNC;
|
||||
fiemap->fm_extent_count = max_extents;
|
||||
fiemap->fm_mapped_extents = 0;
|
||||
|
||||
if ( ioctl( fd, FS_IOC_FIEMAP, fiemap ) < 0 ) {
|
||||
debug( "Couldn't get fiemap, returning no allocation_map" );
|
||||
return 0; /* it's up to the caller to free the map */
|
||||
}
|
||||
else {
|
||||
for ( unsigned int i = 0; i < fiemap->fm_mapped_extents; i++ ) {
|
||||
bitset_set_range( allocation_map,
|
||||
fiemap->fm_extents[i].fe_logical,
|
||||
fiemap->fm_extents[i].fe_length );
|
||||
}
|
||||
|
||||
|
||||
/* must move the offset on, but careful not to jump max_length
|
||||
* if we've actually hit max_offsets.
|
||||
*/
|
||||
if (fiemap->fm_mapped_extents > 0) {
|
||||
struct fiemap_extent *last = &fiemap->fm_extents[
|
||||
fiemap->fm_mapped_extents-1
|
||||
];
|
||||
offset = last->fe_logical + last->fe_length;
|
||||
}
|
||||
else {
|
||||
offset += fiemap->fm_length;
|
||||
}
|
||||
}
|
||||
fiemap->fm_length = max_length;
|
||||
if (offset + max_length > allocation_map->size) {
|
||||
fiemap->fm_length = allocation_map->size - offset;
|
||||
}
|
||||
|
||||
info("Successfully built allocation map");
|
||||
return 1;
|
||||
fiemap->fm_flags = FIEMAP_FLAG_SYNC;
|
||||
fiemap->fm_extent_count = max_extents;
|
||||
fiemap->fm_mapped_extents = 0;
|
||||
|
||||
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
|
||||
debug("Couldn't get fiemap, returning no allocation_map");
|
||||
return 0; /* it's up to the caller to free the map */
|
||||
} else {
|
||||
for (unsigned int i = 0; i < fiemap->fm_mapped_extents; i++) {
|
||||
bitset_set_range(allocation_map,
|
||||
fiemap->fm_extents[i].fe_logical,
|
||||
fiemap->fm_extents[i].fe_length);
|
||||
}
|
||||
|
||||
|
||||
/* must move the offset on, but careful not to jump max_length
|
||||
* if we've actually hit max_offsets.
|
||||
*/
|
||||
if (fiemap->fm_mapped_extents > 0) {
|
||||
struct fiemap_extent *last =
|
||||
&fiemap->fm_extents[fiemap->fm_mapped_extents - 1];
|
||||
offset = last->fe_logical + last->fe_length;
|
||||
} else {
|
||||
offset += fiemap->fm_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info("Successfully built allocation map");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **out_map)
|
||||
int open_and_mmap(const char *filename, int *out_fd, uint64_t * out_size,
|
||||
void **out_map)
|
||||
{
|
||||
/*
|
||||
* size and out_size are intentionally of different types.
|
||||
* lseek64() uses off64_t to signal errors in the sign bit.
|
||||
* Since we check for these errors before trying to assign to
|
||||
* *out_size, we know *out_size can never go negative.
|
||||
*/
|
||||
off64_t size;
|
||||
/*
|
||||
* size and out_size are intentionally of different types.
|
||||
* lseek64() uses off64_t to signal errors in the sign bit.
|
||||
* Since we check for these errors before trying to assign to
|
||||
* *out_size, we know *out_size can never go negative.
|
||||
*/
|
||||
off64_t size;
|
||||
|
||||
/* O_DIRECT should not be used with mmap() */
|
||||
*out_fd = open(filename, O_RDWR | O_NOATIME );
|
||||
/* O_DIRECT should not be used with mmap() */
|
||||
*out_fd = open(filename, O_RDWR | O_NOATIME);
|
||||
|
||||
if (*out_fd < 1) {
|
||||
warn("open(%s) failed: does it exist?", filename);
|
||||
return *out_fd;
|
||||
if (*out_fd < 1) {
|
||||
warn("open(%s) failed: does it exist?", filename);
|
||||
return *out_fd;
|
||||
}
|
||||
|
||||
size = lseek64(*out_fd, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
warn("lseek64() failed");
|
||||
return size;
|
||||
}
|
||||
|
||||
/* If discs are not in multiples of 512, then odd things happen,
|
||||
* resulting in reads/writes past the ends of files.
|
||||
*/
|
||||
if (size != (size & (~0x1ff))) {
|
||||
warn("file does not fit into 512-byte sectors; the end of the file will be ignored.");
|
||||
size &= ~0x1ff;
|
||||
}
|
||||
|
||||
if (out_size) {
|
||||
*out_size = size;
|
||||
}
|
||||
|
||||
if (out_map) {
|
||||
*out_map = mmap64(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
*out_fd, 0);
|
||||
if (((long) *out_map) == -1) {
|
||||
warn("mmap64() failed");
|
||||
return -1;
|
||||
}
|
||||
debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd,
|
||||
*out_map);
|
||||
} else {
|
||||
debug("opened %s size %ld on fd %d", filename, size, *out_fd);
|
||||
}
|
||||
|
||||
size = lseek64(*out_fd, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
warn("lseek64() failed");
|
||||
return size;
|
||||
}
|
||||
|
||||
/* If discs are not in multiples of 512, then odd things happen,
|
||||
* resulting in reads/writes past the ends of files.
|
||||
*/
|
||||
if ( size != (size & (~0x1ff))) {
|
||||
warn("file does not fit into 512-byte sectors; the end of the file will be ignored.");
|
||||
size &= ~0x1ff;
|
||||
}
|
||||
|
||||
if (out_size) {
|
||||
*out_size = size;
|
||||
}
|
||||
|
||||
if (out_map) {
|
||||
*out_map = mmap64(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
|
||||
*out_fd, 0);
|
||||
if (((long) *out_map) == -1) {
|
||||
warn("mmap64() failed");
|
||||
return -1;
|
||||
}
|
||||
debug("opened %s size %ld on fd %d @ %p", filename, size, *out_fd, *out_map);
|
||||
}
|
||||
else {
|
||||
debug("opened %s size %ld on fd %d", filename, size, *out_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int writeloop(int filedes, const void *buffer, size_t size)
|
||||
{
|
||||
size_t written=0;
|
||||
while (written < size) {
|
||||
ssize_t result = write(filedes, buffer+written, size-written);
|
||||
if (result == -1) {
|
||||
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
|
||||
continue; // busy-wait
|
||||
}
|
||||
return -1; // failure
|
||||
}
|
||||
written += result;
|
||||
size_t written = 0;
|
||||
while (written < size) {
|
||||
ssize_t result = write(filedes, buffer + written, size - written);
|
||||
if (result == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
continue; // busy-wait
|
||||
}
|
||||
return -1; // failure
|
||||
}
|
||||
return 0;
|
||||
written += result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readloop(int filedes, void *buffer, size_t size)
|
||||
{
|
||||
size_t readden=0;
|
||||
while (readden < size) {
|
||||
ssize_t result = read(filedes, buffer+readden, size-readden);
|
||||
size_t readden = 0;
|
||||
while (readden < size) {
|
||||
ssize_t result = read(filedes, buffer + readden, size - readden);
|
||||
|
||||
if ( result == 0 /* EOF */ ) {
|
||||
warn( "end-of-file detected while reading after %i bytes", readden );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( result == -1 ) {
|
||||
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
|
||||
continue; // busy-wait
|
||||
}
|
||||
return -1; // failure
|
||||
}
|
||||
readden += result;
|
||||
if (result == 0 /* EOF */ ) {
|
||||
warn("end-of-file detected while reading after %i bytes",
|
||||
readden);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (result == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
continue; // busy-wait
|
||||
}
|
||||
return -1; // failure
|
||||
}
|
||||
readden += result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count)
|
||||
int sendfileloop(int out_fd, int in_fd, off64_t * offset, size_t count)
|
||||
{
|
||||
size_t sent=0;
|
||||
while (sent < count) {
|
||||
ssize_t result = sendfile64(out_fd, in_fd, offset, count-sent);
|
||||
debug("sendfile64(out_fd=%d, in_fd=%d, offset=%p, count-sent=%ld) = %ld", out_fd, in_fd, offset, count-sent, result);
|
||||
size_t sent = 0;
|
||||
while (sent < count) {
|
||||
ssize_t result = sendfile64(out_fd, in_fd, offset, count - sent);
|
||||
debug
|
||||
("sendfile64(out_fd=%d, in_fd=%d, offset=%p, count-sent=%ld) = %ld",
|
||||
out_fd, in_fd, offset, count - sent, result);
|
||||
|
||||
if (result == -1) {
|
||||
debug( "%s (%i) calling sendfile64()", strerror(errno), errno );
|
||||
return -1;
|
||||
}
|
||||
sent += result;
|
||||
debug("sent=%ld, count=%ld", sent, count);
|
||||
if (result == -1) {
|
||||
debug("%s (%i) calling sendfile64()", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
debug("exiting sendfileloop");
|
||||
return 0;
|
||||
sent += result;
|
||||
debug("sent=%ld, count=%ld", sent, count);
|
||||
}
|
||||
debug("exiting sendfileloop");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <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;
|
||||
size_t spliced=0;
|
||||
const unsigned int flags = SPLICE_F_MORE | SPLICE_F_MOVE | flags2;
|
||||
size_t spliced = 0;
|
||||
|
||||
//debug("spliceloop(%d, %ld, %d, %ld, %ld)", fd_in, off_in ? *off_in : 0, fd_out, off_out ? *off_out : 0, len);
|
||||
//debug("spliceloop(%d, %ld, %d, %ld, %ld)", fd_in, off_in ? *off_in : 0, fd_out, off_out ? *off_out : 0, len);
|
||||
|
||||
while (spliced < len) {
|
||||
ssize_t result = splice(fd_in, off_in, fd_out, off_out, len, flags);
|
||||
if (result < 0) {
|
||||
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len);
|
||||
if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK) ) {
|
||||
return spliced;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
spliced += result;
|
||||
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len);
|
||||
}
|
||||
while (spliced < len) {
|
||||
ssize_t result =
|
||||
splice(fd_in, off_in, fd_out, off_out, len, flags);
|
||||
if (result < 0) {
|
||||
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len);
|
||||
if (errno == EAGAIN && (flags & SPLICE_F_NONBLOCK)) {
|
||||
return spliced;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
spliced += result;
|
||||
//debug("result=%ld (%s), spliced=%ld, len=%ld", result, strerror(errno), spliced, len);
|
||||
}
|
||||
}
|
||||
|
||||
return spliced;
|
||||
return spliced;
|
||||
}
|
||||
|
||||
int splice_via_pipe_loop(int fd_in, int fd_out, size_t len)
|
||||
{
|
||||
|
||||
int pipefd[2]; /* read end, write end */
|
||||
size_t spliced=0;
|
||||
int pipefd[2]; /* read end, write end */
|
||||
size_t spliced = 0;
|
||||
|
||||
if (pipe(pipefd) == -1) {
|
||||
return -1;
|
||||
if (pipe(pipefd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (spliced < len) {
|
||||
ssize_t run = len - spliced;
|
||||
ssize_t s2, s1 =
|
||||
spliceloop(fd_in, NULL, pipefd[1], NULL, run,
|
||||
SPLICE_F_NONBLOCK);
|
||||
/*if (run > 65535)
|
||||
run = 65535; */
|
||||
if (s1 < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (spliced < len) {
|
||||
ssize_t run = len-spliced;
|
||||
ssize_t s2, s1 = spliceloop(fd_in, NULL, pipefd[1], NULL, run, SPLICE_F_NONBLOCK);
|
||||
/*if (run > 65535)
|
||||
run = 65535;*/
|
||||
if (s1 < 0) { break; }
|
||||
|
||||
s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0);
|
||||
if (s2 < 0) { break; }
|
||||
spliced += s2;
|
||||
s2 = spliceloop(pipefd[0], NULL, fd_out, NULL, s1, 0);
|
||||
if (s2 < 0) {
|
||||
break;
|
||||
}
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
spliced += s2;
|
||||
}
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return spliced < len ? -1 : 0;
|
||||
return spliced < len ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Reads single bytes from fd until either an EOF or a newline appears.
|
||||
@@ -244,117 +252,123 @@ int splice_via_pipe_loop(int fd_in, int fd_out, size_t len)
|
||||
* Returns the number of read bytes: the length of the line without the
|
||||
* newline, plus the trailing null.
|
||||
*/
|
||||
int read_until_newline(int fd, char* buf, int bufsize)
|
||||
int read_until_newline(int fd, char *buf, int bufsize)
|
||||
{
|
||||
int cur;
|
||||
int cur;
|
||||
|
||||
for (cur=0; cur < bufsize; cur++) {
|
||||
int result = read(fd, buf+cur, 1);
|
||||
if (result <= 0) { return -1; }
|
||||
if (buf[cur] == 10) {
|
||||
buf[cur] = '\0';
|
||||
break;
|
||||
}
|
||||
for (cur = 0; cur < bufsize; cur++) {
|
||||
int result = read(fd, buf + cur, 1);
|
||||
if (result <= 0) {
|
||||
return -1;
|
||||
}
|
||||
if (buf[cur] == 10) {
|
||||
buf[cur] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cur+1;
|
||||
return cur + 1;
|
||||
}
|
||||
|
||||
int read_lines_until_blankline(int fd, int max_line_length, char ***lines)
|
||||
{
|
||||
int lines_count = 0;
|
||||
char line[max_line_length+1];
|
||||
*lines = NULL;
|
||||
int lines_count = 0;
|
||||
char line[max_line_length + 1];
|
||||
*lines = NULL;
|
||||
|
||||
memset(line, 0, max_line_length+1);
|
||||
memset(line, 0, max_line_length + 1);
|
||||
|
||||
while (1) {
|
||||
int readden = read_until_newline(fd, line, max_line_length);
|
||||
/* readden will be:
|
||||
* 1 for an empty line
|
||||
* -1 for an eof
|
||||
* -1 for a read error
|
||||
*/
|
||||
if (readden <= 1) { return lines_count; }
|
||||
*lines = xrealloc(*lines, (lines_count+1) * sizeof(char*));
|
||||
(*lines)[lines_count] = strdup(line);
|
||||
if ((*lines)[lines_count][0] == 0) {
|
||||
return lines_count;
|
||||
}
|
||||
lines_count++;
|
||||
while (1) {
|
||||
int readden = read_until_newline(fd, line, max_line_length);
|
||||
/* readden will be:
|
||||
* 1 for an empty line
|
||||
* -1 for an eof
|
||||
* -1 for a read error
|
||||
*/
|
||||
if (readden <= 1) {
|
||||
return lines_count;
|
||||
}
|
||||
*lines = xrealloc(*lines, (lines_count + 1) * sizeof(char *));
|
||||
(*lines)[lines_count] = strdup(line);
|
||||
if ((*lines)[lines_count][0] == 0) {
|
||||
return lines_count;
|
||||
}
|
||||
lines_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fd_is_closed( int fd_in )
|
||||
int fd_is_closed(int fd_in)
|
||||
{
|
||||
int errno_old = errno;
|
||||
int result = fcntl( fd_in, F_GETFL ) < 0;
|
||||
errno = errno_old;
|
||||
return result;
|
||||
int errno_old = errno;
|
||||
int result = fcntl(fd_in, F_GETFL) < 0;
|
||||
errno = errno_old;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline int io_errno_permanent(void)
|
||||
{
|
||||
return ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR );
|
||||
return (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR);
|
||||
}
|
||||
|
||||
|
||||
/* Returns -1 if the operation failed, or the number of bytes read if all is
|
||||
* well. Note that 0 bytes may be returned. Unlike read(), this is not an EOF! */
|
||||
ssize_t iobuf_read(int fd, struct iobuf *iobuf, size_t default_size )
|
||||
ssize_t iobuf_read(int fd, struct iobuf * iobuf, size_t default_size)
|
||||
{
|
||||
size_t left;
|
||||
ssize_t count;
|
||||
size_t left;
|
||||
ssize_t count;
|
||||
|
||||
if ( iobuf->needle == 0 ) {
|
||||
iobuf->size = default_size;
|
||||
}
|
||||
if (iobuf->needle == 0) {
|
||||
iobuf->size = default_size;
|
||||
}
|
||||
|
||||
left = iobuf->size - iobuf->needle;
|
||||
debug( "Reading %"PRIu32" of %"PRIu32" bytes from fd %i", left, iobuf->size, fd );
|
||||
left = iobuf->size - iobuf->needle;
|
||||
debug("Reading %" PRIu32 " of %" PRIu32 " bytes from fd %i", left,
|
||||
iobuf->size, fd);
|
||||
|
||||
count = read( fd, iobuf->buf + iobuf->needle, left );
|
||||
count = read(fd, iobuf->buf + iobuf->needle, left);
|
||||
|
||||
if ( count > 0 ) {
|
||||
iobuf->needle += count;
|
||||
debug( "read() returned %"PRIu32" bytes", count );
|
||||
} else if ( count == 0 ) {
|
||||
warn( "read() returned EOF on fd %i", fd );
|
||||
errno = 0;
|
||||
return -1;
|
||||
} else if ( count == -1 ) {
|
||||
if ( io_errno_permanent() ) {
|
||||
warn( SHOW_ERRNO( "read() failed on fd %i", fd ) );
|
||||
} else {
|
||||
debug( SHOW_ERRNO( "read() returned 0 bytes" ) );
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t iobuf_write( int fd, struct iobuf *iobuf )
|
||||
{
|
||||
size_t left = iobuf->size - iobuf->needle;
|
||||
ssize_t count;
|
||||
|
||||
debug( "Writing %"PRIu32" of %"PRIu32" bytes to fd %i", left, iobuf->size, fd );
|
||||
count = write( fd, iobuf->buf + iobuf->needle, left );
|
||||
|
||||
if ( count >= 0 ) {
|
||||
iobuf->needle += count;
|
||||
debug( "write() returned %"PRIu32" bytes", count );
|
||||
if (count > 0) {
|
||||
iobuf->needle += count;
|
||||
debug("read() returned %" PRIu32 " bytes", count);
|
||||
} else if (count == 0) {
|
||||
warn("read() returned EOF on fd %i", fd);
|
||||
errno = 0;
|
||||
return -1;
|
||||
} else if (count == -1) {
|
||||
if (io_errno_permanent()) {
|
||||
warn(SHOW_ERRNO("read() failed on fd %i", fd));
|
||||
} else {
|
||||
if ( io_errno_permanent() ) {
|
||||
warn( SHOW_ERRNO( "write() failed on fd %i", fd ) );
|
||||
} else {
|
||||
debug( SHOW_ERRNO( "write() returned 0 bytes" ) );
|
||||
count = 0;
|
||||
}
|
||||
debug(SHOW_ERRNO("read() returned 0 bytes"));
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t iobuf_write(int fd, struct iobuf * iobuf)
|
||||
{
|
||||
size_t left = iobuf->size - iobuf->needle;
|
||||
ssize_t count;
|
||||
|
||||
debug("Writing %" PRIu32 " of %" PRIu32 " bytes to fd %i", left,
|
||||
iobuf->size, fd);
|
||||
count = write(fd, iobuf->buf + iobuf->needle, left);
|
||||
|
||||
if (count >= 0) {
|
||||
iobuf->needle += count;
|
||||
debug("write() returned %" PRIu32 " bytes", count);
|
||||
} else {
|
||||
if (io_errno_permanent()) {
|
||||
warn(SHOW_ERRNO("write() failed on fd %i", fd));
|
||||
} else {
|
||||
debug(SHOW_ERRNO("write() returned 0 bytes"));
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@@ -3,16 +3,16 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
struct iobuf {
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
size_t needle;
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
size_t needle;
|
||||
};
|
||||
|
||||
ssize_t iobuf_read( int fd, struct iobuf* iobuf, size_t default_size );
|
||||
ssize_t iobuf_write( int fd, struct iobuf* iobuf );
|
||||
ssize_t iobuf_read(int fd, struct iobuf *iobuf, size_t default_size);
|
||||
ssize_t iobuf_write(int fd, struct iobuf *iobuf);
|
||||
|
||||
#include "serve.h"
|
||||
struct bitset; /* don't need whole of bitset.h here */
|
||||
struct bitset; /* don't need whole of bitset.h here */
|
||||
|
||||
/** Scan the file opened in ''fd'', set bits in ''allocation_map'' that
|
||||
* correspond to which blocks are physically allocated on disc (or part-
|
||||
@@ -20,7 +20,7 @@ struct bitset; /* don't need whole of bitset.h here */
|
||||
* than you've asked for, any block or part block will count as "allocated"
|
||||
* with the corresponding bit set. Returns 1 if successful, 0 otherwise.
|
||||
*/
|
||||
int build_allocation_map(struct bitset * allocation_map, int fd);
|
||||
int build_allocation_map(struct bitset *allocation_map, int fd);
|
||||
|
||||
/** Repeat a write() operation that succeeds partially until ''size'' bytes
|
||||
* are written, or an error is returned, when it returns -1 as usual.
|
||||
@@ -35,10 +35,11 @@ int readloop(int filedes, void *buffer, size_t size);
|
||||
/** Repeat a sendfile() operation that succeeds partially until ''size'' bytes
|
||||
* are written, or an error is returned, when it returns -1 as usual.
|
||||
*/
|
||||
int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count);
|
||||
int sendfileloop(int out_fd, int in_fd, off64_t * offset, size_t count);
|
||||
|
||||
/** Repeat a splice() operation until we have 'len' bytes. */
|
||||
ssize_t spliceloop(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags2);
|
||||
ssize_t spliceloop(int fd_in, loff_t * off_in, int fd_out,
|
||||
loff_t * off_out, size_t len, unsigned int flags2);
|
||||
|
||||
/** Copy ''len'' bytes from ''fd_in'' to ''fd_out'' by creating a temporary
|
||||
* pipe and using the Linux splice call repeatedly until it has transferred
|
||||
@@ -50,7 +51,7 @@ int splice_via_pipe_loop(int fd_in, int fd_out, size_t len);
|
||||
* until an LF character is received, which is written to the buffer at a zero
|
||||
* byte. Returns -1 on error, or the number of bytes written to the buffer.
|
||||
*/
|
||||
int read_until_newline(int fd, char* buf, int bufsize);
|
||||
int read_until_newline(int fd, char *buf, int bufsize);
|
||||
|
||||
/** Read a number of lines using read_until_newline, until an empty line is
|
||||
* received (i.e. the sequence LF LF). The data is read from ''fd'' and
|
||||
@@ -65,12 +66,12 @@ int read_lines_until_blankline(int fd, int max_line_length, char ***lines);
|
||||
* ''out_size'' and the address of the mmap in ''out_map''. If anything goes
|
||||
* wrong, returns -1 setting errno, otherwise 0.
|
||||
*/
|
||||
int open_and_mmap( const char* filename, int* out_fd, uint64_t* out_size, void **out_map);
|
||||
int open_and_mmap(const char *filename, int *out_fd, uint64_t * out_size,
|
||||
void **out_map);
|
||||
|
||||
|
||||
/** Check to see whether the given file descriptor is closed.
|
||||
*/
|
||||
int fd_is_closed( int fd_in );
|
||||
int fd_is_closed(int fd_in);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define MODE_H
|
||||
|
||||
|
||||
void mode(char* mode, int argc, char **argv);
|
||||
void mode(char *mode, int argc, char **argv);
|
||||
|
||||
|
||||
#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"
|
||||
|
||||
#ifdef DEBUG
|
||||
# define VERBOSE_LOG_LEVEL 0
|
||||
#define VERBOSE_LOG_LEVEL 0
|
||||
#else
|
||||
# define VERBOSE_LOG_LEVEL 1
|
||||
#define VERBOSE_LOG_LEVEL 1
|
||||
#endif
|
||||
|
||||
#define QUIET_LOG_LEVEL 4
|
||||
@@ -91,7 +91,6 @@ void mode(char* mode, int argc, char **argv);
|
||||
#define MAX_SPEED_LINE \
|
||||
"\t--" OPT_MAX_SPEED ",-m <bps>\tMaximum speed of the migration, in bytes/sec.\n"
|
||||
|
||||
char * help_help_text;
|
||||
char *help_help_text;
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -8,55 +8,54 @@
|
||||
* We intentionally ignore the reserved 128 bytes at the end of the
|
||||
* request, since there's nothing we can do with them.
|
||||
*/
|
||||
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to )
|
||||
void nbd_r2h_init(struct nbd_init_raw *from, struct nbd_init *to)
|
||||
{
|
||||
memcpy( to->passwd, from->passwd, 8 );
|
||||
to->magic = be64toh( from->magic );
|
||||
to->size = be64toh( from->size );
|
||||
to->flags = be32toh( from->flags );
|
||||
memcpy(to->passwd, from->passwd, 8);
|
||||
to->magic = be64toh(from->magic);
|
||||
to->size = be64toh(from->size);
|
||||
to->flags = be32toh(from->flags);
|
||||
}
|
||||
|
||||
void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to)
|
||||
void nbd_h2r_init(struct nbd_init *from, struct nbd_init_raw *to)
|
||||
{
|
||||
memcpy( to->passwd, from->passwd, 8 );
|
||||
to->magic = htobe64( from->magic );
|
||||
to->size = htobe64( from->size );
|
||||
to->flags = htobe32( from->flags );
|
||||
memcpy(to->passwd, from->passwd, 8);
|
||||
to->magic = htobe64(from->magic);
|
||||
to->size = htobe64(from->size);
|
||||
to->flags = htobe32(from->flags);
|
||||
}
|
||||
|
||||
|
||||
void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to )
|
||||
void nbd_r2h_request(struct nbd_request_raw *from, struct nbd_request *to)
|
||||
{
|
||||
to->magic = be32toh( from->magic );
|
||||
to->flags = be16toh( from->flags );
|
||||
to->type = be16toh( from->type );
|
||||
to->handle.w = from->handle.w;
|
||||
to->from = be64toh( from->from );
|
||||
to->len = be32toh( from->len );
|
||||
to->magic = be32toh(from->magic);
|
||||
to->flags = be16toh(from->flags);
|
||||
to->type = be16toh(from->type);
|
||||
to->handle.w = from->handle.w;
|
||||
to->from = be64toh(from->from);
|
||||
to->len = be32toh(from->len);
|
||||
}
|
||||
|
||||
void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to )
|
||||
void nbd_h2r_request(struct nbd_request *from, struct nbd_request_raw *to)
|
||||
{
|
||||
to->magic = htobe32( from->magic );
|
||||
to->flags = htobe16( from->flags );
|
||||
to->type = htobe16( from->type );
|
||||
to->handle.w = from->handle.w;
|
||||
to->from = htobe64( from->from );
|
||||
to->len = htobe32( from->len );
|
||||
to->magic = htobe32(from->magic);
|
||||
to->flags = htobe16(from->flags);
|
||||
to->type = htobe16(from->type);
|
||||
to->handle.w = from->handle.w;
|
||||
to->from = htobe64(from->from);
|
||||
to->len = htobe32(from->len);
|
||||
}
|
||||
|
||||
|
||||
void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to )
|
||||
void nbd_r2h_reply(struct nbd_reply_raw *from, struct nbd_reply *to)
|
||||
{
|
||||
to->magic = be32toh( from->magic );
|
||||
to->error = be32toh( from->error );
|
||||
to->handle.w = from->handle.w;
|
||||
to->magic = be32toh(from->magic);
|
||||
to->error = be32toh(from->error);
|
||||
to->handle.w = from->handle.w;
|
||||
}
|
||||
|
||||
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to )
|
||||
void nbd_h2r_reply(struct nbd_reply *from, struct nbd_reply_raw *to)
|
||||
{
|
||||
to->magic = htobe32( from->magic );
|
||||
to->error = htobe32( from->error );
|
||||
to->handle.w = from->handle.w;
|
||||
to->magic = htobe32(from->magic);
|
||||
to->error = htobe32(from->error);
|
||||
to->handle.w = from->handle.w;
|
||||
}
|
||||
|
||||
|
@@ -29,8 +29,8 @@
|
||||
#define FLAG_READ_ONLY (1 << 1) /* Device is read-only */
|
||||
#define FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */
|
||||
#define FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
|
||||
#define FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */
|
||||
#define FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */
|
||||
#define FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */
|
||||
#define FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */
|
||||
|
||||
#define CMD_FLAG_NO_HOLE (1 << 1)
|
||||
#endif
|
||||
@@ -48,8 +48,8 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef union nbd_handle_t {
|
||||
uint8_t b[8];
|
||||
uint64_t w;
|
||||
uint8_t b[8];
|
||||
uint64_t w;
|
||||
} nbd_handle_t;
|
||||
|
||||
/* The _raw types are the types as they appear on the wire. Non-_raw
|
||||
@@ -58,58 +58,57 @@ typedef union nbd_handle_t {
|
||||
* for converting host to raw.
|
||||
*/
|
||||
struct nbd_init_raw {
|
||||
char passwd[8];
|
||||
__be64 magic;
|
||||
__be64 size;
|
||||
__be32 flags;
|
||||
char reserved[124];
|
||||
char passwd[8];
|
||||
__be64 magic;
|
||||
__be64 size;
|
||||
__be32 flags;
|
||||
char reserved[124];
|
||||
};
|
||||
|
||||
struct nbd_request_raw {
|
||||
__be32 magic;
|
||||
__be16 flags;
|
||||
__be16 type; /* == READ || == WRITE || == FLUSH */
|
||||
nbd_handle_t handle;
|
||||
__be64 from;
|
||||
__be32 len;
|
||||
} __attribute__((packed));
|
||||
__be32 magic;
|
||||
__be16 flags;
|
||||
__be16 type; /* == READ || == WRITE || == FLUSH */
|
||||
nbd_handle_t handle;
|
||||
__be64 from;
|
||||
__be32 len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct nbd_reply_raw {
|
||||
__be32 magic;
|
||||
__be32 error; /* 0 = ok, else error */
|
||||
nbd_handle_t handle; /* handle you got from request */
|
||||
__be32 magic;
|
||||
__be32 error; /* 0 = ok, else error */
|
||||
nbd_handle_t handle; /* handle you got from request */
|
||||
};
|
||||
|
||||
struct nbd_init {
|
||||
char passwd[8];
|
||||
uint64_t magic;
|
||||
uint64_t size;
|
||||
uint32_t flags;
|
||||
char reserved[124];
|
||||
char passwd[8];
|
||||
uint64_t magic;
|
||||
uint64_t size;
|
||||
uint32_t flags;
|
||||
char reserved[124];
|
||||
};
|
||||
|
||||
struct nbd_request {
|
||||
uint32_t magic;
|
||||
uint16_t flags;
|
||||
uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */
|
||||
nbd_handle_t handle;
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
} __attribute__((packed));
|
||||
uint32_t magic;
|
||||
uint16_t flags;
|
||||
uint16_t type; /* == READ || == WRITE || == DISCONNECT || == FLUSH */
|
||||
nbd_handle_t handle;
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct nbd_reply {
|
||||
uint32_t magic;
|
||||
uint32_t error; /* 0 = ok, else error */
|
||||
nbd_handle_t handle; /* handle you got from request */
|
||||
uint32_t magic;
|
||||
uint32_t error; /* 0 = ok, else error */
|
||||
nbd_handle_t handle; /* handle you got from request */
|
||||
};
|
||||
|
||||
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to );
|
||||
void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to );
|
||||
void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to );
|
||||
void nbd_r2h_init(struct nbd_init_raw *from, struct nbd_init *to);
|
||||
void nbd_r2h_request(struct nbd_request_raw *from, struct nbd_request *to);
|
||||
void nbd_r2h_reply(struct nbd_reply_raw *from, struct nbd_reply *to);
|
||||
|
||||
void nbd_h2r_init( struct nbd_init * from, struct nbd_init_raw * to);
|
||||
void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to );
|
||||
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to );
|
||||
void nbd_h2r_init(struct nbd_init *from, struct nbd_init_raw *to);
|
||||
void nbd_h2r_request(struct nbd_request *from, struct nbd_request_raw *to);
|
||||
void nbd_h2r_reply(struct nbd_reply *from, struct nbd_reply_raw *to);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -10,118 +10,116 @@ int atoi(const char *nptr);
|
||||
)
|
||||
|
||||
/* FIXME: should change this to return negative on error like everything else */
|
||||
int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
|
||||
int parse_ip_to_sockaddr(struct sockaddr *out, char *src)
|
||||
{
|
||||
NULLCHECK( out );
|
||||
NULLCHECK( src );
|
||||
NULLCHECK(out);
|
||||
NULLCHECK(src);
|
||||
|
||||
char temp[64];
|
||||
struct sockaddr_in *v4 = (struct sockaddr_in *) out;
|
||||
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out;
|
||||
char temp[64];
|
||||
struct sockaddr_in *v4 = (struct sockaddr_in *) out;
|
||||
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out;
|
||||
|
||||
/* allow user to start with [ and end with any other invalid char */
|
||||
{
|
||||
int i=0, j=0;
|
||||
if (src[i] == '[') { i++; }
|
||||
for (; i<64 && IS_IP_VALID_CHAR(src[i]); i++) {
|
||||
temp[j++] = src[i];
|
||||
}
|
||||
temp[j] = 0;
|
||||
/* allow user to start with [ and end with any other invalid char */
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
if (src[i] == '[') {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (temp[0] == '0' && temp[1] == '\0') {
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_addr.s_addr = INADDR_ANY;
|
||||
return 1;
|
||||
for (; i < 64 && IS_IP_VALID_CHAR(src[i]); i++) {
|
||||
temp[j++] = src[i];
|
||||
}
|
||||
temp[j] = 0;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) {
|
||||
out->sa_family = AF_INET;
|
||||
return 1;
|
||||
}
|
||||
if (temp[0] == '0' && temp[1] == '\0') {
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_addr.s_addr = INADDR_ANY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) {
|
||||
out->sa_family = AF_INET6;
|
||||
return 1;
|
||||
}
|
||||
if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) {
|
||||
out->sa_family = AF_INET;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) {
|
||||
out->sa_family = AF_INET6;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int parse_to_sockaddr(struct sockaddr* out, char* address)
|
||||
int parse_to_sockaddr(struct sockaddr *out, char *address)
|
||||
{
|
||||
struct sockaddr_un* un = (struct sockaddr_un*) out;
|
||||
struct sockaddr_un *un = (struct sockaddr_un *) out;
|
||||
|
||||
NULLCHECK( address );
|
||||
NULLCHECK(address);
|
||||
|
||||
if ( address[0] == '/' ) {
|
||||
un->sun_family = AF_UNIX;
|
||||
strncpy( un->sun_path, address, 108 ); /* FIXME: linux only */
|
||||
return 1;
|
||||
}
|
||||
if (address[0] == '/') {
|
||||
un->sun_family = AF_UNIX;
|
||||
strncpy(un->sun_path, address, 108); /* FIXME: linux only */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parse_ip_to_sockaddr( out, address );
|
||||
return parse_ip_to_sockaddr(out, address);
|
||||
}
|
||||
|
||||
int parse_acl(struct ip_and_mask (**out)[], int max, char **entries)
|
||||
{
|
||||
struct ip_and_mask* list;
|
||||
int i;
|
||||
struct ip_and_mask *list;
|
||||
int i;
|
||||
|
||||
if (max == 0) {
|
||||
*out = NULL;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
list = xmalloc(max * sizeof(struct ip_and_mask));
|
||||
*out = (struct ip_and_mask (*)[])list;
|
||||
debug("acl alloc: %p", *out);
|
||||
}
|
||||
if (max == 0) {
|
||||
*out = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
list = xmalloc(max * sizeof(struct ip_and_mask));
|
||||
*out = (struct ip_and_mask(*)[]) list;
|
||||
debug("acl alloc: %p", *out);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
int j;
|
||||
struct ip_and_mask* outentry = &list[i];
|
||||
for (i = 0; i < max; i++) {
|
||||
int j;
|
||||
struct ip_and_mask *outentry = &list[i];
|
||||
# define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128)
|
||||
if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) {
|
||||
return i;
|
||||
}
|
||||
if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
for (j=0; entries[i][j] && entries[i][j] != '/'; j++)
|
||||
; // increment j!
|
||||
for (j = 0; entries[i][j] && entries[i][j] != '/'; j++); // increment j!
|
||||
|
||||
if (entries[i][j] == '/') {
|
||||
outentry->mask = atoi(entries[i]+j+1);
|
||||
if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outentry->mask = MAX_MASK_BITS;
|
||||
}
|
||||
if (entries[i][j] == '/') {
|
||||
outentry->mask = atoi(entries[i] + j + 1);
|
||||
if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS) {
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
outentry->mask = MAX_MASK_BITS;
|
||||
}
|
||||
# undef MAX_MASK_BITS
|
||||
debug("acl ptr[%d]: %p %d",i, outentry, outentry->mask);
|
||||
}
|
||||
debug("acl ptr[%d]: %p %d", i, outentry, outentry->mask);
|
||||
}
|
||||
|
||||
for (i=0; i < max; i++) {
|
||||
debug("acl entry %d @ %p has mask %d", i, list[i], list[i].mask);
|
||||
}
|
||||
for (i = 0; i < max; i++) {
|
||||
debug("acl entry %d @ %p has mask %d", i, list[i], list[i].mask);
|
||||
}
|
||||
|
||||
return max;
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
void parse_port( char *s_port, struct sockaddr_in *out )
|
||||
void parse_port(char *s_port, struct sockaddr_in *out)
|
||||
{
|
||||
NULLCHECK( s_port );
|
||||
NULLCHECK(s_port);
|
||||
|
||||
int raw_port;
|
||||
int raw_port;
|
||||
|
||||
raw_port = atoi( s_port );
|
||||
if ( raw_port < 0 || raw_port > 65535 ) {
|
||||
fatal( "Port number must be >= 0 and <= 65535" );
|
||||
}
|
||||
out->sin_port = htobe16( raw_port );
|
||||
raw_port = atoi(s_port);
|
||||
if (raw_port < 0 || raw_port > 65535) {
|
||||
fatal("Port number must be >= 0 and <= 65535");
|
||||
}
|
||||
out->sin_port = htobe16(raw_port);
|
||||
}
|
||||
|
||||
|
@@ -8,22 +8,21 @@
|
||||
#include <unistd.h>
|
||||
|
||||
union mysockaddr {
|
||||
unsigned short family;
|
||||
struct sockaddr generic;
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
struct sockaddr_un un;
|
||||
unsigned short family;
|
||||
struct sockaddr generic;
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
struct sockaddr_un un;
|
||||
};
|
||||
|
||||
struct ip_and_mask {
|
||||
union mysockaddr ip;
|
||||
int mask;
|
||||
union mysockaddr ip;
|
||||
int mask;
|
||||
};
|
||||
|
||||
int parse_ip_to_sockaddr(struct sockaddr* out, char* src);
|
||||
int parse_to_sockaddr(struct sockaddr* out, char* src);
|
||||
int parse_ip_to_sockaddr(struct sockaddr *out, char *src);
|
||||
int parse_to_sockaddr(struct sockaddr *out, char *src);
|
||||
int parse_acl(struct ip_and_mask (**out)[], int max, char **entries);
|
||||
void parse_port( char *s_port, struct sockaddr_in *out );
|
||||
void parse_port(char *s_port, struct sockaddr_in *out);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -8,214 +8,217 @@
|
||||
#include <string.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);
|
||||
if( fd < 0 ){
|
||||
warn( "Couldn't create client socket");
|
||||
return -1;
|
||||
}
|
||||
int fd =
|
||||
socket(to->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_STREAM,
|
||||
0);
|
||||
if (fd < 0) {
|
||||
warn("Couldn't create client socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL != from) {
|
||||
if ( 0 > bind( fd, from, sizeof(struct sockaddr_in6 ) ) ){
|
||||
warn( SHOW_ERRNO( "bind() to source address failed" ) );
|
||||
if ( 0 > close( fd ) ) { /* Non-fatal leak */
|
||||
warn( SHOW_ERRNO( "Failed to close fd %i", fd ) );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (NULL != from) {
|
||||
if (0 > bind(fd, from, sizeof(struct sockaddr_in6))) {
|
||||
warn(SHOW_ERRNO("bind() to source address failed"));
|
||||
if (0 > close(fd)) { /* Non-fatal leak */
|
||||
warn(SHOW_ERRNO("Failed to close fd %i", fd));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 > sock_try_connect( fd, to, sizeof( struct sockaddr_in6 ), 15 ) ) {
|
||||
warn( SHOW_ERRNO( "connect failed" ) );
|
||||
if ( 0 > close( fd ) ) { /* Non-fatal leak */
|
||||
warn( SHOW_ERRNO( "Failed to close fd %i", fd ) );
|
||||
}
|
||||
return -1;
|
||||
if (0 > sock_try_connect(fd, to, sizeof(struct sockaddr_in6), 15)) {
|
||||
warn(SHOW_ERRNO("connect failed"));
|
||||
if (0 > close(fd)) { /* Non-fatal leak */
|
||||
warn(SHOW_ERRNO("Failed to close fd %i", fd));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( sock_set_tcp_nodelay( fd, 1 ) == -1 ) {
|
||||
warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) );
|
||||
}
|
||||
if (sock_set_tcp_nodelay(fd, 1) == -1) {
|
||||
warn(SHOW_ERRNO("Failed to set TCP_NODELAY"));
|
||||
}
|
||||
|
||||
return fd;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int nbd_check_hello( struct nbd_init_raw* init_raw, uint64_t* out_size, uint32_t* out_flags )
|
||||
int nbd_check_hello(struct nbd_init_raw *init_raw, uint64_t * out_size,
|
||||
uint32_t * out_flags)
|
||||
{
|
||||
if ( strncmp( init_raw->passwd, INIT_PASSWD, 8 ) != 0 ) {
|
||||
warn( "wrong passwd" );
|
||||
goto fail;
|
||||
}
|
||||
if ( be64toh( init_raw->magic ) != INIT_MAGIC ) {
|
||||
warn( "wrong magic (%x)", be64toh( init_raw->magic ) );
|
||||
goto fail;
|
||||
}
|
||||
if (strncmp(init_raw->passwd, INIT_PASSWD, 8) != 0) {
|
||||
warn("wrong passwd");
|
||||
goto fail;
|
||||
}
|
||||
if (be64toh(init_raw->magic) != INIT_MAGIC) {
|
||||
warn("wrong magic (%x)", be64toh(init_raw->magic));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( NULL != out_size ) {
|
||||
*out_size = be64toh( init_raw->size );
|
||||
}
|
||||
if (NULL != out_size) {
|
||||
*out_size = be64toh(init_raw->size);
|
||||
}
|
||||
|
||||
if ( NULL != out_flags ) {
|
||||
*out_flags = be32toh( init_raw->flags );
|
||||
}
|
||||
if (NULL != out_flags) {
|
||||
*out_flags = be32toh(init_raw->flags);
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int socket_nbd_read_hello(int fd, uint64_t * out_size,
|
||||
uint32_t * out_flags)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
|
||||
|
||||
if (0 > readloop(fd, &init_raw, sizeof(init_raw))) {
|
||||
warn("Couldn't read init");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nbd_check_hello(&init_raw, out_size, out_flags);
|
||||
}
|
||||
|
||||
int socket_nbd_read_hello( int fd, uint64_t* out_size, uint32_t* out_flags )
|
||||
void nbd_hello_to_buf(struct nbd_init_raw *buf, off64_t out_size,
|
||||
uint32_t out_flags)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
|
||||
memcpy(&init.passwd, INIT_PASSWD, 8);
|
||||
init.magic = INIT_MAGIC;
|
||||
init.size = out_size;
|
||||
init.flags = out_flags;
|
||||
|
||||
if ( 0 > readloop( fd, &init_raw, sizeof(init_raw) ) ) {
|
||||
warn( "Couldn't read init" );
|
||||
return 0;
|
||||
}
|
||||
memset(buf, 0, sizeof(struct nbd_init_raw)); // ensure reserved is 0s
|
||||
nbd_h2r_init(&init, buf);
|
||||
|
||||
return nbd_check_hello( &init_raw, out_size, out_flags );
|
||||
return;
|
||||
}
|
||||
|
||||
void nbd_hello_to_buf( struct nbd_init_raw *buf, off64_t out_size, uint32_t out_flags )
|
||||
int socket_nbd_write_hello(int fd, off64_t out_size, uint32_t out_flags)
|
||||
{
|
||||
struct nbd_init init;
|
||||
struct nbd_init_raw init_raw;
|
||||
nbd_hello_to_buf(&init_raw, out_size, out_flags);
|
||||
|
||||
memcpy( &init.passwd, INIT_PASSWD, 8 );
|
||||
init.magic = INIT_MAGIC;
|
||||
init.size = out_size;
|
||||
init.flags = out_flags;
|
||||
|
||||
memset( buf, 0, sizeof( struct nbd_init_raw ) ); // ensure reserved is 0s
|
||||
nbd_h2r_init( &init, buf );
|
||||
|
||||
return;
|
||||
if (0 > writeloop(fd, &init_raw, sizeof(init_raw))) {
|
||||
warn(SHOW_ERRNO("failed to write hello to socket"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int socket_nbd_write_hello( int fd, off64_t out_size, uint32_t out_flags )
|
||||
void fill_request(struct nbd_request_raw *request_raw, uint16_t type,
|
||||
uint16_t flags, uint64_t from, uint32_t len)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
nbd_hello_to_buf( &init_raw, out_size, out_flags );
|
||||
|
||||
if ( 0 > writeloop( fd, &init_raw, sizeof( init_raw ) ) ) {
|
||||
warn( SHOW_ERRNO( "failed to write hello to socket" ) );
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
request_raw->magic = htobe32(REQUEST_MAGIC);
|
||||
request_raw->type = htobe16(type);
|
||||
request_raw->flags = htobe16(flags);
|
||||
request_raw->handle.w =
|
||||
(((uint64_t) rand()) << 32) | ((uint64_t) rand());
|
||||
request_raw->from = htobe64(from);
|
||||
request_raw->len = htobe32(len);
|
||||
}
|
||||
|
||||
void fill_request(struct nbd_request_raw *request_raw, uint16_t type, uint16_t flags, uint64_t from, uint32_t len)
|
||||
void read_reply(int fd, uint64_t request_raw_handle,
|
||||
struct nbd_reply *reply)
|
||||
{
|
||||
request_raw->magic = htobe32(REQUEST_MAGIC);
|
||||
request_raw->type = htobe16(type);
|
||||
request_raw->flags = htobe16(flags);
|
||||
request_raw->handle.w = (((uint64_t)rand()) << 32) | ((uint64_t)rand());
|
||||
request_raw->from = htobe64(from);
|
||||
request_raw->len = htobe32(len);
|
||||
struct nbd_reply_raw reply_raw;
|
||||
|
||||
ERROR_IF_NEGATIVE(readloop
|
||||
(fd, &reply_raw, sizeof(struct nbd_reply_raw)),
|
||||
"Couldn't read reply");
|
||||
|
||||
nbd_r2h_reply(&reply_raw, reply);
|
||||
|
||||
if (reply->magic != REPLY_MAGIC) {
|
||||
error("Reply magic incorrect (%x)", reply->magic);
|
||||
}
|
||||
if (reply->error != 0) {
|
||||
error("Server replied with error %d", reply->error);
|
||||
}
|
||||
if (request_raw_handle != reply_raw.handle.w) {
|
||||
error("Did not reply with correct handle");
|
||||
}
|
||||
}
|
||||
|
||||
void read_reply(int fd, uint64_t request_raw_handle, struct nbd_reply *reply)
|
||||
void wait_for_data(int fd, int timeout_secs)
|
||||
{
|
||||
struct nbd_reply_raw reply_raw;
|
||||
fd_set fds;
|
||||
struct timeval tv = { timeout_secs, 0 };
|
||||
int selected;
|
||||
|
||||
ERROR_IF_NEGATIVE(readloop(fd, &reply_raw, sizeof(struct nbd_reply_raw)),
|
||||
"Couldn't read reply");
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
nbd_r2h_reply( &reply_raw, reply );
|
||||
selected =
|
||||
sock_try_select(FD_SETSIZE, &fds, NULL, NULL,
|
||||
timeout_secs >= 0 ? &tv : NULL);
|
||||
|
||||
if (reply->magic != REPLY_MAGIC) {
|
||||
error("Reply magic incorrect (%x)", reply->magic);
|
||||
}
|
||||
if (reply->error != 0) {
|
||||
error("Server replied with error %d", reply->error);
|
||||
}
|
||||
if (request_raw_handle != reply_raw.handle.w) {
|
||||
error("Did not reply with correct handle");
|
||||
}
|
||||
}
|
||||
|
||||
void wait_for_data( int fd, int timeout_secs )
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv = { timeout_secs, 0 };
|
||||
int selected;
|
||||
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( fd, &fds );
|
||||
|
||||
selected = sock_try_select(
|
||||
FD_SETSIZE, &fds, NULL, NULL, timeout_secs >=0 ? &tv : NULL
|
||||
);
|
||||
|
||||
FATAL_IF( -1 == selected, "Select failed" );
|
||||
ERROR_IF( 0 == selected, "Timed out waiting for reply" );
|
||||
FATAL_IF(-1 == selected, "Select failed");
|
||||
ERROR_IF(0 == selected, "Timed out waiting for reply");
|
||||
}
|
||||
|
||||
|
||||
void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs)
|
||||
void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd,
|
||||
void *out_buf, int timeout_secs)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_reply reply;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_reply reply;
|
||||
|
||||
fill_request(&request_raw, REQUEST_READ, 0, from, len);
|
||||
FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
|
||||
"Couldn't write request");
|
||||
fill_request(&request_raw, REQUEST_READ, 0, from, len);
|
||||
FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
|
||||
"Couldn't write request");
|
||||
|
||||
|
||||
wait_for_data( fd, timeout_secs );
|
||||
read_reply(fd, request_raw.handle.w, &reply);
|
||||
wait_for_data(fd, timeout_secs);
|
||||
read_reply(fd, request_raw.handle.w, &reply);
|
||||
|
||||
if (out_buf) {
|
||||
FATAL_IF_NEGATIVE(readloop(fd, out_buf, len),
|
||||
"Read failed");
|
||||
}
|
||||
else {
|
||||
FATAL_IF_NEGATIVE(
|
||||
splice_via_pipe_loop(fd, out_fd, len),
|
||||
"Splice failed"
|
||||
);
|
||||
}
|
||||
if (out_buf) {
|
||||
FATAL_IF_NEGATIVE(readloop(fd, out_buf, len), "Read failed");
|
||||
} else {
|
||||
FATAL_IF_NEGATIVE(splice_via_pipe_loop(fd, out_fd, len),
|
||||
"Splice failed");
|
||||
}
|
||||
}
|
||||
|
||||
void socket_nbd_write(int fd, uint64_t from, uint32_t len, int in_fd, void* in_buf, int timeout_secs)
|
||||
void socket_nbd_write(int fd, uint64_t from, uint32_t len, int in_fd,
|
||||
void *in_buf, int timeout_secs)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_reply reply;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_reply reply;
|
||||
|
||||
fill_request(&request_raw, REQUEST_WRITE, 0, from, len);
|
||||
ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
|
||||
"Couldn't write request");
|
||||
fill_request(&request_raw, REQUEST_WRITE, 0, from, len);
|
||||
ERROR_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
|
||||
"Couldn't write request");
|
||||
|
||||
if (in_buf) {
|
||||
ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len),
|
||||
"Write failed");
|
||||
}
|
||||
else {
|
||||
ERROR_IF_NEGATIVE(
|
||||
splice_via_pipe_loop(in_fd, fd, len),
|
||||
"Splice failed"
|
||||
);
|
||||
}
|
||||
if (in_buf) {
|
||||
ERROR_IF_NEGATIVE(writeloop(fd, in_buf, len), "Write failed");
|
||||
} else {
|
||||
ERROR_IF_NEGATIVE(splice_via_pipe_loop(in_fd, fd, len),
|
||||
"Splice failed");
|
||||
}
|
||||
|
||||
wait_for_data( fd, timeout_secs );
|
||||
read_reply(fd, request_raw.handle.w, &reply);
|
||||
wait_for_data(fd, timeout_secs);
|
||||
read_reply(fd, request_raw.handle.w, &reply);
|
||||
}
|
||||
|
||||
|
||||
int socket_nbd_disconnect( int fd )
|
||||
int socket_nbd_disconnect(int fd)
|
||||
{
|
||||
int success = 1;
|
||||
struct nbd_request_raw request_raw;
|
||||
int success = 1;
|
||||
struct nbd_request_raw request_raw;
|
||||
|
||||
fill_request( &request_raw, REQUEST_DISCONNECT, 0, 0, 0 );
|
||||
/* FIXME: This shouldn't be a FATAL error. We should just drop
|
||||
* the mirror without affecting the main server.
|
||||
*/
|
||||
FATAL_IF_NEGATIVE( writeloop( fd, &request_raw, sizeof( request_raw ) ),
|
||||
"Failed to write the disconnect request." );
|
||||
return success;
|
||||
fill_request(&request_raw, REQUEST_DISCONNECT, 0, 0, 0);
|
||||
/* FIXME: This shouldn't be a FATAL error. We should just drop
|
||||
* the mirror without affecting the main server.
|
||||
*/
|
||||
FATAL_IF_NEGATIVE(writeloop(fd, &request_raw, sizeof(request_raw)),
|
||||
"Failed to write the disconnect request.");
|
||||
return success;
|
||||
}
|
||||
|
||||
#define CHECK_RANGE(error_type) { \
|
||||
@@ -237,23 +240,26 @@ int socket_nbd_disconnect( int fd )
|
||||
}\
|
||||
}
|
||||
|
||||
void do_read(struct mode_readwrite_params* params)
|
||||
void do_read(struct mode_readwrite_params *params)
|
||||
{
|
||||
params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic);
|
||||
FATAL_IF_NEGATIVE( params->client, "Couldn't connect." );
|
||||
CHECK_RANGE("read");
|
||||
socket_nbd_read(params->client, params->from, params->len,
|
||||
params->data_fd, NULL, 10);
|
||||
close(params->client);
|
||||
params->client =
|
||||
socket_connect(¶ms->connect_to.generic,
|
||||
¶ms->connect_from.generic);
|
||||
FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
|
||||
CHECK_RANGE("read");
|
||||
socket_nbd_read(params->client, params->from, params->len,
|
||||
params->data_fd, NULL, 10);
|
||||
close(params->client);
|
||||
}
|
||||
|
||||
void do_write(struct mode_readwrite_params* params)
|
||||
void do_write(struct mode_readwrite_params *params)
|
||||
{
|
||||
params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic);
|
||||
FATAL_IF_NEGATIVE( params->client, "Couldn't connect." );
|
||||
CHECK_RANGE("write");
|
||||
socket_nbd_write(params->client, params->from, params->len,
|
||||
params->data_fd, NULL, 10);
|
||||
close(params->client);
|
||||
params->client =
|
||||
socket_connect(¶ms->connect_to.generic,
|
||||
¶ms->connect_from.generic);
|
||||
FATAL_IF_NEGATIVE(params->client, "Couldn't connect.");
|
||||
CHECK_RANGE("write");
|
||||
socket_nbd_write(params->client, params->from, params->len,
|
||||
params->data_fd, NULL, 10);
|
||||
close(params->client);
|
||||
}
|
||||
|
||||
|
@@ -6,18 +6,21 @@
|
||||
#include <sys/socket.h>
|
||||
#include "nbdtypes.h"
|
||||
|
||||
int socket_connect(struct sockaddr* to, struct sockaddr* from);
|
||||
int socket_nbd_read_hello(int fd, uint64_t* size, uint32_t* flags);
|
||||
int socket_connect(struct sockaddr *to, struct sockaddr *from);
|
||||
int socket_nbd_read_hello(int fd, uint64_t * size, uint32_t * flags);
|
||||
int socket_nbd_write_hello(int fd, uint64_t size, uint32_t flags);
|
||||
void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs);
|
||||
void socket_nbd_write(int fd, uint64_t from, uint32_t len, int out_fd, void* out_buf, int timeout_secs);
|
||||
int socket_nbd_disconnect( int fd );
|
||||
void socket_nbd_read(int fd, uint64_t from, uint32_t len, int out_fd,
|
||||
void *out_buf, int timeout_secs);
|
||||
void socket_nbd_write(int fd, uint64_t from, uint32_t len, int out_fd,
|
||||
void *out_buf, int timeout_secs);
|
||||
int socket_nbd_disconnect(int fd);
|
||||
|
||||
/* as you can see, we're slowly accumulating code that should really be in an
|
||||
* NBD library */
|
||||
|
||||
void nbd_hello_to_buf( struct nbd_init_raw* buf, uint64_t out_size, uint32_t out_flags );
|
||||
int nbd_check_hello( struct nbd_init_raw* init_raw, uint64_t* out_size, uint32_t* out_flags );
|
||||
void nbd_hello_to_buf(struct nbd_init_raw *buf, uint64_t out_size,
|
||||
uint32_t out_flags);
|
||||
int nbd_check_hello(struct nbd_init_raw *init_raw, uint64_t * out_size,
|
||||
uint32_t * out_flags);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -4,64 +4,62 @@
|
||||
#include <stdlib.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;
|
||||
FILE * out;
|
||||
int exit_status;
|
||||
char *response_text;
|
||||
FILE *out;
|
||||
int exit_status;
|
||||
|
||||
NULLCHECK( response );
|
||||
NULLCHECK(response);
|
||||
|
||||
exit_status = atoi(response);
|
||||
response_text = strchr( response, ':' );
|
||||
exit_status = atoi(response);
|
||||
response_text = strchr(response, ':');
|
||||
|
||||
FATAL_IF_NULL( response_text,
|
||||
"Error parsing server response: '%s'", response );
|
||||
FATAL_IF_NULL(response_text,
|
||||
"Error parsing server response: '%s'", response);
|
||||
|
||||
out = exit_status > 0 ? stderr : stdout;
|
||||
fprintf(out, "%s\n", response_text + 2);
|
||||
out = exit_status > 0 ? stderr : stdout;
|
||||
fprintf(out, "%s\n", response_text + 2);
|
||||
}
|
||||
|
||||
void do_remote_command(char* command, char* socket_name, int argc, char** argv)
|
||||
void do_remote_command(char *command, char *socket_name, int argc,
|
||||
char **argv)
|
||||
{
|
||||
char newline=10;
|
||||
int i;
|
||||
debug( "connecting to run remote command %s", command );
|
||||
int remote = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
struct sockaddr_un address;
|
||||
char response[max_response];
|
||||
char newline = 10;
|
||||
int i;
|
||||
debug("connecting to run remote command %s", command);
|
||||
int remote = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
struct sockaddr_un address;
|
||||
char response[max_response];
|
||||
|
||||
memset(&address, 0, sizeof(address));
|
||||
memset(&address, 0, sizeof(address));
|
||||
|
||||
FATAL_IF_NEGATIVE(remote, "Couldn't create client socket");
|
||||
FATAL_IF_NEGATIVE(remote, "Couldn't create client socket");
|
||||
|
||||
address.sun_family = AF_UNIX;
|
||||
strncpy(address.sun_path, socket_name, sizeof(address.sun_path));
|
||||
address.sun_family = AF_UNIX;
|
||||
strncpy(address.sun_path, socket_name, sizeof(address.sun_path));
|
||||
|
||||
FATAL_IF_NEGATIVE(
|
||||
connect(remote, (struct sockaddr*) &address, sizeof(address)),
|
||||
"Couldn't connect to %s", socket_name
|
||||
);
|
||||
FATAL_IF_NEGATIVE(connect
|
||||
(remote, (struct sockaddr *) &address,
|
||||
sizeof(address)), "Couldn't connect to %s",
|
||||
socket_name);
|
||||
|
||||
write(remote, command, strlen(command));
|
||||
write(remote, &newline, 1);
|
||||
for (i=0; i<argc; i++) {
|
||||
if ( NULL != argv[i] ) {
|
||||
write(remote, argv[i], strlen(argv[i]));
|
||||
}
|
||||
write(remote, &newline, 1);
|
||||
write(remote, command, strlen(command));
|
||||
write(remote, &newline, 1);
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (NULL != argv[i]) {
|
||||
write(remote, argv[i], strlen(argv[i]));
|
||||
}
|
||||
write(remote, &newline, 1);
|
||||
}
|
||||
write(remote, &newline, 1);
|
||||
|
||||
FATAL_IF_NEGATIVE(
|
||||
read_until_newline(remote, response, max_response),
|
||||
"Couldn't read response from %s", socket_name
|
||||
);
|
||||
FATAL_IF_NEGATIVE(read_until_newline(remote, response, max_response),
|
||||
"Couldn't read response from %s", socket_name);
|
||||
|
||||
print_response( response );
|
||||
print_response(response);
|
||||
|
||||
exit(atoi(response));
|
||||
exit(atoi(response));
|
||||
}
|
||||
|
||||
|
@@ -29,13 +29,13 @@
|
||||
#define ERR_MSG_WRITE "Couldn't write to a signaling pipe."
|
||||
#define ERR_MSG_READ "Couldn't read from a signaling pipe."
|
||||
|
||||
void self_pipe_server_error( int err, char *msg )
|
||||
void self_pipe_server_error(int err, char *msg)
|
||||
{
|
||||
char errbuf[1024] = {0};
|
||||
char errbuf[1024] = { 0 };
|
||||
|
||||
strerror_r( err, errbuf, 1024 );
|
||||
strerror_r(err, errbuf, 1024);
|
||||
|
||||
fatal( "%s\t%d (%s)", msg, err, errbuf );
|
||||
fatal("%s\t%d (%s)", msg, err, errbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,33 +47,36 @@ void self_pipe_server_error( int err, char *msg )
|
||||
* Remember to call self_pipe_destroy when you're done with the return
|
||||
* value.
|
||||
*/
|
||||
struct self_pipe * self_pipe_create(void)
|
||||
struct self_pipe *self_pipe_create(void)
|
||||
{
|
||||
struct self_pipe *sig = xmalloc( sizeof( struct self_pipe ) );
|
||||
int fds[2];
|
||||
struct self_pipe *sig = xmalloc(sizeof(struct self_pipe));
|
||||
int fds[2];
|
||||
|
||||
if ( NULL == sig ) { return NULL; }
|
||||
if (NULL == sig) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( pipe( fds ) ) {
|
||||
free( sig );
|
||||
self_pipe_server_error( errno, ERR_MSG_PIPE );
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
while( close( fds[0] ) == -1 && errno == EINTR );
|
||||
while( close( fds[1] ) == -1 && errno == EINTR );
|
||||
free( sig );
|
||||
self_pipe_server_error( fcntl_err, ERR_MSG_FCNTL );
|
||||
if (fcntl(fds[0], F_SETFL, O_NONBLOCK)
|
||||
|| fcntl(fds[1], F_SETFL, O_NONBLOCK)) {
|
||||
int fcntl_err = errno;
|
||||
while (close(fds[0]) == -1 && errno == EINTR);
|
||||
while (close(fds[1]) == -1 && errno == EINTR);
|
||||
free(sig);
|
||||
self_pipe_server_error(fcntl_err, ERR_MSG_FCNTL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig->read_fd = fds[0];
|
||||
sig->write_fd = fds[1];
|
||||
sig->read_fd = fds[0];
|
||||
sig->write_fd = fds[1];
|
||||
|
||||
return sig;
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,19 +86,19 @@ struct self_pipe * self_pipe_create(void)
|
||||
* Returns 1 on success. Can fail if weirdness happened to the write fd
|
||||
* of the pipe in the self_pipe struct.
|
||||
*/
|
||||
int self_pipe_signal( struct self_pipe * sig )
|
||||
int self_pipe_signal(struct self_pipe *sig)
|
||||
{
|
||||
NULLCHECK( sig );
|
||||
FATAL_IF( 1 == sig->write_fd, "Shouldn't be writing to stdout" );
|
||||
FATAL_IF( 2 == sig->write_fd, "Shouldn't be writing to stderr" );
|
||||
NULLCHECK(sig);
|
||||
FATAL_IF(1 == sig->write_fd, "Shouldn't be writing to stdout");
|
||||
FATAL_IF(2 == sig->write_fd, "Shouldn't be writing to stderr");
|
||||
|
||||
int written = write( sig->write_fd, "X", 1 );
|
||||
if ( written != 1 ) {
|
||||
self_pipe_server_error( errno, ERR_MSG_WRITE );
|
||||
return 0;
|
||||
}
|
||||
int written = write(sig->write_fd, "X", 1);
|
||||
if (written != 1) {
|
||||
self_pipe_server_error(errno, ERR_MSG_WRITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,11 +109,11 @@ int self_pipe_signal( struct self_pipe * sig )
|
||||
* Returns the number of bytes read, which will be 1 on success and 0 if
|
||||
* there was no signal.
|
||||
*/
|
||||
int self_pipe_signal_clear( struct self_pipe *sig )
|
||||
int self_pipe_signal_clear(struct self_pipe *sig)
|
||||
{
|
||||
char buf[1];
|
||||
char buf[1];
|
||||
|
||||
return 1 == read( sig->read_fd, buf, 1 );
|
||||
return 1 == read(sig->read_fd, buf, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,30 +121,30 @@ int self_pipe_signal_clear( struct self_pipe *sig )
|
||||
* Close the pipe and free the self_pipe. Do not try to use the
|
||||
* self_pipe struct after calling this, the innards are mush.
|
||||
*/
|
||||
int self_pipe_destroy( struct self_pipe * sig )
|
||||
int self_pipe_destroy(struct self_pipe *sig)
|
||||
{
|
||||
NULLCHECK(sig);
|
||||
NULLCHECK(sig);
|
||||
|
||||
while( close( sig->read_fd ) == -1 && errno == EINTR );
|
||||
while( close( sig->write_fd ) == -1 && errno == EINTR );
|
||||
while (close(sig->read_fd) == -1 && errno == EINTR);
|
||||
while (close(sig->write_fd) == -1 && errno == EINTR);
|
||||
|
||||
/* Just in case anyone *does* try to use this after free,
|
||||
* we should set the memory locations to an error value
|
||||
*/
|
||||
sig->read_fd = -1;
|
||||
sig->write_fd = -1;
|
||||
/* Just in case anyone *does* try to use this after free,
|
||||
* we should set the memory locations to an error value
|
||||
*/
|
||||
sig->read_fd = -1;
|
||||
sig->write_fd = -1;
|
||||
|
||||
free( sig );
|
||||
return 1;
|
||||
free(sig);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int self_pipe_fd_set( struct self_pipe * sig, fd_set * fds)
|
||||
int self_pipe_fd_set(struct self_pipe *sig, fd_set * fds)
|
||||
{
|
||||
FD_SET( sig->read_fd, fds );
|
||||
return 1;
|
||||
FD_SET(sig->read_fd, fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int self_pipe_fd_isset( struct self_pipe * sig, fd_set * fds)
|
||||
int self_pipe_fd_isset(struct self_pipe *sig, fd_set * fds)
|
||||
{
|
||||
return FD_ISSET( sig->read_fd, fds );
|
||||
return FD_ISSET(sig->read_fd, fds);
|
||||
}
|
||||
|
@@ -4,16 +4,16 @@
|
||||
#include <sys/select.h>
|
||||
|
||||
struct self_pipe {
|
||||
int read_fd;
|
||||
int write_fd;
|
||||
int read_fd;
|
||||
int write_fd;
|
||||
};
|
||||
|
||||
|
||||
struct self_pipe * self_pipe_create(void);
|
||||
int self_pipe_signal( struct self_pipe * sig );
|
||||
int self_pipe_signal_clear( struct self_pipe *sig );
|
||||
int self_pipe_destroy( struct self_pipe * sig );
|
||||
int self_pipe_fd_set( struct self_pipe * sig, fd_set * fds );
|
||||
int self_pipe_fd_isset( struct self_pipe *sig, fd_set *fds );
|
||||
struct self_pipe *self_pipe_create(void);
|
||||
int self_pipe_signal(struct self_pipe *sig);
|
||||
int self_pipe_signal_clear(struct self_pipe *sig);
|
||||
int self_pipe_destroy(struct self_pipe *sig);
|
||||
int self_pipe_fd_set(struct self_pipe *sig, fd_set * fds);
|
||||
int self_pipe_fd_isset(struct self_pipe *sig, fd_set * fds);
|
||||
|
||||
#endif
|
||||
|
@@ -9,279 +9,287 @@
|
||||
#include "sockutil.h"
|
||||
#include "util.h"
|
||||
|
||||
size_t sockaddr_size( const struct sockaddr* sa )
|
||||
size_t sockaddr_size(const struct sockaddr * sa)
|
||||
{
|
||||
struct sockaddr_un* un = (struct sockaddr_un*) sa;
|
||||
size_t ret = 0;
|
||||
struct sockaddr_un *un = (struct sockaddr_un *) sa;
|
||||
size_t ret = 0;
|
||||
|
||||
switch( sa->sa_family ) {
|
||||
case AF_INET:
|
||||
ret = sizeof( struct sockaddr_in );
|
||||
break;
|
||||
case AF_INET6:
|
||||
ret = sizeof( struct sockaddr_in6 );
|
||||
break;
|
||||
case AF_UNIX:
|
||||
ret = sizeof( un->sun_family ) + SUN_LEN( un );
|
||||
break;
|
||||
}
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
ret = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ret = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
case AF_UNIX:
|
||||
ret = sizeof(un->sun_family) + SUN_LEN(un);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* sockaddr_address_string( const struct sockaddr* sa, char* dest, size_t len )
|
||||
const char *sockaddr_address_string(const struct sockaddr *sa, char *dest,
|
||||
size_t len)
|
||||
{
|
||||
NULLCHECK( sa );
|
||||
NULLCHECK( dest );
|
||||
NULLCHECK(sa);
|
||||
NULLCHECK(dest);
|
||||
|
||||
struct sockaddr_in* in = ( struct sockaddr_in* ) sa;
|
||||
struct sockaddr_in6* in6 = ( struct sockaddr_in6* ) sa;
|
||||
struct sockaddr_un* un = ( struct sockaddr_un* ) sa;
|
||||
struct sockaddr_in *in = (struct sockaddr_in *) sa;
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) sa;
|
||||
struct sockaddr_un *un = (struct sockaddr_un *) sa;
|
||||
|
||||
unsigned short real_port = ntohs( in->sin_port ); // common to in and in6
|
||||
const char* ret = NULL;
|
||||
unsigned short real_port = ntohs(in->sin_port); // common to in and in6
|
||||
const char *ret = NULL;
|
||||
|
||||
memset( dest, 0, len );
|
||||
memset(dest, 0, len);
|
||||
|
||||
if ( sa->sa_family == AF_INET ) {
|
||||
ret = inet_ntop( AF_INET, &in->sin_addr, dest, len );
|
||||
} else if ( sa->sa_family == AF_INET6 ) {
|
||||
ret = inet_ntop( AF_INET6, &in6->sin6_addr, dest, len );
|
||||
} else if ( sa->sa_family == AF_UNIX ) {
|
||||
ret = strncpy( dest, un->sun_path, SUN_LEN( un ) );
|
||||
}
|
||||
if (sa->sa_family == AF_INET) {
|
||||
ret = inet_ntop(AF_INET, &in->sin_addr, dest, len);
|
||||
} else if (sa->sa_family == AF_INET6) {
|
||||
ret = inet_ntop(AF_INET6, &in6->sin6_addr, dest, len);
|
||||
} else if (sa->sa_family == AF_UNIX) {
|
||||
ret = strncpy(dest, un->sun_path, SUN_LEN(un));
|
||||
}
|
||||
|
||||
if ( ret == NULL ) {
|
||||
strncpy( dest, "???", len );
|
||||
}
|
||||
if (ret == NULL) {
|
||||
strncpy(dest, "???", len);
|
||||
}
|
||||
|
||||
if ( NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX ) {
|
||||
size_t size = strlen( dest );
|
||||
snprintf( dest + size, len - size, " port %d", real_port );
|
||||
}
|
||||
if (NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX) {
|
||||
size_t size = strlen(dest);
|
||||
snprintf(dest + size, len - size, " port %d", real_port);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sock_set_reuseaddr( int fd, int optval )
|
||||
int sock_set_reuseaddr(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_keepalive_params( int fd, int time, int intvl, int probes)
|
||||
int sock_set_keepalive_params(int fd, int time, int intvl, int probes)
|
||||
{
|
||||
if (sock_set_keepalive(fd, 1) ||
|
||||
sock_set_tcp_keepidle(fd, time) ||
|
||||
sock_set_tcp_keepintvl(fd, intvl) ||
|
||||
sock_set_tcp_keepcnt(fd, probes)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
if (sock_set_keepalive(fd, 1) ||
|
||||
sock_set_tcp_keepidle(fd, time) ||
|
||||
sock_set_tcp_keepintvl(fd, intvl) ||
|
||||
sock_set_tcp_keepcnt(fd, probes)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sock_set_keepalive( int fd, int optval )
|
||||
int sock_set_keepalive(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_tcp_keepidle( int fd, int optval )
|
||||
int sock_set_tcp_keepidle(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_tcp_keepintvl( int fd, int optval )
|
||||
int sock_set_tcp_keepintvl(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_tcp_keepcnt( int fd, int optval )
|
||||
int sock_set_tcp_keepcnt(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
/* Set the tcp_nodelay option */
|
||||
int sock_set_tcp_nodelay( int fd, int optval )
|
||||
int sock_set_tcp_nodelay(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval,
|
||||
sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_tcp_cork( int fd, int optval )
|
||||
int sock_set_tcp_cork(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval) );
|
||||
return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval));
|
||||
}
|
||||
|
||||
int sock_set_nonblock( int fd, int optval )
|
||||
int sock_set_nonblock(int fd, int optval)
|
||||
{
|
||||
int flags = fcntl( fd, F_GETFL );
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
|
||||
if ( flags == -1 ) {
|
||||
return -1;
|
||||
}
|
||||
if (flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( optval ) {
|
||||
flags = flags | O_NONBLOCK;
|
||||
if (optval) {
|
||||
flags = flags | O_NONBLOCK;
|
||||
} else {
|
||||
flags = flags & (~O_NONBLOCK);
|
||||
}
|
||||
|
||||
return fcntl(fd, F_SETFL, flags);
|
||||
}
|
||||
|
||||
int sock_try_bind(int fd, const struct sockaddr *sa)
|
||||
{
|
||||
int bind_result;
|
||||
char s_address[256];
|
||||
int retry = 10;
|
||||
|
||||
sockaddr_address_string(sa, &s_address[0], 256);
|
||||
|
||||
do {
|
||||
bind_result = bind(fd, sa, sockaddr_size(sa));
|
||||
if (0 == bind_result) {
|
||||
info("Bound to %s", s_address);
|
||||
break;
|
||||
} else {
|
||||
flags = flags & (~O_NONBLOCK);
|
||||
warn(SHOW_ERRNO("Couldn't bind to %s", s_address));
|
||||
|
||||
switch (errno) {
|
||||
/* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF,
|
||||
* EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT,
|
||||
* ENOMEM, ENOTDIR, EROFS
|
||||
*
|
||||
* Any of these other than EADDRINUSE & EADDRNOTAVAIL signify
|
||||
* that there's a logic error somewhere.
|
||||
*
|
||||
* EADDRINUSE is fatal: if there's something already where we
|
||||
* want to be listening, we have no guarantees that any clients
|
||||
* will cope with it.
|
||||
*/
|
||||
case EADDRNOTAVAIL:
|
||||
retry--;
|
||||
if (retry) {
|
||||
debug("retrying");
|
||||
sleep(1);
|
||||
}
|
||||
continue;
|
||||
case EADDRINUSE:
|
||||
warn("%s in use, giving up.", s_address);
|
||||
retry = 0;
|
||||
break;
|
||||
default:
|
||||
warn("giving up");
|
||||
retry = 0;
|
||||
}
|
||||
}
|
||||
} while (retry);
|
||||
|
||||
return bind_result;
|
||||
}
|
||||
|
||||
int sock_try_select(int nfds, fd_set * readfds, fd_set * writefds,
|
||||
fd_set * exceptfds, struct timeval *timeout)
|
||||
{
|
||||
int result;
|
||||
|
||||
do {
|
||||
result = select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
if (errno != EINTR) {
|
||||
break;
|
||||
}
|
||||
|
||||
return fcntl( fd, F_SETFL, flags );
|
||||
} while (result == -1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int sock_try_bind( int fd, const struct sockaddr* sa )
|
||||
int sock_try_connect(int fd, struct sockaddr *to, socklen_t addrlen,
|
||||
int wait)
|
||||
{
|
||||
int bind_result;
|
||||
char s_address[256];
|
||||
int retry = 10;
|
||||
fd_set fds;
|
||||
struct timeval tv = { wait, 0 };
|
||||
int result = 0;
|
||||
|
||||
sockaddr_address_string( sa, &s_address[0], 256 );
|
||||
if (sock_set_nonblock(fd, 1) == -1) {
|
||||
warn(SHOW_ERRNO
|
||||
("Failed to set socket non-blocking for connect()"));
|
||||
return connect(fd, to, addrlen);
|
||||
}
|
||||
|
||||
do {
|
||||
bind_result = bind( fd, sa, sockaddr_size( sa ) );
|
||||
if ( 0 == bind_result ) {
|
||||
info( "Bound to %s", s_address );
|
||||
break;
|
||||
}
|
||||
else {
|
||||
warn( SHOW_ERRNO( "Couldn't bind to %s", s_address ) );
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
switch ( errno ) {
|
||||
/* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF,
|
||||
* EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT,
|
||||
* ENOMEM, ENOTDIR, EROFS
|
||||
*
|
||||
* Any of these other than EADDRINUSE & EADDRNOTAVAIL signify
|
||||
* that there's a logic error somewhere.
|
||||
*
|
||||
* EADDRINUSE is fatal: if there's something already where we
|
||||
* want to be listening, we have no guarantees that any clients
|
||||
* will cope with it.
|
||||
*/
|
||||
case EADDRNOTAVAIL:
|
||||
retry--;
|
||||
if (retry) {
|
||||
debug( "retrying" );
|
||||
sleep( 1 );
|
||||
}
|
||||
continue;
|
||||
case EADDRINUSE:
|
||||
warn( "%s in use, giving up.", s_address );
|
||||
retry = 0;
|
||||
break;
|
||||
default:
|
||||
warn( "giving up" );
|
||||
retry = 0;
|
||||
}
|
||||
}
|
||||
} while ( retry );
|
||||
do {
|
||||
result = connect(fd, to, addrlen);
|
||||
|
||||
return bind_result;
|
||||
}
|
||||
|
||||
int sock_try_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
int result;
|
||||
|
||||
do {
|
||||
result = select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
if ( errno != EINTR ) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while ( result == -1 );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int sock_try_connect( int fd, struct sockaddr* to, socklen_t addrlen, int wait )
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv = { wait, 0 };
|
||||
int result = 0;
|
||||
|
||||
if ( sock_set_nonblock( fd, 1 ) == -1 ) {
|
||||
warn( SHOW_ERRNO( "Failed to set socket non-blocking for connect()" ) );
|
||||
return connect( fd, to, addrlen );
|
||||
}
|
||||
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( fd, &fds );
|
||||
|
||||
do {
|
||||
result = connect( fd, to, addrlen );
|
||||
|
||||
if ( result == -1 ) {
|
||||
switch( errno ) {
|
||||
case EINPROGRESS:
|
||||
result = 0;
|
||||
break; /* success */
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
/* Try connect() again. This only breaks out of the switch,
|
||||
* not the do...while loop. since result == -1, we go again.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
warn( SHOW_ERRNO( "Failed to connect()" ) );
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} while ( result == -1 );
|
||||
|
||||
if ( -1 == sock_try_select( FD_SETSIZE, NULL, &fds, NULL, &tv) ) {
|
||||
warn( SHOW_ERRNO( "failed to select() on non-blocking connect" ) );
|
||||
result = -1;
|
||||
if (result == -1) {
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
result = 0;
|
||||
break; /* success */
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
/* Try connect() again. This only breaks out of the switch,
|
||||
* not the do...while loop. since result == -1, we go again.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
warn(SHOW_ERRNO("Failed to connect()"));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} while (result == -1);
|
||||
|
||||
if ( !FD_ISSET( fd, &fds ) ) {
|
||||
result = -1;
|
||||
errno = ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
if (-1 == sock_try_select(FD_SETSIZE, NULL, &fds, NULL, &tv)) {
|
||||
warn(SHOW_ERRNO("failed to select() on non-blocking connect"));
|
||||
result = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int scratch;
|
||||
socklen_t s_size = sizeof( scratch );
|
||||
if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size ) == -1 ) {
|
||||
result = -1;
|
||||
warn( SHOW_ERRNO( "getsockopt() failed" ) );
|
||||
goto out;
|
||||
}
|
||||
if (!FD_ISSET(fd, &fds)) {
|
||||
result = -1;
|
||||
errno = ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( scratch == EINPROGRESS ) {
|
||||
scratch = ETIMEDOUT;
|
||||
}
|
||||
int scratch;
|
||||
socklen_t s_size = sizeof(scratch);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &scratch, &s_size) == -1) {
|
||||
result = -1;
|
||||
warn(SHOW_ERRNO("getsockopt() failed"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = scratch ? -1 : 0;
|
||||
errno = scratch;
|
||||
if (scratch == EINPROGRESS) {
|
||||
scratch = ETIMEDOUT;
|
||||
}
|
||||
|
||||
out:
|
||||
if ( sock_set_nonblock( fd, 0 ) == -1 ) {
|
||||
warn( SHOW_ERRNO( "Failed to make socket blocking after connect()" ) );
|
||||
return -1;
|
||||
}
|
||||
result = scratch ? -1 : 0;
|
||||
errno = scratch;
|
||||
|
||||
debug( "sock_try_connect: %i", result );
|
||||
return result;
|
||||
out:
|
||||
if (sock_set_nonblock(fd, 0) == -1) {
|
||||
warn(SHOW_ERRNO("Failed to make socket blocking after connect()"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("sock_try_connect: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int sock_try_close( int fd )
|
||||
int sock_try_close(int fd)
|
||||
{
|
||||
int result;
|
||||
int result;
|
||||
|
||||
do {
|
||||
result = close( fd );
|
||||
do {
|
||||
result = close(fd);
|
||||
|
||||
if ( result == -1 ) {
|
||||
if ( EINTR == errno ) {
|
||||
continue; /* retry EINTR */
|
||||
} else {
|
||||
warn( SHOW_ERRNO( "Failed to close() fd %i", fd ) );
|
||||
break; /* Other errors get reported */
|
||||
}
|
||||
}
|
||||
if (result == -1) {
|
||||
if (EINTR == errno) {
|
||||
continue; /* retry EINTR */
|
||||
} else {
|
||||
warn(SHOW_ERRNO("Failed to close() fd %i", fd));
|
||||
break; /* Other errors get reported */
|
||||
}
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
} while (0);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -7,15 +7,16 @@
|
||||
#include <sys/select.h>
|
||||
|
||||
/* Returns the size of the sockaddr, or 0 on error */
|
||||
size_t sockaddr_size(const struct sockaddr* sa);
|
||||
size_t sockaddr_size(const struct sockaddr *sa);
|
||||
|
||||
/* Convert a sockaddr into an address. Like inet_ntop, it returns dest if
|
||||
* successful, NULL otherwise. In the latter case, dest will contain "???"
|
||||
*/
|
||||
const char* sockaddr_address_string(const struct sockaddr* sa, char* dest, size_t len);
|
||||
const char *sockaddr_address_string(const struct sockaddr *sa, char *dest,
|
||||
size_t len);
|
||||
|
||||
/* Configure TCP keepalive on a socket */
|
||||
int sock_set_keepalive_params( int fd, int time, int intvl, int probes);
|
||||
int sock_set_keepalive_params(int fd, int time, int intvl, int probes);
|
||||
|
||||
/* Set the SOL_KEEPALIVE otion */
|
||||
int sock_set_keepalive(int fd, int optval);
|
||||
@@ -41,16 +42,17 @@ int sock_set_tcp_cork(int fd, int optval);
|
||||
int sock_set_nonblock(int fd, int optval);
|
||||
|
||||
/* Attempt to bind the fd to the sockaddr, retrying common transient failures */
|
||||
int sock_try_bind(int fd, const struct sockaddr* sa);
|
||||
int sock_try_bind(int fd, const struct sockaddr *sa);
|
||||
|
||||
/* Try to call select(), retrying EINTR */
|
||||
int sock_try_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
|
||||
int sock_try_select(int nfds, fd_set * readfds, fd_set * writefds,
|
||||
fd_set * exceptfds, struct timeval *timeout);
|
||||
|
||||
/* Try to call connect(), timing out after wait seconds */
|
||||
int sock_try_connect( int fd, struct sockaddr* to, socklen_t addrlen, int wait );
|
||||
int sock_try_connect(int fd, struct sockaddr *to, socklen_t addrlen,
|
||||
int wait);
|
||||
|
||||
/* Try to call close(), retrying EINTR */
|
||||
int sock_try_close( int fd );
|
||||
int sock_try_close(int fd);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -17,72 +17,75 @@ char *log_context = "";
|
||||
|
||||
void error_init(void)
|
||||
{
|
||||
pthread_key_create(&cleanup_handler_key, free);
|
||||
pthread_key_create(&cleanup_handler_key, free);
|
||||
}
|
||||
|
||||
void error_handler(int fatal)
|
||||
{
|
||||
DECLARE_ERROR_CONTEXT(context);
|
||||
DECLARE_ERROR_CONTEXT(context);
|
||||
|
||||
if (context) {
|
||||
longjmp(context->jmp, fatal ? 1 : 2 );
|
||||
}
|
||||
else {
|
||||
if ( fatal ) { abort(); }
|
||||
else { pthread_exit((void*) 1); }
|
||||
if (context) {
|
||||
longjmp(context->jmp, fatal ? 1 : 2);
|
||||
} else {
|
||||
if (fatal) {
|
||||
abort();
|
||||
} else {
|
||||
pthread_exit((void *) 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void exit_err( const char *msg )
|
||||
void exit_err(const char *msg)
|
||||
{
|
||||
fprintf( stderr, "%s\n", msg );
|
||||
exit( 1 );
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void mylog(int line_level, const char* format, ...)
|
||||
void mylog(int line_level, const char *format, ...)
|
||||
{
|
||||
if (line_level < log_level) { return; }
|
||||
if (line_level < log_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list argptr;
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, format);
|
||||
vfprintf(stderr, format, argptr);
|
||||
va_end(argptr);
|
||||
va_start(argptr, format);
|
||||
vfprintf(stderr, format, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
uint64_t monotonic_time_ms()
|
||||
{
|
||||
struct timespec ts;
|
||||
uint64_t seconds_ms, nanoseconds_ms;
|
||||
struct timespec ts;
|
||||
uint64_t seconds_ms, nanoseconds_ms;
|
||||
|
||||
FATAL_IF_NEGATIVE(
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts),
|
||||
SHOW_ERRNO( "clock_gettime failed" )
|
||||
FATAL_IF_NEGATIVE(clock_gettime(CLOCK_MONOTONIC, &ts),
|
||||
SHOW_ERRNO("clock_gettime failed")
|
||||
);
|
||||
|
||||
seconds_ms = ts.tv_sec;
|
||||
seconds_ms = seconds_ms * 1000;
|
||||
seconds_ms = ts.tv_sec;
|
||||
seconds_ms = seconds_ms * 1000;
|
||||
|
||||
nanoseconds_ms = ts.tv_nsec;
|
||||
nanoseconds_ms = nanoseconds_ms / 1000000;
|
||||
nanoseconds_ms = ts.tv_nsec;
|
||||
nanoseconds_ms = nanoseconds_ms / 1000000;
|
||||
|
||||
return seconds_ms + nanoseconds_ms;
|
||||
return seconds_ms + nanoseconds_ms;
|
||||
}
|
||||
|
||||
|
||||
void* xrealloc(void* ptr, size_t size)
|
||||
void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void* p = realloc(ptr, size);
|
||||
FATAL_IF_NULL(p, "couldn't xrealloc %d bytes", ptr ? "realloc" : "malloc", size);
|
||||
return p;
|
||||
void *p = realloc(ptr, size);
|
||||
FATAL_IF_NULL(p, "couldn't xrealloc %d bytes",
|
||||
ptr ? "realloc" : "malloc", size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* xmalloc(size_t size)
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void* p = xrealloc(NULL, size);
|
||||
memset(p, 0, size);
|
||||
return p;
|
||||
void *p = xrealloc(NULL, size);
|
||||
memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@@ -10,10 +10,11 @@
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void* xrealloc(void* ptr, size_t size);
|
||||
void* xmalloc(size_t size);
|
||||
void *xrealloc(void *ptr, size_t size);
|
||||
void *xmalloc(size_t size);
|
||||
|
||||
typedef void (cleanup_handler)(void* /* context */, int /* is fatal? */);
|
||||
typedef void (cleanup_handler) (void * /* context */ ,
|
||||
int /* is fatal? */ );
|
||||
|
||||
/* set from 0 - 5 depending on what level of verbosity you want */
|
||||
extern int log_level;
|
||||
@@ -25,15 +26,15 @@ void error_init(void);
|
||||
extern char *log_context;
|
||||
|
||||
|
||||
void exit_err( const char * );
|
||||
void exit_err(const char *);
|
||||
|
||||
/* error_set_handler must be a macro not a function due to setjmp stack rules */
|
||||
#include <setjmp.h>
|
||||
|
||||
struct error_handler_context {
|
||||
jmp_buf jmp;
|
||||
cleanup_handler* handler;
|
||||
void* data;
|
||||
jmp_buf jmp;
|
||||
cleanup_handler *handler;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define DECLARE_ERROR_CONTEXT(name) \
|
||||
@@ -87,7 +88,7 @@ extern pthread_key_t cleanup_handler_key;
|
||||
void error_handler(int fatal);
|
||||
|
||||
/* mylog a line at the given level (0 being most verbose) */
|
||||
void mylog(int line_level, const char* format, ...);
|
||||
void mylog(int line_level, const char *format, ...);
|
||||
|
||||
/* Returns the current time, in milliseconds, from CLOCK_MONOTONIC */
|
||||
uint64_t monotonic_time_ms(void);
|
||||
@@ -98,9 +99,9 @@ uint64_t monotonic_time_ms(void);
|
||||
#define myloglev(level, msg, ...) mylog( level, "%"PRIu64":%c:%d %p %s %s:%d: "msg"\n", monotonic_time_ms(), levstr(level), getpid(),pthread_self(), log_context, __FILE__, __LINE__, ##__VA_ARGS__ )
|
||||
|
||||
#ifdef DEBUG
|
||||
# define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__)
|
||||
#define debug(msg, ...) myloglev(0, msg, ##__VA_ARGS__)
|
||||
#else
|
||||
# define debug(msg, ...) /* no-op */
|
||||
#define debug(msg, ...) /* no-op */
|
||||
#endif
|
||||
|
||||
/* informational message, not expected to be compiled out */
|
||||
@@ -162,4 +163,3 @@ uint64_t monotonic_time_ms(void);
|
||||
#define WARN_IF_NEGATIVE( value, msg, ... ) if ( value < 0 ) { warn( msg, ##__VA_ARGS__ ); }
|
||||
|
||||
#endif
|
||||
|
||||
|
19
src/main.c
19
src/main.c
@@ -5,18 +5,17 @@
|
||||
#include <stdlib.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 */
|
||||
error_init();
|
||||
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
|
||||
error_init();
|
||||
|
||||
srand(time(NULL));
|
||||
srand(time(NULL));
|
||||
|
||||
if (argc < 2) {
|
||||
exit_err( help_help_text );
|
||||
}
|
||||
mode(argv[1], argc-1, argv+1); /* never returns */
|
||||
if (argc < 2) {
|
||||
exit_err(help_help_text);
|
||||
}
|
||||
mode(argv[1], argc - 1, argv + 1); /* never returns */
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
260
src/proxy-main.c
260
src/proxy-main.c
@@ -8,164 +8,158 @@
|
||||
|
||||
|
||||
static struct option proxy_options[] = {
|
||||
GETOPT_HELP,
|
||||
GETOPT_ADDR,
|
||||
GETOPT_PORT,
|
||||
GETOPT_CONNECT_ADDR,
|
||||
GETOPT_CONNECT_PORT,
|
||||
GETOPT_BIND,
|
||||
GETOPT_CACHE,
|
||||
GETOPT_QUIET,
|
||||
GETOPT_VERBOSE,
|
||||
{0}
|
||||
GETOPT_HELP,
|
||||
GETOPT_ADDR,
|
||||
GETOPT_PORT,
|
||||
GETOPT_CONNECT_ADDR,
|
||||
GETOPT_CONNECT_PORT,
|
||||
GETOPT_BIND,
|
||||
GETOPT_CACHE,
|
||||
GETOPT_QUIET,
|
||||
GETOPT_VERBOSE,
|
||||
{0}
|
||||
};
|
||||
|
||||
static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE;
|
||||
static char proxy_help_text[] =
|
||||
"Usage: flexnbd-proxy <options>\n\n"
|
||||
"Resiliently proxy an NBD connection between client and server\n"
|
||||
"We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n"
|
||||
HELP_LINE
|
||||
"\t--" OPT_ADDR ",-l <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_CONNECT_ADDR ",-C <ADDR>\tAddress 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_CACHE ",-c[=<CACHE-BYTES>]\tUse a RAM read cache of the given size.\n"
|
||||
QUIET_LINE
|
||||
VERBOSE_LINE;
|
||||
"Usage: flexnbd-proxy <options>\n\n"
|
||||
"Resiliently proxy an NBD connection between client and server\n"
|
||||
"We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n"
|
||||
HELP_LINE
|
||||
"\t--" OPT_ADDR ",-l <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_CONNECT_ADDR ",-C <ADDR>\tAddress 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_CACHE
|
||||
",-c[=<CACHE-BYTES>]\tUse a RAM read cache of the given size.\n"
|
||||
QUIET_LINE VERBOSE_LINE;
|
||||
|
||||
static char proxy_default_cache_size[] = "4096";
|
||||
|
||||
void read_proxy_param(
|
||||
int c,
|
||||
char **downstream_addr,
|
||||
char **downstream_port,
|
||||
char **upstream_addr,
|
||||
char **upstream_port,
|
||||
char **bind_addr,
|
||||
char **cache_bytes)
|
||||
void read_proxy_param(int c,
|
||||
char **downstream_addr,
|
||||
char **downstream_port,
|
||||
char **upstream_addr,
|
||||
char **upstream_port,
|
||||
char **bind_addr, char **cache_bytes)
|
||||
{
|
||||
switch( c ) {
|
||||
case 'h' :
|
||||
fprintf( stdout, "%s\n", proxy_help_text );
|
||||
exit( 0 );
|
||||
case 'l':
|
||||
*downstream_addr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
*downstream_port = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
*upstream_addr = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
*upstream_port = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
*bind_addr = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
*cache_bytes = optarg ? optarg : proxy_default_cache_size;
|
||||
break;
|
||||
case 'q':
|
||||
log_level = QUIET_LOG_LEVEL;
|
||||
break;
|
||||
case 'v':
|
||||
log_level = VERBOSE_LOG_LEVEL;
|
||||
break;
|
||||
default:
|
||||
exit_err( proxy_help_text );
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
case 'h':
|
||||
fprintf(stdout, "%s\n", proxy_help_text);
|
||||
exit(0);
|
||||
case 'l':
|
||||
*downstream_addr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
*downstream_port = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
*upstream_addr = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
*upstream_port = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
*bind_addr = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
*cache_bytes = optarg ? optarg : proxy_default_cache_size;
|
||||
break;
|
||||
case 'q':
|
||||
log_level = QUIET_LOG_LEVEL;
|
||||
break;
|
||||
case 'v':
|
||||
log_level = VERBOSE_LOG_LEVEL;
|
||||
break;
|
||||
default:
|
||||
exit_err(proxy_help_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct proxier * proxy = NULL;
|
||||
struct proxier *proxy = NULL;
|
||||
|
||||
void my_exit(int signum)
|
||||
{
|
||||
info( "Exit signalled (%i)", signum );
|
||||
if ( NULL != proxy ) {
|
||||
proxy_cleanup( proxy );
|
||||
};
|
||||
exit( 0 );
|
||||
info("Exit signalled (%i)", signum);
|
||||
if (NULL != proxy) {
|
||||
proxy_cleanup(proxy);
|
||||
};
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char *downstream_addr = NULL;
|
||||
char *downstream_port = NULL;
|
||||
char *upstream_addr = NULL;
|
||||
char *upstream_port = NULL;
|
||||
char *bind_addr = NULL;
|
||||
char *cache_bytes = NULL;
|
||||
int success;
|
||||
int c;
|
||||
char *downstream_addr = NULL;
|
||||
char *downstream_port = NULL;
|
||||
char *upstream_addr = NULL;
|
||||
char *upstream_port = NULL;
|
||||
char *bind_addr = NULL;
|
||||
char *cache_bytes = NULL;
|
||||
int success;
|
||||
|
||||
sigset_t mask;
|
||||
struct sigaction exit_action;
|
||||
sigset_t mask;
|
||||
struct sigaction exit_action;
|
||||
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGTERM );
|
||||
sigaddset( &mask, SIGQUIT );
|
||||
sigaddset( &mask, SIGINT );
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGQUIT);
|
||||
sigaddset(&mask, SIGINT);
|
||||
|
||||
exit_action.sa_handler = my_exit;
|
||||
exit_action.sa_mask = mask;
|
||||
exit_action.sa_flags = 0;
|
||||
exit_action.sa_handler = my_exit;
|
||||
exit_action.sa_mask = mask;
|
||||
exit_action.sa_flags = 0;
|
||||
|
||||
srand(time(NULL));
|
||||
srand(time(NULL));
|
||||
|
||||
while (1) {
|
||||
c = getopt_long( argc, argv, proxy_short_options, proxy_options, NULL );
|
||||
if ( -1 == c ) { break; }
|
||||
read_proxy_param( c,
|
||||
&downstream_addr,
|
||||
&downstream_port,
|
||||
&upstream_addr,
|
||||
&upstream_port,
|
||||
&bind_addr,
|
||||
&cache_bytes
|
||||
);
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, proxy_short_options, proxy_options,
|
||||
NULL);
|
||||
if (-1 == c) {
|
||||
break;
|
||||
}
|
||||
read_proxy_param(c,
|
||||
&downstream_addr,
|
||||
&downstream_port,
|
||||
&upstream_addr,
|
||||
&upstream_port, &bind_addr, &cache_bytes);
|
||||
}
|
||||
|
||||
if ( NULL == downstream_addr ){
|
||||
fprintf( stderr, "--addr is required.\n" );
|
||||
exit_err( proxy_help_text );
|
||||
} else if ( NULL == upstream_addr || NULL == upstream_port ){
|
||||
fprintf( stderr, "both --conn-addr and --conn-port are required.\n" );
|
||||
exit_err( proxy_help_text );
|
||||
}
|
||||
if (NULL == downstream_addr) {
|
||||
fprintf(stderr, "--addr is required.\n");
|
||||
exit_err(proxy_help_text);
|
||||
} else if (NULL == upstream_addr || NULL == upstream_port) {
|
||||
fprintf(stderr,
|
||||
"both --conn-addr and --conn-port are required.\n");
|
||||
exit_err(proxy_help_text);
|
||||
}
|
||||
|
||||
proxy = proxy_create(
|
||||
downstream_addr,
|
||||
downstream_port,
|
||||
upstream_addr,
|
||||
upstream_port,
|
||||
bind_addr,
|
||||
cache_bytes
|
||||
);
|
||||
proxy = proxy_create(downstream_addr,
|
||||
downstream_port,
|
||||
upstream_addr,
|
||||
upstream_port, bind_addr, cache_bytes);
|
||||
|
||||
/* Set these *after* proxy has been assigned to */
|
||||
sigaction(SIGTERM, &exit_action, NULL);
|
||||
sigaction(SIGQUIT, &exit_action, NULL);
|
||||
sigaction(SIGINT, &exit_action, NULL);
|
||||
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
|
||||
/* Set these *after* proxy has been assigned to */
|
||||
sigaction(SIGTERM, &exit_action, NULL);
|
||||
sigaction(SIGQUIT, &exit_action, NULL);
|
||||
sigaction(SIGINT, &exit_action, NULL);
|
||||
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
|
||||
|
||||
if ( NULL != downstream_port ) {
|
||||
info(
|
||||
"Proxying between %s %s (downstream) and %s %s (upstream)",
|
||||
downstream_addr, downstream_port, upstream_addr, upstream_port
|
||||
);
|
||||
} else {
|
||||
info(
|
||||
"Proxying between %s (downstream) and %s %s (upstream)",
|
||||
downstream_addr, upstream_addr, upstream_port
|
||||
);
|
||||
}
|
||||
if (NULL != downstream_port) {
|
||||
info("Proxying between %s %s (downstream) and %s %s (upstream)",
|
||||
downstream_addr, downstream_port, upstream_addr,
|
||||
upstream_port);
|
||||
} else {
|
||||
info("Proxying between %s (downstream) and %s %s (upstream)",
|
||||
downstream_addr, upstream_addr, upstream_port);
|
||||
}
|
||||
|
||||
success = do_proxy( proxy );
|
||||
proxy_destroy( proxy );
|
||||
success = do_proxy(proxy);
|
||||
proxy_destroy(proxy);
|
||||
|
||||
return success ? 0 : 1;
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -2,67 +2,77 @@
|
||||
#include "util.h"
|
||||
|
||||
|
||||
struct prefetch* prefetch_create( size_t size_bytes ){
|
||||
struct prefetch *prefetch_create(size_t size_bytes)
|
||||
{
|
||||
|
||||
struct prefetch* out = xmalloc( sizeof( struct prefetch ) );
|
||||
NULLCHECK( out );
|
||||
struct prefetch *out = xmalloc(sizeof(struct prefetch));
|
||||
NULLCHECK(out);
|
||||
|
||||
out->buffer = xmalloc( size_bytes );
|
||||
NULLCHECK( out->buffer );
|
||||
out->buffer = xmalloc(size_bytes);
|
||||
NULLCHECK(out->buffer);
|
||||
|
||||
out->size = size_bytes;
|
||||
out->is_full = 0;
|
||||
out->from = 0;
|
||||
out->len = 0;
|
||||
out->size = size_bytes;
|
||||
out->is_full = 0;
|
||||
out->from = 0;
|
||||
out->len = 0;
|
||||
|
||||
return out;
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
void prefetch_destroy( struct prefetch *prefetch ) {
|
||||
if( prefetch ) {
|
||||
free( prefetch->buffer );
|
||||
free( prefetch );
|
||||
}
|
||||
void prefetch_destroy(struct prefetch *prefetch)
|
||||
{
|
||||
if (prefetch) {
|
||||
free(prefetch->buffer);
|
||||
free(prefetch);
|
||||
}
|
||||
}
|
||||
|
||||
size_t prefetch_size( struct prefetch *prefetch){
|
||||
if ( prefetch ) {
|
||||
return prefetch->size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
size_t prefetch_size(struct prefetch *prefetch)
|
||||
{
|
||||
if (prefetch) {
|
||||
return prefetch->size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void prefetch_set_is_empty( struct prefetch *prefetch ){
|
||||
prefetch_set_full( prefetch, 0 );
|
||||
void prefetch_set_is_empty(struct prefetch *prefetch)
|
||||
{
|
||||
prefetch_set_full(prefetch, 0);
|
||||
}
|
||||
|
||||
void prefetch_set_is_full( struct prefetch *prefetch ){
|
||||
prefetch_set_full( prefetch, 1 );
|
||||
void prefetch_set_is_full(struct prefetch *prefetch)
|
||||
{
|
||||
prefetch_set_full(prefetch, 1);
|
||||
}
|
||||
|
||||
void prefetch_set_full( struct prefetch *prefetch, int val ){
|
||||
if( prefetch ) {
|
||||
prefetch->is_full = val;
|
||||
}
|
||||
void prefetch_set_full(struct prefetch *prefetch, int val)
|
||||
{
|
||||
if (prefetch) {
|
||||
prefetch->is_full = val;
|
||||
}
|
||||
}
|
||||
|
||||
int prefetch_is_full( struct prefetch *prefetch ){
|
||||
if( prefetch ) {
|
||||
return prefetch->is_full;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
int prefetch_is_full(struct prefetch *prefetch)
|
||||
{
|
||||
if (prefetch) {
|
||||
return prefetch->is_full;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len ){
|
||||
NULLCHECK( prefetch );
|
||||
return from >= prefetch->from &&
|
||||
from + len <= prefetch->from + prefetch->len;
|
||||
int prefetch_contains(struct prefetch *prefetch, uint64_t from,
|
||||
uint32_t len)
|
||||
{
|
||||
NULLCHECK(prefetch);
|
||||
return from >= prefetch->from &&
|
||||
from + len <= prefetch->from + prefetch->len;
|
||||
}
|
||||
|
||||
char *prefetch_offset( struct prefetch *prefetch, uint64_t from ){
|
||||
NULLCHECK( prefetch );
|
||||
return prefetch->buffer + (from - prefetch->from);
|
||||
char *prefetch_offset(struct prefetch *prefetch, uint64_t from)
|
||||
{
|
||||
NULLCHECK(prefetch);
|
||||
return prefetch->buffer + (from - prefetch->from);
|
||||
}
|
||||
|
@@ -7,27 +7,28 @@
|
||||
#define PREFETCH_BUFSIZE 4096
|
||||
|
||||
struct prefetch {
|
||||
/* True if there is data in the buffer. */
|
||||
int is_full;
|
||||
/* The start point of the current content of buffer */
|
||||
uint64_t from;
|
||||
/* The length of the current content of buffer */
|
||||
uint32_t len;
|
||||
/* True if there is data in the buffer. */
|
||||
int is_full;
|
||||
/* The start point of the current content of buffer */
|
||||
uint64_t from;
|
||||
/* The length of the current content of buffer */
|
||||
uint32_t len;
|
||||
|
||||
/* The total size of the buffer, in bytes. */
|
||||
size_t size;
|
||||
/* The total size of the buffer, in bytes. */
|
||||
size_t size;
|
||||
|
||||
char *buffer;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
struct prefetch* prefetch_create( size_t size_bytes );
|
||||
void prefetch_destroy( struct prefetch *prefetch );
|
||||
size_t prefetch_size( struct prefetch *);
|
||||
void prefetch_set_is_empty( struct prefetch *prefetch );
|
||||
void prefetch_set_is_full( struct prefetch *prefetch );
|
||||
void prefetch_set_full( struct prefetch *prefetch, int val );
|
||||
int prefetch_is_full( struct prefetch *prefetch );
|
||||
int prefetch_contains( struct prefetch *prefetch, uint64_t from, uint32_t len );
|
||||
char *prefetch_offset( struct prefetch *prefetch, uint64_t from );
|
||||
struct prefetch *prefetch_create(size_t size_bytes);
|
||||
void prefetch_destroy(struct prefetch *prefetch);
|
||||
size_t prefetch_size(struct prefetch *);
|
||||
void prefetch_set_is_empty(struct prefetch *prefetch);
|
||||
void prefetch_set_is_full(struct prefetch *prefetch);
|
||||
void prefetch_set_full(struct prefetch *prefetch, int val);
|
||||
int prefetch_is_full(struct prefetch *prefetch);
|
||||
int prefetch_contains(struct prefetch *prefetch, uint64_t from,
|
||||
uint32_t len);
|
||||
char *prefetch_offset(struct prefetch *prefetch, uint64_t from);
|
||||
|
||||
#endif
|
||||
|
1548
src/proxy/proxy.c
1548
src/proxy/proxy.c
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
#include "self_pipe.h"
|
||||
|
||||
#ifdef PREFETCH
|
||||
#include "prefetch.h"
|
||||
#include "prefetch.h"
|
||||
#endif
|
||||
|
||||
/** UPSTREAM_TIMEOUT
|
||||
@@ -21,80 +21,77 @@
|
||||
|
||||
struct proxier {
|
||||
/** address/port to bind to */
|
||||
union mysockaddr listen_on;
|
||||
union mysockaddr listen_on;
|
||||
|
||||
/** address/port to connect to */
|
||||
union mysockaddr connect_to;
|
||||
union mysockaddr connect_to;
|
||||
|
||||
/** address to bind to when making outgoing connections */
|
||||
union mysockaddr connect_from;
|
||||
int bind; /* Set to true if we should use it */
|
||||
union mysockaddr connect_from;
|
||||
int bind; /* Set to true if we should use it */
|
||||
|
||||
/* The socket we listen() on and accept() against */
|
||||
int listen_fd;
|
||||
/* The socket we listen() on and accept() against */
|
||||
int listen_fd;
|
||||
|
||||
/* The socket returned by accept() that we receive requests from and send
|
||||
* responses to
|
||||
*/
|
||||
int downstream_fd;
|
||||
/* The socket returned by accept() that we receive requests from and send
|
||||
* responses to
|
||||
*/
|
||||
int downstream_fd;
|
||||
|
||||
/* The socket returned by connect() that we send requests to and receive
|
||||
* responses from
|
||||
*/
|
||||
int upstream_fd;
|
||||
/* The socket returned by connect() that we send requests to and receive
|
||||
* responses from
|
||||
*/
|
||||
int upstream_fd;
|
||||
|
||||
/* This is the size we advertise to the downstream server */
|
||||
uint64_t upstream_size;
|
||||
/* This is the size we advertise to the downstream server */
|
||||
uint64_t upstream_size;
|
||||
|
||||
/* These are the transmission flags sent as part of the handshake */
|
||||
uint32_t upstream_flags;
|
||||
/* These are the transmission flags sent as part of the handshake */
|
||||
uint32_t upstream_flags;
|
||||
|
||||
/* We transform the raw request header into here */
|
||||
struct nbd_request req_hdr;
|
||||
/* We transform the raw request header into here */
|
||||
struct nbd_request req_hdr;
|
||||
|
||||
/* We transform the raw reply header into here */
|
||||
struct nbd_reply rsp_hdr;
|
||||
/* We transform the raw reply header into here */
|
||||
struct nbd_reply rsp_hdr;
|
||||
|
||||
/* Used for our non-blocking negotiation with upstream. TODO: maybe use
|
||||
* for downstream as well ( we currently overload rsp ) */
|
||||
struct iobuf init;
|
||||
/* Used for our non-blocking negotiation with upstream. TODO: maybe use
|
||||
* for downstream as well ( we currently overload rsp ) */
|
||||
struct iobuf init;
|
||||
|
||||
/* The current NBD request from downstream */
|
||||
struct iobuf req;
|
||||
/* The current NBD request from downstream */
|
||||
struct iobuf req;
|
||||
|
||||
/* The current NBD reply from upstream */
|
||||
struct iobuf rsp;
|
||||
/* The current NBD reply from upstream */
|
||||
struct iobuf rsp;
|
||||
|
||||
/* It's starting to feel like we need an object for a single proxy session.
|
||||
* These two track how many requests we've sent so far, and whether the
|
||||
* NBD_INIT code has been sent to the client yet.
|
||||
*/
|
||||
uint64_t req_count;
|
||||
int hello_sent;
|
||||
/* It's starting to feel like we need an object for a single proxy session.
|
||||
* These two track how many requests we've sent so far, and whether the
|
||||
* NBD_INIT code has been sent to the client yet.
|
||||
*/
|
||||
uint64_t req_count;
|
||||
int hello_sent;
|
||||
|
||||
/** These are only used if we pass --cache on the command line */
|
||||
|
||||
/* While the in-flight request has been munged by prefetch, these two are
|
||||
* set to true, and the original length of the request, respectively */
|
||||
int is_prefetch_req;
|
||||
uint32_t prefetch_req_orig_len;
|
||||
/* While the in-flight request has been munged by prefetch, these two are
|
||||
* set to true, and the original length of the request, respectively */
|
||||
int is_prefetch_req;
|
||||
uint32_t prefetch_req_orig_len;
|
||||
|
||||
/* And here, we actually store the prefetched data once it's returned */
|
||||
struct prefetch *prefetch;
|
||||
/* And here, we actually store the prefetched data once it's returned */
|
||||
struct prefetch *prefetch;
|
||||
|
||||
/** */
|
||||
};
|
||||
|
||||
struct proxier* proxy_create(
|
||||
char* s_downstream_address,
|
||||
char* s_downstream_port,
|
||||
char* s_upstream_address,
|
||||
char* s_upstream_port,
|
||||
char* s_upstream_bind,
|
||||
char* s_cache_bytes);
|
||||
int do_proxy( struct proxier* proxy );
|
||||
void proxy_cleanup( struct proxier* proxy );
|
||||
void proxy_destroy( struct proxier* proxy );
|
||||
struct proxier *proxy_create(char *s_downstream_address,
|
||||
char *s_downstream_port,
|
||||
char *s_upstream_address,
|
||||
char *s_upstream_port,
|
||||
char *s_upstream_bind, char *s_cache_bytes);
|
||||
int do_proxy(struct proxier *proxy);
|
||||
void proxy_cleanup(struct proxier *proxy);
|
||||
void proxy_destroy(struct proxier *proxy);
|
||||
|
||||
#endif
|
||||
|
||||
|
149
src/server/acl.c
149
src/server/acl.c
@@ -6,103 +6,104 @@
|
||||
#include "acl.h"
|
||||
|
||||
|
||||
struct acl * acl_create( int len, char ** lines, int default_deny )
|
||||
struct acl *acl_create(int len, char **lines, int default_deny)
|
||||
{
|
||||
struct acl * acl;
|
||||
struct acl *acl;
|
||||
|
||||
acl = (struct acl *)xmalloc( sizeof( struct acl ) );
|
||||
acl->len = parse_acl( &acl->entries, len, lines );
|
||||
acl->default_deny = default_deny;
|
||||
return acl;
|
||||
acl = (struct acl *) xmalloc(sizeof(struct acl));
|
||||
acl->len = parse_acl(&acl->entries, len, lines);
|
||||
acl->default_deny = default_deny;
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
||||
static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 };
|
||||
static int testmasks[9] = { 0, 128, 192, 224, 240, 248, 252, 254, 255 };
|
||||
|
||||
/** Test whether AF_INET or AF_INET6 sockaddr is included in the given access
|
||||
* control list, returning 1 if it is, and 0 if not.
|
||||
*/
|
||||
static int is_included_in_acl(int list_length, struct ip_and_mask (*list)[], union mysockaddr* test)
|
||||
static int is_included_in_acl(int list_length,
|
||||
struct ip_and_mask (*list)[],
|
||||
union mysockaddr *test)
|
||||
{
|
||||
NULLCHECK( test );
|
||||
NULLCHECK(test);
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i=0; i < list_length; i++) {
|
||||
struct ip_and_mask *entry = &(*list)[i];
|
||||
int testbits;
|
||||
unsigned char *raw_address1 = NULL, *raw_address2 = NULL;
|
||||
for (i = 0; i < list_length; i++) {
|
||||
struct ip_and_mask *entry = &(*list)[i];
|
||||
int testbits;
|
||||
unsigned char *raw_address1 = NULL, *raw_address2 = NULL;
|
||||
|
||||
debug("checking acl entry %d (%d/%d)", i, test->generic.sa_family, entry->ip.family);
|
||||
debug("checking acl entry %d (%d/%d)", i, test->generic.sa_family,
|
||||
entry->ip.family);
|
||||
|
||||
if (test->generic.sa_family != entry->ip.family) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test->generic.sa_family == AF_INET) {
|
||||
debug("it's an AF_INET");
|
||||
raw_address1 = (unsigned char*) &test->v4.sin_addr;
|
||||
raw_address2 = (unsigned char*) &entry->ip.v4.sin_addr;
|
||||
}
|
||||
else if (test->generic.sa_family == AF_INET6) {
|
||||
debug("it's an AF_INET6");
|
||||
raw_address1 = (unsigned char*) &test->v6.sin6_addr;
|
||||
raw_address2 = (unsigned char*) &entry->ip.v6.sin6_addr;
|
||||
}
|
||||
else {
|
||||
fatal( "Can't check an ACL for this address type." );
|
||||
}
|
||||
|
||||
debug("testbits=%d", entry->mask);
|
||||
|
||||
for (testbits = entry->mask; testbits > 0; testbits -= 8) {
|
||||
debug("testbits=%d, c1=%02x, c2=%02x", testbits, raw_address1[0], raw_address2[0]);
|
||||
if (testbits >= 8) {
|
||||
if (raw_address1[0] != raw_address2[0]) { goto no_match; }
|
||||
}
|
||||
else {
|
||||
if ((raw_address1[0] & testmasks[testbits%8]) !=
|
||||
(raw_address2[0] & testmasks[testbits%8]) ) {
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
|
||||
raw_address1++;
|
||||
raw_address2++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
no_match: ;
|
||||
debug("no match");
|
||||
if (test->generic.sa_family != entry->ip.family) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acl_includes( struct acl * acl, union mysockaddr * addr )
|
||||
{
|
||||
NULLCHECK( acl );
|
||||
|
||||
if ( 0 == acl->len ) {
|
||||
return !( acl->default_deny );
|
||||
if (test->generic.sa_family == AF_INET) {
|
||||
debug("it's an AF_INET");
|
||||
raw_address1 = (unsigned char *) &test->v4.sin_addr;
|
||||
raw_address2 = (unsigned char *) &entry->ip.v4.sin_addr;
|
||||
} else if (test->generic.sa_family == AF_INET6) {
|
||||
debug("it's an AF_INET6");
|
||||
raw_address1 = (unsigned char *) &test->v6.sin6_addr;
|
||||
raw_address2 = (unsigned char *) &entry->ip.v6.sin6_addr;
|
||||
} else {
|
||||
fatal("Can't check an ACL for this address type.");
|
||||
}
|
||||
else {
|
||||
return is_included_in_acl( acl->len, acl->entries, addr );
|
||||
|
||||
debug("testbits=%d", entry->mask);
|
||||
|
||||
for (testbits = entry->mask; testbits > 0; testbits -= 8) {
|
||||
debug("testbits=%d, c1=%02x, c2=%02x", testbits,
|
||||
raw_address1[0], raw_address2[0]);
|
||||
if (testbits >= 8) {
|
||||
if (raw_address1[0] != raw_address2[0]) {
|
||||
goto no_match;
|
||||
}
|
||||
} else {
|
||||
if ((raw_address1[0] & testmasks[testbits % 8]) !=
|
||||
(raw_address2[0] & testmasks[testbits % 8])) {
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
|
||||
raw_address1++;
|
||||
raw_address2++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
no_match:;
|
||||
debug("no match");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acl_default_deny( struct acl * acl )
|
||||
int acl_includes(struct acl *acl, union mysockaddr *addr)
|
||||
{
|
||||
NULLCHECK( acl );
|
||||
return acl->default_deny;
|
||||
NULLCHECK(acl);
|
||||
|
||||
if (0 == acl->len) {
|
||||
return !(acl->default_deny);
|
||||
} else {
|
||||
return is_included_in_acl(acl->len, acl->entries, addr);
|
||||
}
|
||||
}
|
||||
|
||||
void acl_destroy( struct acl * acl )
|
||||
int acl_default_deny(struct acl *acl)
|
||||
{
|
||||
free( acl->entries );
|
||||
acl->len = 0;
|
||||
acl->entries = NULL;
|
||||
free( acl );
|
||||
NULLCHECK(acl);
|
||||
return acl->default_deny;
|
||||
}
|
||||
|
||||
void acl_destroy(struct acl *acl)
|
||||
{
|
||||
free(acl->entries);
|
||||
acl->len = 0;
|
||||
acl->entries = NULL;
|
||||
free(acl);
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@
|
||||
#include "parse.h"
|
||||
|
||||
struct acl {
|
||||
int len;
|
||||
int default_deny;
|
||||
struct ip_and_mask (*entries)[];
|
||||
int len;
|
||||
int default_deny;
|
||||
struct ip_and_mask (*entries)[];
|
||||
};
|
||||
|
||||
/** Allocate a new acl structure, parsing the given lines to sockaddr
|
||||
@@ -17,21 +17,21 @@ struct acl {
|
||||
* default_deny controls the behaviour of an empty list: if true, all
|
||||
* requests will be denied. If true, all requests will be accepted.
|
||||
*/
|
||||
struct acl * acl_create( int len, char **lines, int default_deny );
|
||||
struct acl *acl_create(int len, char **lines, int default_deny);
|
||||
|
||||
|
||||
/** Check to see whether an address is allowed by an acl.
|
||||
* See acl_create for how the default_deny setting affects this.
|
||||
*/
|
||||
int acl_includes( struct acl *, union mysockaddr *);
|
||||
int acl_includes(struct acl *, union mysockaddr *);
|
||||
|
||||
/** Get the default_deny status */
|
||||
int acl_default_deny( struct acl * );
|
||||
int acl_default_deny(struct acl *);
|
||||
|
||||
|
||||
/** Free the acl structure and the internal acl entries table.
|
||||
*/
|
||||
void acl_destroy( struct acl * );
|
||||
void acl_destroy(struct acl *);
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -12,8 +12,8 @@
|
||||
* poking at the bits directly without using these
|
||||
* accessors/macros
|
||||
*/
|
||||
typedef uint64_t bitfield_word_t;
|
||||
typedef bitfield_word_t * bitfield_p;
|
||||
typedef uint64_t bitfield_word_t;
|
||||
typedef bitfield_word_t *bitfield_p;
|
||||
|
||||
#define BITFIELD_WORD_SIZE sizeof(bitfield_word_t)
|
||||
#define BITS_PER_WORD (BITFIELD_WORD_SIZE * 8)
|
||||
@@ -30,65 +30,78 @@ typedef bitfield_word_t * bitfield_p;
|
||||
((_bytes + (BITFIELD_WORD_SIZE-1)) / BITFIELD_WORD_SIZE)
|
||||
|
||||
/** Return the bit value ''idx'' in array ''b'' */
|
||||
static inline int bit_get(bitfield_p b, uint64_t idx) {
|
||||
return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD-1))) & 1;
|
||||
static inline int bit_get(bitfield_p b, uint64_t idx)
|
||||
{
|
||||
return (BIT_WORD(b, idx) >> (idx & (BITS_PER_WORD - 1))) & 1;
|
||||
}
|
||||
|
||||
/** Return 1 if the bit at ''idx'' in array ''b'' is set */
|
||||
static inline int bit_is_set(bitfield_p b, uint64_t idx) {
|
||||
return bit_get(b, idx);
|
||||
static inline int bit_is_set(bitfield_p b, uint64_t idx)
|
||||
{
|
||||
return bit_get(b, idx);
|
||||
}
|
||||
|
||||
/** Return 1 if the bit at ''idx'' in array ''b'' is clear */
|
||||
static inline int bit_is_clear(bitfield_p b, uint64_t idx) {
|
||||
return !bit_get(b, idx);
|
||||
static inline int bit_is_clear(bitfield_p b, uint64_t idx)
|
||||
{
|
||||
return !bit_get(b, idx);
|
||||
}
|
||||
|
||||
/** Tests whether the bit at ''idx'' in array ''b'' has value ''value'' */
|
||||
static inline int bit_has_value(bitfield_p b, uint64_t idx, int value) {
|
||||
return bit_get(b, idx) == !!value;
|
||||
static inline int bit_has_value(bitfield_p b, uint64_t idx, int value)
|
||||
{
|
||||
return bit_get(b, idx) == ! !value;
|
||||
}
|
||||
|
||||
/** Sets the bit ''idx'' in array ''b'' */
|
||||
static inline void bit_set(bitfield_p b, uint64_t idx) {
|
||||
BIT_WORD(b, idx) |= BIT_MASK(idx);
|
||||
static inline void bit_set(bitfield_p b, uint64_t idx)
|
||||
{
|
||||
BIT_WORD(b, idx) |= BIT_MASK(idx);
|
||||
}
|
||||
|
||||
/** Clears the bit ''idx'' in array ''b'' */
|
||||
static inline void bit_clear(bitfield_p b, uint64_t idx) {
|
||||
BIT_WORD(b, idx) &= ~BIT_MASK(idx);
|
||||
static inline void bit_clear(bitfield_p b, uint64_t idx)
|
||||
{
|
||||
BIT_WORD(b, idx) &= ~BIT_MASK(idx);
|
||||
}
|
||||
|
||||
/** Sets ''len'' bits in array ''b'' starting at offset ''from'' */
|
||||
static inline void bit_set_range(bitfield_p b, uint64_t from, uint64_t len)
|
||||
{
|
||||
for ( ; (from % BITS_PER_WORD) != 0 && len > 0 ; len-- ) {
|
||||
bit_set( b, from++ );
|
||||
}
|
||||
for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) {
|
||||
bit_set(b, from++);
|
||||
}
|
||||
|
||||
if (len >= BITS_PER_WORD) {
|
||||
memset(&BIT_WORD(b, from), 0xff, len / 8 );
|
||||
from += len;
|
||||
len = len % BITS_PER_WORD;
|
||||
from -= len;
|
||||
}
|
||||
if (len >= BITS_PER_WORD) {
|
||||
memset(&BIT_WORD(b, from), 0xff, len / 8);
|
||||
from += len;
|
||||
len = len % BITS_PER_WORD;
|
||||
from -= len;
|
||||
}
|
||||
|
||||
for ( ; len > 0 ; len-- ) {
|
||||
bit_set( b, from++ );
|
||||
}
|
||||
for (; len > 0; len--) {
|
||||
bit_set(b, from++);
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears ''len'' bits in array ''b'' starting at offset ''from'' */
|
||||
static inline void bit_clear_range(bitfield_p b, uint64_t from, uint64_t len)
|
||||
static inline void bit_clear_range(bitfield_p b, uint64_t from,
|
||||
uint64_t len)
|
||||
{
|
||||
for ( ; (from % BITS_PER_WORD) != 0 && len > 0 ; len-- ) {
|
||||
bit_clear( b, from++ );
|
||||
}
|
||||
for (; (from % BITS_PER_WORD) != 0 && len > 0; len--) {
|
||||
bit_clear(b, from++);
|
||||
}
|
||||
|
||||
if (len >= BITS_PER_WORD) {
|
||||
memset(&BIT_WORD(b, from), 0, len / 8 );
|
||||
from += len;
|
||||
len = len % BITS_PER_WORD;
|
||||
from -= len;
|
||||
}
|
||||
if (len >= BITS_PER_WORD) {
|
||||
memset(&BIT_WORD(b, from), 0, len / 8);
|
||||
from += len;
|
||||
len = len % BITS_PER_WORD;
|
||||
from -= len;
|
||||
}
|
||||
|
||||
for ( ; len > 0 ; len-- ) {
|
||||
bit_clear( b, from++ );
|
||||
}
|
||||
for (; len > 0; len--) {
|
||||
bit_clear(b, from++);
|
||||
}
|
||||
}
|
||||
|
||||
/** Counts the number of contiguous bits in array ''b'', starting at ''from''
|
||||
@@ -96,52 +109,54 @@ static inline void bit_clear_range(bitfield_p b, uint64_t from, uint64_t len)
|
||||
* bits that are the same as the first one specified. If ''run_is_set'' is
|
||||
* non-NULL, the value of that bit is placed into it.
|
||||
*/
|
||||
static inline uint64_t bit_run_count(bitfield_p b, uint64_t from, uint64_t len, int *run_is_set) {
|
||||
uint64_t count = 0;
|
||||
int first_value = bit_get(b, from);
|
||||
bitfield_word_t word_match = first_value ? -1 : 0;
|
||||
static inline uint64_t bit_run_count(bitfield_p b, uint64_t from,
|
||||
uint64_t len, int *run_is_set)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
int first_value = bit_get(b, from);
|
||||
bitfield_word_t word_match = first_value ? -1 : 0;
|
||||
|
||||
if ( run_is_set != NULL ) {
|
||||
*run_is_set = first_value;
|
||||
if (run_is_set != NULL) {
|
||||
*run_is_set = first_value;
|
||||
}
|
||||
|
||||
for (; ((from + count) % BITS_PER_WORD) != 0 && len > 0; len--) {
|
||||
if (bit_has_value(b, from + count, first_value)) {
|
||||
count++;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; ((from + count) % BITS_PER_WORD) != 0 && len > 0; len--) {
|
||||
if (bit_has_value(b, from + count, first_value)) {
|
||||
count++;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
for (; len >= BITS_PER_WORD; len -= BITS_PER_WORD) {
|
||||
if (BIT_WORD(b, from + count) == word_match) {
|
||||
count += BITS_PER_WORD;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; len >= BITS_PER_WORD ; len -= BITS_PER_WORD ) {
|
||||
if (BIT_WORD(b, from + count) == word_match) {
|
||||
count += BITS_PER_WORD;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
for (; len > 0; len--) {
|
||||
if (bit_has_value(b, from + count, first_value)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; len > 0; len-- ) {
|
||||
if ( bit_has_value(b, from + count, first_value) ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
enum bitset_stream_events {
|
||||
BITSET_STREAM_UNSET = 0,
|
||||
BITSET_STREAM_SET = 1,
|
||||
BITSET_STREAM_ON = 2,
|
||||
BITSET_STREAM_OFF = 3
|
||||
BITSET_STREAM_UNSET = 0,
|
||||
BITSET_STREAM_SET = 1,
|
||||
BITSET_STREAM_ON = 2,
|
||||
BITSET_STREAM_OFF = 3
|
||||
};
|
||||
#define BITSET_STREAM_EVENTS_ENUM_SIZE 4
|
||||
|
||||
struct bitset_stream_entry {
|
||||
enum bitset_stream_events event;
|
||||
uint64_t from;
|
||||
uint64_t len;
|
||||
enum bitset_stream_events event;
|
||||
uint64_t from;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
/** Limit the stream size to 1MB for now.
|
||||
@@ -152,14 +167,14 @@ struct bitset_stream_entry {
|
||||
#define BITSET_STREAM_SIZE ( ( 1024 * 1024 ) / sizeof( struct bitset_stream_entry ) )
|
||||
|
||||
struct bitset_stream {
|
||||
struct bitset_stream_entry entries[BITSET_STREAM_SIZE];
|
||||
int in;
|
||||
int out;
|
||||
int size;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond_not_full;
|
||||
pthread_cond_t cond_not_empty;
|
||||
uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE];
|
||||
struct bitset_stream_entry entries[BITSET_STREAM_SIZE];
|
||||
int in;
|
||||
int out;
|
||||
int size;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond_not_full;
|
||||
pthread_cond_t cond_not_empty;
|
||||
uint64_t queued_bytes[BITSET_STREAM_EVENTS_ENUM_SIZE];
|
||||
};
|
||||
|
||||
|
||||
@@ -169,47 +184,49 @@ struct bitset_stream {
|
||||
* written reliably by multiple threads.
|
||||
*/
|
||||
struct bitset {
|
||||
pthread_mutex_t lock;
|
||||
uint64_t size;
|
||||
int resolution;
|
||||
struct bitset_stream *stream;
|
||||
int stream_enabled;
|
||||
bitfield_word_t bits[];
|
||||
pthread_mutex_t lock;
|
||||
uint64_t size;
|
||||
int resolution;
|
||||
struct bitset_stream *stream;
|
||||
int stream_enabled;
|
||||
bitfield_word_t bits[];
|
||||
};
|
||||
|
||||
/** Allocate a bitset for a file of the given size, and chunks of the
|
||||
* given resolution.
|
||||
*/
|
||||
static inline struct bitset *bitset_alloc( uint64_t size, int resolution )
|
||||
static inline struct bitset *bitset_alloc(uint64_t size, int resolution)
|
||||
{
|
||||
// calculate a size to allocate that is a multiple of the size of the
|
||||
// bitfield word
|
||||
size_t bitfield_size =
|
||||
BIT_WORDS_FOR_SIZE((( size + resolution - 1 ) / resolution)) * sizeof( bitfield_word_t );
|
||||
struct bitset *bitset = xmalloc(sizeof( struct bitset ) + ( bitfield_size / 8 ) );
|
||||
// calculate a size to allocate that is a multiple of the size of the
|
||||
// bitfield word
|
||||
size_t bitfield_size =
|
||||
BIT_WORDS_FOR_SIZE(((size + resolution -
|
||||
1) / resolution)) * sizeof(bitfield_word_t);
|
||||
struct bitset *bitset =
|
||||
xmalloc(sizeof(struct bitset) + (bitfield_size / 8));
|
||||
|
||||
bitset->size = size;
|
||||
bitset->resolution = resolution;
|
||||
/* don't actually need to call pthread_mutex_destroy '*/
|
||||
pthread_mutex_init(&bitset->lock, NULL);
|
||||
bitset->stream = xmalloc( sizeof( struct bitset_stream ) );
|
||||
pthread_mutex_init( &bitset->stream->mutex, NULL );
|
||||
bitset->size = size;
|
||||
bitset->resolution = resolution;
|
||||
/* don't actually need to call pthread_mutex_destroy ' */
|
||||
pthread_mutex_init(&bitset->lock, NULL);
|
||||
bitset->stream = xmalloc(sizeof(struct bitset_stream));
|
||||
pthread_mutex_init(&bitset->stream->mutex, NULL);
|
||||
|
||||
/* Technically don't need to call pthread_cond_destroy either */
|
||||
pthread_cond_init( &bitset->stream->cond_not_full, NULL );
|
||||
pthread_cond_init( &bitset->stream->cond_not_empty, NULL );
|
||||
/* Technically don't need to call pthread_cond_destroy either */
|
||||
pthread_cond_init(&bitset->stream->cond_not_full, NULL);
|
||||
pthread_cond_init(&bitset->stream->cond_not_empty, NULL);
|
||||
|
||||
return bitset;
|
||||
return bitset;
|
||||
}
|
||||
|
||||
static inline void bitset_free( struct bitset * set )
|
||||
static inline void bitset_free(struct bitset *set)
|
||||
{
|
||||
/* TODO: free our mutex... */
|
||||
/* TODO: free our mutex... */
|
||||
|
||||
free( set->stream );
|
||||
set->stream = NULL;
|
||||
free(set->stream);
|
||||
set->stream = NULL;
|
||||
|
||||
free( set );
|
||||
free(set);
|
||||
}
|
||||
|
||||
#define INT_FIRST_AND_LAST \
|
||||
@@ -224,215 +241,201 @@ static inline void bitset_free( struct bitset * set )
|
||||
FATAL_IF_NEGATIVE(pthread_mutex_unlock(&set->lock), "Error unlocking bitset")
|
||||
|
||||
|
||||
static inline void bitset_stream_enqueue(
|
||||
struct bitset * set,
|
||||
enum bitset_stream_events event,
|
||||
uint64_t from,
|
||||
uint64_t len
|
||||
)
|
||||
static inline void bitset_stream_enqueue(struct bitset *set,
|
||||
enum bitset_stream_events event,
|
||||
uint64_t from, uint64_t len)
|
||||
{
|
||||
struct bitset_stream * stream = set->stream;
|
||||
struct bitset_stream *stream = set->stream;
|
||||
|
||||
pthread_mutex_lock( &stream->mutex );
|
||||
pthread_mutex_lock(&stream->mutex);
|
||||
|
||||
while ( stream->size == BITSET_STREAM_SIZE ) {
|
||||
pthread_cond_wait( &stream->cond_not_full, &stream->mutex );
|
||||
}
|
||||
while (stream->size == BITSET_STREAM_SIZE) {
|
||||
pthread_cond_wait(&stream->cond_not_full, &stream->mutex);
|
||||
}
|
||||
|
||||
stream->entries[stream->in].event = event;
|
||||
stream->entries[stream->in].from = from;
|
||||
stream->entries[stream->in].len = len;
|
||||
stream->queued_bytes[event] += len;
|
||||
stream->entries[stream->in].event = event;
|
||||
stream->entries[stream->in].from = from;
|
||||
stream->entries[stream->in].len = len;
|
||||
stream->queued_bytes[event] += len;
|
||||
|
||||
stream->size++;
|
||||
stream->in++;
|
||||
stream->in %= BITSET_STREAM_SIZE;
|
||||
stream->size++;
|
||||
stream->in++;
|
||||
stream->in %= BITSET_STREAM_SIZE;
|
||||
|
||||
pthread_mutex_unlock( & stream->mutex );
|
||||
pthread_cond_signal( &stream->cond_not_empty );
|
||||
pthread_mutex_unlock(&stream->mutex);
|
||||
pthread_cond_signal(&stream->cond_not_empty);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void bitset_stream_dequeue(
|
||||
struct bitset * set,
|
||||
struct bitset_stream_entry * out
|
||||
)
|
||||
static inline void bitset_stream_dequeue(struct bitset *set,
|
||||
struct bitset_stream_entry *out)
|
||||
{
|
||||
struct bitset_stream * stream = set->stream;
|
||||
struct bitset_stream_entry * dequeued;
|
||||
struct bitset_stream *stream = set->stream;
|
||||
struct bitset_stream_entry *dequeued;
|
||||
|
||||
pthread_mutex_lock( &stream->mutex );
|
||||
pthread_mutex_lock(&stream->mutex);
|
||||
|
||||
while ( stream->size == 0 ) {
|
||||
pthread_cond_wait( &stream->cond_not_empty, &stream->mutex );
|
||||
}
|
||||
while (stream->size == 0) {
|
||||
pthread_cond_wait(&stream->cond_not_empty, &stream->mutex);
|
||||
}
|
||||
|
||||
dequeued = &stream->entries[stream->out];
|
||||
dequeued = &stream->entries[stream->out];
|
||||
|
||||
if ( out != NULL ) {
|
||||
out->event = dequeued->event;
|
||||
out->from = dequeued->from;
|
||||
out->len = dequeued->len;
|
||||
}
|
||||
if (out != NULL) {
|
||||
out->event = dequeued->event;
|
||||
out->from = dequeued->from;
|
||||
out->len = dequeued->len;
|
||||
}
|
||||
|
||||
stream->queued_bytes[dequeued->event] -= dequeued->len;
|
||||
stream->size--;
|
||||
stream->out++;
|
||||
stream->out %= BITSET_STREAM_SIZE;
|
||||
stream->queued_bytes[dequeued->event] -= dequeued->len;
|
||||
stream->size--;
|
||||
stream->out++;
|
||||
stream->out %= BITSET_STREAM_SIZE;
|
||||
|
||||
pthread_mutex_unlock( &stream->mutex );
|
||||
pthread_cond_signal( &stream->cond_not_full );
|
||||
pthread_mutex_unlock(&stream->mutex);
|
||||
pthread_cond_signal(&stream->cond_not_full);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline size_t bitset_stream_size( struct bitset * set )
|
||||
static inline size_t bitset_stream_size(struct bitset *set)
|
||||
{
|
||||
size_t size;
|
||||
size_t size;
|
||||
|
||||
pthread_mutex_lock( &set->stream->mutex );
|
||||
size = set->stream->size;
|
||||
pthread_mutex_unlock( &set->stream->mutex );
|
||||
pthread_mutex_lock(&set->stream->mutex);
|
||||
size = set->stream->size;
|
||||
pthread_mutex_unlock(&set->stream->mutex);
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline uint64_t bitset_stream_queued_bytes(
|
||||
struct bitset * set,
|
||||
enum bitset_stream_events event
|
||||
)
|
||||
static inline uint64_t bitset_stream_queued_bytes(struct bitset *set,
|
||||
enum bitset_stream_events
|
||||
event)
|
||||
{
|
||||
uint64_t total;
|
||||
uint64_t total;
|
||||
|
||||
pthread_mutex_lock( &set->stream->mutex );
|
||||
total = set->stream->queued_bytes[event];
|
||||
pthread_mutex_unlock( &set->stream->mutex );
|
||||
pthread_mutex_lock(&set->stream->mutex);
|
||||
total = set->stream->queued_bytes[event];
|
||||
pthread_mutex_unlock(&set->stream->mutex);
|
||||
|
||||
return total;
|
||||
return total;
|
||||
}
|
||||
|
||||
static inline void bitset_enable_stream( struct bitset * set )
|
||||
static inline void bitset_enable_stream(struct bitset *set)
|
||||
{
|
||||
BITSET_LOCK;
|
||||
set->stream_enabled = 1;
|
||||
bitset_stream_enqueue( set, BITSET_STREAM_ON, 0, set->size );
|
||||
BITSET_UNLOCK;
|
||||
BITSET_LOCK;
|
||||
set->stream_enabled = 1;
|
||||
bitset_stream_enqueue(set, BITSET_STREAM_ON, 0, set->size);
|
||||
BITSET_UNLOCK;
|
||||
}
|
||||
|
||||
static inline void bitset_disable_stream( struct bitset * set )
|
||||
static inline void bitset_disable_stream(struct bitset *set)
|
||||
{
|
||||
BITSET_LOCK;
|
||||
bitset_stream_enqueue( set, BITSET_STREAM_OFF, 0, set->size );
|
||||
set->stream_enabled = 0;
|
||||
BITSET_UNLOCK;
|
||||
BITSET_LOCK;
|
||||
bitset_stream_enqueue(set, BITSET_STREAM_OFF, 0, set->size);
|
||||
set->stream_enabled = 0;
|
||||
BITSET_UNLOCK;
|
||||
}
|
||||
|
||||
/** Set the bits in a bitset which correspond to the given bytes in the larger
|
||||
* file.
|
||||
*/
|
||||
static inline void bitset_set_range(
|
||||
struct bitset * set,
|
||||
uint64_t from,
|
||||
uint64_t len)
|
||||
static inline void bitset_set_range(struct bitset *set,
|
||||
uint64_t from, uint64_t len)
|
||||
{
|
||||
INT_FIRST_AND_LAST;
|
||||
BITSET_LOCK;
|
||||
bit_set_range(set->bits, first, bitlen);
|
||||
INT_FIRST_AND_LAST;
|
||||
BITSET_LOCK;
|
||||
bit_set_range(set->bits, first, bitlen);
|
||||
|
||||
if ( set->stream_enabled ) {
|
||||
bitset_stream_enqueue( set, BITSET_STREAM_SET, from, len );
|
||||
}
|
||||
if (set->stream_enabled) {
|
||||
bitset_stream_enqueue(set, BITSET_STREAM_SET, from, len);
|
||||
}
|
||||
|
||||
BITSET_UNLOCK;
|
||||
BITSET_UNLOCK;
|
||||
}
|
||||
|
||||
|
||||
/** Set every bit in the bitset. */
|
||||
static inline void bitset_set( struct bitset * set )
|
||||
static inline void bitset_set(struct bitset *set)
|
||||
{
|
||||
bitset_set_range(set, 0, set->size);
|
||||
bitset_set_range(set, 0, set->size);
|
||||
}
|
||||
|
||||
/** Clear the bits in a bitset which correspond to the given bytes in the
|
||||
* larger file.
|
||||
*/
|
||||
static inline void bitset_clear_range(
|
||||
struct bitset * set,
|
||||
uint64_t from,
|
||||
uint64_t len)
|
||||
static inline void bitset_clear_range(struct bitset *set,
|
||||
uint64_t from, uint64_t len)
|
||||
{
|
||||
INT_FIRST_AND_LAST;
|
||||
BITSET_LOCK;
|
||||
bit_clear_range(set->bits, first, bitlen);
|
||||
INT_FIRST_AND_LAST;
|
||||
BITSET_LOCK;
|
||||
bit_clear_range(set->bits, first, bitlen);
|
||||
|
||||
if ( set->stream_enabled ) {
|
||||
bitset_stream_enqueue( set, BITSET_STREAM_UNSET, from, len );
|
||||
}
|
||||
if (set->stream_enabled) {
|
||||
bitset_stream_enqueue(set, BITSET_STREAM_UNSET, from, len);
|
||||
}
|
||||
|
||||
BITSET_UNLOCK;
|
||||
BITSET_UNLOCK;
|
||||
}
|
||||
|
||||
|
||||
/** Clear every bit in the bitset. */
|
||||
static inline void bitset_clear( struct bitset * set )
|
||||
static inline void bitset_clear(struct bitset *set)
|
||||
{
|
||||
bitset_clear_range(set, 0, set->size);
|
||||
bitset_clear_range(set, 0, set->size);
|
||||
}
|
||||
|
||||
/** As per bitset_run_count but also tells you whether the run it found was set
|
||||
* or unset, atomically.
|
||||
*/
|
||||
static inline uint64_t bitset_run_count_ex(
|
||||
struct bitset * set,
|
||||
uint64_t from,
|
||||
uint64_t len,
|
||||
int* run_is_set
|
||||
)
|
||||
static inline uint64_t bitset_run_count_ex(struct bitset *set,
|
||||
uint64_t from,
|
||||
uint64_t len, int *run_is_set)
|
||||
{
|
||||
uint64_t run;
|
||||
uint64_t run;
|
||||
|
||||
/* Clip our requests to the end of the bitset, avoiding uint underflow. */
|
||||
if ( from > set->size ) {
|
||||
return 0;
|
||||
}
|
||||
len = ( len + from ) > set->size ? ( set->size - from ) : len;
|
||||
/* Clip our requests to the end of the bitset, avoiding uint underflow. */
|
||||
if (from > set->size) {
|
||||
return 0;
|
||||
}
|
||||
len = (len + from) > set->size ? (set->size - from) : len;
|
||||
|
||||
INT_FIRST_AND_LAST;
|
||||
INT_FIRST_AND_LAST;
|
||||
|
||||
BITSET_LOCK;
|
||||
run = bit_run_count(set->bits, first, bitlen, run_is_set) * set->resolution;
|
||||
run -= (from % set->resolution);
|
||||
BITSET_UNLOCK;
|
||||
BITSET_LOCK;
|
||||
run =
|
||||
bit_run_count(set->bits, first, bitlen,
|
||||
run_is_set) * set->resolution;
|
||||
run -= (from % set->resolution);
|
||||
BITSET_UNLOCK;
|
||||
|
||||
return run;
|
||||
return run;
|
||||
}
|
||||
|
||||
/** Counts the number of contiguous bytes that are represented as a run in
|
||||
* the bit field.
|
||||
*/
|
||||
static inline uint64_t bitset_run_count(
|
||||
struct bitset * set,
|
||||
uint64_t from,
|
||||
uint64_t len)
|
||||
static inline uint64_t bitset_run_count(struct bitset *set,
|
||||
uint64_t from, uint64_t len)
|
||||
{
|
||||
return bitset_run_count_ex( set, from, len, NULL );
|
||||
return bitset_run_count_ex(set, from, len, NULL);
|
||||
}
|
||||
|
||||
/** Tests whether the bit field is clear for the given file offset.
|
||||
*/
|
||||
static inline int bitset_is_clear_at( struct bitset * set, uint64_t at )
|
||||
static inline int bitset_is_clear_at(struct bitset *set, uint64_t at)
|
||||
{
|
||||
return bit_is_clear(set->bits, at/set->resolution);
|
||||
return bit_is_clear(set->bits, at / set->resolution);
|
||||
}
|
||||
|
||||
/** Tests whether the bit field is set for the given file offset.
|
||||
*/
|
||||
static inline int bitset_is_set_at( struct bitset * set, uint64_t at )
|
||||
static inline int bitset_is_set_at(struct bitset *set, uint64_t at)
|
||||
{
|
||||
return bit_is_set(set->bits, at/set->resolution);
|
||||
return bit_is_set(set->bits, at / set->resolution);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
1009
src/server/client.c
1009
src/server/client.c
File diff suppressed because it is too large
Load Diff
@@ -19,41 +19,40 @@
|
||||
|
||||
|
||||
struct client {
|
||||
/* When we call pthread_join, if the thread is already dead
|
||||
* we can get an ESRCH. Since we have no other way to tell
|
||||
* if that ESRCH is from a dead thread or a thread that never
|
||||
* existed, we use a `stopped` flag to indicate a thread which
|
||||
* did exist, but went away. Only check this after a
|
||||
* pthread_join call.
|
||||
*/
|
||||
int stopped;
|
||||
int socket;
|
||||
/* When we call pthread_join, if the thread is already dead
|
||||
* we can get an ESRCH. Since we have no other way to tell
|
||||
* if that ESRCH is from a dead thread or a thread that never
|
||||
* existed, we use a `stopped` flag to indicate a thread which
|
||||
* did exist, but went away. Only check this after a
|
||||
* pthread_join call.
|
||||
*/
|
||||
int stopped;
|
||||
int socket;
|
||||
|
||||
int fileno;
|
||||
char* mapped;
|
||||
int fileno;
|
||||
char *mapped;
|
||||
|
||||
uint64_t mapped_size;
|
||||
uint64_t mapped_size;
|
||||
|
||||
struct self_pipe * stop_signal;
|
||||
struct self_pipe *stop_signal;
|
||||
|
||||
struct server* serve; /* FIXME: remove above duplication */
|
||||
struct server *serve; /* FIXME: remove above duplication */
|
||||
|
||||
/* Have we seen a REQUEST_DISCONNECT message? */
|
||||
int disconnect;
|
||||
/* Have we seen a REQUEST_DISCONNECT message? */
|
||||
int disconnect;
|
||||
|
||||
/* kill the whole server if a request has been outstanding too long,
|
||||
* assuming use_killswitch is set in serve
|
||||
*/
|
||||
timer_t killswitch;
|
||||
/* kill the whole server if a request has been outstanding too long,
|
||||
* assuming use_killswitch is set in serve
|
||||
*/
|
||||
timer_t killswitch;
|
||||
|
||||
};
|
||||
|
||||
void client_killswitch_hit(int signal, siginfo_t *info, void *ptr);
|
||||
void client_killswitch_hit(int signal, siginfo_t * info, void *ptr);
|
||||
|
||||
void* client_serve(void* client_uncast);
|
||||
struct client * client_create( struct server * serve, int socket );
|
||||
void client_destroy( struct client * client );
|
||||
void client_signal_stop( struct client * client );
|
||||
void *client_serve(void *client_uncast);
|
||||
struct client *client_create(struct server *serve, int socket);
|
||||
void client_destroy(struct client *client);
|
||||
void client_signal_stop(struct client *client);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -44,590 +44,570 @@
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
struct control * control_create(
|
||||
struct flexnbd * flexnbd,
|
||||
const char * csn)
|
||||
struct control *control_create(struct flexnbd *flexnbd, const char *csn)
|
||||
{
|
||||
struct control * control = xmalloc( sizeof( struct control ) );
|
||||
struct control *control = xmalloc(sizeof(struct control));
|
||||
|
||||
NULLCHECK( csn );
|
||||
NULLCHECK(csn);
|
||||
|
||||
control->flexnbd = flexnbd;
|
||||
control->socket_name = csn;
|
||||
control->open_signal = self_pipe_create();
|
||||
control->close_signal = self_pipe_create();
|
||||
control->mirror_state_mbox = mbox_create();
|
||||
control->flexnbd = flexnbd;
|
||||
control->socket_name = csn;
|
||||
control->open_signal = self_pipe_create();
|
||||
control->close_signal = self_pipe_create();
|
||||
control->mirror_state_mbox = mbox_create();
|
||||
|
||||
return control;
|
||||
return control;
|
||||
}
|
||||
|
||||
|
||||
void control_signal_close( struct control * control)
|
||||
void control_signal_close(struct control *control)
|
||||
{
|
||||
|
||||
NULLCHECK( control );
|
||||
self_pipe_signal( control->close_signal );
|
||||
NULLCHECK(control);
|
||||
self_pipe_signal(control->close_signal);
|
||||
}
|
||||
|
||||
|
||||
void control_destroy( struct control * control )
|
||||
void control_destroy(struct control *control)
|
||||
{
|
||||
NULLCHECK( control );
|
||||
NULLCHECK(control);
|
||||
|
||||
mbox_destroy( control->mirror_state_mbox );
|
||||
self_pipe_destroy( control->close_signal );
|
||||
self_pipe_destroy( control->open_signal );
|
||||
free( control );
|
||||
mbox_destroy(control->mirror_state_mbox);
|
||||
self_pipe_destroy(control->close_signal);
|
||||
self_pipe_destroy(control->open_signal);
|
||||
free(control);
|
||||
}
|
||||
|
||||
struct control_client * control_client_create(
|
||||
struct flexnbd * flexnbd,
|
||||
int client_fd ,
|
||||
struct mbox * state_mbox )
|
||||
struct control_client *control_client_create(struct flexnbd *flexnbd,
|
||||
int client_fd,
|
||||
struct mbox *state_mbox)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
NULLCHECK(flexnbd);
|
||||
|
||||
struct control_client * control_client =
|
||||
xmalloc( sizeof( struct control_client ) );
|
||||
struct control_client *control_client =
|
||||
xmalloc(sizeof(struct control_client));
|
||||
|
||||
control_client->socket = client_fd;
|
||||
control_client->flexnbd = flexnbd;
|
||||
control_client->mirror_state_mbox = state_mbox;
|
||||
return control_client;
|
||||
control_client->socket = client_fd;
|
||||
control_client->flexnbd = flexnbd;
|
||||
control_client->mirror_state_mbox = state_mbox;
|
||||
return control_client;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void control_client_destroy( struct control_client * client )
|
||||
void control_client_destroy(struct control_client *client)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
free( client );
|
||||
NULLCHECK(client);
|
||||
free(client);
|
||||
}
|
||||
|
||||
|
||||
void control_respond(struct control_client * client);
|
||||
void control_respond(struct control_client *client);
|
||||
|
||||
void control_handle_client( struct control * control, int client_fd )
|
||||
void control_handle_client(struct control *control, int client_fd)
|
||||
{
|
||||
NULLCHECK( control );
|
||||
NULLCHECK( control->flexnbd );
|
||||
struct control_client * control_client =
|
||||
control_client_create(
|
||||
control->flexnbd,
|
||||
client_fd ,
|
||||
control->mirror_state_mbox);
|
||||
NULLCHECK(control);
|
||||
NULLCHECK(control->flexnbd);
|
||||
struct control_client *control_client =
|
||||
control_client_create(control->flexnbd,
|
||||
client_fd,
|
||||
control->mirror_state_mbox);
|
||||
|
||||
/* We intentionally don't spawn a thread for the client here.
|
||||
* This is to avoid having more than one thread potentially
|
||||
* waiting on the migration commit status.
|
||||
*/
|
||||
control_respond( control_client );
|
||||
/* We intentionally don't spawn a thread for the client here.
|
||||
* This is to avoid having more than one thread potentially
|
||||
* waiting on the migration commit status.
|
||||
*/
|
||||
control_respond(control_client);
|
||||
}
|
||||
|
||||
|
||||
void control_accept_client( struct control * control )
|
||||
void control_accept_client(struct control *control)
|
||||
{
|
||||
|
||||
int client_fd;
|
||||
union mysockaddr client_address;
|
||||
socklen_t addrlen = sizeof( union mysockaddr );
|
||||
int client_fd;
|
||||
union mysockaddr client_address;
|
||||
socklen_t addrlen = sizeof(union mysockaddr);
|
||||
|
||||
client_fd = accept( control->control_fd, &client_address.generic, &addrlen );
|
||||
FATAL_IF( -1 == client_fd, "control accept failed" );
|
||||
client_fd =
|
||||
accept(control->control_fd, &client_address.generic, &addrlen);
|
||||
FATAL_IF(-1 == client_fd, "control accept failed");
|
||||
|
||||
control_handle_client( control, client_fd );
|
||||
control_handle_client(control, client_fd);
|
||||
}
|
||||
|
||||
int control_accept( struct control * control )
|
||||
int control_accept(struct control *control)
|
||||
{
|
||||
NULLCHECK( control );
|
||||
NULLCHECK(control);
|
||||
|
||||
fd_set fds;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( control->control_fd, &fds );
|
||||
self_pipe_fd_set( control->close_signal, &fds );
|
||||
debug("Control thread selecting");
|
||||
FATAL_UNLESS( 0 < select( FD_SETSIZE, &fds, NULL, NULL, NULL ),
|
||||
"Control select failed." );
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(control->control_fd, &fds);
|
||||
self_pipe_fd_set(control->close_signal, &fds);
|
||||
debug("Control thread selecting");
|
||||
FATAL_UNLESS(0 < select(FD_SETSIZE, &fds, NULL, NULL, NULL),
|
||||
"Control select failed.");
|
||||
|
||||
if ( self_pipe_fd_isset( control->close_signal, &fds ) ){
|
||||
return 0;
|
||||
}
|
||||
if (self_pipe_fd_isset(control->close_signal, &fds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( FD_ISSET( control->control_fd, &fds ) ) {
|
||||
control_accept_client( control );
|
||||
}
|
||||
return 1;
|
||||
if (FD_ISSET(control->control_fd, &fds)) {
|
||||
control_accept_client(control);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void control_accept_loop( struct control * control )
|
||||
void control_accept_loop(struct control *control)
|
||||
{
|
||||
while( control_accept( control ) );
|
||||
while (control_accept(control));
|
||||
}
|
||||
|
||||
|
||||
int open_control_socket( const char * socket_name )
|
||||
int open_control_socket(const char *socket_name)
|
||||
{
|
||||
struct sockaddr_un bind_address;
|
||||
int control_fd;
|
||||
struct sockaddr_un bind_address;
|
||||
int control_fd;
|
||||
|
||||
if (!socket_name) {
|
||||
fatal( "Tried to open a control socket without a socket name" );
|
||||
}
|
||||
if (!socket_name) {
|
||||
fatal("Tried to open a control socket without a socket name");
|
||||
}
|
||||
|
||||
control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
FATAL_IF_NEGATIVE(control_fd ,
|
||||
"Couldn't create control socket");
|
||||
control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
FATAL_IF_NEGATIVE(control_fd, "Couldn't create control socket");
|
||||
|
||||
memset(&bind_address, 0, sizeof(struct sockaddr_un));
|
||||
bind_address.sun_family = AF_UNIX;
|
||||
strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1);
|
||||
memset(&bind_address, 0, sizeof(struct sockaddr_un));
|
||||
bind_address.sun_family = AF_UNIX;
|
||||
strncpy(bind_address.sun_path, socket_name,
|
||||
sizeof(bind_address.sun_path) - 1);
|
||||
|
||||
//unlink(socket_name); /* ignore failure */
|
||||
//unlink(socket_name); /* ignore failure */
|
||||
|
||||
FATAL_IF_NEGATIVE(
|
||||
bind(control_fd , &bind_address, sizeof(bind_address)),
|
||||
"Couldn't bind control socket to %s: %s",
|
||||
socket_name, strerror( errno )
|
||||
FATAL_IF_NEGATIVE(bind
|
||||
(control_fd, &bind_address, sizeof(bind_address)),
|
||||
"Couldn't bind control socket to %s: %s",
|
||||
socket_name, strerror(errno)
|
||||
);
|
||||
|
||||
FATAL_IF_NEGATIVE(
|
||||
listen(control_fd , 5),
|
||||
"Couldn't listen on control socket"
|
||||
);
|
||||
return control_fd;
|
||||
FATAL_IF_NEGATIVE(listen(control_fd, 5),
|
||||
"Couldn't listen on control socket");
|
||||
return control_fd;
|
||||
}
|
||||
|
||||
|
||||
void control_listen(struct control* control)
|
||||
void control_listen(struct control *control)
|
||||
{
|
||||
NULLCHECK( control );
|
||||
control->control_fd = open_control_socket( control->socket_name );
|
||||
NULLCHECK(control);
|
||||
control->control_fd = open_control_socket(control->socket_name);
|
||||
}
|
||||
|
||||
void control_wait_for_open_signal( struct control * control )
|
||||
void control_wait_for_open_signal(struct control *control)
|
||||
{
|
||||
fd_set fds;
|
||||
FD_ZERO( &fds );
|
||||
self_pipe_fd_set( control->open_signal, &fds );
|
||||
FATAL_IF_NEGATIVE( select( FD_SETSIZE, &fds, NULL, NULL, NULL ),
|
||||
"select() failed" );
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
self_pipe_fd_set(control->open_signal, &fds);
|
||||
FATAL_IF_NEGATIVE(select(FD_SETSIZE, &fds, NULL, NULL, NULL),
|
||||
"select() failed");
|
||||
|
||||
self_pipe_signal_clear( control->open_signal );
|
||||
self_pipe_signal_clear(control->open_signal);
|
||||
}
|
||||
|
||||
|
||||
void control_serve( struct control * control )
|
||||
void control_serve(struct control *control)
|
||||
{
|
||||
NULLCHECK( control );
|
||||
NULLCHECK(control);
|
||||
|
||||
control_wait_for_open_signal( control );
|
||||
control_listen( control );
|
||||
while( control_accept( control ) );
|
||||
control_wait_for_open_signal(control);
|
||||
control_listen(control);
|
||||
while (control_accept(control));
|
||||
}
|
||||
|
||||
|
||||
void control_cleanup(
|
||||
struct control * control,
|
||||
int fatal __attribute__((unused)) )
|
||||
void control_cleanup(struct control *control,
|
||||
int fatal __attribute__ ((unused)))
|
||||
{
|
||||
NULLCHECK( control );
|
||||
unlink( control->socket_name );
|
||||
close( control->control_fd );
|
||||
NULLCHECK(control);
|
||||
unlink(control->socket_name);
|
||||
close(control->control_fd);
|
||||
}
|
||||
|
||||
|
||||
void * control_runner( void * control_uncast )
|
||||
void *control_runner(void *control_uncast)
|
||||
{
|
||||
debug("Control thread");
|
||||
NULLCHECK( control_uncast );
|
||||
struct control * control = (struct control *)control_uncast;
|
||||
debug("Control thread");
|
||||
NULLCHECK(control_uncast);
|
||||
struct control *control = (struct control *) control_uncast;
|
||||
|
||||
error_set_handler( (cleanup_handler*)control_cleanup, control );
|
||||
error_set_handler((cleanup_handler *) control_cleanup, control);
|
||||
|
||||
control_serve( control );
|
||||
control_serve(control);
|
||||
|
||||
control_cleanup( control, 0 );
|
||||
pthread_exit( NULL );
|
||||
control_cleanup(control, 0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
||||
#define write_socket(msg) write(client_fd, (msg "\n"), strlen((msg))+1)
|
||||
|
||||
void control_write_mirror_response( enum mirror_state mirror_state, int client_fd )
|
||||
void control_write_mirror_response(enum mirror_state mirror_state,
|
||||
int client_fd)
|
||||
{
|
||||
switch (mirror_state) {
|
||||
case MS_INIT:
|
||||
case MS_UNKNOWN:
|
||||
write_socket( "1: Mirror failed to initialise" );
|
||||
fatal( "Impossible mirror state: %d", mirror_state );
|
||||
case MS_FAIL_CONNECT:
|
||||
write_socket( "1: Mirror failed to connect");
|
||||
break;
|
||||
case MS_FAIL_REJECTED:
|
||||
write_socket( "1: Mirror was rejected" );
|
||||
break;
|
||||
case MS_FAIL_NO_HELLO:
|
||||
write_socket( "1: Remote server failed to respond");
|
||||
break;
|
||||
case MS_FAIL_SIZE_MISMATCH:
|
||||
write_socket( "1: Remote size does not match local size" );
|
||||
break;
|
||||
case MS_ABANDONED:
|
||||
write_socket( "1: Mirroring abandoned" );
|
||||
break;
|
||||
case MS_GO:
|
||||
case MS_DONE: /* Yes, I know we know better, but it's simpler this way */
|
||||
write_socket( "0: Mirror started" );
|
||||
break;
|
||||
default:
|
||||
fatal( "Unhandled mirror state: %d", mirror_state );
|
||||
}
|
||||
switch (mirror_state) {
|
||||
case MS_INIT:
|
||||
case MS_UNKNOWN:
|
||||
write_socket("1: Mirror failed to initialise");
|
||||
fatal("Impossible mirror state: %d", mirror_state);
|
||||
case MS_FAIL_CONNECT:
|
||||
write_socket("1: Mirror failed to connect");
|
||||
break;
|
||||
case MS_FAIL_REJECTED:
|
||||
write_socket("1: Mirror was rejected");
|
||||
break;
|
||||
case MS_FAIL_NO_HELLO:
|
||||
write_socket("1: Remote server failed to respond");
|
||||
break;
|
||||
case MS_FAIL_SIZE_MISMATCH:
|
||||
write_socket("1: Remote size does not match local size");
|
||||
break;
|
||||
case MS_ABANDONED:
|
||||
write_socket("1: Mirroring abandoned");
|
||||
break;
|
||||
case MS_GO:
|
||||
case MS_DONE: /* Yes, I know we know better, but it's simpler this way */
|
||||
write_socket("0: Mirror started");
|
||||
break;
|
||||
default:
|
||||
fatal("Unhandled mirror state: %d", mirror_state);
|
||||
}
|
||||
}
|
||||
|
||||
#undef write_socket
|
||||
|
||||
|
||||
/* Call this in the thread where you want to receive the mirror state */
|
||||
enum mirror_state control_client_mirror_wait(
|
||||
struct control_client* client)
|
||||
enum mirror_state control_client_mirror_wait(struct control_client *client)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK( client->mirror_state_mbox );
|
||||
NULLCHECK(client);
|
||||
NULLCHECK(client->mirror_state_mbox);
|
||||
|
||||
struct mbox * mbox = client->mirror_state_mbox;
|
||||
enum mirror_state mirror_state;
|
||||
enum mirror_state * contents;
|
||||
struct mbox *mbox = client->mirror_state_mbox;
|
||||
enum mirror_state mirror_state;
|
||||
enum mirror_state *contents;
|
||||
|
||||
contents = (enum mirror_state*)mbox_receive( mbox );
|
||||
NULLCHECK( contents );
|
||||
contents = (enum mirror_state *) mbox_receive(mbox);
|
||||
NULLCHECK(contents);
|
||||
|
||||
mirror_state = *contents;
|
||||
mirror_state = *contents;
|
||||
|
||||
free( contents );
|
||||
free(contents);
|
||||
|
||||
return mirror_state;
|
||||
return mirror_state;
|
||||
}
|
||||
|
||||
#define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1)
|
||||
/** Command parser to start mirror process from socket input */
|
||||
int control_mirror(struct control_client* client, int linesc, char** lines)
|
||||
int control_mirror(struct control_client *client, int linesc, char **lines)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK(client);
|
||||
|
||||
struct flexnbd * flexnbd = client->flexnbd;
|
||||
union mysockaddr *connect_to = xmalloc( sizeof( union mysockaddr ) );
|
||||
union mysockaddr *connect_from = NULL;
|
||||
uint64_t max_Bps = UINT64_MAX;
|
||||
int action_at_finish;
|
||||
int raw_port;
|
||||
struct flexnbd *flexnbd = client->flexnbd;
|
||||
union mysockaddr *connect_to = xmalloc(sizeof(union mysockaddr));
|
||||
union mysockaddr *connect_from = NULL;
|
||||
uint64_t max_Bps = UINT64_MAX;
|
||||
int action_at_finish;
|
||||
int raw_port;
|
||||
|
||||
|
||||
if (linesc < 2) {
|
||||
write_socket("1: mirror takes at least two parameters");
|
||||
return -1;
|
||||
if (linesc < 2) {
|
||||
write_socket("1: mirror takes at least two parameters");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_ip_to_sockaddr(&connect_to->generic, lines[0]) == 0) {
|
||||
write_socket("1: bad IP address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
raw_port = atoi(lines[1]);
|
||||
if (raw_port < 0 || raw_port > 65535) {
|
||||
write_socket("1: bad IP port number");
|
||||
return -1;
|
||||
}
|
||||
connect_to->v4.sin_port = htobe16(raw_port);
|
||||
|
||||
action_at_finish = ACTION_EXIT;
|
||||
if (linesc > 2) {
|
||||
if (strcmp("exit", lines[2]) == 0) {
|
||||
action_at_finish = ACTION_EXIT;
|
||||
} else if (strcmp("unlink", lines[2]) == 0) {
|
||||
action_at_finish = ACTION_UNLINK;
|
||||
} else if (strcmp("nothing", lines[2]) == 0) {
|
||||
action_at_finish = ACTION_NOTHING;
|
||||
} else {
|
||||
write_socket("1: action must be 'exit' or 'nothing'");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (linesc > 3) {
|
||||
connect_from = xmalloc(sizeof(union mysockaddr));
|
||||
if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) {
|
||||
write_socket("1: bad bind address");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (linesc > 4) {
|
||||
errno = 0;
|
||||
max_Bps = strtoull(lines[4], NULL, 10);
|
||||
if (errno == ERANGE) {
|
||||
write_socket("1: max_bps out of range");
|
||||
return -1;
|
||||
} else if (errno != 0) {
|
||||
write_socket("1: max_bps couldn't be parsed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (linesc > 5) {
|
||||
write_socket("1: unrecognised parameters to mirror");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct server *serve = flexnbd_server(flexnbd);
|
||||
|
||||
server_lock_start_mirror(serve);
|
||||
{
|
||||
if (server_mirror_can_start(serve)) {
|
||||
serve->mirror_super = mirror_super_create(serve->filename,
|
||||
connect_to,
|
||||
connect_from,
|
||||
max_Bps,
|
||||
action_at_finish,
|
||||
client->
|
||||
mirror_state_mbox);
|
||||
serve->mirror = serve->mirror_super->mirror;
|
||||
server_prevent_mirror_start(serve);
|
||||
} else {
|
||||
if (serve->mirror_super) {
|
||||
warn("Tried to start a second mirror run");
|
||||
write_socket("1: mirror already running");
|
||||
} else {
|
||||
warn("Cannot start mirroring, shutting down");
|
||||
write_socket("1: shutting down");
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_ip_to_sockaddr(&connect_to->generic, lines[0]) == 0) {
|
||||
write_socket("1: bad IP address");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
server_unlock_start_mirror(serve);
|
||||
|
||||
raw_port = atoi(lines[1]);
|
||||
if (raw_port < 0 || raw_port > 65535) {
|
||||
write_socket("1: bad IP port number");
|
||||
return -1;
|
||||
}
|
||||
connect_to->v4.sin_port = htobe16(raw_port);
|
||||
/* Do this outside the lock to minimise the length of time the
|
||||
* sighandler can block the serve thread
|
||||
*/
|
||||
if (serve->mirror_super) {
|
||||
FATAL_IF(0 != pthread_create(&serve->mirror_super->thread,
|
||||
NULL,
|
||||
mirror_super_runner,
|
||||
serve),
|
||||
"Failed to create mirror thread");
|
||||
|
||||
action_at_finish = ACTION_EXIT;
|
||||
if (linesc > 2) {
|
||||
if (strcmp("exit", lines[2]) == 0) {
|
||||
action_at_finish = ACTION_EXIT;
|
||||
}
|
||||
else if (strcmp( "unlink", lines[2]) == 0 ) {
|
||||
action_at_finish = ACTION_UNLINK;
|
||||
}
|
||||
else if (strcmp("nothing", lines[2]) == 0) {
|
||||
action_at_finish = ACTION_NOTHING;
|
||||
}
|
||||
else {
|
||||
write_socket("1: action must be 'exit' or 'nothing'");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
debug("Control thread mirror super waiting");
|
||||
enum mirror_state state = control_client_mirror_wait(client);
|
||||
debug("Control thread writing response");
|
||||
control_write_mirror_response(state, client->socket);
|
||||
}
|
||||
|
||||
if (linesc > 3) {
|
||||
connect_from = xmalloc( sizeof( union mysockaddr ) );
|
||||
if (parse_ip_to_sockaddr(&connect_from->generic, lines[3]) == 0) {
|
||||
write_socket("1: bad bind address");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
debug("Control thread going away.");
|
||||
|
||||
if (linesc > 4) {
|
||||
errno = 0;
|
||||
max_Bps = strtoull( lines[4], NULL, 10 );
|
||||
if ( errno == ERANGE ) {
|
||||
write_socket( "1: max_bps out of range" );
|
||||
return -1;
|
||||
} else if ( errno != 0 ) {
|
||||
write_socket( "1: max_bps couldn't be parsed" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (linesc > 5) {
|
||||
write_socket("1: unrecognised parameters to mirror");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct server * serve = flexnbd_server(flexnbd);
|
||||
|
||||
server_lock_start_mirror( serve );
|
||||
{
|
||||
if ( server_mirror_can_start( serve ) ) {
|
||||
serve->mirror_super = mirror_super_create(
|
||||
serve->filename,
|
||||
connect_to,
|
||||
connect_from,
|
||||
max_Bps ,
|
||||
action_at_finish,
|
||||
client->mirror_state_mbox );
|
||||
serve->mirror = serve->mirror_super->mirror;
|
||||
server_prevent_mirror_start( serve );
|
||||
} else {
|
||||
if ( serve->mirror_super ) {
|
||||
warn( "Tried to start a second mirror run" );
|
||||
write_socket( "1: mirror already running" );
|
||||
} else {
|
||||
warn( "Cannot start mirroring, shutting down" );
|
||||
write_socket( "1: shutting down" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
server_unlock_start_mirror( serve );
|
||||
|
||||
/* Do this outside the lock to minimise the length of time the
|
||||
* sighandler can block the serve thread
|
||||
*/
|
||||
if ( serve->mirror_super ) {
|
||||
FATAL_IF( 0 != pthread_create(
|
||||
&serve->mirror_super->thread,
|
||||
NULL,
|
||||
mirror_super_runner,
|
||||
serve
|
||||
),
|
||||
"Failed to create mirror thread"
|
||||
);
|
||||
|
||||
debug("Control thread mirror super waiting");
|
||||
enum mirror_state state =
|
||||
control_client_mirror_wait( client );
|
||||
debug("Control thread writing response");
|
||||
control_write_mirror_response( state, client->socket );
|
||||
}
|
||||
|
||||
debug( "Control thread going away." );
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int control_mirror_max_bps( struct control_client* client, int linesc, char** lines )
|
||||
int control_mirror_max_bps(struct control_client *client, int linesc,
|
||||
char **lines)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK( client->flexnbd );
|
||||
NULLCHECK(client);
|
||||
NULLCHECK(client->flexnbd);
|
||||
|
||||
struct server* serve = flexnbd_server( client->flexnbd );
|
||||
uint64_t max_Bps;
|
||||
struct server *serve = flexnbd_server(client->flexnbd);
|
||||
uint64_t max_Bps;
|
||||
|
||||
if ( !serve->mirror_super ) {
|
||||
write_socket( "1: Not currently mirroring" );
|
||||
return -1;
|
||||
}
|
||||
if (!serve->mirror_super) {
|
||||
write_socket("1: Not currently mirroring");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( linesc != 1 ) {
|
||||
write_socket( "1: Bad format" );
|
||||
return -1;
|
||||
}
|
||||
if (linesc != 1) {
|
||||
write_socket("1: Bad format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
max_Bps = strtoull( lines[0], NULL, 10 );
|
||||
if ( errno == ERANGE ) {
|
||||
write_socket( "1: max_bps out of range" );
|
||||
return -1;
|
||||
} else if ( errno != 0 ) {
|
||||
write_socket( "1: max_bps couldn't be parsed" );
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
max_Bps = strtoull(lines[0], NULL, 10);
|
||||
if (errno == ERANGE) {
|
||||
write_socket("1: max_bps out of range");
|
||||
return -1;
|
||||
} else if (errno != 0) {
|
||||
write_socket("1: max_bps couldn't be parsed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
serve->mirror->max_bytes_per_second = max_Bps;
|
||||
write_socket( "0: updated" );
|
||||
serve->mirror->max_bytes_per_second = max_Bps;
|
||||
write_socket("0: updated");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef write_socket
|
||||
|
||||
/** Command parser to alter access control list from socket input */
|
||||
int control_acl(struct control_client* client, int linesc, char** lines)
|
||||
int control_acl(struct control_client *client, int linesc, char **lines)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK( client->flexnbd );
|
||||
struct flexnbd * flexnbd = client->flexnbd;
|
||||
NULLCHECK(client);
|
||||
NULLCHECK(client->flexnbd);
|
||||
struct flexnbd *flexnbd = client->flexnbd;
|
||||
|
||||
int default_deny = flexnbd_default_deny( flexnbd );
|
||||
struct acl * new_acl = acl_create( linesc, lines, default_deny );
|
||||
int default_deny = flexnbd_default_deny(flexnbd);
|
||||
struct acl *new_acl = acl_create(linesc, lines, default_deny);
|
||||
|
||||
if (new_acl->len != linesc) {
|
||||
warn("Bad ACL spec: %s", lines[new_acl->len] );
|
||||
write(client->socket, "1: bad spec: ", 13);
|
||||
write(client->socket, lines[new_acl->len],
|
||||
strlen(lines[new_acl->len]));
|
||||
write(client->socket, "\n", 1);
|
||||
acl_destroy( new_acl );
|
||||
}
|
||||
else {
|
||||
flexnbd_replace_acl( flexnbd, new_acl );
|
||||
info("ACL set");
|
||||
write( client->socket, "0: updated\n", 11);
|
||||
}
|
||||
if (new_acl->len != linesc) {
|
||||
warn("Bad ACL spec: %s", lines[new_acl->len]);
|
||||
write(client->socket, "1: bad spec: ", 13);
|
||||
write(client->socket, lines[new_acl->len],
|
||||
strlen(lines[new_acl->len]));
|
||||
write(client->socket, "\n", 1);
|
||||
acl_destroy(new_acl);
|
||||
} else {
|
||||
flexnbd_replace_acl(flexnbd, new_acl);
|
||||
info("ACL set");
|
||||
write(client->socket, "0: updated\n", 11);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int control_break(
|
||||
struct control_client* client,
|
||||
int linesc __attribute__ ((unused)),
|
||||
char** lines __attribute__((unused))
|
||||
)
|
||||
int control_break(struct control_client *client,
|
||||
int linesc __attribute__ ((unused)),
|
||||
char **lines __attribute__ ((unused))
|
||||
)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK( client->flexnbd );
|
||||
NULLCHECK(client);
|
||||
NULLCHECK(client->flexnbd);
|
||||
|
||||
int result = 0;
|
||||
struct flexnbd* flexnbd = client->flexnbd;
|
||||
int result = 0;
|
||||
struct flexnbd *flexnbd = client->flexnbd;
|
||||
|
||||
struct server * serve = flexnbd_server( flexnbd );
|
||||
struct server *serve = flexnbd_server(flexnbd);
|
||||
|
||||
server_lock_start_mirror( serve );
|
||||
{
|
||||
if ( server_is_mirroring( serve ) ) {
|
||||
server_lock_start_mirror(serve);
|
||||
{
|
||||
if (server_is_mirroring(serve)) {
|
||||
|
||||
info( "Signaling to abandon mirror" );
|
||||
server_abandon_mirror( serve );
|
||||
debug( "Abandon signaled" );
|
||||
info("Signaling to abandon mirror");
|
||||
server_abandon_mirror(serve);
|
||||
debug("Abandon signaled");
|
||||
|
||||
if ( server_is_closed( serve ) ) {
|
||||
info( "Mirror completed while canceling" );
|
||||
write( client->socket,
|
||||
"1: mirror completed\n", 20 );
|
||||
}
|
||||
else {
|
||||
info( "Mirror successfully stopped." );
|
||||
write( client->socket,
|
||||
"0: mirror stopped\n", 18 );
|
||||
result = 1;
|
||||
}
|
||||
if (server_is_closed(serve)) {
|
||||
info("Mirror completed while canceling");
|
||||
write(client->socket, "1: mirror completed\n", 20);
|
||||
} else {
|
||||
info("Mirror successfully stopped.");
|
||||
write(client->socket, "0: mirror stopped\n", 18);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
warn( "Not mirroring." );
|
||||
write( client->socket, "1: not mirroring\n", 17 );
|
||||
}
|
||||
} else {
|
||||
warn("Not mirroring.");
|
||||
write(client->socket, "1: not mirroring\n", 17);
|
||||
}
|
||||
server_unlock_start_mirror( serve );
|
||||
}
|
||||
server_unlock_start_mirror(serve);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** FIXME: add some useful statistics */
|
||||
int control_status(
|
||||
struct control_client* client,
|
||||
int linesc __attribute__ ((unused)),
|
||||
char** lines __attribute__((unused))
|
||||
)
|
||||
int control_status(struct control_client *client,
|
||||
int linesc __attribute__ ((unused)),
|
||||
char **lines __attribute__ ((unused))
|
||||
)
|
||||
{
|
||||
NULLCHECK( client );
|
||||
NULLCHECK( client->flexnbd );
|
||||
struct status * status = flexnbd_status_create( client->flexnbd );
|
||||
NULLCHECK(client);
|
||||
NULLCHECK(client->flexnbd);
|
||||
struct status *status = flexnbd_status_create(client->flexnbd);
|
||||
|
||||
write( client->socket, "0: ", 3 );
|
||||
status_write( status, client->socket );
|
||||
status_destroy( status );
|
||||
write(client->socket, "0: ", 3);
|
||||
status_write(status, client->socket);
|
||||
status_destroy(status);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void control_client_cleanup(struct control_client* client,
|
||||
int fatal __attribute__ ((unused)) )
|
||||
void control_client_cleanup(struct control_client *client,
|
||||
int fatal __attribute__ ((unused)))
|
||||
{
|
||||
if (client->socket) { close(client->socket); }
|
||||
if (client->socket) {
|
||||
close(client->socket);
|
||||
}
|
||||
|
||||
/* This is wrongness */
|
||||
if ( server_acl_locked( client->flexnbd->serve ) ) { server_unlock_acl( client->flexnbd->serve ); }
|
||||
/* This is wrongness */
|
||||
if (server_acl_locked(client->flexnbd->serve)) {
|
||||
server_unlock_acl(client->flexnbd->serve);
|
||||
}
|
||||
|
||||
control_client_destroy( client );
|
||||
control_client_destroy(client);
|
||||
}
|
||||
|
||||
/** Master command parser for control socket connections, delegates quickly */
|
||||
void control_respond(struct control_client * client)
|
||||
void control_respond(struct control_client *client)
|
||||
{
|
||||
char **lines = NULL;
|
||||
char **lines = NULL;
|
||||
|
||||
error_set_handler((cleanup_handler*) control_client_cleanup, client);
|
||||
error_set_handler((cleanup_handler *) control_client_cleanup, client);
|
||||
|
||||
int i, linesc;
|
||||
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
||||
int i, linesc;
|
||||
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
||||
|
||||
if (linesc < 1)
|
||||
{
|
||||
write(client->socket, "9: missing command\n", 19);
|
||||
/* ignore failure */
|
||||
if (linesc < 1) {
|
||||
write(client->socket, "9: missing command\n", 19);
|
||||
/* ignore failure */
|
||||
} else if (strcmp(lines[0], "acl") == 0) {
|
||||
info("acl command received");
|
||||
if (control_acl(client, linesc - 1, lines + 1) < 0) {
|
||||
debug("acl command failed");
|
||||
}
|
||||
else if (strcmp(lines[0], "acl") == 0) {
|
||||
info("acl command received" );
|
||||
if (control_acl(client, linesc-1, lines+1) < 0) {
|
||||
debug("acl command failed");
|
||||
}
|
||||
} else if (strcmp(lines[0], "mirror") == 0) {
|
||||
info("mirror command received");
|
||||
if (control_mirror(client, linesc - 1, lines + 1) < 0) {
|
||||
debug("mirror command failed");
|
||||
}
|
||||
else if (strcmp(lines[0], "mirror") == 0) {
|
||||
info("mirror command received" );
|
||||
if (control_mirror(client, linesc-1, lines+1) < 0) {
|
||||
debug("mirror command failed");
|
||||
}
|
||||
} else if (strcmp(lines[0], "break") == 0) {
|
||||
info("break command received");
|
||||
if (control_break(client, linesc - 1, lines + 1) < 0) {
|
||||
debug("break command failed");
|
||||
}
|
||||
else if (strcmp(lines[0], "break") == 0) {
|
||||
info( "break command received" );
|
||||
if ( control_break( client, linesc-1, lines+1) < 0) {
|
||||
debug( "break command failed" );
|
||||
}
|
||||
} else if (strcmp(lines[0], "status") == 0) {
|
||||
info("status command received");
|
||||
if (control_status(client, linesc - 1, lines + 1) < 0) {
|
||||
debug("status command failed");
|
||||
}
|
||||
else if (strcmp(lines[0], "status") == 0) {
|
||||
info("status command received" );
|
||||
if (control_status(client, linesc-1, lines+1) < 0) {
|
||||
debug("status command failed");
|
||||
}
|
||||
} else if ( strcmp( lines[0], "mirror_max_bps" ) == 0 ) {
|
||||
info( "mirror_max_bps command received" );
|
||||
if( control_mirror_max_bps( client, linesc-1, lines+1 ) < 0 ) {
|
||||
debug( "mirror_max_bps command failed" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
write(client->socket, "10: unknown command\n", 23);
|
||||
} else if (strcmp(lines[0], "mirror_max_bps") == 0) {
|
||||
info("mirror_max_bps command received");
|
||||
if (control_mirror_max_bps(client, linesc - 1, lines + 1) < 0) {
|
||||
debug("mirror_max_bps command failed");
|
||||
}
|
||||
} else {
|
||||
write(client->socket, "10: unknown command\n", 23);
|
||||
}
|
||||
|
||||
for (i=0; i<linesc; i++) {
|
||||
free(lines[i]);
|
||||
}
|
||||
free(lines);
|
||||
for (i = 0; i < linesc; i++) {
|
||||
free(lines[i]);
|
||||
}
|
||||
free(lines);
|
||||
|
||||
control_client_cleanup(client, 0);
|
||||
debug("control command handled" );
|
||||
control_client_cleanup(client, 0);
|
||||
debug("control command handled");
|
||||
}
|
||||
|
||||
|
@@ -13,47 +13,46 @@ struct server;
|
||||
#include "mbox.h"
|
||||
|
||||
struct control {
|
||||
struct flexnbd * flexnbd;
|
||||
int control_fd;
|
||||
const char * socket_name;
|
||||
struct flexnbd *flexnbd;
|
||||
int control_fd;
|
||||
const char *socket_name;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_t thread;
|
||||
|
||||
struct self_pipe * open_signal;
|
||||
struct self_pipe * close_signal;
|
||||
struct self_pipe *open_signal;
|
||||
struct self_pipe *close_signal;
|
||||
|
||||
/* This is owned by the control object, and used by a
|
||||
* mirror_super to communicate the state of a mirror attempt as
|
||||
* early as feasible. It can't be owned by the mirror_super
|
||||
* object because the mirror_super object can be freed at any
|
||||
* time (including while the control_client is waiting on it),
|
||||
* whereas the control object lasts for the lifetime of the
|
||||
* process (and we can only have a mirror thread if the control
|
||||
* thread has started it).
|
||||
*/
|
||||
struct mbox * mirror_state_mbox;
|
||||
/* This is owned by the control object, and used by a
|
||||
* mirror_super to communicate the state of a mirror attempt as
|
||||
* early as feasible. It can't be owned by the mirror_super
|
||||
* object because the mirror_super object can be freed at any
|
||||
* time (including while the control_client is waiting on it),
|
||||
* whereas the control object lasts for the lifetime of the
|
||||
* process (and we can only have a mirror thread if the control
|
||||
* thread has started it).
|
||||
*/
|
||||
struct mbox *mirror_state_mbox;
|
||||
};
|
||||
|
||||
struct control_client{
|
||||
int socket;
|
||||
struct flexnbd * flexnbd;
|
||||
struct control_client {
|
||||
int socket;
|
||||
struct flexnbd *flexnbd;
|
||||
|
||||
/* Passed in on creation. We know it's all right to do this
|
||||
* because we know there's only ever one control_client.
|
||||
*/
|
||||
struct mbox * mirror_state_mbox;
|
||||
/* Passed in on creation. We know it's all right to do this
|
||||
* because we know there's only ever one control_client.
|
||||
*/
|
||||
struct mbox *mirror_state_mbox;
|
||||
};
|
||||
|
||||
struct control * control_create(
|
||||
struct flexnbd *,
|
||||
const char * control_socket_name );
|
||||
void control_signal_close( struct control * );
|
||||
void control_destroy( struct control * );
|
||||
struct control *control_create(struct flexnbd *,
|
||||
const char *control_socket_name);
|
||||
void control_signal_close(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 serve_open_control_socket(struct server* params);
|
||||
void accept_control_connection(struct server *params, int client_fd,
|
||||
union mysockaddr *client_address);
|
||||
void serve_open_control_socket(struct server *params);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -43,223 +43,206 @@
|
||||
|
||||
int flexnbd_build_signal_fd(void)
|
||||
{
|
||||
sigset_t mask;
|
||||
int sfd;
|
||||
sigset_t mask;
|
||||
int sfd;
|
||||
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGTERM );
|
||||
sigaddset( &mask, SIGQUIT );
|
||||
sigaddset( &mask, SIGINT );
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGQUIT);
|
||||
sigaddset(&mask, SIGINT);
|
||||
|
||||
FATAL_UNLESS( 0 == pthread_sigmask( SIG_BLOCK, &mask, NULL ),
|
||||
"Signal blocking failed" );
|
||||
FATAL_UNLESS(0 == pthread_sigmask(SIG_BLOCK, &mask, NULL),
|
||||
"Signal blocking failed");
|
||||
|
||||
sfd = signalfd( -1, &mask, 0 );
|
||||
FATAL_IF( -1 == sfd, "Failed to get a signal fd" );
|
||||
sfd = signalfd(-1, &mask, 0);
|
||||
FATAL_IF(-1 == sfd, "Failed to get a signal fd");
|
||||
|
||||
return sfd;
|
||||
return sfd;
|
||||
}
|
||||
|
||||
|
||||
void flexnbd_create_shared(
|
||||
struct flexnbd * flexnbd,
|
||||
const char * s_ctrl_sock)
|
||||
void flexnbd_create_shared(struct flexnbd *flexnbd,
|
||||
const char *s_ctrl_sock)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
if ( s_ctrl_sock ){
|
||||
flexnbd->control =
|
||||
control_create( flexnbd, s_ctrl_sock );
|
||||
}
|
||||
else {
|
||||
flexnbd->control = NULL;
|
||||
}
|
||||
NULLCHECK(flexnbd);
|
||||
if (s_ctrl_sock) {
|
||||
flexnbd->control = control_create(flexnbd, s_ctrl_sock);
|
||||
} else {
|
||||
flexnbd->control = NULL;
|
||||
}
|
||||
|
||||
flexnbd->signal_fd = flexnbd_build_signal_fd();
|
||||
flexnbd->signal_fd = flexnbd_build_signal_fd();
|
||||
}
|
||||
|
||||
|
||||
struct flexnbd * flexnbd_create_serving(
|
||||
char* s_ip_address,
|
||||
char* s_port,
|
||||
char* s_file,
|
||||
char* s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char** s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch)
|
||||
struct flexnbd *flexnbd_create_serving(char *s_ip_address,
|
||||
char *s_port,
|
||||
char *s_file,
|
||||
char *s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char **s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch)
|
||||
{
|
||||
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) );
|
||||
flexnbd->serve = server_create(
|
||||
flexnbd,
|
||||
s_ip_address,
|
||||
s_port,
|
||||
s_file,
|
||||
default_deny,
|
||||
acl_entries,
|
||||
s_acl_entries,
|
||||
max_nbd_clients,
|
||||
use_killswitch,
|
||||
1);
|
||||
flexnbd_create_shared( flexnbd, s_ctrl_sock );
|
||||
struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
|
||||
flexnbd->serve = server_create(flexnbd,
|
||||
s_ip_address,
|
||||
s_port,
|
||||
s_file,
|
||||
default_deny,
|
||||
acl_entries,
|
||||
s_acl_entries,
|
||||
max_nbd_clients, use_killswitch, 1);
|
||||
flexnbd_create_shared(flexnbd, s_ctrl_sock);
|
||||
|
||||
// Beats installing one handler per client instance
|
||||
if ( use_killswitch ) {
|
||||
struct sigaction act = {
|
||||
.sa_sigaction = client_killswitch_hit,
|
||||
.sa_flags = SA_RESTART | SA_SIGINFO
|
||||
};
|
||||
// Beats installing one handler per client instance
|
||||
if (use_killswitch) {
|
||||
struct sigaction act = {
|
||||
.sa_sigaction = client_killswitch_hit,
|
||||
.sa_flags = SA_RESTART | SA_SIGINFO
|
||||
};
|
||||
|
||||
FATAL_UNLESS(
|
||||
0 == sigaction( CLIENT_KILLSWITCH_SIGNAL, &act, NULL ),
|
||||
"Installing client killswitch signal failed"
|
||||
);
|
||||
}
|
||||
FATAL_UNLESS(0 == sigaction(CLIENT_KILLSWITCH_SIGNAL, &act, NULL),
|
||||
"Installing client killswitch signal failed");
|
||||
}
|
||||
|
||||
return flexnbd;
|
||||
return flexnbd;
|
||||
}
|
||||
|
||||
struct flexnbd * flexnbd_create_listening(
|
||||
char* s_ip_address,
|
||||
char* s_port,
|
||||
char* s_file,
|
||||
char* s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char** s_acl_entries )
|
||||
struct flexnbd *flexnbd_create_listening(char *s_ip_address,
|
||||
char *s_port,
|
||||
char *s_file,
|
||||
char *s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char **s_acl_entries)
|
||||
{
|
||||
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) );
|
||||
flexnbd->serve = server_create(
|
||||
flexnbd,
|
||||
s_ip_address,
|
||||
s_port,
|
||||
s_file,
|
||||
default_deny,
|
||||
acl_entries,
|
||||
s_acl_entries,
|
||||
1, 0, 0);
|
||||
flexnbd_create_shared( flexnbd, s_ctrl_sock );
|
||||
struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
|
||||
flexnbd->serve = server_create(flexnbd,
|
||||
s_ip_address,
|
||||
s_port,
|
||||
s_file,
|
||||
default_deny,
|
||||
acl_entries, s_acl_entries, 1, 0, 0);
|
||||
flexnbd_create_shared(flexnbd, s_ctrl_sock);
|
||||
|
||||
// listen can't use killswitch, as mirror may pause on sending things
|
||||
// for a very long time.
|
||||
// listen can't use killswitch, as mirror may pause on sending things
|
||||
// for a very long time.
|
||||
|
||||
return flexnbd;
|
||||
return flexnbd;
|
||||
}
|
||||
|
||||
void flexnbd_spawn_control(struct flexnbd * flexnbd )
|
||||
void flexnbd_spawn_control(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
NULLCHECK( flexnbd->control );
|
||||
NULLCHECK(flexnbd);
|
||||
NULLCHECK(flexnbd->control);
|
||||
|
||||
pthread_t * control_thread = &flexnbd->control->thread;
|
||||
pthread_t *control_thread = &flexnbd->control->thread;
|
||||
|
||||
FATAL_UNLESS( 0 == pthread_create(
|
||||
control_thread,
|
||||
NULL,
|
||||
control_runner,
|
||||
flexnbd->control ),
|
||||
"Couldn't create the control thread" );
|
||||
FATAL_UNLESS(0 == pthread_create(control_thread,
|
||||
NULL,
|
||||
control_runner,
|
||||
flexnbd->control),
|
||||
"Couldn't create the control thread");
|
||||
}
|
||||
|
||||
void flexnbd_stop_control( struct flexnbd * flexnbd )
|
||||
void flexnbd_stop_control(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
NULLCHECK( flexnbd->control );
|
||||
NULLCHECK(flexnbd);
|
||||
NULLCHECK(flexnbd->control);
|
||||
|
||||
control_signal_close( flexnbd->control );
|
||||
pthread_t tid = flexnbd->control->thread;
|
||||
FATAL_UNLESS( 0 == pthread_join( tid, NULL ),
|
||||
"Failed joining the control thread" );
|
||||
debug( "Control thread %p pthread_join returned", tid );
|
||||
control_signal_close(flexnbd->control);
|
||||
pthread_t tid = flexnbd->control->thread;
|
||||
FATAL_UNLESS(0 == pthread_join(tid, NULL),
|
||||
"Failed joining the control thread");
|
||||
debug("Control thread %p pthread_join returned", tid);
|
||||
}
|
||||
|
||||
|
||||
int flexnbd_signal_fd( struct flexnbd * flexnbd )
|
||||
int flexnbd_signal_fd(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
return flexnbd->signal_fd;
|
||||
NULLCHECK(flexnbd);
|
||||
return flexnbd->signal_fd;
|
||||
}
|
||||
|
||||
void flexnbd_destroy( struct flexnbd * flexnbd )
|
||||
void flexnbd_destroy(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
if ( flexnbd->control ) {
|
||||
control_destroy( flexnbd->control );
|
||||
}
|
||||
NULLCHECK(flexnbd);
|
||||
if (flexnbd->control) {
|
||||
control_destroy(flexnbd->control);
|
||||
}
|
||||
|
||||
close( flexnbd->signal_fd );
|
||||
free( flexnbd );
|
||||
close(flexnbd->signal_fd);
|
||||
free(flexnbd);
|
||||
}
|
||||
|
||||
|
||||
struct server * flexnbd_server( struct flexnbd * flexnbd )
|
||||
struct server *flexnbd_server(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
return flexnbd->serve;
|
||||
NULLCHECK(flexnbd);
|
||||
return flexnbd->serve;
|
||||
}
|
||||
|
||||
void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl )
|
||||
void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
server_replace_acl( flexnbd_server(flexnbd), acl );
|
||||
NULLCHECK(flexnbd);
|
||||
server_replace_acl(flexnbd_server(flexnbd), acl);
|
||||
}
|
||||
|
||||
|
||||
struct status * flexnbd_status_create( struct flexnbd * flexnbd )
|
||||
struct status *flexnbd_status_create(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
struct status * status;
|
||||
NULLCHECK(flexnbd);
|
||||
struct status *status;
|
||||
|
||||
status = status_create( flexnbd_server( flexnbd ) );
|
||||
return status;
|
||||
status = status_create(flexnbd_server(flexnbd));
|
||||
return status;
|
||||
}
|
||||
|
||||
void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve )
|
||||
void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
flexnbd->serve = serve;
|
||||
NULLCHECK(flexnbd);
|
||||
flexnbd->serve = serve;
|
||||
}
|
||||
|
||||
|
||||
/* Get the default_deny of the current server object. */
|
||||
int flexnbd_default_deny( struct flexnbd * flexnbd )
|
||||
int flexnbd_default_deny(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
return server_default_deny( flexnbd->serve );
|
||||
NULLCHECK(flexnbd);
|
||||
return server_default_deny(flexnbd->serve);
|
||||
}
|
||||
|
||||
|
||||
void make_writable( const char * filename )
|
||||
void make_writable(const char *filename)
|
||||
{
|
||||
NULLCHECK( filename );
|
||||
FATAL_IF_NEGATIVE( chmod( filename, S_IWUSR ),
|
||||
"Couldn't chmod %s: %s",
|
||||
filename,
|
||||
strerror( errno ) );
|
||||
NULLCHECK(filename);
|
||||
FATAL_IF_NEGATIVE(chmod(filename, S_IWUSR),
|
||||
"Couldn't chmod %s: %s", filename, strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
int flexnbd_serve( struct flexnbd * flexnbd )
|
||||
int flexnbd_serve(struct flexnbd *flexnbd)
|
||||
{
|
||||
NULLCHECK( flexnbd );
|
||||
int success;
|
||||
struct self_pipe * open_signal = NULL;
|
||||
NULLCHECK(flexnbd);
|
||||
int success;
|
||||
struct self_pipe *open_signal = NULL;
|
||||
|
||||
if ( flexnbd->control ){
|
||||
debug( "Spawning control thread" );
|
||||
flexnbd_spawn_control( flexnbd );
|
||||
open_signal = flexnbd->control->open_signal;
|
||||
}
|
||||
if (flexnbd->control) {
|
||||
debug("Spawning control thread");
|
||||
flexnbd_spawn_control(flexnbd);
|
||||
open_signal = flexnbd->control->open_signal;
|
||||
}
|
||||
|
||||
success = do_serve( flexnbd->serve, open_signal );
|
||||
debug("do_serve success is %d", success );
|
||||
success = do_serve(flexnbd->serve, open_signal);
|
||||
debug("do_serve success is %d", success);
|
||||
|
||||
if ( flexnbd->control ) {
|
||||
debug( "Stopping control thread" );
|
||||
flexnbd_stop_control( flexnbd );
|
||||
debug("Control thread stopped");
|
||||
}
|
||||
if (flexnbd->control) {
|
||||
debug("Stopping control thread");
|
||||
flexnbd_stop_control(flexnbd);
|
||||
debug("Control thread stopped");
|
||||
}
|
||||
|
||||
return success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@@ -13,54 +13,51 @@
|
||||
|
||||
/* Carries the "globals". */
|
||||
struct flexnbd {
|
||||
/* Our serve pointer should never be dereferenced outside a
|
||||
* flexnbd_switch_lock/unlock pair.
|
||||
*/
|
||||
struct server * serve;
|
||||
/* Our serve pointer should never be dereferenced outside a
|
||||
* flexnbd_switch_lock/unlock pair.
|
||||
*/
|
||||
struct server *serve;
|
||||
|
||||
/* We only have a control object if a control socket name was
|
||||
* passed on the command line.
|
||||
*/
|
||||
struct control * control;
|
||||
/* We only have a control object if a control socket name was
|
||||
* passed on the command line.
|
||||
*/
|
||||
struct control *control;
|
||||
|
||||
/* File descriptor for a signalfd(2) signal stream. */
|
||||
int signal_fd;
|
||||
/* File descriptor for a signalfd(2) signal stream. */
|
||||
int signal_fd;
|
||||
};
|
||||
|
||||
|
||||
struct flexnbd * flexnbd_create(void);
|
||||
struct flexnbd * flexnbd_create_serving(
|
||||
char* s_ip_address,
|
||||
char* s_port,
|
||||
char* s_file,
|
||||
char* s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char** s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch);
|
||||
struct flexnbd *flexnbd_create(void);
|
||||
struct flexnbd *flexnbd_create_serving(char *s_ip_address,
|
||||
char *s_port,
|
||||
char *s_file,
|
||||
char *s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char **s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch);
|
||||
|
||||
struct flexnbd * flexnbd_create_listening(
|
||||
char* s_ip_address,
|
||||
char* s_port,
|
||||
char* s_file,
|
||||
char* s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char** s_acl_entries );
|
||||
struct flexnbd *flexnbd_create_listening(char *s_ip_address,
|
||||
char *s_port,
|
||||
char *s_file,
|
||||
char *s_ctrl_sock,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char **s_acl_entries);
|
||||
|
||||
void flexnbd_destroy( struct flexnbd * );
|
||||
void flexnbd_destroy(struct flexnbd *);
|
||||
enum mirror_state;
|
||||
enum mirror_state flexnbd_get_mirror_state( struct flexnbd * );
|
||||
int flexnbd_default_deny( struct flexnbd * );
|
||||
void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve );
|
||||
int flexnbd_signal_fd( struct flexnbd * flexnbd );
|
||||
enum mirror_state flexnbd_get_mirror_state(struct flexnbd *);
|
||||
int flexnbd_default_deny(struct flexnbd *);
|
||||
void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve);
|
||||
int flexnbd_signal_fd(struct flexnbd *flexnbd);
|
||||
|
||||
|
||||
int flexnbd_serve( struct flexnbd * flexnbd );
|
||||
int flexnbd_proxy( struct flexnbd * flexnbd );
|
||||
struct server * flexnbd_server( struct flexnbd * flexnbd );
|
||||
void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl );
|
||||
struct status * flexnbd_status_create( struct flexnbd * flexnbd );
|
||||
int flexnbd_serve(struct flexnbd *flexnbd);
|
||||
int flexnbd_proxy(struct flexnbd *flexnbd);
|
||||
struct server *flexnbd_server(struct flexnbd *flexnbd);
|
||||
void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl);
|
||||
struct status *flexnbd_status_create(struct flexnbd *flexnbd);
|
||||
#endif
|
||||
|
||||
|
@@ -4,72 +4,70 @@
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
struct flexthread_mutex * flexthread_mutex_create(void)
|
||||
struct flexthread_mutex *flexthread_mutex_create(void)
|
||||
{
|
||||
struct flexthread_mutex * ftm =
|
||||
xmalloc( sizeof( struct flexthread_mutex ) );
|
||||
struct flexthread_mutex *ftm =
|
||||
xmalloc(sizeof(struct flexthread_mutex));
|
||||
|
||||
FATAL_UNLESS( 0 == pthread_mutex_init( &ftm->mutex, NULL ),
|
||||
"Mutex initialisation failed" );
|
||||
return ftm;
|
||||
FATAL_UNLESS(0 == pthread_mutex_init(&ftm->mutex, NULL),
|
||||
"Mutex initialisation failed");
|
||||
return ftm;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void flexthread_mutex_destroy( struct flexthread_mutex * ftm )
|
||||
void flexthread_mutex_destroy(struct flexthread_mutex *ftm)
|
||||
{
|
||||
NULLCHECK( ftm );
|
||||
NULLCHECK(ftm);
|
||||
|
||||
if( flexthread_mutex_held( ftm ) ) {
|
||||
flexthread_mutex_unlock( ftm );
|
||||
}
|
||||
else if ( (pthread_t)NULL != ftm->holder ) {
|
||||
/* This "should never happen": if we can try to destroy
|
||||
* a mutex currently held by another thread, there's a
|
||||
* logic bug somewhere. I know the test here is racy,
|
||||
* but there's not a lot we can do about it at this
|
||||
* point.
|
||||
*/
|
||||
fatal( "Attempted to destroy a flexthread_mutex"\
|
||||
" held by another thread!" );
|
||||
}
|
||||
if (flexthread_mutex_held(ftm)) {
|
||||
flexthread_mutex_unlock(ftm);
|
||||
} else if ((pthread_t) NULL != ftm->holder) {
|
||||
/* This "should never happen": if we can try to destroy
|
||||
* a mutex currently held by another thread, there's a
|
||||
* logic bug somewhere. I know the test here is racy,
|
||||
* but there's not a lot we can do about it at this
|
||||
* point.
|
||||
*/
|
||||
fatal("Attempted to destroy a flexthread_mutex"
|
||||
" held by another thread!");
|
||||
}
|
||||
|
||||
FATAL_UNLESS( 0 == pthread_mutex_destroy( &ftm->mutex ),
|
||||
"Mutex destroy failed" );
|
||||
free( ftm );
|
||||
FATAL_UNLESS(0 == pthread_mutex_destroy(&ftm->mutex),
|
||||
"Mutex destroy failed");
|
||||
free(ftm);
|
||||
}
|
||||
|
||||
|
||||
int flexthread_mutex_lock( struct flexthread_mutex * ftm )
|
||||
int flexthread_mutex_lock(struct flexthread_mutex *ftm)
|
||||
{
|
||||
NULLCHECK( ftm );
|
||||
NULLCHECK(ftm);
|
||||
|
||||
int failure = pthread_mutex_lock( &ftm->mutex );
|
||||
if ( 0 == failure ) {
|
||||
ftm->holder = pthread_self();
|
||||
}
|
||||
int failure = pthread_mutex_lock(&ftm->mutex);
|
||||
if (0 == failure) {
|
||||
ftm->holder = pthread_self();
|
||||
}
|
||||
|
||||
return failure;
|
||||
return failure;
|
||||
}
|
||||
|
||||
|
||||
int flexthread_mutex_unlock( struct flexthread_mutex * ftm )
|
||||
int flexthread_mutex_unlock(struct flexthread_mutex *ftm)
|
||||
{
|
||||
NULLCHECK( ftm );
|
||||
NULLCHECK(ftm);
|
||||
|
||||
pthread_t orig = ftm->holder;
|
||||
ftm->holder = (pthread_t)NULL;
|
||||
int failure = pthread_mutex_unlock( &ftm->mutex );
|
||||
if ( 0 != failure ) {
|
||||
ftm->holder = orig;
|
||||
}
|
||||
return failure;
|
||||
pthread_t orig = ftm->holder;
|
||||
ftm->holder = (pthread_t) NULL;
|
||||
int failure = pthread_mutex_unlock(&ftm->mutex);
|
||||
if (0 != failure) {
|
||||
ftm->holder = orig;
|
||||
}
|
||||
return failure;
|
||||
}
|
||||
|
||||
|
||||
int flexthread_mutex_held( struct flexthread_mutex * ftm )
|
||||
int flexthread_mutex_held(struct flexthread_mutex *ftm)
|
||||
{
|
||||
NULLCHECK( ftm );
|
||||
return pthread_self() == ftm->holder;
|
||||
NULLCHECK(ftm);
|
||||
return pthread_self() == ftm->holder;
|
||||
}
|
||||
|
||||
|
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
|
||||
struct flexthread_mutex {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t holder;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t holder;
|
||||
};
|
||||
|
||||
struct flexthread_mutex * flexthread_mutex_create(void);
|
||||
void flexthread_mutex_destroy( struct flexthread_mutex * );
|
||||
struct flexthread_mutex *flexthread_mutex_create(void);
|
||||
void flexthread_mutex_destroy(struct flexthread_mutex *);
|
||||
|
||||
int flexthread_mutex_lock( struct flexthread_mutex * );
|
||||
int flexthread_mutex_unlock( struct flexthread_mutex * );
|
||||
int flexthread_mutex_held( struct flexthread_mutex * );
|
||||
int flexthread_mutex_lock(struct flexthread_mutex *);
|
||||
int flexthread_mutex_unlock(struct flexthread_mutex *);
|
||||
int flexthread_mutex_held(struct flexthread_mutex *);
|
||||
|
||||
#endif
|
||||
|
@@ -3,75 +3,75 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct mbox * mbox_create( void )
|
||||
struct mbox *mbox_create(void)
|
||||
{
|
||||
struct mbox * mbox = xmalloc( sizeof( struct mbox ) );
|
||||
FATAL_UNLESS( 0 == pthread_cond_init( &mbox->filled_cond, NULL ),
|
||||
"Failed to initialise a condition variable" );
|
||||
FATAL_UNLESS( 0 == pthread_cond_init( &mbox->emptied_cond, NULL ),
|
||||
"Failed to initialise a condition variable" );
|
||||
FATAL_UNLESS( 0 == pthread_mutex_init( &mbox->mutex, NULL ),
|
||||
"Failed to initialise a mutex" );
|
||||
return mbox;
|
||||
struct mbox *mbox = xmalloc(sizeof(struct mbox));
|
||||
FATAL_UNLESS(0 == pthread_cond_init(&mbox->filled_cond, NULL),
|
||||
"Failed to initialise a condition variable");
|
||||
FATAL_UNLESS(0 == pthread_cond_init(&mbox->emptied_cond, NULL),
|
||||
"Failed to initialise a condition variable");
|
||||
FATAL_UNLESS(0 == pthread_mutex_init(&mbox->mutex, NULL),
|
||||
"Failed to initialise a mutex");
|
||||
return mbox;
|
||||
}
|
||||
|
||||
void mbox_post( struct mbox * mbox, void * contents )
|
||||
void mbox_post(struct mbox *mbox, void *contents)
|
||||
{
|
||||
pthread_mutex_lock( &mbox->mutex );
|
||||
{
|
||||
if (mbox->full){
|
||||
pthread_cond_wait( &mbox->emptied_cond, &mbox->mutex );
|
||||
}
|
||||
mbox->contents = contents;
|
||||
mbox->full = 1;
|
||||
while( 0 != pthread_cond_signal( &mbox->filled_cond ) );
|
||||
pthread_mutex_lock(&mbox->mutex);
|
||||
{
|
||||
if (mbox->full) {
|
||||
pthread_cond_wait(&mbox->emptied_cond, &mbox->mutex);
|
||||
}
|
||||
pthread_mutex_unlock( &mbox->mutex );
|
||||
mbox->contents = contents;
|
||||
mbox->full = 1;
|
||||
while (0 != pthread_cond_signal(&mbox->filled_cond));
|
||||
}
|
||||
pthread_mutex_unlock(&mbox->mutex);
|
||||
}
|
||||
|
||||
|
||||
void * mbox_contents( struct mbox * mbox )
|
||||
void *mbox_contents(struct mbox *mbox)
|
||||
{
|
||||
return mbox->contents;
|
||||
return mbox->contents;
|
||||
}
|
||||
|
||||
|
||||
int mbox_is_full( struct mbox * mbox )
|
||||
int mbox_is_full(struct mbox *mbox)
|
||||
{
|
||||
return mbox->full;
|
||||
return mbox->full;
|
||||
}
|
||||
|
||||
|
||||
void * mbox_receive( struct mbox * mbox )
|
||||
void *mbox_receive(struct mbox *mbox)
|
||||
{
|
||||
NULLCHECK( mbox );
|
||||
void * result;
|
||||
NULLCHECK(mbox);
|
||||
void *result;
|
||||
|
||||
pthread_mutex_lock( &mbox->mutex );
|
||||
{
|
||||
if ( !mbox->full ) {
|
||||
pthread_cond_wait( &mbox->filled_cond, &mbox->mutex );
|
||||
}
|
||||
mbox->full = 0;
|
||||
result = mbox->contents;
|
||||
mbox->contents = NULL;
|
||||
|
||||
while( 0 != pthread_cond_signal( &mbox->emptied_cond));
|
||||
pthread_mutex_lock(&mbox->mutex);
|
||||
{
|
||||
if (!mbox->full) {
|
||||
pthread_cond_wait(&mbox->filled_cond, &mbox->mutex);
|
||||
}
|
||||
pthread_mutex_unlock( &mbox->mutex );
|
||||
mbox->full = 0;
|
||||
result = mbox->contents;
|
||||
mbox->contents = NULL;
|
||||
|
||||
return result;
|
||||
while (0 != pthread_cond_signal(&mbox->emptied_cond));
|
||||
}
|
||||
pthread_mutex_unlock(&mbox->mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void mbox_destroy( struct mbox * mbox )
|
||||
void mbox_destroy(struct mbox *mbox)
|
||||
{
|
||||
NULLCHECK( mbox );
|
||||
NULLCHECK(mbox);
|
||||
|
||||
while( 0 != pthread_cond_destroy( &mbox->emptied_cond ) );
|
||||
while( 0 != pthread_cond_destroy( &mbox->filled_cond ) );
|
||||
while (0 != pthread_cond_destroy(&mbox->emptied_cond));
|
||||
while (0 != pthread_cond_destroy(&mbox->filled_cond));
|
||||
|
||||
while( 0 != pthread_mutex_destroy( &mbox->mutex ) );
|
||||
while (0 != pthread_mutex_destroy(&mbox->mutex));
|
||||
|
||||
free( mbox );
|
||||
free(mbox);
|
||||
}
|
||||
|
@@ -14,42 +14,42 @@
|
||||
|
||||
|
||||
struct mbox {
|
||||
void * contents;
|
||||
void *contents;
|
||||
|
||||
/** Marker to tell us if there's content in the box.
|
||||
* Keeping this separate allows us to use NULL for the contents.
|
||||
*/
|
||||
int full;
|
||||
int full;
|
||||
|
||||
/** This gets signaled by mbox_post, and waited on by
|
||||
* mbox_receive */
|
||||
pthread_cond_t filled_cond;
|
||||
pthread_cond_t filled_cond;
|
||||
/** This is signaled by mbox_receive, and waited on by mbox_post */
|
||||
pthread_cond_t emptied_cond;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t emptied_cond;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
|
||||
/* Create an mbox. */
|
||||
struct mbox * mbox_create(void);
|
||||
struct mbox *mbox_create(void);
|
||||
|
||||
/* Put something in the mbox, blocking if it's already full.
|
||||
* That something can be NULL if you want.
|
||||
*/
|
||||
void mbox_post( struct mbox *, void *);
|
||||
void mbox_post(struct mbox *, void *);
|
||||
|
||||
/* See what's in the mbox. This isn't thread-safe. */
|
||||
void * mbox_contents( struct mbox *);
|
||||
void *mbox_contents(struct mbox *);
|
||||
|
||||
/* See if anything has been put into the mbox. This isn't thread-safe.
|
||||
* */
|
||||
int mbox_is_full( struct mbox *);
|
||||
int mbox_is_full(struct mbox *);
|
||||
|
||||
/* Get the contents from the mbox, blocking if there's nothing there. */
|
||||
void * mbox_receive( struct mbox *);
|
||||
void *mbox_receive(struct mbox *);
|
||||
|
||||
/* Free the mbox and destroy the associated pthread bits. */
|
||||
void mbox_destroy( struct mbox *);
|
||||
void mbox_destroy(struct mbox *);
|
||||
|
||||
|
||||
#endif
|
||||
|
1579
src/server/mirror.c
1579
src/server/mirror.c
File diff suppressed because it is too large
Load Diff
@@ -58,65 +58,65 @@ enum mirror_state;
|
||||
#define MS_REQUEST_LIMIT_SECS_F 60.0
|
||||
|
||||
enum mirror_finish_action {
|
||||
ACTION_EXIT,
|
||||
ACTION_UNLINK,
|
||||
ACTION_NOTHING
|
||||
ACTION_EXIT,
|
||||
ACTION_UNLINK,
|
||||
ACTION_NOTHING
|
||||
};
|
||||
|
||||
enum mirror_state {
|
||||
MS_UNKNOWN,
|
||||
MS_INIT,
|
||||
MS_GO,
|
||||
MS_ABANDONED,
|
||||
MS_DONE,
|
||||
MS_FAIL_CONNECT,
|
||||
MS_FAIL_REJECTED,
|
||||
MS_FAIL_NO_HELLO,
|
||||
MS_FAIL_SIZE_MISMATCH
|
||||
MS_UNKNOWN,
|
||||
MS_INIT,
|
||||
MS_GO,
|
||||
MS_ABANDONED,
|
||||
MS_DONE,
|
||||
MS_FAIL_CONNECT,
|
||||
MS_FAIL_REJECTED,
|
||||
MS_FAIL_NO_HELLO,
|
||||
MS_FAIL_SIZE_MISMATCH
|
||||
};
|
||||
|
||||
struct mirror {
|
||||
pthread_t thread;
|
||||
pthread_t thread;
|
||||
|
||||
/* Signal to this then join the thread if you want to abandon mirroring */
|
||||
struct self_pipe * abandon_signal;
|
||||
/* Signal to this then join the thread if you want to abandon mirroring */
|
||||
struct self_pipe *abandon_signal;
|
||||
|
||||
union mysockaddr * connect_to;
|
||||
union mysockaddr * connect_from;
|
||||
int client;
|
||||
const char * filename;
|
||||
union mysockaddr *connect_to;
|
||||
union mysockaddr *connect_from;
|
||||
int client;
|
||||
const char *filename;
|
||||
|
||||
/* Limiter, used to restrict migration speed Only dirty bytes (those going
|
||||
* over the network) are considered */
|
||||
uint64_t max_bytes_per_second;
|
||||
/* Limiter, used to restrict migration speed Only dirty bytes (those going
|
||||
* over the network) are considered */
|
||||
uint64_t max_bytes_per_second;
|
||||
|
||||
enum mirror_finish_action action_at_finish;
|
||||
enum mirror_finish_action action_at_finish;
|
||||
|
||||
char *mapped;
|
||||
char *mapped;
|
||||
|
||||
/* We need to send every byte at least once; we do so by */
|
||||
uint64_t offset;
|
||||
/* We need to send every byte at least once; we do so by */
|
||||
uint64_t offset;
|
||||
|
||||
enum mirror_state commit_state;
|
||||
enum mirror_state commit_state;
|
||||
|
||||
/* commit_signal is sent immediately after attempting to connect
|
||||
* and checking the remote size, whether successful or not.
|
||||
*/
|
||||
struct mbox * commit_signal;
|
||||
/* commit_signal is sent immediately after attempting to connect
|
||||
* and checking the remote size, whether successful or not.
|
||||
*/
|
||||
struct mbox *commit_signal;
|
||||
|
||||
/* The time (from monotonic_time_ms()) the migration was started. Can be
|
||||
* used to calculate bps, etc. */
|
||||
uint64_t migration_started;
|
||||
/* The time (from monotonic_time_ms()) the migration was started. Can be
|
||||
* used to calculate bps, etc. */
|
||||
uint64_t migration_started;
|
||||
|
||||
/* Running count of all bytes we've transferred */
|
||||
uint64_t all_dirty;
|
||||
/* Running count of all bytes we've transferred */
|
||||
uint64_t all_dirty;
|
||||
};
|
||||
|
||||
|
||||
struct mirror_super {
|
||||
struct mirror * mirror;
|
||||
pthread_t thread;
|
||||
struct mbox * state_mbox;
|
||||
struct mirror *mirror;
|
||||
pthread_t thread;
|
||||
struct mbox *state_mbox;
|
||||
};
|
||||
|
||||
|
||||
@@ -127,15 +127,13 @@ struct mirror_super {
|
||||
struct server;
|
||||
struct flexnbd;
|
||||
|
||||
struct mirror_super * mirror_super_create(
|
||||
const char * filename,
|
||||
union mysockaddr * connect_to,
|
||||
union mysockaddr * connect_from,
|
||||
uint64_t max_Bps,
|
||||
enum mirror_finish_action action_at_finish,
|
||||
struct mbox * state_mbox
|
||||
);
|
||||
void * mirror_super_runner( void * serve_uncast );
|
||||
struct mirror_super *mirror_super_create(const char *filename,
|
||||
union mysockaddr *connect_to,
|
||||
union mysockaddr *connect_from,
|
||||
uint64_t max_Bps,
|
||||
enum mirror_finish_action
|
||||
action_at_finish,
|
||||
struct mbox *state_mbox);
|
||||
void *mirror_super_runner(void *serve_uncast);
|
||||
|
||||
#endif
|
||||
|
||||
|
1481
src/server/mode.c
1481
src/server/mode.c
File diff suppressed because it is too large
Load Diff
1208
src/server/serve.c
1208
src/server/serve.c
File diff suppressed because it is too large
Load Diff
@@ -3,20 +3,20 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h> /* for sig_atomic_t */
|
||||
#include <signal.h> /* for sig_atomic_t */
|
||||
|
||||
#include "flexnbd.h"
|
||||
#include "parse.h"
|
||||
#include "acl.h"
|
||||
|
||||
|
||||
static const int block_allocation_resolution = 4096;//128<<10;
|
||||
static const int block_allocation_resolution = 4096; //128<<10;
|
||||
|
||||
|
||||
struct client_tbl_entry {
|
||||
pthread_t thread;
|
||||
union mysockaddr address;
|
||||
struct client * client;
|
||||
pthread_t thread;
|
||||
union mysockaddr address;
|
||||
struct client *client;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,146 +25,143 @@ struct client_tbl_entry {
|
||||
#define CLIENT_KEEPALIVE_INTVL 10
|
||||
#define CLIENT_KEEPALIVE_PROBES 3
|
||||
struct server {
|
||||
/* The flexnbd wrapper this server is attached to */
|
||||
struct flexnbd * flexnbd;
|
||||
/* The flexnbd wrapper this server is attached to */
|
||||
struct flexnbd *flexnbd;
|
||||
|
||||
/** address/port to bind to */
|
||||
union mysockaddr bind_to;
|
||||
union mysockaddr bind_to;
|
||||
/** (static) file name to serve */
|
||||
char* filename;
|
||||
char *filename;
|
||||
/** TCP backlog for listen() */
|
||||
int tcp_backlog;
|
||||
int tcp_backlog;
|
||||
/** (static) file name of UNIX control socket (or NULL if none) */
|
||||
char* control_socket_name;
|
||||
char *control_socket_name;
|
||||
/** size of file */
|
||||
uint64_t size;
|
||||
uint64_t size;
|
||||
|
||||
/** to interrupt accept loop and clients, write() to close_signal[1] */
|
||||
struct self_pipe * close_signal;
|
||||
struct self_pipe *close_signal;
|
||||
|
||||
/** access control list */
|
||||
struct acl * acl;
|
||||
struct acl *acl;
|
||||
/** acl_updated_signal will be signalled after the acl struct
|
||||
* has been replaced
|
||||
*/
|
||||
struct self_pipe * acl_updated_signal;
|
||||
struct self_pipe *acl_updated_signal;
|
||||
|
||||
/* Claimed around any updates to the ACL. */
|
||||
struct flexthread_mutex * l_acl;
|
||||
/* Claimed around any updates to the ACL. */
|
||||
struct flexthread_mutex *l_acl;
|
||||
|
||||
/* Claimed around starting a mirror so that it doesn't race with
|
||||
* shutting down on a SIGTERM. */
|
||||
struct flexthread_mutex * l_start_mirror;
|
||||
/* Claimed around starting a mirror so that it doesn't race with
|
||||
* shutting down on a SIGTERM. */
|
||||
struct flexthread_mutex *l_start_mirror;
|
||||
|
||||
struct mirror* mirror;
|
||||
struct mirror_super * mirror_super;
|
||||
/* This is used to stop the mirror from starting after we
|
||||
* receive a SIGTERM */
|
||||
int mirror_can_start;
|
||||
struct mirror *mirror;
|
||||
struct mirror_super *mirror_super;
|
||||
/* This is used to stop the mirror from starting after we
|
||||
* receive a SIGTERM */
|
||||
int mirror_can_start;
|
||||
|
||||
int server_fd;
|
||||
int control_fd;
|
||||
int server_fd;
|
||||
int control_fd;
|
||||
|
||||
/* the allocation_map keeps track of which blocks in the backing file
|
||||
* have been allocated, or part-allocated on disc, with unallocated
|
||||
* blocks presumed to contain zeroes (i.e. represented as sparse files
|
||||
* by the filesystem). We can use this information when receiving
|
||||
* incoming writes, and avoid writing zeroes to unallocated sections
|
||||
* of the file which would needlessly increase disc usage. This
|
||||
* bitmap will start at all-zeroes for an empty file, and tend towards
|
||||
* all-ones as the file is written to (i.e. we assume that allocated
|
||||
* blocks can never become unallocated again, as is the case with ext3
|
||||
* at least).
|
||||
*/
|
||||
struct bitset * allocation_map;
|
||||
/* when starting up, this thread builds the allocation_map */
|
||||
pthread_t allocation_map_builder_thread;
|
||||
/* the allocation_map keeps track of which blocks in the backing file
|
||||
* have been allocated, or part-allocated on disc, with unallocated
|
||||
* blocks presumed to contain zeroes (i.e. represented as sparse files
|
||||
* by the filesystem). We can use this information when receiving
|
||||
* incoming writes, and avoid writing zeroes to unallocated sections
|
||||
* of the file which would needlessly increase disc usage. This
|
||||
* bitmap will start at all-zeroes for an empty file, and tend towards
|
||||
* all-ones as the file is written to (i.e. we assume that allocated
|
||||
* blocks can never become unallocated again, as is the case with ext3
|
||||
* at least).
|
||||
*/
|
||||
struct bitset *allocation_map;
|
||||
/* when starting up, this thread builds the allocation_map */
|
||||
pthread_t allocation_map_builder_thread;
|
||||
|
||||
/* when the thread has finished, it sets this to 1 */
|
||||
volatile sig_atomic_t allocation_map_built;
|
||||
volatile sig_atomic_t allocation_map_not_built;
|
||||
/* when the thread has finished, it sets this to 1 */
|
||||
volatile sig_atomic_t allocation_map_built;
|
||||
volatile sig_atomic_t allocation_map_not_built;
|
||||
|
||||
int max_nbd_clients;
|
||||
struct client_tbl_entry *nbd_client;
|
||||
int max_nbd_clients;
|
||||
struct client_tbl_entry *nbd_client;
|
||||
|
||||
/** Should clients use the killswitch? */
|
||||
int use_killswitch;
|
||||
int use_killswitch;
|
||||
|
||||
/** If this isn't set, newly accepted clients will be closed immediately */
|
||||
int allow_new_clients;
|
||||
int allow_new_clients;
|
||||
|
||||
/* Marker for whether this server has control over the data in
|
||||
* the file, or if we're waiting to receive it from an inbound
|
||||
* migration which hasn't yet finished.
|
||||
*
|
||||
* It's the value which controls the exit status of a serve or
|
||||
* listen process.
|
||||
*/
|
||||
int success;
|
||||
/* Marker for whether this server has control over the data in
|
||||
* the file, or if we're waiting to receive it from an inbound
|
||||
* migration which hasn't yet finished.
|
||||
*
|
||||
* It's the value which controls the exit status of a serve or
|
||||
* listen process.
|
||||
*/
|
||||
int success;
|
||||
};
|
||||
|
||||
struct server * server_create(
|
||||
struct flexnbd * flexnbd,
|
||||
char* s_ip_address,
|
||||
char* s_port,
|
||||
char* s_file,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char** s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch,
|
||||
int success );
|
||||
void server_destroy( struct server * );
|
||||
int server_is_closed(struct server* serve);
|
||||
void serve_signal_close( struct server *serve );
|
||||
void serve_wait_for_close( struct server * serve );
|
||||
void server_replace_acl( struct server *serve, struct acl * acl);
|
||||
void server_control_arrived( struct server *serve );
|
||||
int server_is_in_control( struct server *serve );
|
||||
int server_default_deny( struct server * serve );
|
||||
int server_acl_locked( struct server * serve );
|
||||
void server_lock_acl( struct server *serve );
|
||||
void server_unlock_acl( struct server *serve );
|
||||
void server_lock_start_mirror( struct server *serve );
|
||||
void server_unlock_start_mirror( struct server *serve );
|
||||
int server_is_mirroring( struct server * serve );
|
||||
struct server *server_create(struct flexnbd *flexnbd,
|
||||
char *s_ip_address,
|
||||
char *s_port,
|
||||
char *s_file,
|
||||
int default_deny,
|
||||
int acl_entries,
|
||||
char **s_acl_entries,
|
||||
int max_nbd_clients,
|
||||
int use_killswitch, int success);
|
||||
void server_destroy(struct server *);
|
||||
int server_is_closed(struct server *serve);
|
||||
void serve_signal_close(struct server *serve);
|
||||
void serve_wait_for_close(struct server *serve);
|
||||
void server_replace_acl(struct server *serve, struct acl *acl);
|
||||
void server_control_arrived(struct server *serve);
|
||||
int server_is_in_control(struct server *serve);
|
||||
int server_default_deny(struct server *serve);
|
||||
int server_acl_locked(struct server *serve);
|
||||
void server_lock_acl(struct server *serve);
|
||||
void server_unlock_acl(struct server *serve);
|
||||
void server_lock_start_mirror(struct server *serve);
|
||||
void server_unlock_start_mirror(struct server *serve);
|
||||
int server_is_mirroring(struct server *serve);
|
||||
|
||||
uint64_t server_mirror_bytes_remaining( struct server * serve );
|
||||
uint64_t server_mirror_eta( struct server * serve );
|
||||
uint64_t server_mirror_bps( struct server * serve );
|
||||
uint64_t server_mirror_bytes_remaining(struct server *serve);
|
||||
uint64_t server_mirror_eta(struct server *serve);
|
||||
uint64_t server_mirror_bps(struct server *serve);
|
||||
|
||||
void server_abandon_mirror( struct server * serve );
|
||||
void server_prevent_mirror_start( struct server *serve );
|
||||
void server_allow_mirror_start( struct server *serve );
|
||||
int server_mirror_can_start( struct server *serve );
|
||||
void server_abandon_mirror(struct server *serve);
|
||||
void server_prevent_mirror_start(struct server *serve);
|
||||
void server_allow_mirror_start(struct server *serve);
|
||||
int server_mirror_can_start(struct server *serve);
|
||||
|
||||
/* These three functions are used by mirror around the final pass, to close
|
||||
* existing clients and prevent new ones from being around
|
||||
*/
|
||||
|
||||
void server_forbid_new_clients( struct server *serve );
|
||||
void server_close_clients( struct server *serve );
|
||||
void server_join_clients( struct server *serve );
|
||||
void server_allow_new_clients( struct server *serve );
|
||||
void server_forbid_new_clients(struct server *serve);
|
||||
void server_close_clients(struct server *serve);
|
||||
void server_join_clients(struct server *serve);
|
||||
void server_allow_new_clients(struct server *serve);
|
||||
|
||||
/* Returns a count (ish) of the number of currently-running client threads */
|
||||
int server_count_clients( struct server *params );
|
||||
int server_count_clients(struct server *params);
|
||||
|
||||
void server_unlink( struct server * serve );
|
||||
void server_unlink(struct server *serve);
|
||||
|
||||
int do_serve( struct server *, struct self_pipe * );
|
||||
int do_serve(struct server *, struct self_pipe *);
|
||||
|
||||
struct mode_readwrite_params {
|
||||
union mysockaddr connect_to;
|
||||
union mysockaddr connect_from;
|
||||
union mysockaddr connect_to;
|
||||
union mysockaddr connect_from;
|
||||
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
|
||||
int data_fd;
|
||||
int client;
|
||||
int data_fd;
|
||||
int client;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -2,41 +2,44 @@
|
||||
#include "serve.h"
|
||||
#include "util.h"
|
||||
|
||||
struct status * status_create( struct server * serve )
|
||||
struct status *status_create(struct server *serve)
|
||||
{
|
||||
NULLCHECK( serve );
|
||||
struct status * status;
|
||||
NULLCHECK(serve);
|
||||
struct status *status;
|
||||
|
||||
status = xmalloc( sizeof( struct status ) );
|
||||
status->pid = getpid();
|
||||
status->size = serve->size;
|
||||
status->has_control = serve->success;
|
||||
status = xmalloc(sizeof(struct status));
|
||||
status->pid = getpid();
|
||||
status->size = serve->size;
|
||||
status->has_control = serve->success;
|
||||
|
||||
status->clients_allowed = serve->allow_new_clients;
|
||||
status->num_clients = server_count_clients( serve );
|
||||
status->clients_allowed = serve->allow_new_clients;
|
||||
status->num_clients = server_count_clients(serve);
|
||||
|
||||
server_lock_start_mirror( serve );
|
||||
server_lock_start_mirror(serve);
|
||||
|
||||
status->is_mirroring = NULL != serve->mirror;
|
||||
if ( status->is_mirroring ) {
|
||||
status->migration_duration = monotonic_time_ms();
|
||||
status->is_mirroring = NULL != serve->mirror;
|
||||
if (status->is_mirroring) {
|
||||
status->migration_duration = monotonic_time_ms();
|
||||
|
||||
if ( ( serve->mirror->migration_started ) < status->migration_duration ) {
|
||||
status->migration_duration -= serve->mirror->migration_started;
|
||||
} else {
|
||||
status->migration_duration = 0;
|
||||
}
|
||||
status->migration_duration /= 1000;
|
||||
status->migration_speed = server_mirror_bps( serve );
|
||||
status->migration_speed_limit = serve->mirror->max_bytes_per_second;
|
||||
|
||||
status->migration_seconds_left = server_mirror_eta( serve );
|
||||
status->migration_bytes_left = server_mirror_bytes_remaining( serve );
|
||||
if ((serve->mirror->migration_started) <
|
||||
status->migration_duration) {
|
||||
status->migration_duration -= serve->mirror->migration_started;
|
||||
} else {
|
||||
status->migration_duration = 0;
|
||||
}
|
||||
status->migration_duration /= 1000;
|
||||
status->migration_speed = server_mirror_bps(serve);
|
||||
status->migration_speed_limit =
|
||||
serve->mirror->max_bytes_per_second;
|
||||
|
||||
server_unlock_start_mirror( serve );
|
||||
status->migration_seconds_left = server_mirror_eta(serve);
|
||||
status->migration_bytes_left =
|
||||
server_mirror_bytes_remaining(serve);
|
||||
}
|
||||
|
||||
return status;
|
||||
server_unlock_start_mirror(serve);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
@@ -48,33 +51,32 @@ struct status * status_create( struct server * serve )
|
||||
#define PRINT_UINT64( var ) \
|
||||
do{dprintf( fd, #var "=%"PRIu64" ", status->var );}while(0)
|
||||
|
||||
int status_write( struct status * status, int fd )
|
||||
int status_write(struct status *status, int fd)
|
||||
{
|
||||
PRINT_INT( pid );
|
||||
PRINT_UINT64( size );
|
||||
PRINT_BOOL( is_mirroring );
|
||||
PRINT_BOOL( clients_allowed );
|
||||
PRINT_INT( num_clients );
|
||||
PRINT_BOOL( has_control );
|
||||
PRINT_INT(pid);
|
||||
PRINT_UINT64(size);
|
||||
PRINT_BOOL(is_mirroring);
|
||||
PRINT_BOOL(clients_allowed);
|
||||
PRINT_INT(num_clients);
|
||||
PRINT_BOOL(has_control);
|
||||
|
||||
if ( status->is_mirroring ) {
|
||||
PRINT_UINT64( migration_speed );
|
||||
PRINT_UINT64( migration_duration );
|
||||
PRINT_UINT64( migration_seconds_left );
|
||||
PRINT_UINT64( migration_bytes_left );
|
||||
if ( status->migration_speed_limit < UINT64_MAX ) {
|
||||
PRINT_UINT64( migration_speed_limit );
|
||||
};
|
||||
}
|
||||
if (status->is_mirroring) {
|
||||
PRINT_UINT64(migration_speed);
|
||||
PRINT_UINT64(migration_duration);
|
||||
PRINT_UINT64(migration_seconds_left);
|
||||
PRINT_UINT64(migration_bytes_left);
|
||||
if (status->migration_speed_limit < UINT64_MAX) {
|
||||
PRINT_UINT64(migration_speed_limit);
|
||||
};
|
||||
}
|
||||
|
||||
dprintf(fd, "\n");
|
||||
return 1;
|
||||
dprintf(fd, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void status_destroy( struct status * status )
|
||||
void status_destroy(struct status *status)
|
||||
{
|
||||
NULLCHECK( status );
|
||||
free( status );
|
||||
NULLCHECK(status);
|
||||
free(status);
|
||||
}
|
||||
|
||||
|
@@ -75,30 +75,29 @@
|
||||
#include <unistd.h>
|
||||
|
||||
struct status {
|
||||
pid_t pid;
|
||||
uint64_t size;
|
||||
int has_control;
|
||||
int clients_allowed;
|
||||
int num_clients;
|
||||
int is_mirroring;
|
||||
pid_t pid;
|
||||
uint64_t size;
|
||||
int has_control;
|
||||
int clients_allowed;
|
||||
int num_clients;
|
||||
int is_mirroring;
|
||||
|
||||
uint64_t migration_duration;
|
||||
uint64_t migration_speed;
|
||||
uint64_t migration_speed_limit;
|
||||
uint64_t migration_seconds_left;
|
||||
uint64_t migration_bytes_left;
|
||||
uint64_t migration_duration;
|
||||
uint64_t migration_speed;
|
||||
uint64_t migration_speed_limit;
|
||||
uint64_t migration_seconds_left;
|
||||
uint64_t migration_bytes_left;
|
||||
};
|
||||
|
||||
/** Create a status object for the given server. */
|
||||
struct status * status_create( struct server * );
|
||||
struct status *status_create(struct server *);
|
||||
|
||||
/** Output the given status object to the given file descriptot */
|
||||
int status_write( struct status *, int fd );
|
||||
int status_write(struct status *, int fd);
|
||||
|
||||
/** Free the status object */
|
||||
void status_destroy( struct status * );
|
||||
void status_destroy(struct status *);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -4,226 +4,221 @@
|
||||
#include "acl.h"
|
||||
#include "util.h"
|
||||
|
||||
START_TEST( test_null_acl )
|
||||
START_TEST(test_null_acl)
|
||||
{
|
||||
struct acl *acl = acl_create( 0,NULL, 0 );
|
||||
struct acl *acl = acl_create(0, NULL, 0);
|
||||
|
||||
fail_if( NULL == acl, "No acl alloced." );
|
||||
fail_unless( 0 == acl->len, "Incorrect length" );
|
||||
fail_if(NULL == acl, "No acl alloced.");
|
||||
fail_unless(0 == acl->len, "Incorrect length");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_parses_single_line )
|
||||
END_TEST START_TEST(test_parses_single_line)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
char *lines[] = { "127.0.0.1" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
|
||||
fail_unless( 1 == acl->len, "Incorrect length." );
|
||||
fail_if( NULL == acl->entries, "No entries present." );
|
||||
fail_unless(1 == acl->len, "Incorrect length.");
|
||||
fail_if(NULL == acl->entries, "No entries present.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_parses_multiple_lines )
|
||||
END_TEST START_TEST(test_parses_multiple_lines)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1", "::1"};
|
||||
struct acl * acl = acl_create( 2, lines, 0 );
|
||||
union mysockaddr e0, e1;
|
||||
char *lines[] = { "127.0.0.1", "::1" };
|
||||
struct acl *acl = acl_create(2, lines, 0);
|
||||
union mysockaddr e0, e1;
|
||||
|
||||
parse_ip_to_sockaddr( &e0.generic, lines[0] );
|
||||
parse_ip_to_sockaddr( &e1.generic, lines[1] );
|
||||
parse_ip_to_sockaddr(&e0.generic, lines[0]);
|
||||
parse_ip_to_sockaddr(&e1.generic, lines[1]);
|
||||
|
||||
fail_unless( acl->len == 2, "Multiple lines not parsed" );
|
||||
fail_unless(acl->len == 2, "Multiple lines not parsed");
|
||||
|
||||
struct ip_and_mask *entry;
|
||||
entry = &(*acl->entries)[0];
|
||||
fail_unless(entry->ip.family == e0.family, "entry 0 has wrong family!");
|
||||
entry = &(*acl->entries)[1];
|
||||
fail_unless(entry->ip.family == e1.family, "entry 1 has wrong family!");
|
||||
struct ip_and_mask *entry;
|
||||
entry = &(*acl->entries)[0];
|
||||
fail_unless(entry->ip.family == e0.family,
|
||||
"entry 0 has wrong family!");
|
||||
entry = &(*acl->entries)[1];
|
||||
fail_unless(entry->ip.family == e1.family,
|
||||
"entry 1 has wrong family!");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_destroy_doesnt_crash )
|
||||
END_TEST START_TEST(test_destroy_doesnt_crash)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
char *lines[] = { "127.0.0.1" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
|
||||
acl_destroy( acl );
|
||||
acl_destroy(acl);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_includes_single_address )
|
||||
END_TEST START_TEST(test_includes_single_address)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
union mysockaddr x;
|
||||
char *lines[] = { "127.0.0.1" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.1");
|
||||
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_includes_single_address_when_netmask_specified_ipv4 )
|
||||
START_TEST(test_includes_single_address_when_netmask_specified_ipv4)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1/24"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
union mysockaddr x;
|
||||
char *lines[] = { "127.0.0.1/24" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.0" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.0");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.1");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.255" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.255");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_includes_single_address_when_netmask_specified_ipv6 )
|
||||
START_TEST(test_includes_single_address_when_netmask_specified_ipv6)
|
||||
{
|
||||
char *lines[] = {"fe80::/10"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
union mysockaddr x;
|
||||
char *lines[] = { "fe80::/10" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "fe80::1" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "fe80::1");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "fe80::2" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "fe80::2");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "fe80:ffff:ffff::ffff" );
|
||||
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
|
||||
parse_ip_to_sockaddr(&x.generic, "fe80:ffff:ffff::ffff");
|
||||
fail_unless(acl_includes(acl, &x), "Included address wasn't covered");
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_includes_single_address_when_multiple_entries_exist )
|
||||
START_TEST(test_includes_single_address_when_multiple_entries_exist)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1", "::1"};
|
||||
struct acl * acl = acl_create( 2, lines, 0 );
|
||||
union mysockaddr e0;
|
||||
union mysockaddr e1;
|
||||
char *lines[] = { "127.0.0.1", "::1" };
|
||||
struct acl *acl = acl_create(2, lines, 0);
|
||||
union mysockaddr e0;
|
||||
union mysockaddr e1;
|
||||
|
||||
parse_ip_to_sockaddr( &e0.generic, "127.0.0.1" );
|
||||
parse_ip_to_sockaddr( &e1.generic, "::1" );
|
||||
parse_ip_to_sockaddr(&e0.generic, "127.0.0.1");
|
||||
parse_ip_to_sockaddr(&e1.generic, "::1");
|
||||
|
||||
fail_unless( acl_includes( acl, &e0 ), "Included address 0 wasn't covered" );
|
||||
fail_unless( acl_includes( acl, &e1 ), "Included address 1 wasn't covered" );
|
||||
fail_unless(acl_includes(acl, &e0),
|
||||
"Included address 0 wasn't covered");
|
||||
fail_unless(acl_includes(acl, &e1),
|
||||
"Included address 1 wasn't covered");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_doesnt_include_other_address )
|
||||
END_TEST START_TEST(test_doesnt_include_other_address)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
union mysockaddr x;
|
||||
char *lines[] = { "127.0.0.1" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" );
|
||||
fail_if( acl_includes( acl, &x ), "Excluded address was covered." );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.2");
|
||||
fail_if(acl_includes(acl, &x), "Excluded address was covered.");
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_doesnt_include_other_address_when_netmask_specified )
|
||||
START_TEST(test_doesnt_include_other_address_when_netmask_specified)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1/32"};
|
||||
struct acl * acl = acl_create( 1, lines, 0 );
|
||||
union mysockaddr x;
|
||||
char *lines[] = { "127.0.0.1/32" };
|
||||
struct acl *acl = acl_create(1, lines, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" );
|
||||
fail_if( acl_includes( acl, &x ), "Excluded address was covered." );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.2");
|
||||
fail_if(acl_includes(acl, &x), "Excluded address was covered.");
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_doesnt_include_other_address_when_multiple_entries_exist )
|
||||
START_TEST(test_doesnt_include_other_address_when_multiple_entries_exist)
|
||||
{
|
||||
char *lines[] = {"127.0.0.1", "::1"};
|
||||
struct acl * acl = acl_create( 2, lines, 0 );
|
||||
union mysockaddr e0;
|
||||
union mysockaddr e1;
|
||||
char *lines[] = { "127.0.0.1", "::1" };
|
||||
struct acl *acl = acl_create(2, lines, 0);
|
||||
union mysockaddr e0;
|
||||
union mysockaddr e1;
|
||||
|
||||
parse_ip_to_sockaddr( &e0.generic, "127.0.0.2" );
|
||||
parse_ip_to_sockaddr( &e1.generic, "::2" );
|
||||
parse_ip_to_sockaddr(&e0.generic, "127.0.0.2");
|
||||
parse_ip_to_sockaddr(&e1.generic, "::2");
|
||||
|
||||
fail_if( acl_includes( acl, &e0 ), "Excluded address 0 was covered." );
|
||||
fail_if( acl_includes( acl, &e1 ), "Excluded address 1 was covered." );
|
||||
fail_if(acl_includes(acl, &e0), "Excluded address 0 was covered.");
|
||||
fail_if(acl_includes(acl, &e1), "Excluded address 1 was covered.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_default_deny_rejects )
|
||||
END_TEST START_TEST(test_default_deny_rejects)
|
||||
{
|
||||
struct acl * acl = acl_create( 0, NULL, 1 );
|
||||
union mysockaddr x;
|
||||
struct acl *acl = acl_create(0, NULL, 1);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.1");
|
||||
|
||||
fail_if( acl_includes( acl, &x ), "Default deny accepted." );
|
||||
fail_if(acl_includes(acl, &x), "Default deny accepted.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_default_accept_rejects )
|
||||
END_TEST START_TEST(test_default_accept_rejects)
|
||||
{
|
||||
struct acl * acl = acl_create( 0, NULL, 0 );
|
||||
union mysockaddr x;
|
||||
struct acl *acl = acl_create(0, NULL, 0);
|
||||
union mysockaddr x;
|
||||
|
||||
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
|
||||
parse_ip_to_sockaddr(&x.generic, "127.0.0.1");
|
||||
|
||||
fail_unless( acl_includes( acl, &x ), "Default accept rejected." );
|
||||
fail_unless(acl_includes(acl, &x), "Default accept rejected.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* acl_suite(void)
|
||||
END_TEST Suite * acl_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("acl");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_includes = tcase_create("includes");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
Suite *s = suite_create("acl");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_includes = tcase_create("includes");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
|
||||
|
||||
tcase_add_test(tc_create, test_null_acl);
|
||||
tcase_add_test(tc_create, test_parses_single_line);
|
||||
tcase_add_test(tc_includes, test_parses_multiple_lines);
|
||||
tcase_add_test(tc_create, test_null_acl);
|
||||
tcase_add_test(tc_create, test_parses_single_line);
|
||||
tcase_add_test(tc_includes, test_parses_multiple_lines);
|
||||
|
||||
tcase_add_test(tc_includes, test_includes_single_address);
|
||||
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv4);
|
||||
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv6);
|
||||
tcase_add_test(tc_includes, test_includes_single_address);
|
||||
tcase_add_test(tc_includes,
|
||||
test_includes_single_address_when_netmask_specified_ipv4);
|
||||
tcase_add_test(tc_includes,
|
||||
test_includes_single_address_when_netmask_specified_ipv6);
|
||||
|
||||
tcase_add_test(tc_includes, test_includes_single_address_when_multiple_entries_exist);
|
||||
tcase_add_test(tc_includes,
|
||||
test_includes_single_address_when_multiple_entries_exist);
|
||||
|
||||
tcase_add_test(tc_includes, test_doesnt_include_other_address);
|
||||
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_netmask_specified);
|
||||
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_multiple_entries_exist);
|
||||
tcase_add_test(tc_includes, test_doesnt_include_other_address);
|
||||
tcase_add_test(tc_includes,
|
||||
test_doesnt_include_other_address_when_netmask_specified);
|
||||
tcase_add_test(tc_includes,
|
||||
test_doesnt_include_other_address_when_multiple_entries_exist);
|
||||
|
||||
tcase_add_test(tc_includes, test_default_deny_rejects);
|
||||
tcase_add_test(tc_includes, test_default_accept_rejects);
|
||||
tcase_add_test(tc_includes, test_default_deny_rejects);
|
||||
tcase_add_test(tc_includes, test_default_accept_rejects);
|
||||
|
||||
tcase_add_test(tc_destroy, test_destroy_doesnt_crash);
|
||||
tcase_add_test(tc_destroy, test_destroy_doesnt_crash);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_includes);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_includes);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
log_level = 0;
|
||||
log_level = 0;
|
||||
#else
|
||||
log_level = 2;
|
||||
log_level = 2;
|
||||
#endif
|
||||
int number_failed;
|
||||
Suite *s = acl_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = acl_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -9,492 +9,473 @@
|
||||
|
||||
START_TEST(test_bit_set)
|
||||
{
|
||||
uint64_t num = 0;
|
||||
bitfield_p bits = (bitfield_p) #
|
||||
uint64_t num = 0;
|
||||
bitfield_p bits = (bitfield_p) & num;
|
||||
|
||||
#define TEST_BIT_SET(bit, newvalue) \
|
||||
bit_set(bits, (bit)); \
|
||||
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
|
||||
|
||||
TEST_BIT_SET(0, 1);
|
||||
TEST_BIT_SET(1, 3);
|
||||
TEST_BIT_SET(2, 7);
|
||||
TEST_BIT_SET(7, 0x87);
|
||||
TEST_BIT_SET(63, 0x8000000000000087);
|
||||
TEST_BIT_SET(0, 1);
|
||||
TEST_BIT_SET(1, 3);
|
||||
TEST_BIT_SET(2, 7);
|
||||
TEST_BIT_SET(7, 0x87);
|
||||
TEST_BIT_SET(63, 0x8000000000000087);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bit_clear)
|
||||
END_TEST START_TEST(test_bit_clear)
|
||||
{
|
||||
uint64_t num = 0xffffffffffffffff;
|
||||
bitfield_p bits = (bitfield_p) #
|
||||
uint64_t num = 0xffffffffffffffff;
|
||||
bitfield_p bits = (bitfield_p) & num;
|
||||
|
||||
#define TEST_BIT_CLEAR(bit, newvalue) \
|
||||
bit_clear(bits, (bit)); \
|
||||
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
|
||||
|
||||
TEST_BIT_CLEAR(0, 0xfffffffffffffffe);
|
||||
TEST_BIT_CLEAR(1, 0xfffffffffffffffc);
|
||||
TEST_BIT_CLEAR(2, 0xfffffffffffffff8);
|
||||
TEST_BIT_CLEAR(7, 0xffffffffffffff78);
|
||||
TEST_BIT_CLEAR(63,0x7fffffffffffff78);
|
||||
TEST_BIT_CLEAR(0, 0xfffffffffffffffe);
|
||||
TEST_BIT_CLEAR(1, 0xfffffffffffffffc);
|
||||
TEST_BIT_CLEAR(2, 0xfffffffffffffff8);
|
||||
TEST_BIT_CLEAR(7, 0xffffffffffffff78);
|
||||
TEST_BIT_CLEAR(63, 0x7fffffffffffff78);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bit_tests)
|
||||
END_TEST START_TEST(test_bit_tests)
|
||||
{
|
||||
uint64_t num = 0x5555555555555555;
|
||||
bitfield_p bits = (bitfield_p) #
|
||||
uint64_t num = 0x5555555555555555;
|
||||
bitfield_p bits = (bitfield_p) & num;
|
||||
|
||||
fail_unless(bit_has_value(bits, 0, 1), "bit_has_value malfunction");
|
||||
fail_unless(bit_has_value(bits, 1, 0), "bit_has_value malfunction");
|
||||
fail_unless(bit_has_value(bits, 63, 0), "bit_has_value malfunction");
|
||||
fail_unless(bit_is_set(bits, 0), "bit_is_set malfunction");
|
||||
fail_unless(bit_is_clear(bits, 1), "bit_is_clear malfunction");
|
||||
fail_unless(bit_is_set(bits, 62), "bit_is_set malfunction");
|
||||
fail_unless(bit_is_clear(bits, 63), "bit_is_clear malfunction");
|
||||
fail_unless(bit_has_value(bits, 0, 1), "bit_has_value malfunction");
|
||||
fail_unless(bit_has_value(bits, 1, 0), "bit_has_value malfunction");
|
||||
fail_unless(bit_has_value(bits, 63, 0), "bit_has_value malfunction");
|
||||
fail_unless(bit_is_set(bits, 0), "bit_is_set malfunction");
|
||||
fail_unless(bit_is_clear(bits, 1), "bit_is_clear malfunction");
|
||||
fail_unless(bit_is_set(bits, 62), "bit_is_set malfunction");
|
||||
fail_unless(bit_is_clear(bits, 63), "bit_is_clear malfunction");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bit_ranges)
|
||||
END_TEST START_TEST(test_bit_ranges)
|
||||
{
|
||||
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)];
|
||||
uint64_t *longs = (uint64_t *) buffer;
|
||||
uint64_t i;
|
||||
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)];
|
||||
uint64_t *longs = (uint64_t *) buffer;
|
||||
uint64_t i;
|
||||
|
||||
memset(buffer, 0, 4160);
|
||||
memset(buffer, 0, 4160);
|
||||
|
||||
for (i=0; i<64; i++) {
|
||||
bit_set_range(buffer, i*64, i);
|
||||
fail_unless(
|
||||
longs[i] == (1ULL<<i)-1,
|
||||
"longs[%ld] = %lx SHOULD BE %lx",
|
||||
i, longs[i], (1ULL<<i)-1
|
||||
);
|
||||
for (i = 0; i < 64; i++) {
|
||||
bit_set_range(buffer, i * 64, i);
|
||||
fail_unless(longs[i] == (1ULL << i) - 1,
|
||||
"longs[%ld] = %lx SHOULD BE %lx",
|
||||
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++) {
|
||||
bit_clear_range(buffer, i*64, i);
|
||||
fail_unless(longs[i] == 0, "bit_clear_range didn't work at i=%d", i);
|
||||
}
|
||||
for (i = 0; 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);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bit_runs)
|
||||
END_TEST START_TEST(test_bit_runs)
|
||||
{
|
||||
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(256)];
|
||||
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
|
||||
};
|
||||
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(256)];
|
||||
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
|
||||
};
|
||||
|
||||
memset(buffer,0,256);
|
||||
memset(buffer, 0, 256);
|
||||
|
||||
for (i=0; i < 20; i += 2) {
|
||||
ptr += runs[i];
|
||||
bit_set_range(buffer, ptr, runs[i+1]);
|
||||
ptr += runs[i+1];
|
||||
}
|
||||
for (i = 0; i < 20; i += 2) {
|
||||
ptr += runs[i];
|
||||
bit_set_range(buffer, ptr, runs[i + 1]);
|
||||
ptr += runs[i + 1];
|
||||
}
|
||||
|
||||
ptr = 0;
|
||||
ptr = 0;
|
||||
|
||||
for (i=0; i < 20; i += 1) {
|
||||
int run = bit_run_count(buffer, ptr, 2048-ptr, NULL);
|
||||
fail_unless(
|
||||
run == runs[i],
|
||||
"run %d should have been %d, was %d",
|
||||
i, runs[i], run
|
||||
);
|
||||
ptr += runs[i];
|
||||
}
|
||||
for (i = 0; i < 20; i += 1) {
|
||||
int run = bit_run_count(buffer, ptr, 2048 - ptr, NULL);
|
||||
fail_unless(run == runs[i],
|
||||
"run %d should have been %d, was %d", i, runs[i], run);
|
||||
ptr += runs[i];
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset)
|
||||
END_TEST START_TEST(test_bitset)
|
||||
{
|
||||
struct bitset * map;
|
||||
uint64_t *num;
|
||||
struct bitset *map;
|
||||
uint64_t *num;
|
||||
|
||||
map = bitset_alloc(6400, 100);
|
||||
num = (uint64_t*) map->bits;
|
||||
map = bitset_alloc(6400, 100);
|
||||
num = (uint64_t *) map->bits;
|
||||
|
||||
bitset_set_range(map,0,50);
|
||||
ck_assert_int_eq(1, *num);
|
||||
bitset_set_range(map,99,1);
|
||||
ck_assert_int_eq(1, *num);
|
||||
bitset_set_range(map,100,1);
|
||||
ck_assert_int_eq(3, *num);
|
||||
bitset_set_range(map,0,800);
|
||||
ck_assert_int_eq(255, *num);
|
||||
bitset_set_range(map,1499,2);
|
||||
ck_assert_int_eq(0xc0ff, *num);
|
||||
bitset_clear_range(map,1499,2);
|
||||
ck_assert_int_eq(255, *num);
|
||||
bitset_set_range(map, 0, 50);
|
||||
ck_assert_int_eq(1, *num);
|
||||
bitset_set_range(map, 99, 1);
|
||||
ck_assert_int_eq(1, *num);
|
||||
bitset_set_range(map, 100, 1);
|
||||
ck_assert_int_eq(3, *num);
|
||||
bitset_set_range(map, 0, 800);
|
||||
ck_assert_int_eq(255, *num);
|
||||
bitset_set_range(map, 1499, 2);
|
||||
ck_assert_int_eq(0xc0ff, *num);
|
||||
bitset_clear_range(map, 1499, 2);
|
||||
ck_assert_int_eq(255, *num);
|
||||
|
||||
*num = 0;
|
||||
bitset_set_range(map, 1499, 2);
|
||||
bitset_clear_range(map, 1300, 200);
|
||||
ck_assert_int_eq(0x8000, *num);
|
||||
*num = 0;
|
||||
bitset_set_range(map, 1499, 2);
|
||||
bitset_clear_range(map, 1300, 200);
|
||||
ck_assert_int_eq(0x8000, *num);
|
||||
|
||||
*num = 0;
|
||||
bitset_set_range(map, 0, 6400);
|
||||
ck_assert_int_eq(0xffffffffffffffff, *num);
|
||||
bitset_clear_range(map, 3200, 400);
|
||||
ck_assert_int_eq(0xfffffff0ffffffff, *num);
|
||||
*num = 0;
|
||||
bitset_set_range(map, 0, 6400);
|
||||
ck_assert_int_eq(0xffffffffffffffff, *num);
|
||||
bitset_clear_range(map, 3200, 400);
|
||||
ck_assert_int_eq(0xfffffff0ffffffff, *num);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_bitset_set )
|
||||
END_TEST START_TEST(test_bitset_set)
|
||||
{
|
||||
struct bitset * map;
|
||||
uint64_t run;
|
||||
struct bitset *map;
|
||||
uint64_t run;
|
||||
|
||||
map = bitset_alloc(64, 1);
|
||||
map = bitset_alloc(64, 1);
|
||||
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
bitset_set( map );
|
||||
assert_bitset_is( map, 0xffffffffffffffff );
|
||||
bitset_free( map );
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
bitset_set(map);
|
||||
assert_bitset_is(map, 0xffffffffffffffff);
|
||||
bitset_free(map);
|
||||
|
||||
map = bitset_alloc( 6400, 100 );
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
bitset_set( map );
|
||||
assert_bitset_is( map, 0xffffffffffffffff );
|
||||
bitset_free( map );
|
||||
map = bitset_alloc(6400, 100);
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
bitset_set(map);
|
||||
assert_bitset_is(map, 0xffffffffffffffff);
|
||||
bitset_free(map);
|
||||
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc( 53687091200, 4096 );
|
||||
bitset_set( map );
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc(53687091200, 4096);
|
||||
bitset_set(map);
|
||||
|
||||
run = bitset_run_count( map, 0, 53687091200 );
|
||||
ck_assert_int_eq( run, 53687091200 );
|
||||
bitset_free( map );
|
||||
run = bitset_run_count(map, 0, 53687091200);
|
||||
ck_assert_int_eq(run, 53687091200);
|
||||
bitset_free(map);
|
||||
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_bitset_clear )
|
||||
END_TEST START_TEST(test_bitset_clear)
|
||||
{
|
||||
struct bitset * map;
|
||||
uint64_t *num;
|
||||
uint64_t run;
|
||||
struct bitset *map;
|
||||
uint64_t *num;
|
||||
uint64_t run;
|
||||
|
||||
map = bitset_alloc(64, 1);
|
||||
num = (uint64_t*) map->bits;
|
||||
map = bitset_alloc(64, 1);
|
||||
num = (uint64_t *) map->bits;
|
||||
|
||||
ck_assert_int_eq( 0x0000000000000000, *num );
|
||||
bitset_set( map );
|
||||
bitset_clear( map );
|
||||
ck_assert_int_eq( 0x0000000000000000, *num );
|
||||
ck_assert_int_eq(0x0000000000000000, *num);
|
||||
bitset_set(map);
|
||||
bitset_clear(map);
|
||||
ck_assert_int_eq(0x0000000000000000, *num);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc( 53687091200, 4096 );
|
||||
bitset_set( map );
|
||||
bitset_clear( map );
|
||||
run = bitset_run_count( map, 0, 53687091200 );
|
||||
ck_assert_int_eq( run, 53687091200 );
|
||||
bitset_free( map );
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc(53687091200, 4096);
|
||||
bitset_set(map);
|
||||
bitset_clear(map);
|
||||
run = bitset_run_count(map, 0, 53687091200);
|
||||
ck_assert_int_eq(run, 53687091200);
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_bitset_set_range )
|
||||
END_TEST START_TEST(test_bitset_set_range)
|
||||
{
|
||||
struct bitset* map = bitset_alloc( 64, 1 );
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
|
||||
bitset_set_range( map, 8, 8 );
|
||||
assert_bitset_is( map, 0x000000000000ff00 );
|
||||
bitset_set_range(map, 8, 8);
|
||||
assert_bitset_is(map, 0x000000000000ff00);
|
||||
|
||||
bitset_clear( map );
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
bitset_set_range( map, 0, 0 );
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
bitset_clear(map);
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
bitset_set_range(map, 0, 0);
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_bitset_clear_range )
|
||||
END_TEST START_TEST(test_bitset_clear_range)
|
||||
{
|
||||
struct bitset* map = bitset_alloc( 64, 1 );
|
||||
bitset_set( map );
|
||||
assert_bitset_is( map, 0xffffffffffffffff );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
bitset_set(map);
|
||||
assert_bitset_is(map, 0xffffffffffffffff);
|
||||
|
||||
bitset_clear_range( map, 8, 8 );
|
||||
assert_bitset_is( map, 0xffffffffffff00ff );
|
||||
bitset_clear_range(map, 8, 8);
|
||||
assert_bitset_is(map, 0xffffffffffff00ff);
|
||||
|
||||
bitset_set( map );
|
||||
assert_bitset_is( map, 0xffffffffffffffff );
|
||||
bitset_clear_range( map, 0, 0 );
|
||||
assert_bitset_is( map, 0xffffffffffffffff );
|
||||
bitset_set(map);
|
||||
assert_bitset_is(map, 0xffffffffffffffff);
|
||||
bitset_clear_range(map, 0, 0);
|
||||
assert_bitset_is(map, 0xffffffffffffffff);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_bitset_run_count )
|
||||
END_TEST START_TEST(test_bitset_run_count)
|
||||
{
|
||||
struct bitset* map = bitset_alloc( 64, 1 );
|
||||
uint64_t run;
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
uint64_t run;
|
||||
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
|
||||
run = bitset_run_count( map, 0, 64 );
|
||||
ck_assert_int_eq( 64, run );
|
||||
run = bitset_run_count(map, 0, 64);
|
||||
ck_assert_int_eq(64, run);
|
||||
|
||||
bitset_set_range( map, 0, 32 );
|
||||
assert_bitset_is( map, 0x00000000ffffffff );
|
||||
bitset_set_range(map, 0, 32);
|
||||
assert_bitset_is(map, 0x00000000ffffffff);
|
||||
|
||||
run = bitset_run_count( map, 0, 64 );
|
||||
ck_assert_int_eq( 32, run );
|
||||
run = bitset_run_count(map, 0, 64);
|
||||
ck_assert_int_eq(32, run);
|
||||
|
||||
run = bitset_run_count( map, 0, 16 );
|
||||
ck_assert_int_eq( 16, run );
|
||||
run = bitset_run_count(map, 0, 16);
|
||||
ck_assert_int_eq(16, run);
|
||||
|
||||
run = bitset_run_count( map, 16, 64 );
|
||||
ck_assert_int_eq( 16, run );
|
||||
run = bitset_run_count(map, 16, 64);
|
||||
ck_assert_int_eq(16, run);
|
||||
|
||||
run = bitset_run_count( map, 31, 64 );
|
||||
ck_assert_int_eq( 1, run );
|
||||
run = bitset_run_count(map, 31, 64);
|
||||
ck_assert_int_eq(1, run);
|
||||
|
||||
run = bitset_run_count( map, 32, 64 );
|
||||
ck_assert_int_eq( 32, run );
|
||||
run = bitset_run_count(map, 32, 64);
|
||||
ck_assert_int_eq(32, run);
|
||||
|
||||
run = bitset_run_count( map, 32, 32 );
|
||||
ck_assert_int_eq( 32, run );
|
||||
run = bitset_run_count(map, 32, 32);
|
||||
ck_assert_int_eq(32, run);
|
||||
|
||||
run = bitset_run_count( map, 32, 16 );
|
||||
ck_assert_int_eq( 16, run );
|
||||
run = bitset_run_count(map, 32, 16);
|
||||
ck_assert_int_eq(16, run);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
|
||||
map = bitset_alloc( 6400, 100 );
|
||||
assert_bitset_is( map, 0x0000000000000000 );
|
||||
map = bitset_alloc(6400, 100);
|
||||
assert_bitset_is(map, 0x0000000000000000);
|
||||
|
||||
run = bitset_run_count( map, 0, 6400 );
|
||||
ck_assert_int_eq( 6400, run );
|
||||
run = bitset_run_count(map, 0, 6400);
|
||||
ck_assert_int_eq(6400, run);
|
||||
|
||||
bitset_set_range( map, 0, 3200 );
|
||||
bitset_set_range(map, 0, 3200);
|
||||
|
||||
run = bitset_run_count( map, 0, 6400 );
|
||||
ck_assert_int_eq( 3200, run );
|
||||
run = bitset_run_count(map, 0, 6400);
|
||||
ck_assert_int_eq(3200, run);
|
||||
|
||||
run = bitset_run_count( map, 1, 6400 );
|
||||
ck_assert_int_eq( 3199, run );
|
||||
run = bitset_run_count(map, 1, 6400);
|
||||
ck_assert_int_eq(3199, run);
|
||||
|
||||
run = bitset_run_count( map, 3200, 6400 );
|
||||
ck_assert_int_eq( 3200, run );
|
||||
run = bitset_run_count(map, 3200, 6400);
|
||||
ck_assert_int_eq(3200, run);
|
||||
|
||||
run = bitset_run_count( map, 6500, 6400 );
|
||||
ck_assert_int_eq( 0, run );
|
||||
bitset_free( map );
|
||||
run = bitset_run_count(map, 6500, 6400);
|
||||
ck_assert_int_eq(0, run);
|
||||
bitset_free(map);
|
||||
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc( 53687091200, 4096 );
|
||||
bitset_set( map );
|
||||
run = bitset_run_count( map, 0, 53687091200 );
|
||||
ck_assert_int_eq( run, 53687091200 );
|
||||
// Now do something large and representative
|
||||
map = bitset_alloc(53687091200, 4096);
|
||||
bitset_set(map);
|
||||
run = bitset_run_count(map, 0, 53687091200);
|
||||
ck_assert_int_eq(run, 53687091200);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_bitset_set_range_doesnt_push_to_stream )
|
||||
END_TEST START_TEST(test_bitset_set_range_doesnt_push_to_stream)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
bitset_set_range( map, 0, 64 );
|
||||
ck_assert_int_eq( 0, bitset_stream_size( map ) );
|
||||
bitset_free( map );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
bitset_set_range(map, 0, 64);
|
||||
ck_assert_int_eq(0, bitset_stream_size(map));
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_bitset_clear_range_doesnt_push_to_stream )
|
||||
END_TEST START_TEST(test_bitset_clear_range_doesnt_push_to_stream)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
bitset_clear_range( map, 0, 64 );
|
||||
ck_assert_int_eq( 0, bitset_stream_size( map ) );
|
||||
bitset_free( map );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
bitset_clear_range(map, 0, 64);
|
||||
ck_assert_int_eq(0, bitset_stream_size(map));
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_enable_stream)
|
||||
END_TEST START_TEST(test_bitset_enable_stream)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
struct bitset_stream_entry result;
|
||||
memset( &result, 0, sizeof( result ) );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
struct bitset_stream_entry result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
bitset_enable_stream( map );
|
||||
bitset_enable_stream(map);
|
||||
|
||||
ck_assert_int_eq( 1, map->stream_enabled );
|
||||
ck_assert_int_eq(1, map->stream_enabled);
|
||||
|
||||
bitset_stream_dequeue( map, &result );
|
||||
bitset_stream_dequeue(map, &result);
|
||||
|
||||
ck_assert_int_eq( BITSET_STREAM_ON, result.event );
|
||||
ck_assert_int_eq( 0, result.from );
|
||||
ck_assert_int_eq( 64, result.len );
|
||||
ck_assert_int_eq(BITSET_STREAM_ON, result.event);
|
||||
ck_assert_int_eq(0, result.from);
|
||||
ck_assert_int_eq(64, result.len);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_disable_stream)
|
||||
END_TEST START_TEST(test_bitset_disable_stream)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
struct bitset_stream_entry result;
|
||||
memset( &result, 0, sizeof( result ) );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
struct bitset_stream_entry result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
bitset_enable_stream( map );
|
||||
bitset_disable_stream( map );
|
||||
bitset_enable_stream(map);
|
||||
bitset_disable_stream(map);
|
||||
|
||||
ck_assert_int_eq( 0, map->stream_enabled );
|
||||
ck_assert_int_eq( 2, bitset_stream_size( map ) );
|
||||
ck_assert_int_eq(0, map->stream_enabled);
|
||||
ck_assert_int_eq(2, bitset_stream_size(map));
|
||||
|
||||
bitset_stream_dequeue( map, NULL ); // ON
|
||||
bitset_stream_dequeue( map, &result ); // OFF
|
||||
bitset_stream_dequeue(map, NULL); // ON
|
||||
bitset_stream_dequeue(map, &result); // OFF
|
||||
|
||||
ck_assert_int_eq( BITSET_STREAM_OFF, result.event );
|
||||
ck_assert_int_eq( 0, result.from );
|
||||
ck_assert_int_eq( 64, result.len );
|
||||
ck_assert_int_eq(BITSET_STREAM_OFF, result.event);
|
||||
ck_assert_int_eq(0, result.from);
|
||||
ck_assert_int_eq(64, result.len);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_stream_with_set_range)
|
||||
END_TEST START_TEST(test_bitset_stream_with_set_range)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
struct bitset_stream_entry result;
|
||||
memset( &result, 0, sizeof( result ) );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
struct bitset_stream_entry result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
bitset_enable_stream( map );
|
||||
bitset_set_range( map, 0, 32 );
|
||||
bitset_enable_stream(map);
|
||||
bitset_set_range(map, 0, 32);
|
||||
|
||||
ck_assert_int_eq( 2, bitset_stream_size( map ) );
|
||||
ck_assert_int_eq(2, bitset_stream_size(map));
|
||||
|
||||
bitset_stream_dequeue( map, NULL ); // ON
|
||||
bitset_stream_dequeue( map, &result ); // SET
|
||||
bitset_stream_dequeue(map, NULL); // ON
|
||||
bitset_stream_dequeue(map, &result); // SET
|
||||
|
||||
ck_assert_int_eq( BITSET_STREAM_SET, result.event );
|
||||
ck_assert_int_eq( 0, result.from );
|
||||
ck_assert_int_eq( 32, result.len );
|
||||
ck_assert_int_eq(BITSET_STREAM_SET, result.event);
|
||||
ck_assert_int_eq(0, result.from);
|
||||
ck_assert_int_eq(32, result.len);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_stream_with_clear_range)
|
||||
END_TEST START_TEST(test_bitset_stream_with_clear_range)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
struct bitset_stream_entry result;
|
||||
memset( &result, 0, sizeof( result ) );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
struct bitset_stream_entry result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
bitset_enable_stream( map );
|
||||
bitset_clear_range( map, 0, 32 );
|
||||
ck_assert_int_eq( 2, bitset_stream_size( map ) );
|
||||
bitset_enable_stream(map);
|
||||
bitset_clear_range(map, 0, 32);
|
||||
ck_assert_int_eq(2, bitset_stream_size(map));
|
||||
|
||||
bitset_stream_dequeue( map, NULL ); // ON
|
||||
bitset_stream_dequeue( map, &result ); // UNSET
|
||||
bitset_stream_dequeue(map, NULL); // ON
|
||||
bitset_stream_dequeue(map, &result); // UNSET
|
||||
|
||||
ck_assert_int_eq( BITSET_STREAM_UNSET, result.event );
|
||||
ck_assert_int_eq( 0, result.from );
|
||||
ck_assert_int_eq( 32, result.len );
|
||||
ck_assert_int_eq(BITSET_STREAM_UNSET, result.event);
|
||||
ck_assert_int_eq(0, result.from);
|
||||
ck_assert_int_eq(32, result.len);
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_stream_size)
|
||||
END_TEST START_TEST(test_bitset_stream_size)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
bitset_enable_stream( map );
|
||||
bitset_set_range( map, 0, 32 );
|
||||
bitset_set_range( map, 16, 32 );
|
||||
bitset_set_range( map, 7, 16 );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
bitset_enable_stream(map);
|
||||
bitset_set_range(map, 0, 32);
|
||||
bitset_set_range(map, 16, 32);
|
||||
bitset_set_range(map, 7, 16);
|
||||
|
||||
bitset_clear_range( map, 0, 32 );
|
||||
bitset_clear_range( map, 16, 32 );
|
||||
bitset_clear_range( map, 48, 16 );
|
||||
bitset_disable_stream( map );
|
||||
bitset_clear_range(map, 0, 32);
|
||||
bitset_clear_range(map, 16, 32);
|
||||
bitset_clear_range(map, 48, 16);
|
||||
bitset_disable_stream(map);
|
||||
|
||||
ck_assert_int_eq( 8, bitset_stream_size( map ) );
|
||||
ck_assert_int_eq(8, bitset_stream_size(map));
|
||||
|
||||
bitset_free( map );
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bitset_stream_queued_bytes)
|
||||
END_TEST START_TEST(test_bitset_stream_queued_bytes)
|
||||
{
|
||||
struct bitset *map = bitset_alloc( 64, 1 );
|
||||
bitset_enable_stream( map );
|
||||
bitset_set_range( map, 0, 32 );
|
||||
bitset_set_range( map, 16, 32 );
|
||||
bitset_set_range( map, 7, 16 );
|
||||
struct bitset *map = bitset_alloc(64, 1);
|
||||
bitset_enable_stream(map);
|
||||
bitset_set_range(map, 0, 32);
|
||||
bitset_set_range(map, 16, 32);
|
||||
bitset_set_range(map, 7, 16);
|
||||
|
||||
bitset_clear_range( map, 0, 32 );
|
||||
bitset_clear_range( map, 16, 32 );
|
||||
bitset_clear_range( map, 48, 16 );
|
||||
bitset_clear_range( map, 0, 2 );
|
||||
bitset_disable_stream( map );
|
||||
bitset_clear_range(map, 0, 32);
|
||||
bitset_clear_range(map, 16, 32);
|
||||
bitset_clear_range(map, 48, 16);
|
||||
bitset_clear_range(map, 0, 2);
|
||||
bitset_disable_stream(map);
|
||||
|
||||
ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_ON ) );
|
||||
ck_assert_int_eq( 80, bitset_stream_queued_bytes( map, BITSET_STREAM_SET ) );
|
||||
ck_assert_int_eq( 82, bitset_stream_queued_bytes( map, BITSET_STREAM_UNSET ) );
|
||||
ck_assert_int_eq( 64, bitset_stream_queued_bytes( map, BITSET_STREAM_OFF ) );
|
||||
bitset_free( map );
|
||||
ck_assert_int_eq(64,
|
||||
bitset_stream_queued_bytes(map, BITSET_STREAM_ON));
|
||||
ck_assert_int_eq(80,
|
||||
bitset_stream_queued_bytes(map, BITSET_STREAM_SET));
|
||||
ck_assert_int_eq(82,
|
||||
bitset_stream_queued_bytes(map, BITSET_STREAM_UNSET));
|
||||
ck_assert_int_eq(64,
|
||||
bitset_stream_queued_bytes(map, BITSET_STREAM_OFF));
|
||||
bitset_free(map);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite* bitset_suite(void)
|
||||
END_TEST Suite * bitset_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("bitset");
|
||||
Suite *s = suite_create("bitset");
|
||||
|
||||
TCase *tc_bit = tcase_create("bit");
|
||||
tcase_add_test(tc_bit, test_bit_set);
|
||||
tcase_add_test(tc_bit, test_bit_clear);
|
||||
tcase_add_test(tc_bit, test_bit_tests);
|
||||
tcase_add_test(tc_bit, test_bit_ranges);
|
||||
tcase_add_test(tc_bit, test_bit_runs);
|
||||
suite_add_tcase(s, tc_bit);
|
||||
TCase *tc_bit = tcase_create("bit");
|
||||
tcase_add_test(tc_bit, test_bit_set);
|
||||
tcase_add_test(tc_bit, test_bit_clear);
|
||||
tcase_add_test(tc_bit, test_bit_tests);
|
||||
tcase_add_test(tc_bit, test_bit_ranges);
|
||||
tcase_add_test(tc_bit, test_bit_runs);
|
||||
suite_add_tcase(s, tc_bit);
|
||||
|
||||
TCase *tc_bitset = tcase_create("bitset");
|
||||
tcase_add_test(tc_bitset, test_bitset);
|
||||
tcase_add_test(tc_bitset, test_bitset_set);
|
||||
tcase_add_test(tc_bitset, test_bitset_clear);
|
||||
tcase_add_test(tc_bitset, test_bitset_run_count);
|
||||
tcase_add_test(tc_bitset, test_bitset_set_range);
|
||||
tcase_add_test(tc_bitset, test_bitset_clear_range);
|
||||
tcase_add_test(tc_bitset, test_bitset_set_range_doesnt_push_to_stream);
|
||||
tcase_add_test(tc_bitset, test_bitset_clear_range_doesnt_push_to_stream);
|
||||
suite_add_tcase(s, tc_bitset);
|
||||
TCase *tc_bitset = tcase_create("bitset");
|
||||
tcase_add_test(tc_bitset, test_bitset);
|
||||
tcase_add_test(tc_bitset, test_bitset_set);
|
||||
tcase_add_test(tc_bitset, test_bitset_clear);
|
||||
tcase_add_test(tc_bitset, test_bitset_run_count);
|
||||
tcase_add_test(tc_bitset, test_bitset_set_range);
|
||||
tcase_add_test(tc_bitset, test_bitset_clear_range);
|
||||
tcase_add_test(tc_bitset, test_bitset_set_range_doesnt_push_to_stream);
|
||||
tcase_add_test(tc_bitset,
|
||||
test_bitset_clear_range_doesnt_push_to_stream);
|
||||
suite_add_tcase(s, tc_bitset);
|
||||
|
||||
|
||||
TCase *tc_bitset_stream = tcase_create("bitset_stream");
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_enable_stream);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_disable_stream);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_with_set_range);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_with_clear_range);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_size);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes);
|
||||
suite_add_tcase(s, tc_bitset_stream);
|
||||
TCase *tc_bitset_stream = tcase_create("bitset_stream");
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_enable_stream);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_disable_stream);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_with_set_range);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_with_clear_range);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_size);
|
||||
tcase_add_test(tc_bitset_stream, test_bitset_stream_queued_bytes);
|
||||
suite_add_tcase(s, tc_bitset_stream);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
Suite *s = bitset_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = bitset_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -9,114 +9,104 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
struct server fake_server = {0};
|
||||
struct server fake_server = { 0 };
|
||||
|
||||
#define FAKE_SERVER &fake_server
|
||||
#define FAKE_SOCKET (42)
|
||||
|
||||
START_TEST( test_assigns_socket )
|
||||
START_TEST(test_assigns_socket)
|
||||
{
|
||||
struct client * c;
|
||||
struct client *c;
|
||||
|
||||
c = client_create( FAKE_SERVER, FAKE_SOCKET );
|
||||
c = client_create(FAKE_SERVER, FAKE_SOCKET);
|
||||
|
||||
fail_unless( 42 == c->socket, "Socket wasn't assigned." );
|
||||
fail_unless(42 == c->socket, "Socket wasn't assigned.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_assigns_server )
|
||||
END_TEST START_TEST(test_assigns_server)
|
||||
{
|
||||
struct client * c;
|
||||
/* can't predict the storage size so we can't allocate one on
|
||||
* the stack
|
||||
*/
|
||||
c = client_create( FAKE_SERVER, FAKE_SOCKET );
|
||||
struct client *c;
|
||||
/* can't predict the storage size so we can't allocate one on
|
||||
* the stack
|
||||
*/
|
||||
c = client_create(FAKE_SERVER, FAKE_SOCKET);
|
||||
|
||||
fail_unless( FAKE_SERVER == c->serve, "Serve wasn't assigned." );
|
||||
fail_unless(FAKE_SERVER == c->serve, "Serve wasn't assigned.");
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_opens_stop_signal )
|
||||
END_TEST START_TEST(test_opens_stop_signal)
|
||||
{
|
||||
struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET );
|
||||
struct client *c = client_create(FAKE_SERVER, FAKE_SOCKET);
|
||||
|
||||
client_signal_stop( c );
|
||||
client_signal_stop(c);
|
||||
|
||||
fail_unless( 1 == self_pipe_signal_clear( c->stop_signal ),
|
||||
"No signal was sent." );
|
||||
fail_unless(1 == self_pipe_signal_clear(c->stop_signal),
|
||||
"No signal was sent.");
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
END_TEST int fd_is_closed(int);
|
||||
|
||||
int fd_is_closed(int);
|
||||
|
||||
START_TEST( test_closes_stop_signal )
|
||||
START_TEST(test_closes_stop_signal)
|
||||
{
|
||||
struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET );
|
||||
int read_fd = c->stop_signal->read_fd;
|
||||
int write_fd = c->stop_signal->write_fd;
|
||||
struct client *c = client_create(FAKE_SERVER, FAKE_SOCKET);
|
||||
int read_fd = c->stop_signal->read_fd;
|
||||
int write_fd = c->stop_signal->write_fd;
|
||||
|
||||
client_destroy( c );
|
||||
client_destroy(c);
|
||||
|
||||
fail_unless( fd_is_closed( read_fd ), "Stop signal wasn't destroyed." );
|
||||
fail_unless( fd_is_closed( write_fd ), "Stop signal wasn't destroyed." );
|
||||
fail_unless(fd_is_closed(read_fd), "Stop signal wasn't destroyed.");
|
||||
fail_unless(fd_is_closed(write_fd), "Stop signal wasn't destroyed.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_read_request_quits_on_stop_signal )
|
||||
END_TEST START_TEST(test_read_request_quits_on_stop_signal)
|
||||
{
|
||||
int fds[2];
|
||||
struct nbd_request nbdr;
|
||||
pipe( fds );
|
||||
struct client *c = client_create( FAKE_SERVER, fds[0] );
|
||||
int fds[2];
|
||||
struct nbd_request nbdr;
|
||||
pipe(fds);
|
||||
struct client *c = client_create(FAKE_SERVER, fds[0]);
|
||||
|
||||
client_signal_stop( c );
|
||||
client_signal_stop(c);
|
||||
|
||||
int client_serve_request( struct client *);
|
||||
fail_unless( 1 == client_serve_request( c ), "Didn't quit on stop." );
|
||||
int client_serve_request(struct client *);
|
||||
fail_unless(1 == client_serve_request(c), "Didn't quit on stop.");
|
||||
|
||||
close( fds[0] );
|
||||
close( fds[1] );
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *client_suite(void)
|
||||
END_TEST Suite * client_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("client");
|
||||
Suite *s = suite_create("client");
|
||||
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_signal = tcase_create("signal");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_signal = tcase_create("signal");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
|
||||
tcase_add_test(tc_create, test_assigns_socket);
|
||||
tcase_add_test(tc_create, test_assigns_server);
|
||||
tcase_add_test(tc_create, test_assigns_socket);
|
||||
tcase_add_test(tc_create, test_assigns_server);
|
||||
|
||||
tcase_add_test(tc_signal, test_opens_stop_signal);
|
||||
tcase_add_test(tc_signal, test_read_request_quits_on_stop_signal);
|
||||
tcase_add_test(tc_signal, test_opens_stop_signal);
|
||||
tcase_add_test(tc_signal, test_read_request_quits_on_stop_signal);
|
||||
|
||||
tcase_add_test( tc_destroy, test_closes_stop_signal );
|
||||
tcase_add_test(tc_destroy, test_closes_stop_signal);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_signal);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_signal);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = client_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = client_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -4,39 +4,36 @@
|
||||
#include <check.h>
|
||||
|
||||
|
||||
START_TEST( test_assigns_sock_name )
|
||||
START_TEST(test_assigns_sock_name)
|
||||
{
|
||||
struct flexnbd flexnbd = {0};
|
||||
char csn[] = "foobar";
|
||||
struct flexnbd flexnbd = { 0 };
|
||||
char csn[] = "foobar";
|
||||
|
||||
struct control * control = control_create(&flexnbd, csn );
|
||||
struct control *control = control_create(&flexnbd, csn);
|
||||
|
||||
fail_unless( csn == control->socket_name, "Socket name not assigned" );
|
||||
fail_unless(csn == control->socket_name, "Socket name not assigned");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *control_suite(void)
|
||||
END_TEST Suite * control_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("control");
|
||||
Suite *s = suite_create("control");
|
||||
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
|
||||
tcase_add_test(tc_create, test_assigns_sock_name);
|
||||
suite_add_tcase( s, tc_create );
|
||||
tcase_add_test(tc_create, test_assigns_sock_name);
|
||||
suite_add_tcase(s, tc_create);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = control_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = control_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -3,42 +3,38 @@
|
||||
#include <check.h>
|
||||
|
||||
|
||||
START_TEST( test_listening_assigns_sock )
|
||||
START_TEST(test_listening_assigns_sock)
|
||||
{
|
||||
struct flexnbd * flexnbd = flexnbd_create_listening(
|
||||
"127.0.0.1",
|
||||
"4777",
|
||||
"fakefile",
|
||||
"fakesock",
|
||||
0,
|
||||
0,
|
||||
NULL );
|
||||
fail_if( NULL == flexnbd->control->socket_name, "No socket was copied" );
|
||||
struct flexnbd *flexnbd = flexnbd_create_listening("127.0.0.1",
|
||||
"4777",
|
||||
"fakefile",
|
||||
"fakesock",
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
fail_if(NULL == flexnbd->control->socket_name, "No socket was copied");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *flexnbd_suite(void)
|
||||
END_TEST Suite * flexnbd_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("flexnbd");
|
||||
Suite *s = suite_create("flexnbd");
|
||||
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
|
||||
tcase_add_test(tc_create, test_listening_assigns_sock);
|
||||
suite_add_tcase( s, tc_create );
|
||||
tcase_add_test(tc_create, test_listening_assigns_sock);
|
||||
suite_add_tcase(s, tc_create);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = flexnbd_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = flexnbd_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -4,59 +4,57 @@
|
||||
#include <check.h>
|
||||
|
||||
|
||||
START_TEST( test_mutex_create )
|
||||
START_TEST(test_mutex_create)
|
||||
{
|
||||
struct flexthread_mutex * ftm = flexthread_mutex_create();
|
||||
NULLCHECK( ftm );
|
||||
flexthread_mutex_destroy( ftm );
|
||||
struct flexthread_mutex *ftm = flexthread_mutex_create();
|
||||
NULLCHECK(ftm);
|
||||
flexthread_mutex_destroy(ftm);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_mutex_lock )
|
||||
END_TEST START_TEST(test_mutex_lock)
|
||||
{
|
||||
struct flexthread_mutex * ftm = flexthread_mutex_create();
|
||||
struct flexthread_mutex *ftm = flexthread_mutex_create();
|
||||
|
||||
fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held before lock" );
|
||||
flexthread_mutex_lock( ftm );
|
||||
fail_unless( flexthread_mutex_held( ftm ), "Flexthread_mutex is not held inside lock" );
|
||||
flexthread_mutex_unlock( ftm );
|
||||
fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held after unlock" );
|
||||
fail_if(flexthread_mutex_held(ftm),
|
||||
"Flexthread_mutex is held before lock");
|
||||
flexthread_mutex_lock(ftm);
|
||||
fail_unless(flexthread_mutex_held(ftm),
|
||||
"Flexthread_mutex is not held inside lock");
|
||||
flexthread_mutex_unlock(ftm);
|
||||
fail_if(flexthread_mutex_held(ftm),
|
||||
"Flexthread_mutex is held after unlock");
|
||||
|
||||
flexthread_mutex_destroy( ftm );
|
||||
flexthread_mutex_destroy(ftm);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* flexthread_suite(void)
|
||||
END_TEST Suite * flexthread_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("flexthread");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
Suite *s = suite_create("flexthread");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
|
||||
tcase_add_test( tc_create, test_mutex_create );
|
||||
tcase_add_test( tc_create, test_mutex_lock );
|
||||
tcase_add_test(tc_create, test_mutex_create);
|
||||
tcase_add_test(tc_create, test_mutex_lock);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
log_level = 0;
|
||||
log_level = 0;
|
||||
#else
|
||||
log_level = 2;
|
||||
log_level = 2;
|
||||
#endif
|
||||
int number_failed;
|
||||
Suite *s = flexthread_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = flexthread_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -2,133 +2,125 @@
|
||||
|
||||
#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 nread;
|
||||
char buf[5] = {0};
|
||||
pipe(fds);
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = { 0 };
|
||||
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
|
||||
|
||||
|
||||
START_TEST( test_read_until_newline_inserts_null )
|
||||
END_TEST START_TEST(test_read_until_newline_inserts_null)
|
||||
{
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = {0};
|
||||
pipe(fds);
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = { 0 };
|
||||
pipe(fds);
|
||||
|
||||
write( fds[1], "1234\n", 5 );
|
||||
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
|
||||
|
||||
|
||||
START_TEST( test_read_empty_line_inserts_null )
|
||||
END_TEST START_TEST(test_read_empty_line_inserts_null)
|
||||
{
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = {0};
|
||||
pipe(fds);
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = { 0 };
|
||||
pipe(fds);
|
||||
|
||||
write( fds[1], "\n", 1 );
|
||||
nread = read_until_newline( fds[0], buf, 1 );
|
||||
write(fds[1], "\n", 1);
|
||||
nread = read_until_newline(fds[0], buf, 1);
|
||||
|
||||
ck_assert_int_eq( '\0', buf[0] );
|
||||
ck_assert_int_eq( 1, nread );
|
||||
ck_assert_int_eq('\0', buf[0]);
|
||||
ck_assert_int_eq(1, nread);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_read_eof_returns_err )
|
||||
END_TEST START_TEST(test_read_eof_returns_err)
|
||||
{
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = {0};
|
||||
pipe( fds );
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = { 0 };
|
||||
pipe(fds);
|
||||
|
||||
close( fds[1] );
|
||||
nread = read_until_newline( fds[0], buf, 5 );
|
||||
close(fds[1]);
|
||||
nread = read_until_newline(fds[0], buf, 5);
|
||||
|
||||
ck_assert_int_eq( -1, nread );
|
||||
ck_assert_int_eq(-1, nread);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_read_eof_fills_line )
|
||||
END_TEST START_TEST(test_read_eof_fills_line)
|
||||
{
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = {0};
|
||||
pipe(fds);
|
||||
int fds[2];
|
||||
int nread;
|
||||
char buf[5] = { 0 };
|
||||
pipe(fds);
|
||||
|
||||
write( fds[1], "1234", 4 );
|
||||
close( fds[1] );
|
||||
nread = read_until_newline( fds[0], buf, 5 );
|
||||
write(fds[1], "1234", 4);
|
||||
close(fds[1]);
|
||||
nread = read_until_newline(fds[0], buf, 5);
|
||||
|
||||
ck_assert_int_eq( -1, nread );
|
||||
ck_assert_int_eq( '4', buf[3] );
|
||||
ck_assert_int_eq(-1, nread);
|
||||
ck_assert_int_eq('4', buf[3]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_read_lines_until_blankline )
|
||||
END_TEST START_TEST(test_read_lines_until_blankline)
|
||||
{
|
||||
char **lines = NULL;
|
||||
int fds[2];
|
||||
int nlines;
|
||||
pipe( fds );
|
||||
char **lines = NULL;
|
||||
int fds[2];
|
||||
int nlines;
|
||||
pipe(fds);
|
||||
|
||||
write( fds[1], "a\nb\nc\n\n", 7 );
|
||||
write(fds[1], "a\nb\nc\n\n", 7);
|
||||
|
||||
nlines = read_lines_until_blankline( fds[0], 256, &lines );
|
||||
nlines = read_lines_until_blankline(fds[0], 256, &lines);
|
||||
|
||||
ck_assert_int_eq( 3, nlines );
|
||||
ck_assert_int_eq(3, nlines);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *ioutil_suite(void)
|
||||
END_TEST Suite * ioutil_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("ioutil");
|
||||
Suite *s = suite_create("ioutil");
|
||||
|
||||
TCase *tc_read_until_newline = tcase_create("read_until_newline");
|
||||
TCase *tc_read_lines_until_blankline = tcase_create("read_lines_until_blankline");
|
||||
TCase *tc_read_until_newline = tcase_create("read_until_newline");
|
||||
TCase *tc_read_lines_until_blankline =
|
||||
tcase_create("read_lines_until_blankline");
|
||||
|
||||
tcase_add_test(tc_read_until_newline, test_read_until_newline_returns_line_length_plus_null);
|
||||
tcase_add_test(tc_read_until_newline, test_read_until_newline_inserts_null);
|
||||
tcase_add_test(tc_read_until_newline, test_read_empty_line_inserts_null);
|
||||
tcase_add_test(tc_read_until_newline, test_read_eof_returns_err);
|
||||
tcase_add_test(tc_read_until_newline, test_read_eof_fills_line );
|
||||
tcase_add_test(tc_read_until_newline,
|
||||
test_read_until_newline_returns_line_length_plus_null);
|
||||
tcase_add_test(tc_read_until_newline,
|
||||
test_read_until_newline_inserts_null);
|
||||
tcase_add_test(tc_read_until_newline,
|
||||
test_read_empty_line_inserts_null);
|
||||
tcase_add_test(tc_read_until_newline, test_read_eof_returns_err);
|
||||
tcase_add_test(tc_read_until_newline, test_read_eof_fills_line);
|
||||
|
||||
tcase_add_test(tc_read_lines_until_blankline, test_read_lines_until_blankline );
|
||||
tcase_add_test(tc_read_lines_until_blankline,
|
||||
test_read_lines_until_blankline);
|
||||
|
||||
suite_add_tcase(s, tc_read_until_newline);
|
||||
suite_add_tcase(s, tc_read_lines_until_blankline);
|
||||
suite_add_tcase(s, tc_read_until_newline);
|
||||
suite_add_tcase(s, tc_read_lines_until_blankline);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = ioutil_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = ioutil_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -4,83 +4,76 @@
|
||||
#include <pthread.h>
|
||||
#include <check.h>
|
||||
|
||||
START_TEST( test_allocs_cvar )
|
||||
START_TEST(test_allocs_cvar)
|
||||
{
|
||||
struct mbox * mbox = mbox_create();
|
||||
fail_if( NULL == mbox, "Nothing allocated" );
|
||||
struct mbox *mbox = mbox_create();
|
||||
fail_if(NULL == mbox, "Nothing allocated");
|
||||
|
||||
pthread_cond_t cond_zero;
|
||||
/* A freshly inited pthread_cond_t is set to {0} */
|
||||
memset( &cond_zero, 'X', sizeof( cond_zero ) );
|
||||
fail_if( memcmp( &cond_zero, &mbox->filled_cond, sizeof( cond_zero ) ) == 0 ,
|
||||
"Condition variable not allocated" );
|
||||
fail_if( memcmp( &cond_zero, &mbox->emptied_cond, sizeof( cond_zero ) ) == 0 ,
|
||||
"Condition variable not allocated" );
|
||||
pthread_cond_t cond_zero;
|
||||
/* A freshly inited pthread_cond_t is set to {0} */
|
||||
memset(&cond_zero, 'X', sizeof(cond_zero));
|
||||
fail_if(memcmp(&cond_zero, &mbox->filled_cond, sizeof(cond_zero)) == 0,
|
||||
"Condition variable not allocated");
|
||||
fail_if(memcmp(&cond_zero, &mbox->emptied_cond, sizeof(cond_zero)) ==
|
||||
0, "Condition variable not allocated");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_post_stores_value )
|
||||
END_TEST START_TEST(test_post_stores_value)
|
||||
{
|
||||
struct mbox * mbox = mbox_create();
|
||||
struct mbox *mbox = mbox_create();
|
||||
|
||||
void * deadbeef = (void *)0xDEADBEEF;
|
||||
mbox_post( mbox, deadbeef );
|
||||
void *deadbeef = (void *) 0xDEADBEEF;
|
||||
mbox_post(mbox, deadbeef);
|
||||
|
||||
fail_unless( deadbeef == mbox_contents( mbox ),
|
||||
"Contents were not posted" );
|
||||
fail_unless(deadbeef == mbox_contents(mbox),
|
||||
"Contents were not posted");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
void * mbox_receive_runner( void * mbox_uncast )
|
||||
END_TEST void *mbox_receive_runner(void *mbox_uncast)
|
||||
{
|
||||
struct mbox * mbox = (struct mbox *)mbox_uncast;
|
||||
void * contents = NULL;
|
||||
struct mbox *mbox = (struct mbox *) mbox_uncast;
|
||||
void *contents = NULL;
|
||||
|
||||
contents = mbox_receive( mbox );
|
||||
return contents;
|
||||
contents = mbox_receive(mbox);
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
||||
START_TEST( test_receive_blocks_until_post )
|
||||
START_TEST(test_receive_blocks_until_post)
|
||||
{
|
||||
struct mbox * mbox = mbox_create();
|
||||
pthread_t receiver;
|
||||
pthread_create( &receiver, NULL, mbox_receive_runner, mbox );
|
||||
struct mbox *mbox = mbox_create();
|
||||
pthread_t receiver;
|
||||
pthread_create(&receiver, NULL, mbox_receive_runner, mbox);
|
||||
|
||||
void * deadbeef = (void *)0xDEADBEEF;
|
||||
void * retval =NULL;
|
||||
usleep(10000);
|
||||
fail_unless( EBUSY == pthread_tryjoin_np( receiver, &retval ),
|
||||
"Receiver thread wasn't blocked");
|
||||
void *deadbeef = (void *) 0xDEADBEEF;
|
||||
void *retval = NULL;
|
||||
usleep(10000);
|
||||
fail_unless(EBUSY == pthread_tryjoin_np(receiver, &retval),
|
||||
"Receiver thread wasn't blocked");
|
||||
|
||||
mbox_post( mbox, deadbeef );
|
||||
fail_unless( 0 == pthread_join( receiver, &retval ),
|
||||
"Failed to join the receiver thread" );
|
||||
fail_unless( retval == deadbeef,
|
||||
"Return value was wrong" );
|
||||
mbox_post(mbox, deadbeef);
|
||||
fail_unless(0 == pthread_join(receiver, &retval),
|
||||
"Failed to join the receiver thread");
|
||||
fail_unless(retval == deadbeef, "Return value was wrong");
|
||||
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* mbox_suite(void)
|
||||
END_TEST Suite * mbox_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("mbox");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_post = tcase_create("post");
|
||||
Suite *s = suite_create("mbox");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_post = tcase_create("post");
|
||||
|
||||
tcase_add_test(tc_create, test_allocs_cvar);
|
||||
tcase_add_test(tc_create, test_allocs_cvar);
|
||||
|
||||
tcase_add_test( tc_post, test_post_stores_value );
|
||||
tcase_add_test( tc_post, test_receive_blocks_until_post);
|
||||
tcase_add_test(tc_post, test_post_stores_value);
|
||||
tcase_add_test(tc_post, test_receive_blocks_until_post);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_post);
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_post);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,17 +81,16 @@ Suite* mbox_suite(void)
|
||||
int main(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
log_level = 0;
|
||||
log_level = 0;
|
||||
#else
|
||||
log_level = 2;
|
||||
log_level = 2;
|
||||
#endif
|
||||
int number_failed;
|
||||
Suite *s = mbox_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = mbox_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -4,257 +4,246 @@
|
||||
|
||||
START_TEST(test_init_passwd)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
|
||||
memcpy( init_raw.passwd, INIT_PASSWD, 8 );
|
||||
memcpy(init_raw.passwd, INIT_PASSWD, 8);
|
||||
|
||||
nbd_r2h_init( &init_raw, &init );
|
||||
memset( init_raw.passwd, 0, 8 );
|
||||
nbd_h2r_init( &init, &init_raw );
|
||||
nbd_r2h_init(&init_raw, &init);
|
||||
memset(init_raw.passwd, 0, 8);
|
||||
nbd_h2r_init(&init, &init_raw);
|
||||
|
||||
fail_unless( memcmp( init.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied." );
|
||||
fail_unless( memcmp( init_raw.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied back." );
|
||||
fail_unless(memcmp(init.passwd, INIT_PASSWD, 8) == 0,
|
||||
"The password was not copied.");
|
||||
fail_unless(memcmp(init_raw.passwd, INIT_PASSWD, 8) == 0,
|
||||
"The password was not copied back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_init_magic)
|
||||
END_TEST START_TEST(test_init_magic)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
|
||||
init_raw.magic = 12345;
|
||||
nbd_r2h_init( &init_raw, &init );
|
||||
fail_unless( be64toh( 12345 ) == init.magic, "Magic was not converted." );
|
||||
init_raw.magic = 12345;
|
||||
nbd_r2h_init(&init_raw, &init);
|
||||
fail_unless(be64toh(12345) == init.magic, "Magic was not converted.");
|
||||
|
||||
init.magic = 67890;
|
||||
nbd_h2r_init( &init, &init_raw );
|
||||
fail_unless( htobe64( 67890 ) == init_raw.magic, "Magic was not converted back." );
|
||||
init.magic = 67890;
|
||||
nbd_h2r_init(&init, &init_raw);
|
||||
fail_unless(htobe64(67890) == init_raw.magic,
|
||||
"Magic was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_init_size)
|
||||
END_TEST START_TEST(test_init_size)
|
||||
{
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
struct nbd_init_raw init_raw;
|
||||
struct nbd_init init;
|
||||
|
||||
init_raw.size = 12345;
|
||||
nbd_r2h_init( &init_raw, &init );
|
||||
fail_unless( be64toh( 12345 ) == init.size, "Size was not converted." );
|
||||
init_raw.size = 12345;
|
||||
nbd_r2h_init(&init_raw, &init);
|
||||
fail_unless(be64toh(12345) == init.size, "Size was not converted.");
|
||||
|
||||
init.size = 67890;
|
||||
nbd_h2r_init( &init, &init_raw );
|
||||
fail_unless( htobe64( 67890 ) == init_raw.size, "Size was not converted back." );
|
||||
init.size = 67890;
|
||||
nbd_h2r_init(&init, &init_raw);
|
||||
fail_unless(htobe64(67890) == init_raw.size,
|
||||
"Size was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_request_magic )
|
||||
END_TEST START_TEST(test_request_magic)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
request_raw.magic = 12345;
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
fail_unless( be32toh( 12345 ) == request.magic, "Magic was not converted." );
|
||||
request_raw.magic = 12345;
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
fail_unless(be32toh(12345) == request.magic,
|
||||
"Magic was not converted.");
|
||||
|
||||
request.magic = 67890;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
fail_unless( htobe32( 67890 ) == request_raw.magic, "Magic was not converted back." );
|
||||
request.magic = 67890;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
fail_unless(htobe32(67890) == request_raw.magic,
|
||||
"Magic was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_request_type)
|
||||
END_TEST START_TEST(test_request_type)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
request_raw.type = 123;
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
fail_unless( be16toh( 123 ) == request.type, "Type was not converted." );
|
||||
request_raw.type = 123;
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
fail_unless(be16toh(123) == request.type, "Type was not converted.");
|
||||
|
||||
request.type = 234;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
fail_unless( htobe16( 234 ) == request_raw.type, "Type was not converted back." );
|
||||
request.type = 234;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
fail_unless(htobe16(234) == request_raw.type,
|
||||
"Type was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
START_TEST(test_request_flags)
|
||||
END_TEST START_TEST(test_request_flags)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
request_raw.flags = 123;
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
fail_unless( be16toh( 123 ) == request.flags, "Flags were not converted." );
|
||||
request_raw.flags = 123;
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
fail_unless(be16toh(123) == request.flags,
|
||||
"Flags were not converted.");
|
||||
|
||||
request.flags = 234;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
fail_unless( htobe16( 234 ) == request_raw.flags, "Flags were not converted back." );
|
||||
request.flags = 234;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
fail_unless(htobe16(234) == request_raw.flags,
|
||||
"Flags were not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
START_TEST(test_request_handle)
|
||||
END_TEST START_TEST(test_request_handle)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
memcpy( request_raw.handle.b, "MYHANDLE", 8 );
|
||||
memcpy(request_raw.handle.b, "MYHANDLE", 8);
|
||||
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
request_raw.handle.w = 0;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
request_raw.handle.w = 0;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
|
||||
fail_unless( memcmp( request.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
||||
fail_unless( memcmp( request_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
||||
fail_unless(memcmp(request.handle.b, "MYHANDLE", 8) == 0,
|
||||
"The handle was not copied.");
|
||||
fail_unless(memcmp(request_raw.handle.b, "MYHANDLE", 8) == 0,
|
||||
"The handle was not copied back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
START_TEST(test_request_from )
|
||||
END_TEST START_TEST(test_request_from)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
request_raw.from = 12345;
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
fail_unless( be64toh( 12345 ) == request.from, "From was not converted." );
|
||||
request_raw.from = 12345;
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
fail_unless(be64toh(12345) == request.from, "From was not converted.");
|
||||
|
||||
request.from = 67890;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
fail_unless( htobe64( 67890 ) == request_raw.from, "From was not converted back." );
|
||||
request.from = 67890;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
fail_unless(htobe64(67890) == request_raw.from,
|
||||
"From was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
START_TEST(test_request_len )
|
||||
END_TEST START_TEST(test_request_len)
|
||||
{
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
request_raw.len = 12345;
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
fail_unless( be32toh( 12345 ) == request.len, "Type was not converted." );
|
||||
request_raw.len = 12345;
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
fail_unless(be32toh(12345) == request.len, "Type was not converted.");
|
||||
|
||||
request.len = 67890;
|
||||
nbd_h2r_request( &request, &request_raw );
|
||||
fail_unless( htobe32( 67890 ) == request_raw.len, "Type was not converted back." );
|
||||
request.len = 67890;
|
||||
nbd_h2r_request(&request, &request_raw);
|
||||
fail_unless(htobe32(67890) == request_raw.len,
|
||||
"Type was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_reply_magic )
|
||||
END_TEST START_TEST(test_reply_magic)
|
||||
{
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
|
||||
reply_raw.magic = 12345;
|
||||
nbd_r2h_reply( &reply_raw, &reply );
|
||||
fail_unless( be32toh( 12345 ) == reply.magic, "Magic was not converted." );
|
||||
reply_raw.magic = 12345;
|
||||
nbd_r2h_reply(&reply_raw, &reply);
|
||||
fail_unless(be32toh(12345) == reply.magic, "Magic was not converted.");
|
||||
|
||||
reply.magic = 67890;
|
||||
nbd_h2r_reply( &reply, &reply_raw );
|
||||
fail_unless( htobe32( 67890 ) == reply_raw.magic, "Magic was not converted back." );
|
||||
reply.magic = 67890;
|
||||
nbd_h2r_reply(&reply, &reply_raw);
|
||||
fail_unless(htobe32(67890) == reply_raw.magic,
|
||||
"Magic was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_reply_error )
|
||||
END_TEST START_TEST(test_reply_error)
|
||||
{
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
|
||||
reply_raw.error = 12345;
|
||||
nbd_r2h_reply( &reply_raw, &reply );
|
||||
fail_unless( be32toh( 12345 ) == reply.error, "Error was not converted." );
|
||||
reply_raw.error = 12345;
|
||||
nbd_r2h_reply(&reply_raw, &reply);
|
||||
fail_unless(be32toh(12345) == reply.error, "Error was not converted.");
|
||||
|
||||
reply.error = 67890;
|
||||
nbd_h2r_reply( &reply, &reply_raw );
|
||||
fail_unless( htobe32( 67890 ) == reply_raw.error, "Error was not converted back." );
|
||||
reply.error = 67890;
|
||||
nbd_h2r_reply(&reply, &reply_raw);
|
||||
fail_unless(htobe32(67890) == reply_raw.error,
|
||||
"Error was not converted back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_reply_handle)
|
||||
END_TEST START_TEST(test_reply_handle)
|
||||
{
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
struct nbd_reply_raw reply_raw;
|
||||
struct nbd_reply reply;
|
||||
|
||||
memcpy( reply_raw.handle.b, "MYHANDLE", 8 );
|
||||
memcpy(reply_raw.handle.b, "MYHANDLE", 8);
|
||||
|
||||
nbd_r2h_reply( &reply_raw, &reply );
|
||||
reply_raw.handle.w = 0;
|
||||
nbd_h2r_reply( &reply, &reply_raw );
|
||||
nbd_r2h_reply(&reply_raw, &reply);
|
||||
reply_raw.handle.w = 0;
|
||||
nbd_h2r_reply(&reply, &reply_raw);
|
||||
|
||||
fail_unless( memcmp( reply.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
||||
fail_unless( memcmp( reply_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
||||
fail_unless(memcmp(reply.handle.b, "MYHANDLE", 8) == 0,
|
||||
"The handle was not copied.");
|
||||
fail_unless(memcmp(reply_raw.handle.b, "MYHANDLE", 8) == 0,
|
||||
"The handle was not copied back.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_convert_from )
|
||||
END_TEST START_TEST(test_convert_from)
|
||||
{
|
||||
/* Check that we can correctly pull numbers out of an
|
||||
* nbd_request_raw */
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
/* Check that we can correctly pull numbers out of an
|
||||
* nbd_request_raw */
|
||||
struct nbd_request_raw request_raw;
|
||||
struct nbd_request request;
|
||||
|
||||
uint64_t target = 0x8000000000000000;
|
||||
uint64_t target = 0x8000000000000000;
|
||||
|
||||
/* this is stored big-endian */
|
||||
request_raw.from = htobe64(target);
|
||||
/* this is stored big-endian */
|
||||
request_raw.from = htobe64(target);
|
||||
|
||||
/* We expect this to convert big-endian to the host format */
|
||||
nbd_r2h_request( &request_raw, &request );
|
||||
/* We expect this to convert big-endian to the host format */
|
||||
nbd_r2h_request(&request_raw, &request);
|
||||
|
||||
fail_unless( target == request.from, "from was wrong" );
|
||||
fail_unless(target == request.from, "from was wrong");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *nbdtypes_suite(void)
|
||||
END_TEST Suite * nbdtypes_suite(void)
|
||||
{
|
||||
Suite *s = suite_create( "nbdtypes" );
|
||||
TCase *tc_init = tcase_create( "nbd_init" );
|
||||
TCase *tc_request = tcase_create( "nbd_request" );
|
||||
TCase *tc_reply = tcase_create( "nbd_reply" );
|
||||
Suite *s = suite_create("nbdtypes");
|
||||
TCase *tc_init = tcase_create("nbd_init");
|
||||
TCase *tc_request = tcase_create("nbd_request");
|
||||
TCase *tc_reply = tcase_create("nbd_reply");
|
||||
|
||||
tcase_add_test( tc_init, test_init_passwd );
|
||||
tcase_add_test( tc_init, test_init_magic );
|
||||
tcase_add_test( tc_init, test_init_size );
|
||||
tcase_add_test( tc_request, test_request_magic );
|
||||
tcase_add_test( tc_request, test_request_type );
|
||||
tcase_add_test( tc_request, test_request_handle );
|
||||
tcase_add_test( tc_request, test_request_from );
|
||||
tcase_add_test( tc_request, test_request_len );
|
||||
tcase_add_test( tc_request, test_convert_from );
|
||||
tcase_add_test( tc_reply, test_reply_magic );
|
||||
tcase_add_test( tc_reply, test_reply_error );
|
||||
tcase_add_test( tc_reply, test_reply_handle );
|
||||
tcase_add_test(tc_init, test_init_passwd);
|
||||
tcase_add_test(tc_init, test_init_magic);
|
||||
tcase_add_test(tc_init, test_init_size);
|
||||
tcase_add_test(tc_request, test_request_magic);
|
||||
tcase_add_test(tc_request, test_request_type);
|
||||
tcase_add_test(tc_request, test_request_handle);
|
||||
tcase_add_test(tc_request, test_request_from);
|
||||
tcase_add_test(tc_request, test_request_len);
|
||||
tcase_add_test(tc_request, test_convert_from);
|
||||
tcase_add_test(tc_reply, test_reply_magic);
|
||||
tcase_add_test(tc_reply, test_reply_error);
|
||||
tcase_add_test(tc_reply, test_reply_handle);
|
||||
|
||||
suite_add_tcase( s, tc_init );
|
||||
suite_add_tcase( s, tc_request );
|
||||
suite_add_tcase( s, tc_reply );
|
||||
suite_add_tcase(s, tc_init);
|
||||
suite_add_tcase(s, tc_request);
|
||||
suite_add_tcase(s, tc_reply);
|
||||
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
Suite *s = nbdtypes_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = nbdtypes_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -3,45 +3,41 @@
|
||||
|
||||
#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";
|
||||
struct sockaddr saddr;
|
||||
char ip_address[] = "127.0.0.1";
|
||||
struct sockaddr saddr;
|
||||
|
||||
parse_ip_to_sockaddr( &saddr, ip_address );
|
||||
parse_ip_to_sockaddr( &saddr, ip_address );
|
||||
parse_ip_to_sockaddr(&saddr, ip_address);
|
||||
parse_ip_to_sockaddr(&saddr, ip_address);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
Suite* parse_suite(void)
|
||||
END_TEST Suite * parse_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("parse");
|
||||
TCase *tc_create = tcase_create("ip_to_sockaddr");
|
||||
Suite *s = suite_create("parse");
|
||||
TCase *tc_create = tcase_create("ip_to_sockaddr");
|
||||
|
||||
tcase_add_test(tc_create, test_can_parse_ip_address_twice);
|
||||
tcase_add_test(tc_create, test_can_parse_ip_address_twice);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_create);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_LEVEL 0
|
||||
#define LOG_LEVEL 0
|
||||
#else
|
||||
# define LOG_LEVEL 2
|
||||
#define LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
log_level = LOG_LEVEL;
|
||||
int number_failed;
|
||||
Suite *s = parse_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
log_level = LOG_LEVEL;
|
||||
int number_failed;
|
||||
Suite *s = parse_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -21,173 +21,169 @@
|
||||
|
||||
|
||||
|
||||
int fd_read_request( int, struct nbd_request_raw *);
|
||||
int fd_write_reply( int, uint64_t, int );
|
||||
int fd_read_request(int, struct nbd_request_raw *);
|
||||
int fd_write_reply(int, uint64_t, int);
|
||||
|
||||
int marker;
|
||||
|
||||
void error_marker(void * unused __attribute__((unused)),
|
||||
int fatal __attribute__((unused)))
|
||||
void error_marker(void *unused __attribute__ ((unused)),
|
||||
int fatal __attribute__ ((unused)))
|
||||
{
|
||||
marker = 1;
|
||||
return;
|
||||
marker = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
struct respond {
|
||||
int sock_fds[2]; // server end
|
||||
int do_fail;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
struct nbd_request received;
|
||||
int sock_fds[2]; // server end
|
||||
int do_fail;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
struct nbd_request received;
|
||||
};
|
||||
|
||||
void * responder( void *respond_uncast )
|
||||
void *responder(void *respond_uncast)
|
||||
{
|
||||
struct respond * resp = (struct respond *) respond_uncast;
|
||||
int sock_fd = resp->sock_fds[1];
|
||||
struct nbd_request_raw request_raw;
|
||||
uint64_t wrong_handle = 0x80;
|
||||
struct respond *resp = (struct respond *) respond_uncast;
|
||||
int sock_fd = resp->sock_fds[1];
|
||||
struct nbd_request_raw request_raw;
|
||||
uint64_t wrong_handle = 0x80;
|
||||
|
||||
if( fd_read_request( sock_fd, &request_raw ) == -1){
|
||||
fprintf(stderr, "Problem with fd_read_request\n");
|
||||
if (fd_read_request(sock_fd, &request_raw) == -1) {
|
||||
fprintf(stderr, "Problem with fd_read_request\n");
|
||||
} else {
|
||||
nbd_r2h_request(&request_raw, &resp->received);
|
||||
if (resp->do_fail) {
|
||||
fd_write_reply(sock_fd, wrong_handle, 0);
|
||||
} else {
|
||||
nbd_r2h_request( &request_raw, &resp->received);
|
||||
if (resp->do_fail){
|
||||
fd_write_reply( sock_fd, wrong_handle, 0 );
|
||||
}
|
||||
else {
|
||||
fd_write_reply( sock_fd, resp->received.handle.w, 0 );
|
||||
}
|
||||
write( sock_fd, "12345678", 8 );
|
||||
fd_write_reply(sock_fd, resp->received.handle.w, 0);
|
||||
}
|
||||
return NULL;
|
||||
write(sock_fd, "12345678", 8);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct respond * respond_create( int do_fail )
|
||||
struct respond *respond_create(int do_fail)
|
||||
{
|
||||
struct respond * respond = (struct respond *)calloc( 1, sizeof( struct respond ) );
|
||||
socketpair( PF_UNIX, SOCK_STREAM, 0, respond->sock_fds );
|
||||
respond->do_fail = do_fail;
|
||||
struct respond *respond =
|
||||
(struct respond *) calloc(1, sizeof(struct respond));
|
||||
socketpair(PF_UNIX, SOCK_STREAM, 0, respond->sock_fds);
|
||||
respond->do_fail = do_fail;
|
||||
|
||||
pthread_attr_init( &respond->thread_attr );
|
||||
pthread_create( &respond->thread_id, &respond->thread_attr, responder, respond );
|
||||
pthread_attr_init(&respond->thread_attr);
|
||||
pthread_create(&respond->thread_id, &respond->thread_attr, responder,
|
||||
respond);
|
||||
|
||||
return respond;
|
||||
return respond;
|
||||
}
|
||||
|
||||
void respond_destroy( struct respond * respond ){
|
||||
NULLCHECK( respond );
|
||||
|
||||
pthread_join( respond->thread_id, NULL );
|
||||
pthread_attr_destroy( &respond->thread_attr );
|
||||
|
||||
close( respond->sock_fds[0] );
|
||||
close( respond->sock_fds[1] );
|
||||
free( respond );
|
||||
}
|
||||
|
||||
|
||||
void * reader( void * nothing __attribute__((unused)))
|
||||
void respond_destroy(struct respond *respond)
|
||||
{
|
||||
DECLARE_ERROR_CONTEXT( error_context );
|
||||
error_set_handler( (cleanup_handler *)error_marker, error_context );
|
||||
NULLCHECK(respond);
|
||||
|
||||
struct respond * respond = respond_create( 1 );
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
char outbuf[8] = {0};
|
||||
pthread_join(respond->thread_id, NULL);
|
||||
pthread_attr_destroy(&respond->thread_attr);
|
||||
|
||||
socket_nbd_read( respond->sock_fds[0], 0, 8, devnull, outbuf, 1 );
|
||||
|
||||
return NULL;
|
||||
close(respond->sock_fds[0]);
|
||||
close(respond->sock_fds[1]);
|
||||
free(respond);
|
||||
}
|
||||
|
||||
START_TEST( test_rejects_mismatched_handle )
|
||||
|
||||
void *reader(void *nothing __attribute__ ((unused)))
|
||||
{
|
||||
DECLARE_ERROR_CONTEXT(error_context);
|
||||
error_set_handler((cleanup_handler *) error_marker, error_context);
|
||||
|
||||
struct respond *respond = respond_create(1);
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
char outbuf[8] = { 0 };
|
||||
|
||||
socket_nbd_read(respond->sock_fds[0], 0, 8, devnull, outbuf, 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
START_TEST(test_rejects_mismatched_handle)
|
||||
{
|
||||
|
||||
error_init();
|
||||
pthread_t reader_thread;
|
||||
error_init();
|
||||
pthread_t reader_thread;
|
||||
|
||||
log_level=5;
|
||||
log_level = 5;
|
||||
|
||||
marker = 0;
|
||||
pthread_create( &reader_thread, NULL, reader, NULL );
|
||||
FATAL_UNLESS( 0 == pthread_join( reader_thread, NULL ),
|
||||
"pthread_join failed");
|
||||
marker = 0;
|
||||
pthread_create(&reader_thread, NULL, reader, NULL);
|
||||
FATAL_UNLESS(0 == pthread_join(reader_thread, NULL),
|
||||
"pthread_join failed");
|
||||
|
||||
log_level=2;
|
||||
log_level = 2;
|
||||
|
||||
fail_unless( marker == 1, "Error handler wasn't called" );
|
||||
fail_unless(marker == 1, "Error handler wasn't called");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_accepts_matched_handle )
|
||||
END_TEST START_TEST(test_accepts_matched_handle)
|
||||
{
|
||||
struct respond * respond = respond_create( 0 );
|
||||
struct respond *respond = respond_create(0);
|
||||
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
char outbuf[8] = {0};
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
char outbuf[8] = { 0 };
|
||||
|
||||
socket_nbd_read( respond->sock_fds[0], 0, 8, devnull, outbuf, 1 );
|
||||
socket_nbd_read(respond->sock_fds[0], 0, 8, devnull, outbuf, 1);
|
||||
|
||||
respond_destroy( respond );
|
||||
respond_destroy(respond);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_disconnect_doesnt_read_reply )
|
||||
END_TEST START_TEST(test_disconnect_doesnt_read_reply)
|
||||
{
|
||||
struct respond * respond = respond_create( 1 );
|
||||
struct respond *respond = respond_create(1);
|
||||
|
||||
socket_nbd_disconnect( respond->sock_fds[0] );
|
||||
socket_nbd_disconnect(respond->sock_fds[0]);
|
||||
|
||||
respond_destroy( respond );
|
||||
respond_destroy(respond);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* readwrite_suite(void)
|
||||
END_TEST Suite * readwrite_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("readwrite");
|
||||
TCase *tc_transfer = tcase_create("entrust");
|
||||
TCase *tc_disconnect = tcase_create("disconnect");
|
||||
Suite *s = suite_create("readwrite");
|
||||
TCase *tc_transfer = tcase_create("entrust");
|
||||
TCase *tc_disconnect = tcase_create("disconnect");
|
||||
|
||||
|
||||
tcase_add_test(tc_transfer, test_rejects_mismatched_handle);
|
||||
tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0);
|
||||
tcase_add_test(tc_transfer, test_rejects_mismatched_handle);
|
||||
tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0);
|
||||
|
||||
/* This test is a little funny. We respond with a dodgy handle
|
||||
* and check that this *doesn't* cause a message rejection,
|
||||
* because we want to know that the sender won't even try to
|
||||
* read the response.
|
||||
*/
|
||||
tcase_add_exit_test( tc_disconnect, test_disconnect_doesnt_read_reply,0 );
|
||||
/* This test is a little funny. We respond with a dodgy handle
|
||||
* and check that this *doesn't* cause a message rejection,
|
||||
* because we want to know that the sender won't even try to
|
||||
* read the response.
|
||||
*/
|
||||
tcase_add_exit_test(tc_disconnect, test_disconnect_doesnt_read_reply,
|
||||
0);
|
||||
|
||||
suite_add_tcase(s, tc_transfer);
|
||||
suite_add_tcase(s, tc_disconnect);
|
||||
suite_add_tcase(s, tc_transfer);
|
||||
suite_add_tcase(s, tc_disconnect);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_LEVEL 0
|
||||
#define LOG_LEVEL 0
|
||||
#else
|
||||
# define LOG_LEVEL 2
|
||||
#define LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
log_level = LOG_LEVEL;
|
||||
int number_failed;
|
||||
Suite *s = readwrite_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
log_level = LOG_LEVEL;
|
||||
int number_failed;
|
||||
Suite *s = readwrite_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
log_level = 0;
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -9,190 +9,180 @@
|
||||
|
||||
#include "self_pipe.h"
|
||||
|
||||
START_TEST( test_opens_pipe )
|
||||
START_TEST(test_opens_pipe)
|
||||
{
|
||||
struct self_pipe* sig;
|
||||
char buf[] = " ";
|
||||
struct self_pipe *sig;
|
||||
char buf[] = " ";
|
||||
|
||||
sig = self_pipe_create();
|
||||
sig = self_pipe_create();
|
||||
|
||||
write( sig->write_fd, "1", 1 );
|
||||
read( sig->read_fd, buf, 1 );
|
||||
write(sig->write_fd, "1", 1);
|
||||
read(sig->read_fd, buf, 1);
|
||||
|
||||
fail_unless( buf[0] == '1', "Pipe does not seem to be open;" );
|
||||
self_pipe_destroy( sig );
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
void * signal_thread( void * thing )
|
||||
{
|
||||
struct self_pipe *sig = (struct self_pipe *)thing;
|
||||
usleep( 100000 );
|
||||
self_pipe_signal( sig );
|
||||
return NULL;
|
||||
fail_unless(buf[0] == '1', "Pipe does not seem to be open;");
|
||||
self_pipe_destroy(sig);
|
||||
}
|
||||
|
||||
pthread_t start_signal_thread( struct self_pipe *sig )
|
||||
END_TEST void *signal_thread(void *thing)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t thread_id;
|
||||
struct self_pipe *sig = (struct self_pipe *) thing;
|
||||
usleep(100000);
|
||||
self_pipe_signal(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_attr_init( &attr );
|
||||
pthread_create( &thread_id, &attr, signal_thread, sig );
|
||||
pthread_attr_destroy( &attr );
|
||||
pthread_t start_signal_thread(struct self_pipe * sig)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t thread_id;
|
||||
|
||||
return thread_id;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&thread_id, &attr, signal_thread, sig);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
|
||||
START_TEST( test_signals )
|
||||
START_TEST(test_signals)
|
||||
{
|
||||
struct self_pipe* sig;
|
||||
fd_set fds;
|
||||
pthread_t signal_thread_id;
|
||||
struct self_pipe *sig;
|
||||
fd_set fds;
|
||||
pthread_t signal_thread_id;
|
||||
|
||||
sig = self_pipe_create();
|
||||
sig = self_pipe_create();
|
||||
|
||||
FD_ZERO( &fds );
|
||||
self_pipe_fd_set( sig, &fds );
|
||||
FD_ZERO(&fds);
|
||||
self_pipe_fd_set(sig, &fds);
|
||||
|
||||
signal_thread_id = start_signal_thread( sig );
|
||||
if ( select( FD_SETSIZE, &fds, NULL, NULL, NULL ) == -1 ) {
|
||||
fail( strerror(errno) );
|
||||
signal_thread_id = start_signal_thread(sig);
|
||||
if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) == -1) {
|
||||
fail(strerror(errno));
|
||||
}
|
||||
self_pipe_signal_clear(sig);
|
||||
|
||||
fail_unless(self_pipe_fd_isset(sig, &fds),
|
||||
"Signalled pipe was not FD_ISSET.");
|
||||
pthread_join(signal_thread_id, NULL);
|
||||
|
||||
self_pipe_destroy(sig);
|
||||
}
|
||||
|
||||
END_TEST START_TEST(test_clear_returns_immediately)
|
||||
{
|
||||
struct self_pipe *sig;
|
||||
sig = self_pipe_create();
|
||||
fail_unless(0 == self_pipe_signal_clear(sig), "Wrong clear result.");
|
||||
}
|
||||
|
||||
END_TEST START_TEST(test_destroy_closes_read_pipe)
|
||||
{
|
||||
struct self_pipe *sig;
|
||||
ssize_t read_len;
|
||||
int orig_read_fd;
|
||||
|
||||
sig = self_pipe_create();
|
||||
orig_read_fd = sig->read_fd;
|
||||
self_pipe_destroy(sig);
|
||||
|
||||
while ((read_len = read(orig_read_fd, "", 0)) == -1 && errno == EINTR);
|
||||
|
||||
switch (read_len) {
|
||||
case 0:
|
||||
fail("The read fd wasn't closed.");
|
||||
break;
|
||||
case -1:
|
||||
switch (errno) {
|
||||
case EBADF:
|
||||
/* This is what we want */
|
||||
break;
|
||||
case EAGAIN:
|
||||
fail("The read fd wasn't closed.");
|
||||
break;
|
||||
default:
|
||||
fail(strerror(errno));
|
||||
break;
|
||||
}
|
||||
self_pipe_signal_clear( sig );
|
||||
|
||||
fail_unless( self_pipe_fd_isset( sig, &fds ), "Signalled pipe was not FD_ISSET." );
|
||||
pthread_join( signal_thread_id, NULL );
|
||||
|
||||
self_pipe_destroy( sig );
|
||||
break;
|
||||
default:
|
||||
fail("The read fd wasn't closed, and had data in it.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_clear_returns_immediately )
|
||||
END_TEST START_TEST(test_destroy_closes_write_pipe)
|
||||
{
|
||||
struct self_pipe *sig;
|
||||
sig = self_pipe_create();
|
||||
fail_unless( 0 == self_pipe_signal_clear( sig ), "Wrong clear result." );
|
||||
}
|
||||
END_TEST
|
||||
struct self_pipe *sig;
|
||||
ssize_t write_len;
|
||||
int orig_write_fd;
|
||||
|
||||
sig = self_pipe_create();
|
||||
orig_write_fd = sig->write_fd;
|
||||
self_pipe_destroy(sig);
|
||||
|
||||
START_TEST( test_destroy_closes_read_pipe )
|
||||
{
|
||||
struct self_pipe* sig;
|
||||
ssize_t read_len;
|
||||
int orig_read_fd;
|
||||
while ((write_len = write(orig_write_fd, "", 0)) == -1
|
||||
&& errno == EINTR);
|
||||
|
||||
sig = self_pipe_create();
|
||||
orig_read_fd = sig->read_fd;
|
||||
self_pipe_destroy( sig );
|
||||
|
||||
while( (read_len = read( orig_read_fd, "", 0 )) == -1 && errno == EINTR );
|
||||
|
||||
switch( read_len ) {
|
||||
case 0:
|
||||
fail("The read fd wasn't closed." );
|
||||
break;
|
||||
case -1:
|
||||
switch(errno) {
|
||||
case EBADF:
|
||||
/* This is what we want */
|
||||
break;
|
||||
case EAGAIN:
|
||||
fail( "The read fd wasn't closed." );
|
||||
break;
|
||||
default:
|
||||
fail( strerror( errno ) );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fail( "The read fd wasn't closed, and had data in it." );
|
||||
break;
|
||||
switch (write_len) {
|
||||
case 0:
|
||||
fail("The write fd wasn't closed.");
|
||||
break;
|
||||
case -1:
|
||||
switch (errno) {
|
||||
case EPIPE:
|
||||
case EBADF:
|
||||
/* This is what we want */
|
||||
break;
|
||||
case EAGAIN:
|
||||
fail("The write fd wasn't closed.");
|
||||
break;
|
||||
default:
|
||||
fail(strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_destroy_closes_write_pipe )
|
||||
{
|
||||
struct self_pipe * sig;
|
||||
ssize_t write_len;
|
||||
int orig_write_fd;
|
||||
|
||||
sig = self_pipe_create();
|
||||
orig_write_fd = sig->write_fd;
|
||||
self_pipe_destroy( sig );
|
||||
|
||||
while ( ( write_len = write( orig_write_fd, "", 0 ) ) == -1 && errno == EINTR );
|
||||
|
||||
switch( write_len ) {
|
||||
case 0:
|
||||
fail( "The write fd wasn't closed." );
|
||||
break;
|
||||
case -1:
|
||||
switch( errno ) {
|
||||
case EPIPE:
|
||||
case EBADF:
|
||||
/* This is what we want */
|
||||
break;
|
||||
case EAGAIN:
|
||||
fail("The write fd wasn't closed." );
|
||||
break;
|
||||
default:
|
||||
fail( strerror( errno ) );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* To get here, the write(_,_,0) would have to
|
||||
* write some bytes.
|
||||
*/
|
||||
fail( "The write fd wasn't closed, and something REALLY WEIRD is going on." );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
|
||||
Suite *self_pipe_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("self_pipe");
|
||||
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_signal = tcase_create("signal");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
|
||||
tcase_add_test(tc_create, test_opens_pipe);
|
||||
tcase_add_test(tc_signal, test_signals );
|
||||
tcase_add_test(tc_signal, test_clear_returns_immediately );
|
||||
tcase_add_test(tc_destroy, test_destroy_closes_read_pipe );
|
||||
tcase_add_test(tc_destroy, test_destroy_closes_write_pipe );
|
||||
/* We don't test that destroy free()'s the self_pipe pointer because
|
||||
* that'll be caught by valgrind.
|
||||
break;
|
||||
default:
|
||||
/* To get here, the write(_,_,0) would have to
|
||||
* write some bytes.
|
||||
*/
|
||||
fail("The write fd wasn't closed, and something REALLY WEIRD is going on.");
|
||||
break;
|
||||
}
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_signal);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
}
|
||||
|
||||
return s;
|
||||
END_TEST Suite * self_pipe_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("self_pipe");
|
||||
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_signal = tcase_create("signal");
|
||||
TCase *tc_destroy = tcase_create("destroy");
|
||||
|
||||
tcase_add_test(tc_create, test_opens_pipe);
|
||||
tcase_add_test(tc_signal, test_signals);
|
||||
tcase_add_test(tc_signal, test_clear_returns_immediately);
|
||||
tcase_add_test(tc_destroy, test_destroy_closes_read_pipe);
|
||||
tcase_add_test(tc_destroy, test_destroy_closes_write_pipe);
|
||||
/* We don't test that destroy free()'s the self_pipe pointer because
|
||||
* that'll be caught by valgrind.
|
||||
*/
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_signal);
|
||||
suite_add_tcase(s, tc_destroy);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = self_pipe_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = self_pipe_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -15,9 +15,9 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_LEVEL 0
|
||||
#define LOG_LEVEL 0
|
||||
#else
|
||||
# define LOG_LEVEL 2
|
||||
#define LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
|
||||
@@ -28,237 +28,245 @@
|
||||
#define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0)
|
||||
#define myfail_unless( tst, msg ) myfail_if( !(tst), msg )
|
||||
|
||||
char * dummy_file;
|
||||
char *dummy_file;
|
||||
|
||||
char *make_tmpfile(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *fn_buf;
|
||||
char leader[] = "/tmp/check_serve";
|
||||
FILE *fp;
|
||||
char *fn_buf;
|
||||
char leader[] = "/tmp/check_serve";
|
||||
|
||||
fn_buf = (char *)malloc( 1024 );
|
||||
strncpy( fn_buf, leader, sizeof( leader ) - 1);
|
||||
snprintf( &fn_buf[sizeof( leader ) - 1], 10, "%d", getpid() );
|
||||
fp = fopen( fn_buf, "w" );
|
||||
fwrite( fn_buf, 1024, 1, fp );
|
||||
fclose( fp );
|
||||
fn_buf = (char *) malloc(1024);
|
||||
strncpy(fn_buf, leader, sizeof(leader) - 1);
|
||||
snprintf(&fn_buf[sizeof(leader) - 1], 10, "%d", getpid());
|
||||
fp = fopen(fn_buf, "w");
|
||||
fwrite(fn_buf, 1024, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
return fn_buf;
|
||||
return fn_buf;
|
||||
}
|
||||
|
||||
|
||||
void setup( void )
|
||||
void setup(void)
|
||||
{
|
||||
dummy_file = make_tmpfile();
|
||||
dummy_file = make_tmpfile();
|
||||
}
|
||||
|
||||
void teardown( void )
|
||||
void teardown(void)
|
||||
{
|
||||
if( dummy_file ){ unlink( dummy_file ); }
|
||||
free( dummy_file );
|
||||
dummy_file = NULL;
|
||||
if (dummy_file) {
|
||||
unlink(dummy_file);
|
||||
}
|
||||
free(dummy_file);
|
||||
dummy_file = NULL;
|
||||
}
|
||||
|
||||
|
||||
START_TEST( test_replaces_acl )
|
||||
START_TEST(test_replaces_acl)
|
||||
{
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 );
|
||||
struct acl * new_acl = acl_create( 0, NULL, 0 );
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server *s =
|
||||
server_create(&flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL,
|
||||
1, 0, 1);
|
||||
struct acl *new_acl = acl_create(0, NULL, 0);
|
||||
|
||||
server_replace_acl( s, new_acl );
|
||||
server_replace_acl(s, new_acl);
|
||||
|
||||
myfail_unless( s->acl == new_acl, "ACL wasn't replaced." );
|
||||
server_destroy( s );
|
||||
myfail_unless(s->acl == new_acl, "ACL wasn't replaced.");
|
||||
server_destroy(s);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_signals_acl_updated )
|
||||
END_TEST START_TEST(test_signals_acl_updated)
|
||||
{
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 0, 1 );
|
||||
struct acl * new_acl = acl_create( 0, NULL, 0 );
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server *s =
|
||||
server_create(&flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL,
|
||||
1, 0, 1);
|
||||
struct acl *new_acl = acl_create(0, NULL, 0);
|
||||
|
||||
server_replace_acl( s, new_acl );
|
||||
server_replace_acl(s, new_acl);
|
||||
|
||||
myfail_unless( 1 == self_pipe_signal_clear( s->acl_updated_signal ),
|
||||
"No signal sent." );
|
||||
server_destroy( s );
|
||||
myfail_unless(1 == self_pipe_signal_clear(s->acl_updated_signal),
|
||||
"No signal sent.");
|
||||
server_destroy(s);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
int connect_client( char *addr, int actual_port, char *source_addr )
|
||||
END_TEST int connect_client(char *addr, int actual_port, char *source_addr)
|
||||
{
|
||||
int client_fd = -1;
|
||||
int client_fd = -1;
|
||||
|
||||
struct addrinfo hint;
|
||||
struct addrinfo *ailist, *aip;
|
||||
struct addrinfo hint;
|
||||
struct addrinfo *ailist, *aip;
|
||||
|
||||
|
||||
|
||||
|
||||
memset( &hint, '\0', sizeof( struct addrinfo ) );
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
memset(&hint, '\0', sizeof(struct addrinfo));
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
myfail_if( getaddrinfo( addr, NULL, &hint, &ailist ) != 0, "getaddrinfo failed." );
|
||||
myfail_if(getaddrinfo(addr, NULL, &hint, &ailist) != 0,
|
||||
"getaddrinfo failed.");
|
||||
|
||||
int connected = 0;
|
||||
for( aip = ailist; aip; aip = aip->ai_next ) {
|
||||
((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port );
|
||||
client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol );
|
||||
int connected = 0;
|
||||
for (aip = ailist; aip; aip = aip->ai_next) {
|
||||
((struct sockaddr_in *) aip->ai_addr)->sin_port =
|
||||
htons(actual_port);
|
||||
client_fd =
|
||||
socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
|
||||
|
||||
if (source_addr) {
|
||||
struct sockaddr src;
|
||||
if( !parse_ip_to_sockaddr(&src, source_addr)) {
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
bind(client_fd, &src, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
if( client_fd == -1) { continue; }
|
||||
if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) {
|
||||
connected = 1;
|
||||
break;
|
||||
}
|
||||
close( client_fd );
|
||||
if (source_addr) {
|
||||
struct sockaddr src;
|
||||
if (!parse_ip_to_sockaddr(&src, source_addr)) {
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
bind(client_fd, &src, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
myfail_unless( connected, "Didn't connect." );
|
||||
return client_fd;
|
||||
if (client_fd == -1) {
|
||||
continue;
|
||||
}
|
||||
if (connect(client_fd, aip->ai_addr, aip->ai_addrlen) == 0) {
|
||||
connected = 1;
|
||||
break;
|
||||
}
|
||||
close(client_fd);
|
||||
}
|
||||
|
||||
myfail_unless(connected, "Didn't connect.");
|
||||
return client_fd;
|
||||
}
|
||||
|
||||
/* These are "internal" functions we need for the following test. We
|
||||
* shouldn't need them but there's no other way at the moment. */
|
||||
void serve_open_server_socket( struct server * );
|
||||
int server_port( struct server * );
|
||||
void server_accept( struct server * );
|
||||
int fd_is_closed( int );
|
||||
void server_close_clients( struct server * );
|
||||
void serve_open_server_socket(struct server *);
|
||||
int server_port(struct server *);
|
||||
void server_accept(struct server *);
|
||||
int fd_is_closed(int);
|
||||
void server_close_clients(struct server *);
|
||||
|
||||
START_TEST( test_acl_update_closes_bad_client )
|
||||
START_TEST(test_acl_update_closes_bad_client)
|
||||
{
|
||||
/* This is the wrong way round. Rather than pulling the thread
|
||||
* and socket out of the server structure, we should be testing
|
||||
* a client socket.
|
||||
*/
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 0, 1 );
|
||||
struct acl * new_acl = acl_create( 0, NULL, 1 );
|
||||
struct client * c;
|
||||
struct client_tbl_entry * entry;
|
||||
/* This is the wrong way round. Rather than pulling the thread
|
||||
* and socket out of the server structure, we should be testing
|
||||
* a client socket.
|
||||
*/
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct server *s =
|
||||
server_create(&flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL,
|
||||
1, 0, 1);
|
||||
struct acl *new_acl = acl_create(0, NULL, 1);
|
||||
struct client *c;
|
||||
struct client_tbl_entry *entry;
|
||||
|
||||
int actual_port;
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
int actual_port;
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
|
||||
|
||||
serve_open_server_socket( s );
|
||||
actual_port = server_port( s );
|
||||
serve_open_server_socket(s);
|
||||
actual_port = server_port(s);
|
||||
|
||||
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
|
||||
server_accept( s );
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
/* At this point there should be an entry in the nbd_clients
|
||||
* table and a background thread to run the client loop
|
||||
*/
|
||||
myfail_if( entry->thread == 0, "No client thread was started." );
|
||||
server_fd = c->socket;
|
||||
myfail_if( fd_is_closed(server_fd),
|
||||
"Sanity check failed - client socket wasn't open." );
|
||||
client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1");
|
||||
server_accept(s);
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
/* At this point there should be an entry in the nbd_clients
|
||||
* table and a background thread to run the client loop
|
||||
*/
|
||||
myfail_if(entry->thread == 0, "No client thread was started.");
|
||||
server_fd = c->socket;
|
||||
myfail_if(fd_is_closed(server_fd),
|
||||
"Sanity check failed - client socket wasn't open.");
|
||||
|
||||
server_replace_acl( s, new_acl );
|
||||
server_replace_acl(s, new_acl);
|
||||
|
||||
/* accept again, so that we can react to the acl replacement signal */
|
||||
server_accept( s );
|
||||
/* accept again, so that we can react to the acl replacement signal */
|
||||
server_accept(s);
|
||||
|
||||
/* Fail if we time out here */
|
||||
while( !fd_is_closed( server_fd ) );
|
||||
/* Fail if we time out here */
|
||||
while (!fd_is_closed(server_fd));
|
||||
|
||||
close( client_fd );
|
||||
server_close_clients( s );
|
||||
server_destroy( s );
|
||||
close(client_fd);
|
||||
server_close_clients(s);
|
||||
server_destroy(s);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_acl_update_leaves_good_client )
|
||||
END_TEST START_TEST(test_acl_update_leaves_good_client)
|
||||
{
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
struct flexnbd flexnbd;
|
||||
flexnbd.signal_fd = -1;
|
||||
|
||||
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 0, 1 );
|
||||
struct server *s =
|
||||
server_create(&flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL,
|
||||
1, 0, 1);
|
||||
|
||||
char *lines[] = {"127.0.0.1"};
|
||||
struct acl * new_acl = acl_create( 1, lines, 1 );
|
||||
struct client * c;
|
||||
struct client_tbl_entry * entry;
|
||||
char *lines[] = { "127.0.0.1" };
|
||||
struct acl *new_acl = acl_create(1, lines, 1);
|
||||
struct client *c;
|
||||
struct client_tbl_entry *entry;
|
||||
|
||||
int actual_port;
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
int actual_port;
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
|
||||
serve_open_server_socket( s );
|
||||
actual_port = server_port( s );
|
||||
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
|
||||
server_accept( s );
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
/* At this point there should be an entry in the nbd_clients
|
||||
* table and a background thread to run the client loop
|
||||
*/
|
||||
myfail_if( entry->thread == 0, "No client thread was started." );
|
||||
server_fd = c->socket;
|
||||
myfail_if( fd_is_closed(server_fd),
|
||||
"Sanity check failed - client socket wasn't open." );
|
||||
serve_open_server_socket(s);
|
||||
actual_port = server_port(s);
|
||||
client_fd = connect_client("127.0.0.7", actual_port, "127.0.0.1");
|
||||
server_accept(s);
|
||||
entry = &s->nbd_client[0];
|
||||
c = entry->client;
|
||||
/* At this point there should be an entry in the nbd_clients
|
||||
* table and a background thread to run the client loop
|
||||
*/
|
||||
myfail_if(entry->thread == 0, "No client thread was started.");
|
||||
server_fd = c->socket;
|
||||
myfail_if(fd_is_closed(server_fd),
|
||||
"Sanity check failed - client socket wasn't open.");
|
||||
|
||||
server_replace_acl( s, new_acl );
|
||||
server_accept( s );
|
||||
server_replace_acl(s, new_acl);
|
||||
server_accept(s);
|
||||
|
||||
myfail_if( self_pipe_signal_clear( c->stop_signal ),
|
||||
"Client was told to stop." );
|
||||
myfail_if(self_pipe_signal_clear(c->stop_signal),
|
||||
"Client was told to stop.");
|
||||
|
||||
close( client_fd );
|
||||
server_close_clients( s );
|
||||
server_destroy( s );
|
||||
close(client_fd);
|
||||
server_close_clients(s);
|
||||
server_destroy(s);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* serve_suite(void)
|
||||
END_TEST Suite * serve_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("serve");
|
||||
TCase *tc_acl_update = tcase_create("acl_update");
|
||||
Suite *s = suite_create("serve");
|
||||
TCase *tc_acl_update = tcase_create("acl_update");
|
||||
|
||||
tcase_add_checked_fixture( tc_acl_update, setup, NULL );
|
||||
tcase_add_checked_fixture(tc_acl_update, setup, NULL);
|
||||
|
||||
tcase_add_test(tc_acl_update, test_replaces_acl);
|
||||
tcase_add_test(tc_acl_update, test_signals_acl_updated);
|
||||
tcase_add_test(tc_acl_update, test_replaces_acl);
|
||||
tcase_add_test(tc_acl_update, test_signals_acl_updated);
|
||||
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client, 0);
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, 0);
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client,
|
||||
0);
|
||||
tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client,
|
||||
0);
|
||||
|
||||
suite_add_tcase(s, tc_acl_update);
|
||||
suite_add_tcase(s, tc_acl_update);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
log_level = LOG_LEVEL;
|
||||
error_init();
|
||||
int number_failed;
|
||||
Suite *s = serve_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
log_level = LOG_LEVEL;
|
||||
error_init();
|
||||
int number_failed;
|
||||
Suite *s = serve_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -6,110 +6,112 @@
|
||||
|
||||
#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_in* v4 = (struct sockaddr_in*) &sa;
|
||||
char testbuf[128];
|
||||
const char* result;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
|
||||
char testbuf[128];
|
||||
const char *result;
|
||||
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons( 4777 );
|
||||
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr ));
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons(4777);
|
||||
ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
|
||||
|
||||
result = sockaddr_address_string( &sa, &testbuf[0], 128 );
|
||||
ck_assert( result != NULL );
|
||||
result = sockaddr_address_string(&sa, &testbuf[0], 128);
|
||||
ck_assert(result != NULL);
|
||||
|
||||
ck_assert_str_eq( "192.168.0.1 port 4777", testbuf );
|
||||
ck_assert_str_eq("192.168.0.1 port 4777", testbuf);
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_sockaddr_address_string_af_inet6_converts_to_string )
|
||||
START_TEST(test_sockaddr_address_string_af_inet6_converts_to_string)
|
||||
{
|
||||
struct sockaddr_in6 v6_raw;
|
||||
struct sockaddr_in6* v6 = &v6_raw;
|
||||
struct sockaddr* sa = (struct sockaddr*) &v6_raw;
|
||||
struct sockaddr_in6 v6_raw;
|
||||
struct sockaddr_in6 *v6 = &v6_raw;
|
||||
struct sockaddr *sa = (struct sockaddr *) &v6_raw;
|
||||
|
||||
char testbuf[128];
|
||||
const char* result;
|
||||
char testbuf[128];
|
||||
const char *result;
|
||||
|
||||
v6->sin6_family = AF_INET6;
|
||||
v6->sin6_port = htons( 4777 );
|
||||
ck_assert_int_eq( 1, inet_pton( AF_INET6, "fe80::1", &v6->sin6_addr ));
|
||||
v6->sin6_family = AF_INET6;
|
||||
v6->sin6_port = htons(4777);
|
||||
ck_assert_int_eq(1, inet_pton(AF_INET6, "fe80::1", &v6->sin6_addr));
|
||||
|
||||
result = sockaddr_address_string( sa, &testbuf[0], 128 );
|
||||
ck_assert( result != NULL );
|
||||
result = sockaddr_address_string(sa, &testbuf[0], 128);
|
||||
ck_assert(result != NULL);
|
||||
|
||||
ck_assert_str_eq( "fe80::1 port 4777", testbuf );
|
||||
ck_assert_str_eq("fe80::1 port 4777", testbuf);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
END_TEST
|
||||
/* We don't know what it is, so we just call it "???" and return NULL */
|
||||
START_TEST( test_sockaddr_address_string_af_unspec_is_failure )
|
||||
START_TEST(test_sockaddr_address_string_af_unspec_is_failure)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in* v4 = (struct sockaddr_in*) &sa;
|
||||
char testbuf[128];
|
||||
const char* result;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
|
||||
char testbuf[128];
|
||||
const char *result;
|
||||
|
||||
v4->sin_family = AF_UNSPEC;
|
||||
v4->sin_port = htons( 4777 );
|
||||
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr ));
|
||||
v4->sin_family = AF_UNSPEC;
|
||||
v4->sin_port = htons(4777);
|
||||
ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
|
||||
|
||||
result = sockaddr_address_string( &sa, &testbuf[0], 128 );
|
||||
ck_assert( result == NULL );
|
||||
result = sockaddr_address_string(&sa, &testbuf[0], 128);
|
||||
ck_assert(result == NULL);
|
||||
|
||||
ck_assert_str_eq( "???", testbuf );
|
||||
ck_assert_str_eq("???", testbuf);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
END_TEST
|
||||
/* This is a complete failure to parse, rather than a partial failure */
|
||||
START_TEST( test_sockaddr_address_string_doesnt_overflow_short_buffer )
|
||||
START_TEST(test_sockaddr_address_string_doesnt_overflow_short_buffer)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in* v4 = (struct sockaddr_in*) &sa;
|
||||
char testbuf[128];
|
||||
const char* result;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *v4 = (struct sockaddr_in *) &sa;
|
||||
char testbuf[128];
|
||||
const char *result;
|
||||
|
||||
memset( testbuf, 0, 128 );
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons( 4777 );
|
||||
ck_assert_int_eq( 1, inet_pton( AF_INET, "192.168.0.1", &v4->sin_addr ));
|
||||
memset( &testbuf, 0, 128 );
|
||||
memset(testbuf, 0, 128);
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons(4777);
|
||||
ck_assert_int_eq(1, inet_pton(AF_INET, "192.168.0.1", &v4->sin_addr));
|
||||
memset(&testbuf, 0, 128);
|
||||
|
||||
result = sockaddr_address_string( &sa, &testbuf[0], 2 );
|
||||
ck_assert( result == NULL );
|
||||
result = sockaddr_address_string(&sa, &testbuf[0], 2);
|
||||
ck_assert(result == NULL);
|
||||
|
||||
ck_assert_str_eq( "??", testbuf );
|
||||
ck_assert_str_eq("??", testbuf);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *sockutil_suite(void)
|
||||
END_TEST Suite * sockutil_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("sockutil");
|
||||
Suite *s = suite_create("sockutil");
|
||||
|
||||
TCase *tc_sockaddr_address_string = tcase_create("sockaddr_address_string");
|
||||
TCase *tc_sockaddr_address_string =
|
||||
tcase_create("sockaddr_address_string");
|
||||
|
||||
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_inet_converts_to_string);
|
||||
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_inet6_converts_to_string);
|
||||
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_af_unspec_is_failure);
|
||||
tcase_add_test(tc_sockaddr_address_string, test_sockaddr_address_string_doesnt_overflow_short_buffer);
|
||||
suite_add_tcase(s, tc_sockaddr_address_string);
|
||||
tcase_add_test(tc_sockaddr_address_string,
|
||||
test_sockaddr_address_string_af_inet_converts_to_string);
|
||||
tcase_add_test(tc_sockaddr_address_string,
|
||||
test_sockaddr_address_string_af_inet6_converts_to_string);
|
||||
tcase_add_test(tc_sockaddr_address_string,
|
||||
test_sockaddr_address_string_af_unspec_is_failure);
|
||||
tcase_add_test(tc_sockaddr_address_string,
|
||||
test_sockaddr_address_string_doesnt_overflow_short_buffer);
|
||||
suite_add_tcase(s, tc_sockaddr_address_string);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = sockutil_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = sockutil_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -6,366 +6,331 @@
|
||||
|
||||
#include <check.h>
|
||||
|
||||
struct server* mock_server(void)
|
||||
struct server *mock_server(void)
|
||||
{
|
||||
struct server* out = xmalloc( sizeof( struct server ) );
|
||||
out->l_start_mirror = flexthread_mutex_create();
|
||||
out->nbd_client = xmalloc( sizeof( struct client_tbl_entry ) * 4 );
|
||||
out->max_nbd_clients = 4;
|
||||
out->size = 65536;
|
||||
struct server *out = xmalloc(sizeof(struct server));
|
||||
out->l_start_mirror = flexthread_mutex_create();
|
||||
out->nbd_client = xmalloc(sizeof(struct client_tbl_entry) * 4);
|
||||
out->max_nbd_clients = 4;
|
||||
out->size = 65536;
|
||||
|
||||
out->allocation_map = bitset_alloc( 65536, 4096 );
|
||||
out->allocation_map = bitset_alloc(65536, 4096);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
struct server* mock_mirroring_server(void)
|
||||
struct server *mock_mirroring_server(void)
|
||||
{
|
||||
struct server *out = mock_server();
|
||||
out->mirror = xmalloc( sizeof( struct mirror ) );
|
||||
out->mirror_super = xmalloc( sizeof( struct mirror_super ) );
|
||||
return out;
|
||||
struct server *out = mock_server();
|
||||
out->mirror = xmalloc(sizeof(struct mirror));
|
||||
out->mirror_super = xmalloc(sizeof(struct mirror_super));
|
||||
return out;
|
||||
}
|
||||
|
||||
void destroy_mock_server( struct server* serve )
|
||||
void destroy_mock_server(struct server *serve)
|
||||
{
|
||||
if ( NULL != serve->mirror ) {
|
||||
free( serve->mirror );
|
||||
}
|
||||
if (NULL != serve->mirror) {
|
||||
free(serve->mirror);
|
||||
}
|
||||
|
||||
if ( NULL != serve->mirror_super ) {
|
||||
free( serve->mirror_super );
|
||||
}
|
||||
if (NULL != serve->mirror_super) {
|
||||
free(serve->mirror_super);
|
||||
}
|
||||
|
||||
flexthread_mutex_destroy( serve->l_start_mirror );
|
||||
flexthread_mutex_destroy(serve->l_start_mirror);
|
||||
|
||||
bitset_free( serve->allocation_map );
|
||||
free( serve->nbd_client );
|
||||
free( serve );
|
||||
bitset_free(serve->allocation_map);
|
||||
free(serve->nbd_client);
|
||||
free(serve);
|
||||
}
|
||||
|
||||
START_TEST( test_status_create )
|
||||
START_TEST(test_status_create)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
struct status * status = status_create( server );
|
||||
struct server *server = mock_server();
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_if( NULL == status, "Status wasn't allocated" );
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
fail_if(NULL == status, "Status wasn't allocated");
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_gets_has_control )
|
||||
END_TEST START_TEST(test_gets_has_control)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
server->success = 1;
|
||||
struct server *server = mock_server();
|
||||
server->success = 1;
|
||||
|
||||
struct status * status = status_create( server );
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_unless( status->has_control == 1, "has_control wasn't copied" );
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
fail_unless(status->has_control == 1, "has_control wasn't copied");
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_gets_is_mirroring )
|
||||
END_TEST START_TEST(test_gets_is_mirroring)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
struct status * status = status_create( server );
|
||||
struct server *server = mock_server();
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_if( status->is_mirroring, "is_mirroring was set" );
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
fail_if(status->is_mirroring, "is_mirroring was set");
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
|
||||
server = mock_mirroring_server();
|
||||
status = status_create( server );
|
||||
server = mock_mirroring_server();
|
||||
status = status_create(server);
|
||||
|
||||
fail_unless( status->is_mirroring, "is_mirroring wasn't set" );
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
fail_unless(status->is_mirroring, "is_mirroring wasn't set");
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_gets_clients_allowed )
|
||||
END_TEST START_TEST(test_gets_clients_allowed)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
struct status * status = status_create( server );
|
||||
struct server *server = mock_server();
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_if( status->clients_allowed, "clients_allowed was set" );
|
||||
status_destroy( status );
|
||||
fail_if(status->clients_allowed, "clients_allowed was set");
|
||||
status_destroy(status);
|
||||
|
||||
server->allow_new_clients = 1;
|
||||
status = status_create( server );
|
||||
server->allow_new_clients = 1;
|
||||
status = status_create(server);
|
||||
|
||||
fail_unless( status->clients_allowed, "clients_allowed was not set" );
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
fail_unless(status->clients_allowed, "clients_allowed was not set");
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_gets_pid )
|
||||
END_TEST START_TEST(test_gets_pid)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
struct status * status = status_create( server );
|
||||
struct server *server = mock_server();
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_unless( getpid() == status->pid, "Pid wasn't gathered" );
|
||||
fail_unless(getpid() == status->pid, "Pid wasn't gathered");
|
||||
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_gets_size )
|
||||
END_TEST START_TEST(test_gets_size)
|
||||
{
|
||||
struct server * server = mock_server();
|
||||
server->size = 1024;
|
||||
struct server *server = mock_server();
|
||||
server->size = 1024;
|
||||
|
||||
struct status * status = status_create( server );
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_unless( 1024 == status->size, "Size wasn't gathered" );
|
||||
fail_unless(1024 == status->size, "Size wasn't gathered");
|
||||
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_gets_migration_statistics )
|
||||
END_TEST START_TEST(test_gets_migration_statistics)
|
||||
{
|
||||
struct server * server = mock_mirroring_server();
|
||||
server->mirror->all_dirty = 16384;
|
||||
server->mirror->max_bytes_per_second = 32768;
|
||||
server->mirror->offset = 0;
|
||||
struct server *server = mock_mirroring_server();
|
||||
server->mirror->all_dirty = 16384;
|
||||
server->mirror->max_bytes_per_second = 32768;
|
||||
server->mirror->offset = 0;
|
||||
|
||||
/* we have a bit of a time dependency here */
|
||||
server->mirror->migration_started = monotonic_time_ms();
|
||||
/* we have a bit of a time dependency here */
|
||||
server->mirror->migration_started = monotonic_time_ms();
|
||||
|
||||
struct status * status = status_create( server );
|
||||
struct status *status = status_create(server);
|
||||
|
||||
fail_unless (
|
||||
0 == status->migration_duration ||
|
||||
fail_unless(0 == status->migration_duration ||
|
||||
1 == status->migration_duration ||
|
||||
2 == status->migration_duration,
|
||||
"migration_duration is unreasonable!"
|
||||
);
|
||||
"migration_duration is unreasonable!");
|
||||
|
||||
fail_unless(
|
||||
16384 / ( status->migration_duration + 1 ) == status->migration_speed,
|
||||
"migration_speed not calculated correctly"
|
||||
);
|
||||
fail_unless(16384 / (status->migration_duration + 1) ==
|
||||
status->migration_speed,
|
||||
"migration_speed not calculated correctly");
|
||||
|
||||
fail_unless( 32768 == status->migration_speed_limit, "migration_speed_limit not read" );
|
||||
fail_unless(32768 == status->migration_speed_limit,
|
||||
"migration_speed_limit not read");
|
||||
|
||||
// ( size / current_bps ) + 1 happens to be 3 for this test
|
||||
fail_unless( 3 == status->migration_seconds_left, "migration_seconds_left not gathered" );
|
||||
// ( size / current_bps ) + 1 happens to be 3 for this test
|
||||
fail_unless(3 == status->migration_seconds_left,
|
||||
"migration_seconds_left not gathered");
|
||||
|
||||
status_destroy( status );
|
||||
destroy_mock_server( server );
|
||||
status_destroy(status);
|
||||
destroy_mock_server(server);
|
||||
}
|
||||
|
||||
END_TEST
|
||||
|
||||
|
||||
#define RENDER_TEST_SETUP \
|
||||
struct status status; \
|
||||
int fds[2]; \
|
||||
pipe( fds );
|
||||
|
||||
void fail_unless_rendered( int fd, char *fragment )
|
||||
void fail_unless_rendered(int fd, char *fragment)
|
||||
{
|
||||
char buf[1024] = {0};
|
||||
char emsg[1024] = {0};
|
||||
char *found = NULL;
|
||||
char buf[1024] = { 0 };
|
||||
char emsg[1024] = { 0 };
|
||||
char *found = NULL;
|
||||
|
||||
sprintf(emsg, "Fragment: %s not found", fragment );
|
||||
sprintf(emsg, "Fragment: %s not found", fragment);
|
||||
|
||||
fail_unless( read_until_newline( fd, buf, 1024 ) > 0, "Couldn't read" );
|
||||
found = strstr( buf, fragment );
|
||||
fail_if( NULL == found, emsg );
|
||||
fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read");
|
||||
found = strstr(buf, fragment);
|
||||
fail_if(NULL == found, emsg);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void fail_if_rendered( int fd, char *fragment )
|
||||
void fail_if_rendered(int fd, char *fragment)
|
||||
{
|
||||
char buf[1024] = {0};
|
||||
char emsg[1024] = {0};
|
||||
char *found = NULL;
|
||||
char buf[1024] = { 0 };
|
||||
char emsg[1024] = { 0 };
|
||||
char *found = NULL;
|
||||
|
||||
sprintf(emsg, "Fragment: %s found", fragment );
|
||||
sprintf(emsg, "Fragment: %s found", fragment);
|
||||
|
||||
fail_unless( read_until_newline( fd, buf, 1024 ) > 0, "Couldn't read" );
|
||||
found = strstr( buf, fragment );
|
||||
fail_unless( NULL == found, emsg );
|
||||
fail_unless(read_until_newline(fd, buf, 1024) > 0, "Couldn't read");
|
||||
found = strstr(buf, fragment);
|
||||
fail_unless(NULL == found, emsg);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
START_TEST( test_renders_has_control )
|
||||
START_TEST(test_renders_has_control)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
RENDER_TEST_SETUP status.has_control = 1;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "has_control=true");
|
||||
|
||||
status.has_control = 1;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "has_control=true" );
|
||||
|
||||
status.has_control = 0;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "has_control=false" );
|
||||
status.has_control = 0;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "has_control=false");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_renders_is_mirroring )
|
||||
END_TEST START_TEST(test_renders_is_mirroring)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
RENDER_TEST_SETUP status.is_mirroring = 1;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "is_mirroring=true");
|
||||
|
||||
status.is_mirroring = 1;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "is_mirroring=true" );
|
||||
|
||||
status.is_mirroring = 0;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "is_mirroring=false" );
|
||||
status.is_mirroring = 0;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "is_mirroring=false");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_renders_clients_allowed )
|
||||
END_TEST START_TEST(test_renders_clients_allowed)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
RENDER_TEST_SETUP status.clients_allowed = 1;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "clients_allowed=true");
|
||||
|
||||
status.clients_allowed = 1;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "clients_allowed=true" );
|
||||
|
||||
status.clients_allowed = 0;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "clients_allowed=false" );
|
||||
status.clients_allowed = 0;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "clients_allowed=false");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_renders_num_clients )
|
||||
END_TEST START_TEST(test_renders_num_clients)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
RENDER_TEST_SETUP status.num_clients = 0;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "num_clients=0");
|
||||
|
||||
status.num_clients = 0;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "num_clients=0" );
|
||||
|
||||
status.num_clients = 4000;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "num_clients=4000" );
|
||||
status.num_clients = 4000;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "num_clients=4000");
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_renders_pid )
|
||||
END_TEST START_TEST(test_renders_pid)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
|
||||
status.pid = 42;
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "pid=42" );
|
||||
RENDER_TEST_SETUP status.pid = 42;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "pid=42");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_renders_size )
|
||||
END_TEST START_TEST(test_renders_size)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
|
||||
status.size = ( (uint64_t)1 << 33 );
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "size=8589934592" );
|
||||
RENDER_TEST_SETUP status.size = ((uint64_t) 1 << 33);
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "size=8589934592");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST( test_renders_migration_statistics )
|
||||
END_TEST START_TEST(test_renders_migration_statistics)
|
||||
{
|
||||
RENDER_TEST_SETUP
|
||||
RENDER_TEST_SETUP status.is_mirroring = 0;
|
||||
status.migration_duration = 8;
|
||||
status.migration_speed = 40000000;
|
||||
status.migration_speed_limit = 40000001;
|
||||
status.migration_seconds_left = 1;
|
||||
status.migration_bytes_left = 5000;
|
||||
|
||||
status.is_mirroring = 0;
|
||||
status.migration_duration = 8;
|
||||
status.migration_speed = 40000000;
|
||||
status.migration_speed_limit = 40000001;
|
||||
status.migration_seconds_left = 1;
|
||||
status.migration_bytes_left = 5000;
|
||||
status_write(&status, fds[1]);
|
||||
fail_if_rendered(fds[0], "migration_duration");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_if_rendered( fds[0], "migration_duration" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_if_rendered(fds[0], "migration_speed");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_if_rendered( fds[0], "migration_speed" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_if_rendered(fds[0], "migration_speed_limit");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_if_rendered( fds[0], "migration_speed_limit" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_if_rendered(fds[0], "migration_seconds_left");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_if_rendered( fds[0], "migration_seconds_left" );
|
||||
status.is_mirroring = 1;
|
||||
|
||||
status.is_mirroring = 1;
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "migration_duration=8");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "migration_duration=8" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "migration_speed=40000000");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "migration_speed=40000000" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "migration_speed_limit=40000001");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "migration_speed_limit=40000001" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "migration_seconds_left=1");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "migration_seconds_left=1" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_unless_rendered(fds[0], "migration_bytes_left=5000");
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_unless_rendered( fds[0], "migration_bytes_left=5000" );
|
||||
status.migration_speed_limit = UINT64_MAX;
|
||||
|
||||
status.migration_speed_limit = UINT64_MAX;
|
||||
|
||||
status_write( &status, fds[1] );
|
||||
fail_if_rendered( fds[0], "migration_speed_limit" );
|
||||
status_write(&status, fds[1]);
|
||||
fail_if_rendered(fds[0], "migration_speed_limit");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *status_suite(void)
|
||||
END_TEST Suite * status_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("status");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_render = tcase_create("render");
|
||||
Suite *s = suite_create("status");
|
||||
TCase *tc_create = tcase_create("create");
|
||||
TCase *tc_render = tcase_create("render");
|
||||
|
||||
tcase_add_test(tc_create, test_status_create);
|
||||
tcase_add_test(tc_create, test_gets_has_control);
|
||||
tcase_add_test(tc_create, test_gets_is_mirroring);
|
||||
tcase_add_test(tc_create, test_gets_clients_allowed);
|
||||
tcase_add_test(tc_create, test_gets_pid);
|
||||
tcase_add_test(tc_create, test_gets_size);
|
||||
tcase_add_test(tc_create, test_gets_migration_statistics);
|
||||
tcase_add_test(tc_create, test_status_create);
|
||||
tcase_add_test(tc_create, test_gets_has_control);
|
||||
tcase_add_test(tc_create, test_gets_is_mirroring);
|
||||
tcase_add_test(tc_create, test_gets_clients_allowed);
|
||||
tcase_add_test(tc_create, test_gets_pid);
|
||||
tcase_add_test(tc_create, test_gets_size);
|
||||
tcase_add_test(tc_create, test_gets_migration_statistics);
|
||||
|
||||
|
||||
tcase_add_test(tc_render, test_renders_has_control);
|
||||
tcase_add_test(tc_render, test_renders_is_mirroring);
|
||||
tcase_add_test(tc_render, test_renders_clients_allowed);
|
||||
tcase_add_test(tc_render, test_renders_num_clients);
|
||||
tcase_add_test(tc_render, test_renders_pid);
|
||||
tcase_add_test(tc_render, test_renders_size);
|
||||
tcase_add_test(tc_render, test_renders_migration_statistics);
|
||||
tcase_add_test(tc_render, test_renders_has_control);
|
||||
tcase_add_test(tc_render, test_renders_is_mirroring);
|
||||
tcase_add_test(tc_render, test_renders_clients_allowed);
|
||||
tcase_add_test(tc_render, test_renders_num_clients);
|
||||
tcase_add_test(tc_render, test_renders_pid);
|
||||
tcase_add_test(tc_render, test_renders_size);
|
||||
tcase_add_test(tc_render, test_renders_migration_statistics);
|
||||
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_render);
|
||||
suite_add_tcase(s, tc_create);
|
||||
suite_add_tcase(s, tc_render);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
int number_failed;
|
||||
|
||||
Suite *s = status_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
Suite *s = status_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@@ -9,165 +9,156 @@
|
||||
|
||||
|
||||
struct cleanup_bucket {
|
||||
struct self_pipe *called_signal;
|
||||
struct self_pipe *called_signal;
|
||||
};
|
||||
|
||||
struct cleanup_bucket bkt;
|
||||
|
||||
void bucket_init(void){
|
||||
if ( bkt.called_signal ) {
|
||||
self_pipe_destroy( bkt.called_signal );
|
||||
}
|
||||
bkt.called_signal = self_pipe_create();
|
||||
void bucket_init(void)
|
||||
{
|
||||
if (bkt.called_signal) {
|
||||
self_pipe_destroy(bkt.called_signal);
|
||||
}
|
||||
bkt.called_signal = self_pipe_create();
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
bkt.called_signal = NULL;
|
||||
bkt.called_signal = NULL;
|
||||
}
|
||||
|
||||
int handler_called(void)
|
||||
{
|
||||
return self_pipe_signal_clear( bkt.called_signal );
|
||||
return self_pipe_signal_clear(bkt.called_signal);
|
||||
}
|
||||
|
||||
void dummy_cleanup( struct cleanup_bucket * foo, int fatal __attribute__((unused)) )
|
||||
void dummy_cleanup(struct cleanup_bucket *foo, int fatal
|
||||
__attribute__ ((unused)))
|
||||
{
|
||||
if (NULL != foo){
|
||||
self_pipe_signal( foo->called_signal );
|
||||
}
|
||||
if (NULL != foo) {
|
||||
self_pipe_signal(foo->called_signal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void trigger_fatal(void)
|
||||
{
|
||||
error_init();
|
||||
error_set_handler( (cleanup_handler*) dummy_cleanup, &bkt );
|
||||
error_init();
|
||||
error_set_handler((cleanup_handler *) dummy_cleanup, &bkt);
|
||||
|
||||
log_level = 5;
|
||||
log_level = 5;
|
||||
|
||||
fatal("Expected fatal error");
|
||||
fatal("Expected fatal error");
|
||||
}
|
||||
|
||||
void trigger_error( void )
|
||||
void trigger_error(void)
|
||||
{
|
||||
error_init();
|
||||
error_set_handler( (cleanup_handler *) dummy_cleanup, &bkt);
|
||||
log_level = 4;
|
||||
error("Expected error");
|
||||
error_init();
|
||||
error_set_handler((cleanup_handler *) dummy_cleanup, &bkt);
|
||||
log_level = 4;
|
||||
error("Expected error");
|
||||
}
|
||||
|
||||
|
||||
START_TEST( test_fatal_kills_process )
|
||||
START_TEST(test_fatal_kills_process)
|
||||
{
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
pid = fork();
|
||||
|
||||
if ( pid == 0 ) {
|
||||
trigger_fatal();
|
||||
/* If we get here, just block so the test timeout fails
|
||||
* us */
|
||||
sleep(10);
|
||||
}
|
||||
else {
|
||||
int kidret, kidstatus, result;
|
||||
result = waitpid( pid, &kidret, 0 );
|
||||
fail_if( result < 0, "Wait failed." );
|
||||
fail_unless( WIFSIGNALED( kidret ), "Process didn't exit via signal" );
|
||||
kidstatus = WTERMSIG( kidret );
|
||||
ck_assert_int_eq( kidstatus, SIGABRT );
|
||||
}
|
||||
if (pid == 0) {
|
||||
trigger_fatal();
|
||||
/* If we get here, just block so the test timeout fails
|
||||
* us */
|
||||
sleep(10);
|
||||
} else {
|
||||
int kidret, kidstatus, result;
|
||||
result = waitpid(pid, &kidret, 0);
|
||||
fail_if(result < 0, "Wait failed.");
|
||||
fail_unless(WIFSIGNALED(kidret), "Process didn't exit via signal");
|
||||
kidstatus = WTERMSIG(kidret);
|
||||
ck_assert_int_eq(kidstatus, SIGABRT);
|
||||
}
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
void * error_thread( void *nothing __attribute__((unused)) )
|
||||
END_TEST void *error_thread(void *nothing __attribute__ ((unused)))
|
||||
{
|
||||
trigger_error();
|
||||
return NULL;
|
||||
trigger_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
START_TEST( test_error_doesnt_kill_process )
|
||||
START_TEST(test_error_doesnt_kill_process)
|
||||
{
|
||||
bucket_init();
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
bucket_init();
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
|
||||
pthread_attr_init( &attr );
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
pthread_create( &tid, &attr, error_thread, NULL );
|
||||
pthread_join( tid, NULL );
|
||||
pthread_create(&tid, &attr, error_thread, NULL);
|
||||
pthread_join(tid, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_error_calls_handler )
|
||||
END_TEST START_TEST(test_error_calls_handler)
|
||||
{
|
||||
bucket_init();
|
||||
bucket_init();
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
|
||||
pthread_attr_init( &attr );
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
pthread_create( &tid, &attr, error_thread, NULL );
|
||||
pthread_join( tid, NULL );
|
||||
fail_unless( handler_called(), "Handler wasn't called." );
|
||||
pthread_create(&tid, &attr, error_thread, NULL);
|
||||
pthread_join(tid, NULL);
|
||||
fail_unless(handler_called(), "Handler wasn't called.");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST( test_fatal_doesnt_call_handler )
|
||||
END_TEST START_TEST(test_fatal_doesnt_call_handler)
|
||||
{
|
||||
bucket_init();
|
||||
bucket_init();
|
||||
|
||||
pid_t kidpid;
|
||||
pid_t kidpid;
|
||||
|
||||
kidpid = fork();
|
||||
if ( kidpid == 0 ) {
|
||||
trigger_fatal();
|
||||
}
|
||||
else {
|
||||
int kidstatus;
|
||||
int result = waitpid( kidpid, &kidstatus, 0 );
|
||||
fail_if( result < 0, "Wait failed" );
|
||||
fail_if( handler_called(), "Handler was called.");
|
||||
}
|
||||
kidpid = fork();
|
||||
if (kidpid == 0) {
|
||||
trigger_fatal();
|
||||
} else {
|
||||
int kidstatus;
|
||||
int result = waitpid(kidpid, &kidstatus, 0);
|
||||
fail_if(result < 0, "Wait failed");
|
||||
fail_if(handler_called(), "Handler was called.");
|
||||
}
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite* util_suite(void)
|
||||
END_TEST Suite * util_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("util");
|
||||
TCase *tc_process = tcase_create("process");
|
||||
TCase *tc_handler = tcase_create("handler");
|
||||
Suite *s = suite_create("util");
|
||||
TCase *tc_process = tcase_create("process");
|
||||
TCase *tc_handler = tcase_create("handler");
|
||||
|
||||
tcase_add_checked_fixture( tc_process, setup, NULL );
|
||||
tcase_add_checked_fixture(tc_process, setup, NULL);
|
||||
|
||||
tcase_add_test(tc_process, test_fatal_kills_process);
|
||||
tcase_add_test(tc_process, test_error_doesnt_kill_process);
|
||||
tcase_add_test(tc_handler, test_error_calls_handler );
|
||||
tcase_add_test(tc_handler, test_fatal_doesnt_call_handler);
|
||||
tcase_add_test(tc_process, test_fatal_kills_process);
|
||||
tcase_add_test(tc_process, test_error_doesnt_kill_process);
|
||||
tcase_add_test(tc_handler, test_error_calls_handler);
|
||||
tcase_add_test(tc_handler, test_fatal_doesnt_call_handler);
|
||||
|
||||
suite_add_tcase(s, tc_process);
|
||||
suite_add_tcase(s, tc_handler);
|
||||
suite_add_tcase(s, tc_process);
|
||||
suite_add_tcase(s, tc_handler);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int number_failed;
|
||||
Suite *s = util_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
int number_failed;
|
||||
Suite *s = util_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user