[Top][All Lists]
[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;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r7027 - GNUnet/src/util/network_client,
gnunet <=