From c9eb41c0569c02da57c98690715456dbe7279ca7 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 18 Feb 2008 20:13:30 +0000 Subject: [PATCH] Reduce to 20 seconds the time allowed to set SO_REUSEADDR option on sockfilt listener socket. Log some more error descriptions. --- tests/server/sockfilt.c | 106 +++++++++++++++++++++++++++--------------------- tests/server/util.c | 75 +++++++++++++++++++++++----------- tests/server/util.h | 4 +- 3 files changed, 113 insertions(+), 72 deletions(-) diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 7c3404c..042b9f5 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -143,7 +143,7 @@ static void sigpipe_handler(int sig) } #endif -char use_ipv6=FALSE; +bool use_ipv6=FALSE; unsigned short port = DEFAULT_PORT; unsigned short connectport = 0; /* if non-zero, we activate this mode */ @@ -427,25 +427,43 @@ static curl_socket_t sockdaemon(curl_socket_t sock, #endif /* ENABLE_IPV6 */ int flag = 1; int rc; - int maxretr = 12; - int delay= 10; - - rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&flag, sizeof(flag)); - while ((rc < 0) && maxretr) { - maxretr--; - go_sleep(delay); - delay *= 2; /* double the sleep for next attempt */ + int totdelay = 0; + int maxretr = 10; + int delay= 20; + int attempt = 0; + int error = 0; + + do { + attempt++; rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag)); - } - if (rc < 0) { - perror("setsockopt(SO_REUSEADDR)"); + if(rc) { + error = SOCKERRNO; + if(maxretr) { + rc = wait_ms(delay); + if(rc) { + /* should not happen */ + error = SOCKERRNO; + logmsg("wait_ms() failed: (%d) %s", error, strerror(error)); + sclose(sock); + return CURL_SOCKET_BAD; + } + totdelay += delay; + delay *= 2; /* double the sleep for next attempt */ + } + } + } while(rc && maxretr--); + + if(rc) { + logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error: (%d) %s", + attempt, totdelay, error, strerror(error)); + logmsg("Continuing anyway..."); } #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif + memset(&me, 0, sizeof(me)); me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; me.sin_port = htons(*listenport); @@ -453,16 +471,17 @@ static curl_socket_t sockdaemon(curl_socket_t sock, #ifdef ENABLE_IPV6 } else { - memset(&me6, 0, sizeof(struct sockaddr_in6)); + memset(&me6, 0, sizeof(me6)); me6.sin6_family = AF_INET6; me6.sin6_addr = in6addr_any; me6.sin6_port = htons(*listenport); rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6)); } #endif /* ENABLE_IPV6 */ - if(rc < 0) { - perror("binding stream socket"); - logmsg("Error binding socket"); + if(rc) { + error = SOCKERRNO; + logmsg("Error binding socket: (%d) %s", error, strerror(error)); + sclose(sock); return CURL_SOCKET_BAD; } @@ -475,16 +494,21 @@ static curl_socket_t sockdaemon(curl_socket_t sock, if(getsockname(sock, (struct sockaddr *) &add, &socksize)<0) { - logmsg("getsockname() failed with error: %d", SOCKERRNO); + error = SOCKERRNO; + logmsg("getsockname() failed with error: (%d) %s", + error, strerror(error)); + sclose(sock); return CURL_SOCKET_BAD; } *listenport = ntohs(add.sin_port); } /* start accepting connections */ - rc = listen(sock, 4); + rc = listen(sock, 5); if(0 != rc) { - logmsg("listen() failed with error: %d", SOCKERRNO); + error = SOCKERRNO; + logmsg("listen() failed with error: (%d) %s", + error, strerror(error)); sclose(sock); return CURL_SOCKET_BAD; } @@ -492,28 +516,6 @@ static curl_socket_t sockdaemon(curl_socket_t sock, return sock; } -static curl_socket_t mksock(bool ipv6) -{ - curl_socket_t sock; -#ifdef ENABLE_IPV6 - if(!ipv6) -#else - (void)ipv6; -#endif - sock = socket(AF_INET, SOCK_STREAM, 0); -#ifdef ENABLE_IPV6 - else - sock = socket(AF_INET6, SOCK_STREAM, 0); -#endif - - if (CURL_SOCKET_BAD == sock) { - perror("opening stream socket"); - logmsg("Error opening socket"); - } - - return sock; -} - int main(int argc, char *argv[]) { @@ -616,10 +618,19 @@ int main(int argc, char *argv[]) #endif #endif +#ifdef ENABLE_IPV6 + if(!use_ipv6) +#endif + sock = socket(AF_INET, SOCK_STREAM, 0); +#ifdef ENABLE_IPV6 + else + sock = socket(AF_INET6, SOCK_STREAM, 0); +#endif - sock = mksock(use_ipv6); - if (CURL_SOCKET_BAD == sock) { - logmsg("Error opening socket: %d", SOCKERRNO); + if(CURL_SOCKET_BAD == sock) { + error = SOCKERRNO; + logmsg("Error creating socket: (%d) %s", + error, strerror(error)); return 1; } @@ -652,8 +663,9 @@ int main(int argc, char *argv[]) } #endif /* ENABLE_IPV6 */ if(rc) { - perror("connecting stream socket"); - logmsg("Error connecting to port %d", port); + error = SOCKERRNO; + logmsg("Error connecting to port %d: (%d) %s", + port, error, strerror(error)); sclose(sock); return 1; } diff --git a/tests/server/util.c b/tests/server/util.c index 95f8c52..15a4e60 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -165,31 +165,60 @@ char *test2file(long testno) return filename; } -void go_sleep(long ms) +/* + * Portable function used for waiting a specific amount of ms. + * Waiting indefinitely with this function is not allowed, a + * zero or negative timeout value will return immediately. + * + * Return values: + * -1 = system call error, or invalid timeout value + * 0 = specified timeout has elapsed + */ +int wait_ms(int timeout_ms) { -#ifdef HAVE_POLL_FINE - /* portable subsecond "sleep" */ - poll((void *)0, 0, (int)ms); -#else - /* systems without poll() need other solutions */ - -#ifdef WIN32 - /* Windows offers a millisecond sleep */ - Sleep(ms); -#elif defined(MSDOS) - delay(ms); -#else - /* Other systems must use select() for this */ - struct timeval timeout; - - timeout.tv_sec = ms/1000; - ms = ms%1000; - timeout.tv_usec = ms * 1000; - - select(0, NULL, NULL, NULL, &timeout); +#if !defined(MSDOS) && !defined(USE_WINSOCK) +#ifndef HAVE_POLL_FINE + struct timeval pending_tv; #endif - + struct timeval initial_tv; + int pending_ms; + int error; #endif -} + int r = 0; + if(!timeout_ms) + return 0; + if(timeout_ms < 0) { + SET_SOCKERRNO(EINVAL); + return -1; + } +#if defined(MSDOS) + delay(timeout_ms); +#elif defined(USE_WINSOCK) + Sleep(timeout_ms); +#else + pending_ms = timeout_ms; + initial_tv = curlx_tvnow(); + do { +#if defined(HAVE_POLL_FINE) + r = poll(NULL, 0, pending_ms); +#else + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + r = select(0, NULL, NULL, NULL, &pending_tv); +#endif /* HAVE_POLL_FINE */ + if(r != -1) + break; + error = SOCKERRNO; + if(error == EINVAL) + break; + pending_ms = timeout_ms - (int)curlx_tvdiff(curlx_tvnow(), initial_tv); + if(pending_ms <= 0) + break; + } while(r == -1); +#endif /* USE_WINSOCK */ + if(r) + r = -1; + return r; +} diff --git a/tests/server/util.h b/tests/server/util.h index c1eccfa..8c49419 100644 --- a/tests/server/util.h +++ b/tests/server/util.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,6 +49,6 @@ void win32_cleanup(void); /* returns the path name to the test case file */ char *test2file(long testno); -void go_sleep(long ms); +int wait_ms(int timeout_ms); #endif /* __SERVER_UTIL_H */ -- 2.7.4