Reduce to 20 seconds the time allowed to set SO_REUSEADDR option on sockfilt listener...
authorYang Tse <yangsita@gmail.com>
Mon, 18 Feb 2008 20:13:30 +0000 (20:13 +0000)
committerYang Tse <yangsita@gmail.com>
Mon, 18 Feb 2008 20:13:30 +0000 (20:13 +0000)
Log some more error descriptions.

tests/server/sockfilt.c
tests/server/util.c
tests/server/util.h

index 7c3404c..042b9f5 100644 (file)
@@ -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;
     }
index 95f8c52..15a4e60 100644 (file)
@@ -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;
+}
 
index c1eccfa..8c49419 100644 (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
  * 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 */