use bind instead of connect to test if service is running to avoid long timeouts...
authorChristian Grothoff <christian@grothoff.org>
Thu, 11 Aug 2011 11:05:35 +0000 (11:05 +0000)
committerChristian Grothoff <christian@grothoff.org>
Thu, 11 Aug 2011 11:05:35 +0000 (11:05 +0000)
src/arm/arm_api.c
src/arm/gnunet-arm.c
src/transport/Makefile.am
src/util/client.c
src/util/network.c

index c5caa5393da09d025dbc3b0f3c0fb88ff51ddbf1..4114b852851f1704de47f1172ef9d9c1f6d9f5c1 100644 (file)
@@ -379,8 +379,6 @@ arm_service_report (void *cls,
              "Looks like `%s' is not running, will start it.\n",
              "gnunet-service-arm");
 #endif
-  /* FIXME: should we check that HOSTNAME for 'arm' is localhost? */
-
  if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (pos->h->cfg,
                                             "arm", "PREFIX", &loprefix))
@@ -621,6 +619,7 @@ GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
   struct RequestContext *sctx;
   struct GNUNET_CLIENT_Connection *client;
   size_t slen;
+
 #if DEBUG_ARM
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               _("Asked to start service `%s' within %llu ms\n"), service_name,
index c2663aba9464c6c3da1cb6183291a5c06586502b..ccad0f21fc5a0614e7e1afdcd9c574b5307efe4a 100644 (file)
@@ -46,7 +46,7 @@
  * (by checking if running before starting, so really this time is always waited on
  * startup (annoying)).
  */
-#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1000)
+#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 
 /**
  * Timeout for starting services, very short because of the strange way start works
index 74f79013e36df7eddc591e53c069db1ff18ee498..417fdef5aec1beec8f5f556dee76bad3fbb89dbf 100644 (file)
@@ -333,6 +333,7 @@ test_transport_api_disconnect_SOURCES = \
  test_transport_api_disconnect.c
 test_transport_api_disconnect_LDADD = \
  $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
  $(top_builddir)/src/statistics/libgnunetstatistics.la \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(top_builddir)/src/util/libgnunetutil.la 
index 490d1f3da957c8f7d1ca5bdd1befd34a589c33a2..a05c5bf75c28cbc2bca2ee3ce725a7e453afc6a8 100644 (file)
@@ -666,6 +666,15 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 }
 
 
+/**
+ * Send the 'TEST' message to the service.  If successful, prepare to
+ * receive the reply.
+ *
+ * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test
+ * @param size number of bytes available in buf
+ * @param buf where to write the message
+ * @return number of bytes written to buf
+ */
 static size_t
 write_test (void *cls, size_t size, void *buf)
 {
@@ -698,11 +707,13 @@ write_test (void *cls, size_t size, void *buf)
 
 
 /**
- * Wait until the service is running.
+ * Test if the service is running.  If we are given a UNIXPATH or a local address,
+ * we do this NOT by trying to connect to the service, but by trying to BIND to
+ * the same port.  If the BIND fails, we know the service is running.
  *
  * @param service name of the service to wait for
  * @param cfg configuration to use
- * @param timeout how long to wait at most in ms
+ * @param timeout how long to wait at most 
  * @param task task to run if service is running
  *        (reason will be "PREREQ_DONE" (service running)
  *         or "TIMEOUT" (service not known to be running))
@@ -714,12 +725,171 @@ GNUNET_CLIENT_service_test (const char *service,
                             struct GNUNET_TIME_Relative timeout,
                             GNUNET_SCHEDULER_Task task, void *task_cls)
 {
+  char *hostname;
+  unsigned long long port;
+  struct GNUNET_NETWORK_Handle *sock;
   struct GNUNET_CLIENT_Connection *conn;
 
 #if DEBUG_CLIENT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Testing if service `%s' is running.\n", service);
 #endif
+#ifdef AF_UNIX
+  {
+    /* probe UNIX support */
+    struct sockaddr_un s_un;
+    size_t slen;
+    char *unixpath;
+    
+    unixpath = NULL;
+    if ( (GNUNET_OK ==
+         GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                service,
+                                                "UNIXPATH", &unixpath)) &&
+        (0 < strlen (unixpath)) ) /* We have a non-NULL unixpath, does that mean it's valid? */
+      {
+       if (strlen(unixpath) >= sizeof(s_un.sun_path))
+         {
+           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                       _("UNIXPATH `%s' too long, maximum length is %llu\n"),
+                       unixpath, 
+                       sizeof(s_un.sun_path));
+         }
+       else
+         {
+           sock =  GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
+           if (sock != NULL)
+             {
+               memset (&s_un, 0, sizeof (s_un));
+               s_un.sun_family = AF_UNIX;
+               slen = strlen (unixpath) + 1;
+               if (slen >= sizeof (s_un.sun_path))
+                 slen = sizeof (s_un.sun_path) - 1;
+               memcpy (s_un.sun_path,
+                       unixpath,
+                       slen);
+               s_un.sun_path[slen] = '\0';
+               slen = sizeof (struct sockaddr_un);
+#if LINUX
+               s_un.sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_IN_SIN_LEN
+               s_un.sun_len = (u_char) slen;
+#endif
+               if (GNUNET_OK !=
+                   GNUNET_NETWORK_socket_bind (sock,
+                                               (const struct sockaddr*) &s_un,
+                                               slen))
+                 {
+                   /* failed to bind => service must be running */
+                   GNUNET_free (unixpath);
+                   (void) GNUNET_NETWORK_socket_close (sock);
+                   GNUNET_SCHEDULER_add_continuation (task,
+                                                      task_cls,
+                                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+                   return;
+                 }
+               (void) GNUNET_NETWORK_socket_close (sock);
+             }
+           /* let's try IP */
+         }
+      }
+    GNUNET_free_non_null (unixpath);
+  }
+#endif
+
+  hostname = NULL;
+  if ((GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_number (cfg,
+                                              service,
+                                              "PORT",
+                                              &port)) ||
+      (port > 65535) ||
+      (GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_string (cfg,
+                                              service,
+                                              "HOSTNAME", &hostname)))
+    {
+      /* UNIXPATH failed (if possible) AND IP failed => error */
+      service_test_error (task, task_cls);
+      return;
+    }
+  
+  if (0 == strcmp ("localhost", hostname)) 
+    {
+      /* can test using 'bind' */
+      struct sockaddr_in s_in;
+      
+      memset (&s_in, 0, sizeof (s_in));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      s_in.sin_len = saddrlens[1];
+#endif
+      s_in.sin_family = AF_INET;
+      s_in.sin_port = htons (port);
+
+      sock =  GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
+      if (sock != NULL)
+       {
+         if (GNUNET_OK !=
+             GNUNET_NETWORK_socket_bind (sock,
+                                         (const struct sockaddr*) &s_in,
+                                         sizeof (s_in)))
+           {
+             /* failed to bind => service must be running */
+             GNUNET_free (hostname);
+             (void) GNUNET_NETWORK_socket_close (sock);
+             GNUNET_SCHEDULER_add_continuation (task,
+                                                task_cls,
+                                                GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+             return;
+           }
+         (void) GNUNET_NETWORK_socket_close (sock);
+       }        
+    }
+
+  if (0 == strcmp ("ip6-localhost", hostname)) 
+    {
+      /* can test using 'bind' */
+      struct sockaddr_in6 s_in6;
+      
+      memset (&s_in6, 0, sizeof (s_in6));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      s_in6.sin6_len = saddrlens[1];
+#endif
+      s_in6.sin6_family = AF_INET6;
+      s_in6.sin6_port = htons (port);
+
+      sock =  GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
+      if (sock != NULL)
+       {
+         if (GNUNET_OK !=
+             GNUNET_NETWORK_socket_bind (sock,
+                                         (const struct sockaddr*) &s_in6,
+                                         sizeof (s_in6)))
+           {
+             /* failed to bind => service must be running */
+             GNUNET_free (hostname);
+             (void) GNUNET_NETWORK_socket_close (sock);
+             GNUNET_SCHEDULER_add_continuation (task,
+                                                task_cls,
+                                                GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+             return;
+           }
+         (void) GNUNET_NETWORK_socket_close (sock);
+       }        
+    }
+
+  if ( (0 == strcmp ("localhost", hostname)) ||
+       (0 == strcmp ("ip6-localhost", hostname)) )
+    {
+      /* all binds succeeded => claim service not running right now */
+      GNUNET_free_non_null (hostname);
+      service_test_error (task, task_cls);
+      return;
+    }   
+  GNUNET_free_non_null (hostname);
+
+  /* non-localhost, try 'connect' method */
   conn = GNUNET_CLIENT_connect (service, cfg);
   if (conn == NULL)
     {
index 9c6d0c90b93442b1e18e0a905805b7841f818e1c..98eeb7b0ce405ec6bfef6d6b8efc11e07f90e05a 100644 (file)
@@ -321,7 +321,7 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
     SetErrnoFromWinsockError (WSAGetLastError ());
 #endif
   if (ret != 0)
-         return GNUNET_SYSERR;
+    return GNUNET_SYSERR;
 #ifndef MINGW
 #ifndef LINUX
   desc->addr = GNUNET_malloc (address_len);