wip
[oweals/gnunet.git] / src / arm / gnunet-service-arm_interceptor.c
index 9380a8debfe3d3c68c0c7611aa3147c0d5d6f053..c86530b6f603fc72dbf106de27a6b8295deda3a5 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -56,6 +56,7 @@
  */
 #define REASON_ERROR 3
 
+struct ForwardedConnection;
 
 /**
  *
@@ -92,6 +93,11 @@ struct ServiceListeningInfo
    */
   struct GNUNET_NETWORK_Handle *listeningSocket;
 
+  /**
+   *
+   */
+  struct ForwardedConnection *fc;
+
   /**
    * Task doing the accepting.
    */
@@ -187,8 +193,8 @@ struct ForwardedConnection
    * Have we ever successfully written data to the service?
    */
   int first_write_done;
-};
 
+};
 
 /**
  * Array with the names of the services started by default.
@@ -205,11 +211,6 @@ static unsigned int numDefaultServices;
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
-/**
- *
- */
-static struct GNUNET_SCHEDULER_Handle *scheduler;
-
 /**
  *
  */
@@ -293,7 +294,7 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
 #endif
       if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK)
        {
-         GNUNET_SCHEDULER_cancel (scheduler, fc->service_to_client_task);    
+         GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
          fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
        }
       if (fc->armClientSocket != NULL)
@@ -312,8 +313,7 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
 #endif
       if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) 
        {
-         GNUNET_SCHEDULER_cancel (scheduler,
-                                  fc->client_to_service_task);
+         GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
          fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
        }
       if (fc->armClientSocket != NULL)
@@ -331,8 +331,7 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
              "Closing forwarding connection (done with both directions)\n");
 #endif
   if (fc->start_task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (scheduler,
-                            fc->start_task);
+    GNUNET_SCHEDULER_cancel (fc->start_task);
   if ( (NULL != fc->armClientSocket) &&
        (GNUNET_SYSERR ==
        GNUNET_NETWORK_socket_close (fc->armClientSocket)) )
@@ -349,14 +348,20 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
 
 
 /**
- *
+ * Read data from the client and then forward it to the service.
+ * 
+ * @param cls callback data,   struct ForwardedConnection for the communication between client and service
+ * @param tc context 
  */
 static void
 receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
 /**
- *
+ * Receive service messages sent by the service and forward it to client
+ * 
+ * @param cls callback data, struct ForwardedConnection for the communication between client and service
+ * @param tc scheduler context
  */
 static void
 receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
@@ -388,7 +393,7 @@ forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                                                fc->armClientSocket))
     {
       fc->service_to_client_task = 
-       GNUNET_SCHEDULER_add_write_net (scheduler,
+       GNUNET_SCHEDULER_add_write_net (
                                        GNUNET_TIME_UNIT_FOREVER_REL,
                                        fc->armClientSocket,
                                        &forwardToClient, fc);
@@ -421,7 +426,7 @@ forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       fc->service_to_client_bufferPos += numberOfBytesSent;
       fc->service_to_client_bufferDataLength -= numberOfBytesSent;
       fc->service_to_client_task = 
-       GNUNET_SCHEDULER_add_write_net (scheduler, 
+       GNUNET_SCHEDULER_add_write_net (
                                        GNUNET_TIME_UNIT_FOREVER_REL,
                                        fc->armClientSocket,
                                        &forwardToClient, 
@@ -429,8 +434,7 @@ forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       return;
     }
   fc->service_to_client_task =
-    GNUNET_SCHEDULER_add_read_net (scheduler, 
-                                  GNUNET_TIME_UNIT_FOREVER_REL,
+    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                   fc->armServiceSocket,
                                   &receiveFromService, 
                                   fc);
@@ -461,7 +465,7 @@ receiveFromService (void *cls,
                                                fc->armServiceSocket))
     {
       fc->service_to_client_task =
-       GNUNET_SCHEDULER_add_read_net (scheduler,
+       GNUNET_SCHEDULER_add_read_net (
                                       GNUNET_TIME_UNIT_FOREVER_REL,
                                       fc->armServiceSocket,
                                       &receiveFromService, fc);
@@ -491,9 +495,8 @@ receiveFromService (void *cls,
          if ( (fc->client_to_service_bufferDataLength > 0) &&
               (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) )
            {
-             GNUNET_SCHEDULER_cancel (scheduler,
-                                      fc->client_to_service_task);
-             fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
+             GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
+             fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
            }
          fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
 #if DEBUG_SERVICE_MANAGER
@@ -503,12 +506,12 @@ receiveFromService (void *cls,
                      GNUNET_a2s (fc->listen_info->service_addr,
                                  fc->listen_info->service_addr_len),
                      (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
-                                                                    rem).value);
+                                                                    rem).rel_value);
 #endif
          rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
          GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
          fc->start_task
-           = GNUNET_SCHEDULER_add_delayed (scheduler,
+           = GNUNET_SCHEDULER_add_delayed (
                                            GNUNET_TIME_relative_min (fc->back_off,
                                                                      rem),
                                            &start_forwarding,
@@ -533,7 +536,7 @@ receiveFromService (void *cls,
              fc->service_to_client_bufferDataLength);
 #endif
   fc->service_to_client_task = 
-    GNUNET_SCHEDULER_add_write_net (scheduler, 
+    GNUNET_SCHEDULER_add_write_net (
                                    GNUNET_TIME_UNIT_FOREVER_REL,
                                    fc->armClientSocket,
                                    &forwardToClient, fc);
@@ -565,7 +568,7 @@ forwardToService (void *cls,
                                                fc->armServiceSocket))
     {
       fc->client_to_service_task = 
-       GNUNET_SCHEDULER_add_write_net (scheduler,
+       GNUNET_SCHEDULER_add_write_net (
                                        GNUNET_TIME_UNIT_FOREVER_REL,
                                        fc->armServiceSocket,
                                        &forwardToService, fc);
@@ -585,8 +588,7 @@ forwardToService (void *cls,
          if ( (fc->service_to_client_bufferDataLength == 0) &&
               (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
            {
-             GNUNET_SCHEDULER_cancel (scheduler,
-                                      fc->service_to_client_task);
+             GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
              fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
            }
          fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
@@ -597,13 +599,12 @@ forwardToService (void *cls,
                      GNUNET_a2s (fc->listen_info->service_addr,
                                  fc->listen_info->service_addr_len),
                      (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
-                                                                    rem).value);
+                                                                    rem).rel_value);
 #endif
          rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
          GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
          fc->start_task 
-           = GNUNET_SCHEDULER_add_delayed (scheduler,
-                                           GNUNET_TIME_relative_min (fc->back_off,
+           = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
                                                                      rem),
                                            &start_forwarding,
                                            fc);
@@ -631,15 +632,14 @@ forwardToService (void *cls,
       fc->client_to_service_bufferPos += numberOfBytesSent;
       fc->client_to_service_bufferDataLength -= numberOfBytesSent;
       fc->client_to_service_task = 
-       GNUNET_SCHEDULER_add_write_net (scheduler, 
+       GNUNET_SCHEDULER_add_write_net (
                                        GNUNET_TIME_UNIT_FOREVER_REL,
                                        fc->armServiceSocket,
                                        &forwardToService, fc);
       return;
     }
   fc->client_to_service_task =
-    GNUNET_SCHEDULER_add_read_net (scheduler, 
-                                  GNUNET_TIME_UNIT_FOREVER_REL,
+    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                   fc->armClientSocket,
                                   &receiveFromClient, fc);
 }
@@ -661,8 +661,7 @@ receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                                                fc->armClientSocket))
     {
       fc->client_to_service_task =
-       GNUNET_SCHEDULER_add_read_net (scheduler,
-                                      GNUNET_TIME_UNIT_FOREVER_REL,
+       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                       fc->armClientSocket,
                                       &receiveFromClient, fc);
       return;
@@ -700,98 +699,45 @@ receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 #endif
   if (fc->armServiceSocket != NULL)        
     fc->client_to_service_task = 
-      GNUNET_SCHEDULER_add_write_net (scheduler,
+      GNUNET_SCHEDULER_add_write_net (
                                      GNUNET_TIME_UNIT_FOREVER_REL,
                                      fc->armServiceSocket,
                                      &forwardToService, fc);
 }
 
 
-/**
- *
- */
 static void
-start_forwarding (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+fc_acceptConnection (void *cls, 
+                    const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct ForwardedConnection *fc = cls;
-  struct GNUNET_TIME_Relative rem;
+  struct ServiceListeningInfo *sli = cls;
+  struct ForwardedConnection *fc = sli->fc;
 
-  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;
-    }
-  rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
-  if (rem.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;
-    }
-  fc->armServiceSocket =
-    GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
-                                 SOCK_STREAM, 0);
-  if (NULL == fc->armServiceSocket)
+  if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _ ("Unable to start service `%s': %s\n"),
-                 fc->listen_info->serviceName,
-                 STRERROR (errno));
+      GNUNET_assert (GNUNET_OK == GNUNET_NETWORK_socket_close (sli->listeningSocket));
       closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
-    }
-  if ( (GNUNET_SYSERR ==
-       GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
-                                      fc->listen_info->service_addr,
-                                      fc->listen_info->service_addr_len)) &&
-       (errno != EINPROGRESS) )
-    {
-      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).value);
-#endif
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
-      fc->start_task
-       = GNUNET_SCHEDULER_add_delayed (scheduler,
-                                       GNUNET_TIME_relative_min (fc->back_off,
-                                                                 rem),
-                                       &start_forwarding,
-                                       fc);
+      GNUNET_free (sli);
       return;
     }
 #if DEBUG_SERVICE_MANAGER
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Connected to service, now starting forwarding\n");
 #endif
+  fc->armServiceSocket = sli->listeningSocket;
+  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;
   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 (scheduler,
-                                        GNUNET_TIME_UNIT_FOREVER_REL,
+         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 (scheduler, 
-                                         GNUNET_TIME_UNIT_FOREVER_REL,
+         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                          fc->armServiceSocket,
                                          &forwardToService, fc);
     }
@@ -799,20 +745,158 @@ start_forwarding (void *cls,
     {
       if (fc->service_to_client_bufferDataLength == 0) 
        fc->service_to_client_task =
-         GNUNET_SCHEDULER_add_read_net (scheduler,
-                                        GNUNET_TIME_UNIT_FOREVER_REL,
+         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 (scheduler, 
-                                         GNUNET_TIME_UNIT_FOREVER_REL,
+         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                          fc->armClientSocket,
                                          &forwardToClient, fc);
     }
+  GNUNET_free (sli);
 }
 
 
+static struct ServiceListeningInfo *
+service_try_to_connect (const struct sockaddr *addr, 
+                       int pf,
+                       socklen_t addrlen, 
+                       struct ForwardedConnection *fc)
+{
+  struct GNUNET_NETWORK_Handle *sock;
+  struct ServiceListeningInfo *serviceListeningInfo;
+
+  sock = GNUNET_NETWORK_socket_create (pf, SOCK_STREAM, 0);
+  if (sock == NULL)
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
+      return NULL;
+    }  
+  if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
+       (errno != EINPROGRESS) )
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+      return NULL;
+    }  
+  serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+  serviceListeningInfo->serviceName = NULL;
+  serviceListeningInfo->service_addr = GNUNET_malloc (addrlen);
+  memcpy (serviceListeningInfo->service_addr,
+         addr,
+         addrlen);
+  serviceListeningInfo->service_addr_len = addrlen;
+  serviceListeningInfo->listeningSocket = sock;
+  serviceListeningInfo->fc = fc;
+  serviceListeningInfo->acceptTask =
+    GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                   serviceListeningInfo->listeningSocket,
+                                   &fc_acceptConnection, serviceListeningInfo);
+  return serviceListeningInfo;
+}
+
+
+/**
+ *
+ */
+static void
+start_forwarding (void *cls,
+                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ForwardedConnection *fc = cls;
+  struct ServiceListeningInfo *sc;
+  struct sockaddr_in target_ipv4;
+  struct sockaddr_in6 target_ipv6;
+  const struct sockaddr_in *v4;
+  const struct sockaddr_in6 *v6;
+  char listen_address[INET6_ADDRSTRLEN];
+
+  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;
+    }
+  if (0 == GNUNET_TIME_absolute_get_remaining (fc->timeout).rel_value)
+    {
+      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;
+    }
+  switch (fc->listen_info->service_addr->sa_family)
+    {
+    case AF_UNSPEC:
+      GNUNET_break (0);
+      closeClientAndServiceSockets (fc, REASON_ERROR);
+      return;      
+    case AF_INET:
+      v4 = (const struct sockaddr_in *) fc->listen_info->service_addr;
+      inet_ntop (fc->listen_info->service_addr->sa_family, 
+                (const void *) &v4->sin_addr, 
+                listen_address,
+                INET_ADDRSTRLEN);
+      if (0 == strncmp (listen_address, "0.0.0.0", 7))
+       {
+         /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
+         memset (&target_ipv4, 0, sizeof (target_ipv4));
+         inet_pton (AF_INET, "127.0.0.1", &target_ipv4.sin_addr);
+         target_ipv4.sin_family = AF_INET;
+         target_ipv4.sin_port = v4->sin_port;
+         v4 = &target_ipv4;
+       }
+      sc = service_try_to_connect ((const struct sockaddr*) v4,
+                                  PF_INET,
+                                  sizeof (struct sockaddr_in), 
+                                  fc);
+      break;
+    case AF_INET6:
+      v6 = (struct sockaddr_in6 *)fc->listen_info->service_addr;
+      inet_ntop (fc->listen_info->service_addr->sa_family, 
+                (const void *) &v6->sin6_addr, 
+                listen_address, 
+                INET6_ADDRSTRLEN);
+      if ( (strncmp (listen_address, "[::]:", 5) == 0) || (strncmp (listen_address, "::", 2) == 0) )
+       {
+         memset (&target_ipv6, 0, sizeof (target_ipv6));
+         target_ipv6.sin6_addr = in6addr_loopback;
+         target_ipv6.sin6_family = AF_INET6;
+         target_ipv6.sin6_port = v6->sin6_port;
+         v6 = &target_ipv6;
+       }
+      sc = service_try_to_connect ((const struct sockaddr*) v6,
+                                  PF_INET6,
+                                  sizeof (struct sockaddr_in6), 
+                                  fc);
+      break;
+    case AF_UNIX:
+      sc = service_try_to_connect (fc->listen_info->service_addr,
+                                  PF_UNIX,
+                                  fc->listen_info->service_addr_len,
+                                  fc);
+      break;
+    default:
+      GNUNET_break (0);
+      closeClientAndServiceSockets (fc, REASON_ERROR);
+      return;
+    }  
+  if (NULL == sc)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _ ("Unable to start service `%s': %s\n"),
+                 fc->listen_info->serviceName,
+                 STRERROR (errno));
+      closeClientAndServiceSockets (fc, REASON_ERROR);
+      return;
+    }
+}
+
 
 /**
  *
@@ -833,7 +917,7 @@ stop_listening (const char *serviceName)
           (strcmp (pos->serviceName, serviceName) != 0) )
        continue;
       if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK)
-       GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask);
+       GNUNET_SCHEDULER_cancel (pos->acceptTask);
       GNUNET_break (GNUNET_OK ==
                    GNUNET_NETWORK_socket_close (pos->listeningSocket));
       GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
@@ -847,7 +931,6 @@ stop_listening (const char *serviceName)
   return ret;
 }
 
-
 /**
  * First connection has come to the listening socket associated with the service,
  * create the service in order to relay the incoming connection to it
@@ -856,14 +939,14 @@ stop_listening (const char *serviceName)
  * @param tc context 
  */
 static void
-acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+static void
+accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo)
 {
-  struct ServiceListeningInfo *serviceListeningInfo = cls;
   struct ForwardedConnection *fc;
 
-  serviceListeningInfo->acceptTask = GNUNET_SCHEDULER_NO_TASK;
-  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
-    return;
   fc = GNUNET_malloc (sizeof (struct ForwardedConnection));
   fc->listen_info = serviceListeningInfo;
   fc->service_to_client_bufferPos = fc->service_to_client_buffer;
@@ -879,9 +962,11 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                  serviceListeningInfo->serviceName,
                  STRERROR (errno));
       GNUNET_free (fc);
+      GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
+                                  serviceListeningInfoList_tail, 
+                                  serviceListeningInfo); 
       serviceListeningInfo->acceptTask =
-       GNUNET_SCHEDULER_add_read_net (scheduler,
-                                      GNUNET_TIME_UNIT_FOREVER_REL, 
+       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
                                       serviceListeningInfo->listeningSocket,
                                       &acceptConnection,
                                       serviceListeningInfo);
@@ -889,28 +974,100 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     }
   GNUNET_break (GNUNET_OK ==
                GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket));
-  GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
-                              serviceListeningInfoList_tail, 
-                              serviceListeningInfo);
-  start_service (NULL, serviceListeningInfo->serviceName);
+  start_service (NULL, serviceListeningInfo->serviceName, NULL);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
              _("Service `%s' started\n"),
              fc->listen_info->serviceName);
   fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT);
   fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
   fc->client_to_service_task =
-    GNUNET_SCHEDULER_add_read_net (scheduler,
-                                  GNUNET_TIME_UNIT_FOREVER_REL,
+    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                   fc->armClientSocket,
                                   &receiveFromClient, fc);
   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
   fc->start_task 
-    = GNUNET_SCHEDULER_add_now (scheduler,
-                               &start_forwarding,
+    = GNUNET_SCHEDULER_add_now (&start_forwarding,
                                fc);
 }
 
 
+/**
+ * First connection has come to the listening socket associated with the service,
+ * create the service in order to relay the incoming connection to it
+ * 
+ * @param cls callback data, struct ServiceListeningInfo describing a listen socket
+ * @param tc context 
+ */
+static void
+acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceListeningInfo *sli = cls;
+  struct ServiceListeningInfo *pos;
+  struct ServiceListeningInfo *next;
+  int *lsocks;
+  unsigned int ls;
+  int use_lsocks;
+
+  sli->acceptTask = GNUNET_SCHEDULER_NO_TASK;
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    return;
+  GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
+                              serviceListeningInfoList_tail, 
+                              sli);  
+#ifndef MINGW
+  use_lsocks = GNUNET_NO;
+  if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
+                                                    sli->serviceName,
+                                                    "DISABLE_SOCKET_FORWARDING"))
+    use_lsocks = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                      sli->serviceName,
+                                                      "DISABLE_SOCKET_FORWARDING");
+#else
+  use_lsocks = GNUNET_YES;
+#endif
+  if (GNUNET_NO != use_lsocks)
+    {
+      accept_and_forward (sli);
+      return;
+    }
+  lsocks = NULL;
+  ls = 0;
+  next = serviceListeningInfoList_head;
+  while (NULL != (pos = next))
+    {
+      next = pos->next;
+      if (0 == strcmp (pos->serviceName,
+                      sli->serviceName))
+       {
+         GNUNET_array_append (lsocks, ls, 
+                              GNUNET_NETWORK_get_fd (pos->listeningSocket));     
+         GNUNET_free (pos->listeningSocket); /* deliberately no closing! */
+         GNUNET_free (pos->service_addr);
+         GNUNET_free (pos->serviceName);
+         GNUNET_SCHEDULER_cancel (pos->acceptTask);
+         GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
+                                      serviceListeningInfoList_tail, 
+                                      pos);
+         GNUNET_free (pos);
+       }
+    }
+  GNUNET_array_append (lsocks, ls, 
+                      GNUNET_NETWORK_get_fd (sli->listeningSocket));
+  GNUNET_free (sli->listeningSocket); /* deliberately no closing! */
+  GNUNET_free (sli->service_addr);
+  GNUNET_array_append (lsocks, ls, -1);
+  start_service (NULL, 
+                sli->serviceName,
+                lsocks);
+  ls = 0;
+  while (lsocks[ls] != -1)
+    GNUNET_break (0 == close (lsocks[ls++]));      
+  GNUNET_array_grow (lsocks, ls, 0);
+  GNUNET_free (sli->serviceName);
+  GNUNET_free (sli); 
+}
+
+
 /**
  * Creating a listening socket for each of the service's addresses and
  * wait for the first incoming connection to it
@@ -937,6 +1094,8 @@ createListeningSocket (struct sockaddr *sa,
       sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
       break;
     case AF_UNIX:
+      if (strcmp(GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
+        return;
       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
       break;
     default:
@@ -969,7 +1128,7 @@ createListeningSocket (struct sockaddr *sa,
   if (GNUNET_NETWORK_socket_bind
       (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
                  serviceName,
                  GNUNET_a2s (sa, addr_len),
@@ -996,8 +1155,7 @@ createListeningSocket (struct sockaddr *sa,
   serviceListeningInfo->service_addr_len = addr_len;
   serviceListeningInfo->listeningSocket = sock;
   serviceListeningInfo->acceptTask =
-    GNUNET_SCHEDULER_add_read_net (scheduler,
-                                  GNUNET_TIME_UNIT_FOREVER_REL, sock,
+    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
                                   &acceptConnection,
                                   serviceListeningInfo);
   GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
@@ -1046,15 +1204,13 @@ checkPortNumberCB (void *cls,
  * Entry point to the Service Manager
  *
  * @param configurationHandle configuration to use to get services
- * @param sched scheduler to handle clients and services communications
  */
 void
 prepareServices (const struct GNUNET_CONFIGURATION_Handle
-                *configurationHandle, struct GNUNET_SCHEDULER_Handle *sched)
+                *configurationHandle)
 {
   char *defaultServicesString;
 
-  scheduler = sched;
   cfg = configurationHandle;
   /* Split the default services into a list */
   if (GNUNET_OK ==