summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/network/README3
-rw-r--r--include/wolf/port/unused.h (renamed from src/port/unused.h)0
-rw-r--r--tests/network/test1.c189
3 files changed, 180 insertions, 12 deletions
diff --git a/docs/network/README b/docs/network/README
index edfacb2..e011a99 100644
--- a/docs/network/README
+++ b/docs/network/README
@@ -26,4 +26,5 @@ Links:
asynchronous I/O interfaces
- Boinc: http://boinc.berkeley.edu: some ideas around protocol FSMs in
networking
-
+- http://www.artima.com/articles/io_design_patterns1.html: on Reactor
+ and Proactor and a hybrid the emulated Proactor
diff --git a/src/port/unused.h b/include/wolf/port/unused.h
index c18ed27..c18ed27 100644
--- a/src/port/unused.h
+++ b/include/wolf/port/unused.h
diff --git a/tests/network/test1.c b/tests/network/test1.c
index e37f4cb..b5b2aa8 100644
--- a/tests/network/test1.c
+++ b/tests/network/test1.c
@@ -3,24 +3,39 @@
#include "port/stdio.h" /* for fprintf */
#include "port/string.h" /* for memset */
#include "port/stdbool.h" /* for bool, true, false */
+#include "port/unused.h" /* for WOLF_UNUSED */
#include <unistd.h> /* for close */
#include <errno.h> /* for errno */
#include <fcntl.h> /* for fcntl */
#include <sys/select.h> /* for select */
+#include <assert.h> /* for assertions */
+#include <signal.h> /* for signal */
-static void wolf_network_sock_nonblocking( int fd ) {
+static bool wolf_network_sock_nonblocking( int fd ) {
int flags;
flags = fcntl( fd, F_GETFL, 0 /* ignored */ );
+ if( flags < 0 ) return false;
flags |= O_NONBLOCK;
flags = fcntl( fd, F_SETFL, flags );
+ if( flags < 0 ) return false;
+ return true;
}
#define MAX_IDLE_TIMEOUT 10
+#define WRITE_BUFFER_SIZE 1024
+#define READ_BUFFER_SIZE 1024
#define max(a,b) ((a) < (b) ? (b) : (a))
+static bool terminate = false;
+
+static void term_handler( int sig ) {
+ WOLF_UNUSED( sig );
+ terminate = true;
+}
+
int main( int argc, char *argv[] ) {
char *host;
char *service;
@@ -30,6 +45,17 @@ int main( int argc, char *argv[] ) {
int fd;
int res;
int idle_secs;
+ char read_buffer[READ_BUFFER_SIZE];
+ char write_buffer[WRITE_BUFFER_SIZE];
+ size_t stdout_to_write;
+ size_t stdout_written;
+ size_t fd_to_write;
+ size_t fd_written;
+ size_t total_stdin_read;
+ size_t total_fd_read;
+ size_t total_fd_written;
+ size_t total_stdout_written;
+ int count;
if( argc != 3 ) {
fprintf( stderr, "usage: test1 <host> <port>\n" );
@@ -72,11 +98,36 @@ int main( int argc, char *argv[] ) {
goto FAIL;
}
- wolf_network_sock_nonblocking( STDIN_FILENO );
- wolf_network_sock_nonblocking( STDOUT_FILENO );
- wolf_network_sock_nonblocking( fd );
+ if( !wolf_network_sock_nonblocking( STDIN_FILENO ) ) {
+ (void)close( fd );
+ fprintf( stderr, "set nonblocking failed for stdin: %s (%d)\n", strerror( errno ), errno );
+ goto FAIL;
+ }
+ if( !wolf_network_sock_nonblocking( STDOUT_FILENO ) ) {
+ (void)close( fd );
+ fprintf( stderr, "set nonblocking failed for stdout: %s (%d)\n", strerror( errno ), errno );
+ goto FAIL;
+ }
+ if( !wolf_network_sock_nonblocking( fd ) ) {
+ (void)close( fd );
+ fprintf( stderr, "set nonblocking failed for socket: %s (%d)\n", strerror( errno ), errno );
+ goto FAIL;
+ }
idle_secs = 0;
+ count = 0;
+ stdout_to_write = 0;
+ stdout_written = 0;
+ fd_to_write = 0;
+ fd_written = 0;
+ total_stdin_read = 0;
+ total_fd_read = 0;
+ total_fd_written = 0;
+ total_stdout_written = 0;
+
+ signal( SIGTERM, term_handler );
+ signal( SIGINT, term_handler );
+ signal( SIGPIPE, SIG_IGN );
do {
int max_fd;
@@ -84,6 +135,7 @@ int main( int argc, char *argv[] ) {
fd_set write_set;
fd_set error_set;
struct timeval timeout;
+ ssize_t rres;
FD_ZERO( &read_set );
FD_ZERO( &write_set );
@@ -97,14 +149,23 @@ int main( int argc, char *argv[] ) {
max_fd = max( max_fd, STDOUT_FILENO );
max_fd = max( max_fd, fd );
- FD_SET( STDIN_FILENO, &read_set );
- FD_SET( fd, &read_set );
- FD_SET( STDOUT_FILENO, &write_set );
- FD_SET( fd, &write_set );
+ if( fd_to_write == 0 ) {
+ FD_SET( STDIN_FILENO, &read_set );
+ }
FD_SET( STDIN_FILENO, &error_set );
+ if( stdout_to_write > 0 ) {
+ FD_SET( STDOUT_FILENO, &write_set );
+ }
FD_SET( STDOUT_FILENO, &error_set );
+ if( stdout_to_write == 0 ) {
+ FD_SET( fd, &read_set );
+ }
+ if( fd_to_write > 0 ) {
+ FD_SET( fd, &write_set );
+ }
FD_SET( fd, &error_set );
-
+
+ /* wait for events or timeout */
res = select( max_fd + 1, &read_set, &write_set, &error_set, &timeout );
if( res < 0 ) {
if( errno == EINTR || errno == EAGAIN ) {
@@ -128,11 +189,117 @@ int main( int argc, char *argv[] ) {
/* something happened */
idle_secs = 0;
+ /* handle error conditions */
+ if( FD_ISSET( STDOUT_FILENO, &error_set ) ) {
+ fprintf( stderr, "Error flag on stdout!\n" );
+ }
+ if( FD_ISSET( STDIN_FILENO, &error_set ) ) {
+ fprintf( stderr, "Error flag on stdin!\n" );
+ }
+ if( FD_ISSET( fd, &error_set ) ) {
+ fprintf( stderr, "Error flag on socket!\n" );
+ }
+
+ /* empty the socket read buffer to stdout */
if( FD_ISSET( STDOUT_FILENO, &write_set ) ) {
-// res = write( STDOUT_FILENO, write_buf
+ assert( stdout_to_write > 0 );
+ rres = write( STDOUT_FILENO, read_buffer + stdout_written, stdout_to_write );
+ if( rres < 0 ) {
+ if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
+ /* skip */
+ } else {
+ fprintf( stderr, "write to stdout failed: %s (%d)\n",
+ strerror( errno ), errno );
+ (void)close( fd );
+ goto FAIL;
+ }
+ } else {
+ assert( rres >= 0 );
+ stdout_written += (size_t)rres;
+ assert( stdout_to_write >= (size_t)rres );
+ stdout_to_write -= (size_t)rres;
+ total_stdout_written += (size_t)rres;
+ }
+ }
+
+ /* empty the socket write buffer writing to fd */
+ if( FD_ISSET( fd, &write_set ) ) {
+ assert( fd_to_write > 0 );
+ rres = write( fd, write_buffer + fd_written, fd_to_write );
+ if( rres < 0 ) {
+ if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
+ /* skip */
+ } else {
+ fprintf( stderr, "write to socket failed: %s (%d)\n",
+ strerror( errno ), errno );
+ (void)close( fd );
+ goto FAIL;
+ }
+ } else {
+ assert( rres >= 0 );
+ fd_written += (size_t)rres;
+ assert( fd_to_write >= (size_t)rres );
+ fd_to_write -= (size_t)rres;
+ total_fd_written += (size_t)rres;
+ }
+ }
+
+ /* read from socket, fill socket read buffer */
+ if( FD_ISSET( fd, &read_set ) ) {
+ assert( stdout_to_write == 0 );
+ rres = read( fd, read_buffer, READ_BUFFER_SIZE );
+ if( rres < 0 ) {
+ if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
+ /* skip */
+ } else {
+ fprintf( stderr, "read from socket failed: %s (%d)\n",
+ strerror( errno ), errno );
+ (void)close( fd );
+ goto FAIL;
+ }
+ } else if( rres == 0 ) {
+ /* EOF on socket */
+ } else {
+ assert( rres > 0 );
+ stdout_written = 0;
+ stdout_to_write = (size_t)rres;
+ total_fd_read += (size_t)rres;
+ }
+ }
+
+ /* read from stdin, fill socket write buffer */
+ if( FD_ISSET( STDIN_FILENO, &read_set ) ) {
+ assert( fd_to_write == 0 );
+ rres = read( STDIN_FILENO, write_buffer, WRITE_BUFFER_SIZE );
+ if( rres < 0 ) {
+ if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
+ /* skip */
+ } else {
+ fprintf( stderr, "read from stdin failed: %s (%d)\n",
+ strerror( errno ), errno );
+ (void)close( fd );
+ goto FAIL;
+ }
+ } else if( rres == 0 ) {
+ /* EOF on STDIN */
+ } else {
+ assert( rres > 0 );
+ fd_written = 0;
+ fd_to_write = (size_t)rres;
+ total_stdin_read += (size_t)rres;
+ }
}
}
- } while( true );
+
+ count++;
+ if( count % 1000 == 0 ) {
+ fprintf( stderr, "Transfered stdin: %d, stdout: %d, fd-in: %d, fd-out: %d\r",
+ total_stdin_read, total_stdout_written, total_fd_read, total_fd_written );
+ }
+ } while( !terminate );
+
+ fprintf( stderr, "Terminated with stdin: %d, stdout: %d, fd-in: %d, fd-out: %d\n",
+ total_stdin_read, total_stdout_written, total_fd_read, total_fd_written );
END:
res = close( fd );