Reduce to 20 seconds the time allowed to set SO_REUSEADDR option on sockfilt listener socket.

Log some more error descriptions.
This commit is contained in:
Yang Tse 2008-02-18 20:13:30 +00:00
parent 0d722204c3
commit c9eb41c056
3 changed files with 112 additions and 71 deletions

View File

@ -143,7 +143,7 @@ static void sigpipe_handler(int sig)
} }
#endif #endif
char use_ipv6=FALSE; bool use_ipv6=FALSE;
unsigned short port = DEFAULT_PORT; unsigned short port = DEFAULT_PORT;
unsigned short connectport = 0; /* if non-zero, we activate this mode */ 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 */ #endif /* ENABLE_IPV6 */
int flag = 1; int flag = 1;
int rc; int rc;
int maxretr = 12; int totdelay = 0;
int delay= 10; int maxretr = 10;
int delay= 20;
int attempt = 0;
int error = 0;
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, do {
(void *)&flag, sizeof(flag)); attempt++;
while ((rc < 0) && maxretr) {
maxretr--;
go_sleep(delay);
delay *= 2; /* double the sleep for next attempt */
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(void *)&flag, sizeof(flag)); (void *)&flag, sizeof(flag));
} if(rc) {
if (rc < 0) { error = SOCKERRNO;
perror("setsockopt(SO_REUSEADDR)"); 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 #ifdef ENABLE_IPV6
if(!use_ipv6) { if(!use_ipv6) {
#endif #endif
memset(&me, 0, sizeof(me));
me.sin_family = AF_INET; me.sin_family = AF_INET;
me.sin_addr.s_addr = INADDR_ANY; me.sin_addr.s_addr = INADDR_ANY;
me.sin_port = htons(*listenport); me.sin_port = htons(*listenport);
@ -453,16 +471,17 @@ static curl_socket_t sockdaemon(curl_socket_t sock,
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
} }
else { else {
memset(&me6, 0, sizeof(struct sockaddr_in6)); memset(&me6, 0, sizeof(me6));
me6.sin6_family = AF_INET6; me6.sin6_family = AF_INET6;
me6.sin6_addr = in6addr_any; me6.sin6_addr = in6addr_any;
me6.sin6_port = htons(*listenport); me6.sin6_port = htons(*listenport);
rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6)); rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6));
} }
#endif /* ENABLE_IPV6 */ #endif /* ENABLE_IPV6 */
if(rc < 0) { if(rc) {
perror("binding stream socket"); error = SOCKERRNO;
logmsg("Error binding socket"); logmsg("Error binding socket: (%d) %s", error, strerror(error));
sclose(sock);
return CURL_SOCKET_BAD; return CURL_SOCKET_BAD;
} }
@ -475,16 +494,21 @@ static curl_socket_t sockdaemon(curl_socket_t sock,
if(getsockname(sock, (struct sockaddr *) &add, if(getsockname(sock, (struct sockaddr *) &add,
&socksize)<0) { &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; return CURL_SOCKET_BAD;
} }
*listenport = ntohs(add.sin_port); *listenport = ntohs(add.sin_port);
} }
/* start accepting connections */ /* start accepting connections */
rc = listen(sock, 4); rc = listen(sock, 5);
if(0 != rc) { if(0 != rc) {
logmsg("listen() failed with error: %d", SOCKERRNO); error = SOCKERRNO;
logmsg("listen() failed with error: (%d) %s",
error, strerror(error));
sclose(sock); sclose(sock);
return CURL_SOCKET_BAD; return CURL_SOCKET_BAD;
} }
@ -492,28 +516,6 @@ static curl_socket_t sockdaemon(curl_socket_t sock,
return 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[]) int main(int argc, char *argv[])
{ {
@ -616,10 +618,19 @@ int main(int argc, char *argv[])
#endif #endif
#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) {
if (CURL_SOCKET_BAD == sock) { error = SOCKERRNO;
logmsg("Error opening socket: %d", SOCKERRNO); logmsg("Error creating socket: (%d) %s",
error, strerror(error));
return 1; return 1;
} }
@ -652,8 +663,9 @@ int main(int argc, char *argv[])
} }
#endif /* ENABLE_IPV6 */ #endif /* ENABLE_IPV6 */
if(rc) { if(rc) {
perror("connecting stream socket"); error = SOCKERRNO;
logmsg("Error connecting to port %d", port); logmsg("Error connecting to port %d: (%d) %s",
port, error, strerror(error));
sclose(sock); sclose(sock);
return 1; return 1;
} }

View File

@ -165,31 +165,60 @@ char *test2file(long testno)
return filename; 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 #if !defined(MSDOS) && !defined(USE_WINSOCK)
/* portable subsecond "sleep" */ #ifndef HAVE_POLL_FINE
poll((void *)0, 0, (int)ms); struct timeval pending_tv;
#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);
#endif #endif
struct timeval initial_tv;
int pending_ms;
int error;
#endif #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;
} }

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * 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 */ /* returns the path name to the test case file */
char *test2file(long testno); char *test2file(long testno);
void go_sleep(long ms); int wait_ms(int timeout_ms);
#endif /* __SERVER_UTIL_H */ #endif /* __SERVER_UTIL_H */