-ecc sign/verify only
[oweals/gnunet.git] / src / util / client.c
index e098f218331288617dcd4bdd07626d62a3e76cdb..81c696a7b679bc7856a81ea4f415272640681d08 100644 (file)
  * connections between clients and service providers.
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_client_lib.h"
 #include "gnunet_protocols.h"
-#include "gnunet_server_lib.h"
-#include "gnunet_scheduler_lib.h"
+#include "gnunet_util_lib.h"
 
 
 /**
@@ -239,6 +236,11 @@ struct GNUNET_CLIENT_Connection
    */
   int in_receive;
 
+  /**
+   * Is this the first message we are sending to the service?
+   */
+  int first_message;
+
   /**
    * How often have we tried to connect?
    */
@@ -247,6 +249,89 @@ struct GNUNET_CLIENT_Connection
 };
 
 
+/**
+ * Try connecting to the server using UNIX domain sockets.
+ *
+ * @param service_name name of service to connect to
+ * @param cfg configuration to use
+ * @return NULL on error, connection to UNIX otherwise
+ */
+static struct GNUNET_CONNECTION_Handle *
+try_unixpath (const char *service_name,
+             const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+#if AF_UNIX
+  struct GNUNET_CONNECTION_Handle *connection;
+  char *unixpath;
+  struct sockaddr_un s_un;
+
+  unixpath = NULL;
+  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && 
+      (0 < strlen (unixpath)))     
+  {
+    /* We have a non-NULL unixpath, need to validate it */
+    if (strlen (unixpath) >= sizeof (s_un.sun_path))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+          _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+          (unsigned long long) sizeof (s_un.sun_path));
+      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("Using `%s' instead\n"), unixpath);
+    }
+    connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath);
+    if (NULL != connection)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n",
+          unixpath);
+      GNUNET_free (unixpath);
+      return connection;
+    }
+  }
+  GNUNET_free_non_null (unixpath);
+#endif
+  return NULL;
+}
+
+
+/**
+ * Try connecting to the server using UNIX domain sockets.
+ *
+ * @param service_name name of service to connect to
+ * @param cfg configuration to use
+ * @return GNUNET_OK if the configuration is valid, GNUNET_SYSERR if not
+ */
+static int
+test_service_configuration (const char *service_name,
+                           const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  int ret = GNUNET_SYSERR;
+  char *hostname = NULL;
+  unsigned long long port;
+#if AF_UNIX
+  char *unixpath = NULL;
+
+  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && 
+      (0 < strlen (unixpath)))     
+    ret = GNUNET_OK;
+  GNUNET_free_non_null (unixpath);
+#endif
+
+  if ( (GNUNET_YES ==
+       GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) &&
+       (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) && 
+       (port <= 65535) && (0 != port) &&
+       (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
+                                              &hostname)) &&
+       (0 != strlen (hostname)) )
+    ret = GNUNET_OK;
+  GNUNET_free_non_null (hostname);
+  return ret;
+}
+
+
 /**
  * Try to connect to the service.
  *
@@ -261,32 +346,16 @@ do_connect (const char *service_name,
 {
   struct GNUNET_CONNECTION_Handle *connection;
   char *hostname;
-  char *unixpath;
   unsigned long long port;
 
   connection = NULL;
-#if AF_UNIX
   if (0 == (attempt % 2))
   {
-    /* on even rounds, try UNIX */
-    unixpath = NULL;
-    if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && 
-       (0 < strlen (unixpath)))     
-    {
-      /* We have a non-NULL unixpath, need to validate it */
-      connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath);
-      if (NULL != connection)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n",
-             unixpath);
-        GNUNET_free (unixpath);
-        return connection;
-      }
-    }
-    GNUNET_free_non_null (unixpath);
+    /* on even rounds, try UNIX first */
+    connection = try_unixpath (service_name, cfg);
+    if (NULL != connection)
+      return connection;
   }
-#endif
-
   if (GNUNET_YES ==
       GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
   {
@@ -319,28 +388,10 @@ do_connect (const char *service_name,
   }
   if (0 == port)
   {
-#if AF_UNIX
-    if (0 != (attempt % 2))
-    {
-      /* try UNIX */
-      unixpath = NULL;
-      if ((GNUNET_OK ==
-           GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH",
-                                                  &unixpath)) &&
-          (0 < strlen (unixpath)))
-      {
-        connection =
-            GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath);
-        if (NULL != connection)
-        {
-          GNUNET_free (unixpath);
-          GNUNET_free_non_null (hostname);
-          return connection;
-        }
-      }
-      GNUNET_free_non_null (unixpath);
-    }
-#endif
+    /* if port is 0, try UNIX */
+    connection = try_unixpath (service_name, cfg);
+    if (NULL != connection)
+      return connection;
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n",
          service_name);
@@ -367,8 +418,13 @@ GNUNET_CLIENT_connect (const char *service_name,
   struct GNUNET_CLIENT_Connection *client;
   struct GNUNET_CONNECTION_Handle *connection;
 
+  if (GNUNET_OK != 
+      test_service_configuration (service_name,
+                                 cfg))
+    return NULL;
   connection = do_connect (service_name, cfg, 0);
   client = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection));
+  client->first_message = GNUNET_YES;
   client->attempts = 1;
   client->connection = connection;
   client->service_name = GNUNET_strdup (service_name);
@@ -695,40 +751,43 @@ GNUNET_CLIENT_service_test (const char *service,
       {
         LOG (GNUNET_ERROR_TYPE_WARNING,
              _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
-             sizeof (s_un.sun_path));
+             (unsigned long long) sizeof (s_un.sun_path));
+       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+        LOG (GNUNET_ERROR_TYPE_INFO,
+             _("Using `%s' instead\n"), unixpath);
       }
-      else
+    }
+    if (NULL != unixpath)
+    {
+      sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
+      if (NULL != sock)
       {
-        sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
-        if (NULL != sock)
-        {
-          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);
+       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';
+       s_un.sun_path[0] = '\0';
 #endif
 #if HAVE_SOCKADDR_IN_SIN_LEN
-          s_un.sun_len = (u_char) slen;
+       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);
-        }
+       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 */
       }
     }
@@ -888,6 +947,7 @@ client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
   th->client->connection =
       do_connect (th->client->service_name, th->client->cfg, th->client->attempts++);
+  th->client->first_message = GNUNET_YES;
   if (NULL == th->client->connection)
   {
     /* could happen if we're out of sockets */
@@ -899,9 +959,9 @@ client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                                   (th->client->back_off, 2),
                                   GNUNET_TIME_UNIT_SECONDS);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmission failed %u times, trying again in %llums.\n",
+         "Transmission failed %u times, trying again in %s.\n",
          MAX_ATTEMPTS - th->attempts_left,
-         (unsigned long long) delay.rel_value);
+         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return;
@@ -972,9 +1032,9 @@ client_notify (void *cls, size_t size, void *buf)
                                   (client->back_off, 2),
                                   GNUNET_TIME_UNIT_SECONDS);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmission failed %u times, trying again in %llums.\n",
+         "Transmission failed %u times, trying again in %s.\n",
          MAX_ATTEMPTS - th->attempts_left,
-         (unsigned long long) delay.rel_value);
+         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
     client->th = th;
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
@@ -1027,7 +1087,9 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
   th->client = client;
   th->size = size;
   th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  th->auto_retry = auto_retry;
+  /* always auto-retry on first message to service */
+  th->auto_retry = (GNUNET_YES == client->first_message) ? GNUNET_YES : auto_retry;
+  client->first_message = GNUNET_NO;
   th->notify = notify;
   th->notify_cls = notify_cls;
   th->attempts_left = MAX_ATTEMPTS;