gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r13630 - gnunet/src/arm


From: gnunet
Subject: [GNUnet-SVN] r13630 - gnunet/src/arm
Date: Wed, 10 Nov 2010 09:08:37 +0100

Author: grothoff
Date: 2010-11-10 09:08:37 +0100 (Wed, 10 Nov 2010)
New Revision: 13630

Modified:
   gnunet/src/arm/gnunet-service-arm_interceptor.c
Log:
sockets patch from #1616

Modified: gnunet/src/arm/gnunet-service-arm_interceptor.c
===================================================================
--- gnunet/src/arm/gnunet-service-arm_interceptor.c     2010-11-10 07:06:34 UTC 
(rev 13629)
+++ gnunet/src/arm/gnunet-service-arm_interceptor.c     2010-11-10 08:08:37 UTC 
(rev 13630)
@@ -187,9 +187,15 @@
    * Have we ever successfully written data to the service?
    */
   int first_write_done;
+
+
+  /**
+   * Service connection attempts
+   */
+  struct ServiceListeningInfo *service_connect_ipv4;
+  struct ServiceListeningInfo *service_connect_ipv6;
 };
 
-
 /**
  * Array with the names of the services started by default.
  */
@@ -694,6 +700,10 @@
                                      &forwardToService, fc);
 }
 
+static void fc_acceptConnection (void *cls, const struct 
GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6);
+static void fc_acceptConnection_ipv4 (void *cls, const struct 
GNUNET_SCHEDULER_TaskContext *tc);
+static void fc_acceptConnection_ipv6 (void *cls, const struct 
GNUNET_SCHEDULER_TaskContext *tc);
+static int service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, 
struct ForwardedConnection *fc);
 
 /**
  *
@@ -704,103 +714,252 @@
 {
   struct ForwardedConnection *fc = cls;
   struct GNUNET_TIME_Relative rem;
+  int fail = 0;
+  int failures = 0;
+  int is_zero = 0, is_ipv6 = 0, is_ipv4 = 0;
+  struct sockaddr_in *target_ipv4;
+  struct sockaddr_in6 *target_ipv6;
 
+  int free_ipv4 = 1, free_ipv6 = 1;
+  char listen_address[128];
+  uint16_t listening_port;
+
   fc->start_task = GNUNET_SCHEDULER_NO_TASK;
   if ( (NULL != tc) &&
        (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _("Unable to forward to service `%s': shutdown\n"),
-                 fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+               _("Unable to forward to service `%s': shutdown\n"),
+               fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
   rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
   if (rem.rel_value == 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               _("Unable to forward to service `%s': timeout before 
connect\n"),
+               fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+  target_ipv4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+  target_ipv6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
+
+  switch (fc->listen_info->service_addr->sa_family)
+  {
+  case AF_INET:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) 
&((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, 
listen_address, INET_ADDRSTRLEN);
+    if (strncmp (listen_address, "0.0.0.0:", 8) == 0 || strncmp 
(listen_address, "0.0.0.0", 7) == 0)
+      is_zero = 1;
+    is_ipv4 = 1;
+    listening_port = ((struct sockaddr_in 
*)fc->listen_info->service_addr)->sin_port;
+    break;
+  case AF_INET6:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) 
&((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, 
listen_address, INET6_ADDRSTRLEN);
+    if (strncmp (listen_address, "[::]:", 5) == 0 || strncmp (listen_address, 
"::", 2) == 0)
+      is_zero = 1;
+    is_ipv6 = 1;
+    listening_port = ((struct sockaddr_in6 
*)fc->listen_info->service_addr)->sin6_port;
+    break;
+  default:
+    break;
+  }
+
+  fc->service_connect_ipv4 = NULL;
+  fc->service_connect_ipv6 = NULL;
+  if (is_zero)
+  {
+    /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
+    inet_pton (AF_INET, "127.0.0.1", &target_ipv4->sin_addr);
+    target_ipv4->sin_family = AF_INET;
+    target_ipv4->sin_port = listening_port;
+    is_ipv4 = 1;
+    free_ipv4 = 0;
+
+    inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &target_ipv6->sin6_addr);
+    target_ipv6->sin6_family = AF_INET6;
+    target_ipv6->sin6_port = listening_port;
+    is_ipv6 = 1;
+    free_ipv6 = 0;
+  }
+  else
+  {
+    if (is_ipv4)
+      memcpy (target_ipv4, fc->listen_info->service_addr, sizeof (struct 
sockaddr_in));
+    else if (is_ipv6)
+      memcpy (target_ipv6, fc->listen_info->service_addr, sizeof (struct 
sockaddr_in6));
+  }
+
+  if (is_ipv4)
+    failures += free_ipv4 = service_try_to_connect ((struct sockaddr *) 
target_ipv4, sizeof (struct sockaddr_in), fc);
+  if (is_ipv6)
+    failures += free_ipv6 = service_try_to_connect ((struct sockaddr *) 
target_ipv6, sizeof (struct sockaddr_in6), fc);
+
+  if (is_ipv4 + is_ipv6 <= failures)
+    fail = 1;
+
+  if (free_ipv4)
+    GNUNET_free (target_ipv4);
+  if (free_ipv6)
+    GNUNET_free (target_ipv6);
+
+  if (fail)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _ ("Unable to start service `%s': %s\n"),
+               fc->listen_info->serviceName,
+               STRERROR (errno));
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+}
+
+static void
+fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
+{
+  fc_acceptConnection (cls, tc, 1, 0);
+}
+
+static void
+fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
+{
+  fc_acceptConnection (cls, tc, 0, 1);
+}
+
+static void
+fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, 
int is_ipv4, int is_ipv6)
+{
+  struct ForwardedConnection *fc = cls;
+  struct ServiceListeningInfo *sli;
+
+  if (is_ipv4)
+    sli = fc->service_connect_ipv4;
+  else if (is_ipv6)
+    sli = fc->service_connect_ipv6;
+  else
+    GNUNET_break (0);
+
+  if ((tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | 
GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || 
((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket))
+  {
+    GNUNET_NETWORK_socket_close (sli->listeningSocket);
+    if (is_ipv4)
+      fc->service_connect_ipv4 = NULL;
+    else if (is_ipv6)
+      fc->service_connect_ipv6 = NULL;
+  }
+  else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)
+  {
+#if DEBUG_SERVICE_MANAGER
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+       "Connected to service, now starting forwarding\n");
+#endif
+    fc->armServiceSocket = sli->listeningSocket;
+    if ((is_ipv4 && fc->service_connect_ipv6 != NULL))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Unable to forward to service `%s': timeout before 
connect\n"),
-                 fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask);
+      fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now 
(fc_acceptConnection_ipv6, fc);
     }
-  fc->armServiceSocket =
-    GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
-                                 SOCK_STREAM, 0);
-  if (NULL == fc->armServiceSocket)
+    else if (is_ipv6 && fc->service_connect_ipv4 != NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _ ("Unable to start service `%s': %s\n"),
-                 fc->listen_info->serviceName,
-                 STRERROR (errno));
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask);
+      fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now 
(fc_acceptConnection_ipv4, fc);
     }
-  if ( (GNUNET_SYSERR ==
-       GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
-                                      fc->listen_info->service_addr,
-                                      fc->listen_info->service_addr_len)) &&
-       (errno != EINPROGRESS) )
+    GNUNET_free (fc->listen_info->service_addr);
+    fc->listen_info->service_addr = sli->service_addr;
+    fc->listen_info->service_addr_len = sli->service_addr_len;
+    /*fc->listen_info->listeningSocket is it closed already?*/
+    if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
     {
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (fc->armServiceSocket));
-      fc->armServiceSocket = NULL;
-      fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
-  #if DEBUG_SERVICE_MANAGER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Failed to connected to service `%s' at `%s', will try again 
in %llu ms\n",
-                 fc->listen_info->serviceName,
-                 GNUNET_a2s (fc->listen_info->service_addr,
-                             fc->listen_info->service_addr_len),
-                 (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
-                                                                
rem).rel_value);
-#endif
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
-      fc->start_task
-       = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
-                                                                 rem),
-                                       &start_forwarding,
-                                       fc);
-      return;
-    }
-#if DEBUG_SERVICE_MANAGER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Connected to service, now starting forwarding\n");
-#endif
-  if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
-    {
       if (fc->client_to_service_bufferDataLength == 0) 
-       fc->client_to_service_task =
-         GNUNET_SCHEDULER_add_read_net (
+         fc->client_to_service_task =
+           GNUNET_SCHEDULER_add_read_net (
                                         GNUNET_TIME_UNIT_FOREVER_REL,
                                         fc->armClientSocket,
                                         &receiveFromClient, fc);
       else
-       fc->client_to_service_task = 
-         GNUNET_SCHEDULER_add_write_net (
+         fc->client_to_service_task = 
+           GNUNET_SCHEDULER_add_write_net (
                                          GNUNET_TIME_UNIT_FOREVER_REL,
                                          fc->armServiceSocket,
                                          &forwardToService, fc);
     }
-  if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
+    if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
     {
       if (fc->service_to_client_bufferDataLength == 0) 
-       fc->service_to_client_task =
-         GNUNET_SCHEDULER_add_read_net (
+         fc->service_to_client_task =
+           GNUNET_SCHEDULER_add_read_net (
                                         GNUNET_TIME_UNIT_FOREVER_REL,
                                         fc->armServiceSocket,
                                         &receiveFromService, fc);
       else
-       fc->service_to_client_task = 
-         GNUNET_SCHEDULER_add_write_net (
+         fc->service_to_client_task = 
+           GNUNET_SCHEDULER_add_write_net (
                                          GNUNET_TIME_UNIT_FOREVER_REL,
                                          fc->armClientSocket,
                                          &forwardToClient, fc);
     }
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+  GNUNET_free (sli);
 }
 
+static int
+service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct 
ForwardedConnection *fc)
+{
+  struct GNUNET_NETWORK_Handle *sock;
+  struct ServiceListeningInfo *serviceListeningInfo;
 
+  sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
+  if (sock == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n");
+    return 1;
+  }
+  
+  if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) 
&&
+       (errno != EINPROGRESS) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    return 1;
+  }
 
+  serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+  serviceListeningInfo->serviceName = NULL;
+  serviceListeningInfo->service_addr = addr;
+  serviceListeningInfo->service_addr_len = addrlen;
+  serviceListeningInfo->listeningSocket = sock;
+
+  switch (addrlen)
+  {
+  case sizeof (struct sockaddr_in):
+    fc->service_connect_ipv4 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+                                       &fc_acceptConnection_ipv4, fc);
+    break;
+  case sizeof (struct sockaddr_in6):
+    fc->service_connect_ipv6 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+                                       &fc_acceptConnection_ipv6, fc);
+    break;
+  default:
+    GNUNET_break (0);
+    return 1;
+    break;
+  }
+  return 0;
+}
+
+
+
 /**
  *
  */




reply via email to

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