gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r7027 - GNUnet/src/util/network_client


From: gnunet
Subject: [GNUnet-SVN] r7027 - GNUnet/src/util/network_client
Date: Mon, 2 Jun 2008 23:14:48 -0600 (MDT)

Author: grothoff
Date: 2008-06-02 23:14:48 -0600 (Mon, 02 Jun 2008)
New Revision: 7027

Modified:
   GNUnet/src/util/network_client/tcpio.c
Log:
better tcpio

Modified: GNUnet/src/util/network_client/tcpio.c
===================================================================
--- GNUnet/src/util/network_client/tcpio.c      2008-06-02 21:51:05 UTC (rev 
7026)
+++ GNUnet/src/util/network_client/tcpio.c      2008-06-03 05:14:48 UTC (rev 
7027)
@@ -229,7 +229,16 @@
 }
 
 /**
- * Check a socket, open and connect if it is closed and it is a client-socket.
+ * Check a socket, open and connect if it is closed.  This code
+ * supports IPv4 and IPv6 (and may try both).  It also waits a bounded
+ * amount of time for the connection to succeed and may even retry the
+ * same IP version a few times since gnunetd may just be starting or
+ * out of sockets; hence this code could fail on first attempt, will
+ * then wait a few milliseconds, retry and conceivably succeed.  Since
+ * this is then done for multiple address families, the whole thing is
+ * slightly more complicated then your ordinary connect call.  Not to
+ * mention that the code also supports another thread coming in in the
+ * middle and closing the socket for good -- or even opening it!
  */
 int
 GNUNET_client_connection_ensure_connected (struct
@@ -239,6 +248,7 @@
   /* list of address families to try for connecting,
      in order of preference */
   static int addr_families[] = { AF_UNSPEC, AF_INET6, AF_INET, -1 };
+  GNUNET_CronTime select_start;
   struct sockaddr *soaddr;
   socklen_t socklen;
   fd_set rset;
@@ -265,33 +275,33 @@
   host = getGNUnetdHost (sock->ectx, sock->cfg);
   if (host == NULL)
     return GNUNET_SYSERR;
-  af_index = -1;
+  af_index = 0;
+  /* we immediately advance if there is a DNS lookup error 
+   * (which would likely persist) or a socket API error
+   * (which would equally likely persist).  We retry a
+   * few times with a small delay if we may just be having
+   * a connection issue.
+   */
+#define TRIES_PER_AF 4
+#define DELAY_PER_RETRY (250 * GNUNET_CRON_MILLISECONDS)
+#define ADVANCE() do { af_index++; tries = TRIES_PER_AF; } while(0)
+#define RETRY() do { tries--; if (tries == 0) { ADVANCE(); } else { 
GNUNET_thread_sleep(DELAY_PER_RETRY); } } while (0)
+  tries = TRIES_PER_AF;
   /* loop over all possible address families */
   while (1)
     {
-      if (af_index == -1)
-        {
-          tries = 10;
-          af_index = 0;
-        }
-      else
-          af_index++;
       if (addr_families[af_index] == -1)
-        {
-          /* wait for 500ms before trying again */
-          GNUNET_thread_sleep (GNUNET_CRON_MILLISECONDS * 500);
-          af_index = 0;
-          tries--;
-        }
-      if (tries == 0)
-        return GNUNET_SYSERR;
+       return GNUNET_SYSERR;
       soaddr = NULL;
       socklen = 0;
       if (GNUNET_SYSERR ==
           GNUNET_get_ip_from_hostname (sock->ectx, host,
                                        addr_families[af_index], &soaddr,
                                        &socklen))
-        continue;
+       {
+         ADVANCE();
+         continue;
+       }
       GNUNET_mutex_lock (sock->destroylock);
       if (sock->sock != NULL)
         {
@@ -324,7 +334,8 @@
                                   GNUNET_GE_ADMIN | GNUNET_GE_BULK, "socket");
           GNUNET_mutex_unlock (sock->destroylock);
           GNUNET_free (soaddr);
-          continue;
+         ADVANCE();
+         continue;
         }
       sock->sock = GNUNET_socket_create (sock->ectx, NULL, osock);
       GNUNET_socket_set_blocking (sock->sock, GNUNET_NO);
@@ -339,6 +350,10 @@
           GNUNET_socket_destroy (sock->sock);
           sock->sock = NULL;
           GNUNET_mutex_unlock (sock->destroylock);
+         if (errno == ECONNREFUSED)
+           RETRY(); /* gnunetd may just be restarting */
+         else    
+           ADVANCE();
           continue;
         }
       /* we call select() first with a timeout of WAIT_SECONDS to
@@ -350,11 +365,11 @@
       FD_ZERO (&eset);
       FD_SET (osock, &wset);
       FD_SET (osock, &eset);
-#define WAIT_SECONDS 10
-      timeout.tv_sec = WAIT_SECONDS;
-      timeout.tv_usec = 0;
+      timeout.tv_sec = 0;
+      timeout.tv_usec = DELAY_PER_RETRY * TRIES_PER_AF * 1000;
       errno = 0;
-      ret = SELECT (osock + 1, &rset, &wset, &eset, &timeout);
+      select_start = GNUNET_get_time();
+      ret = SELECT (osock + 1, &rset, &wset, &eset, &timeout);      
       if (ret == -1)
         {
           if (errno != EINTR)
@@ -364,9 +379,15 @@
           GNUNET_socket_destroy (sock->sock);
           sock->sock = NULL;
           GNUNET_mutex_unlock (sock->destroylock);
+         if ( (GNUNET_get_time() - select_start > TRIES_PER_AF * 
DELAY_PER_RETRY) ||
+              (errno != EINTR) )
+           ADVANCE(); /* spend enough time trying here */
+         else
+           RETRY();
           continue;
         }
-      if (FD_ISSET (osock, &eset))
+      if ( (FD_ISSET (osock, &eset)) ||
+          (! FD_ISSET (osock, &wset) ) )
         {
           GNUNET_GE_LOG (sock->ectx,
                          GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK,
@@ -374,19 +395,12 @@
           GNUNET_socket_destroy (sock->sock);
           sock->sock = NULL;
           GNUNET_mutex_unlock (sock->destroylock);
-          continue;
+         if (GNUNET_get_time() - select_start > TRIES_PER_AF * DELAY_PER_RETRY)
+           ADVANCE(); /* spend enough time trying here */
+         else
+           RETRY();
+         continue;
         }
-      if (!FD_ISSET (osock, &wset))
-        {
-          GNUNET_GE_LOG (sock->ectx,
-                         GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK,
-                         _("Failed to connect to %s:%u in %ds\n"),
-                         host, port, WAIT_SECONDS);
-          GNUNET_socket_destroy (sock->sock);
-          sock->sock = NULL;
-          GNUNET_mutex_unlock (sock->destroylock);
-          continue;
-        }
       soerr = 0;
       soerrlen = sizeof (soerr);
 
@@ -395,7 +409,6 @@
         GNUNET_GE_LOG_STRERROR (sock->ectx,
                                 GNUNET_GE_WARNING | GNUNET_GE_USER |
                                 GNUNET_GE_BULK, "getsockopt");
-
       if ((soerr != 0) || (ret != 0 && (errno == ENOTSOCK || errno == EBADF)))
         {
           GNUNET_GE_LOG (sock->ectx,
@@ -405,13 +418,22 @@
           GNUNET_socket_destroy (sock->sock);
           sock->sock = NULL;
           GNUNET_mutex_unlock (sock->destroylock);
+         if (GNUNET_get_time() - select_start > TRIES_PER_AF * DELAY_PER_RETRY)
+           ADVANCE(); /* spend enough time trying here */
+         else
+           RETRY();
           continue;
         }
+      /* yayh! connected! */
       break;
     }
   GNUNET_free (host);
   GNUNET_socket_set_blocking (sock->sock, GNUNET_YES);
   GNUNET_mutex_unlock (sock->destroylock);
+#undef ADVANCE
+#undef RETRY
+#undef TRIES_PER_AF
+#undef DELAY_PER_RETRY
   return GNUNET_OK;
 }
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]