diff options
-rw-r--r-- | docs/network/README | 5 | ||||
-rw-r--r-- | tests/GNUmakefile | 2 | ||||
-rw-r--r-- | tests/Makefile.W32 | 2 | ||||
-rw-r--r-- | tests/network/test2.c | 122 |
4 files changed, 83 insertions, 48 deletions
diff --git a/docs/network/README b/docs/network/README index d2829e5..9bf3cc4 100644 --- a/docs/network/README +++ b/docs/network/README @@ -14,6 +14,11 @@ Goals: - reach the 100MBit/s sustained transfer rate (yes I know, there are Gigabits/s NICs out there, but their speed is almost impossible to reach) +- low-level abstraction should try not to hide the BSD-API, but try to + nivelate things in the direction of POSIX. So we are later able to + add specific Unix or Windows code where we want. An abstraction as + in Poco hinders us doing this because we have to think about everything + from the beginning! Links: - Boost ASIO: on design diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 405e207..b5a23cc 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -1,6 +1,6 @@ TOPDIR = .. -SUBDIRS = threads port log gettext daemon service network +SUBDIRS = threads port log gettext network daemon service -include $(TOPDIR)/makefiles/gmake/sub.mk diff --git a/tests/Makefile.W32 b/tests/Makefile.W32 index f76c295..2b592c9 100644 --- a/tests/Makefile.W32 +++ b/tests/Makefile.W32 @@ -1,6 +1,6 @@ TOPDIR = .. -SUBDIRS = threads port log service network +SUBDIRS = threads port log network service !INCLUDE $(TOPDIR)\makefiles\nmake\sub.mk diff --git a/tests/network/test2.c b/tests/network/test2.c index 9b30a9d..f0e711a 100644 --- a/tests/network/test2.c +++ b/tests/network/test2.c @@ -20,6 +20,8 @@ #define DEBUG 0 +#define ACCEPT_TIMEOUT 5 + static bool wolf_network_sock_nonblocking( int fd ) { int flags; @@ -41,6 +43,11 @@ int main( int argc, char* argv[] ) { struct addrinfo *result; wolf_network_sockaddr_union_t client_addr; socklen_t client_addr_len; + fd_set read_set; + struct timeval timeout; + char client_hostname[NI_MAXHOST] = ""; + char client_service[NI_MAXSERV] = ""; + int on; if( argc != 3 ) { fprintf( stderr, "usage: test2 <host> <port>\n" ); @@ -77,7 +84,17 @@ int main( int argc, char* argv[] ) { goto FAIL; } - /* setsockopt SO_REUSEADDR */ + /* setsockopt SO_REUSEADDR, this is handy while testing or deployment, in + * production in can lead to a certain type of rerouting packets to wrong + * servers + */ + on = 1; + res = setsockopt( serv_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof( on ) ); + if( res < 0 ) { + (void)close( serv_fd ); + fprintf( stderr, "setsockopt(SO_REUSEADDR) failed: %s (%d)\n", strerror( errno ), errno ); + goto FAIL; + } /* bind server socket */ res = bind( serv_fd, result->ai_addr, result->ai_addrlen ); @@ -105,6 +122,7 @@ int main( int argc, char* argv[] ) { /* accept the connection in the kernel, select ready for ready tells us there * is a connection ready. Then we have to call accept again and check the result */ +FIRST_ACCEPT_AGAIN: client_addr_len = sizeof( client_addr ); res = accept( serv_fd, &client_addr.addr, &client_addr_len ); if( res < 0 ) { @@ -117,33 +135,74 @@ int main( int argc, char* argv[] ) { } } -#if 0 + /* go into a select and wait till we are ready for read (this indicates a + * possibly new connection) + */ +ACCEPT_SELECT_AGAIN: FD_ZERO( &read_set ); - FD_ZERO( &write_set ); - FD_SET( fd, &read_set ); - FD_SET( fd, &write_set ); - timeout.tv_sec = CONNECT_TIMEOUT; + FD_SET( serv_fd, &read_set ); + timeout.tv_sec = ACCEPT_TIMEOUT; timeout.tv_usec = 0; - res = select( fd + 1, &read_set, &write_set, NULL, &timeout ); + + res = select( serv_fd + 1, &read_set, NULL, NULL, &timeout ); if( res < 0 ) { if( errno == EINTR || errno == EAGAIN ) { - goto CONNECT_SELECT_AGAIN; + goto ACCEPT_SELECT_AGAIN; } else { /* fatal errors */ - fprintf( stderr, "select failed: %s (%d)\n", + fprintf( stderr, "accept/select failed: %s (%d)\n", strerror( errno ), errno ); - (void)close( fd ); + (void)close( serv_fd ); goto FAIL; } } else if( res == 0 ) { - /* connect timeout */ - fprintf( stderr, "Connect timeout..terminating\n" ); - goto FAIL; + /* accept timeout, here we could to periodic stuff, also if we + * get blocked somewhere above we could recover.. + */ + fprintf( stderr, "Idle. No new connections..\n" ); + goto ACCEPT_SELECT_AGAIN; } else { - if( FD_ISSET( fd, &read_set ) || FD_ISSET( fd, &write_set ) ) { - socklen_t sock_error_len; - int sock_error; -#endif + if( FD_ISSET( serv_fd, &read_set ) ) { + /* this is a new connection */ + } else { + /* can't happen! */ + assert( false ); + } + } + + /* second accept, now we have to check for possible "short-and-run-away" + * connects. + */ +ACCEPT_AGAIN: + client_addr_len = sizeof( client_addr ); + res = accept( serv_fd, &client_addr.addr, &client_addr_len ); + if( res < 0 ) { + if( errno == EINTR ) { + /* interrupted, again */ + goto ACCEPT_AGAIN; + } else if( errno == ECONNABORTED || errno == EPROTO ) { + /* connection run away */ + goto FIRST_ACCEPT_AGAIN; + } else { + (void)close( serv_fd ); + fprintf( stderr, "second non-blocking accept failed: %s (%d)\n", strerror( errno ), errno ); + goto FAIL; + } + } + + /* determine where the request came from */ + res = getnameinfo( &client_addr.addr, client_addr_len, + client_hostname, NI_MAXHOST, + client_service, NI_MAXSERV, + NI_NUMERICSERV | NI_NUMERICHOST ); + if( res < 0 ) { + (void)close( serv_fd ); + fprintf( stderr, "getnameinfo failed: %s (%d)\n", + gai_strerror( error ), error ); + goto FAIL; + } + + fprintf( stderr, "New connection from %s, port %s\n", client_hostname, client_service ); goto OK; @@ -221,14 +280,6 @@ int main( int argc, char *argv[] ) { bool stdin_eof; bool fd_write_closed; bool fd_eof; - int max_fd; - fd_set read_set; - fd_set write_set; - struct timeval timeout; - socklen_t peer_addr_len; - union sockaddr_union peer_addr; - char peer_hostname[NI_MAXHOST] = ""; - char peer_service[NI_MAXSERV] = ""; CONNECT_SELECT_AGAIN: sock_error_len = sizeof( int ); @@ -256,27 +307,6 @@ CONNECT_SELECT_AGAIN: } CONNECTED: - /* determine the address of the other end of the connection */ - peer_addr_len = sizeof( peer_addr ); - res = getsockname( fd, &peer_addr.addr, &peer_addr_len ); - if( res < 0 ) { - (void)close( fd ); - fprintf( stderr, "getsockname failed: %s (%d)\n", strerror( errno ), errno ); - goto FAIL; - } - res = getnameinfo( &peer_addr.addr, peer_addr_len, - peer_hostname, NI_MAXHOST, - peer_service, NI_MAXSERV, - NI_NUMERICSERV | NI_NUMERICHOST ); - if( res < 0 ) { - (void)close( fd ); - fprintf( stderr, "getnameinfo failed: %s (%d)\n", - gai_strerror( error ), error ); - goto FAIL; - } - - fprintf( stderr, "Connected to %s, port %s (peer: %s, %s)\n", host, service, - peer_hostname, peer_service ); idle_secs = 0; count = 0; |