expand GNUNET_OS_ProjectData API to also enable de-duplcation of logic for --help
[oweals/gnunet.git] / src / util / client.c
index 73cca2383c197a1843f09b7a3cccea91bd39f81b..d87be74f6d943c1bfdc072906ca6fe8a523b3919 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2006, 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2001-2013 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
  * connections between clients and service providers.
  */
 #include "platform.h"
  * connections between clients and service providers.
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_client_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_protocols.h"
-#include "gnunet_server_lib.h"
-#include "gnunet_scheduler_lib.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_socks.h"
 
 
 /**
 
 
 /**
@@ -59,7 +57,7 @@ struct GNUNET_CLIENT_TransmitHandle
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   /**
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   /**
-   * Closure for notify.
+   * Closure for @e notify.
    */
   void *notify_cls;
 
    */
   void *notify_cls;
 
@@ -73,7 +71,7 @@ struct GNUNET_CLIENT_TransmitHandle
    * If we are re-trying and are delaying to do so,
    * handle to the scheduled task managing the delay.
    */
    * If we are re-trying and are delaying to do so,
    * handle to the scheduled task managing the delay.
    */
-  GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
 
   /**
    * Timeout for the operation overall.
 
   /**
    * Timeout for the operation overall.
@@ -130,7 +128,7 @@ struct TransmitGetResponseContext
   GNUNET_CLIENT_MessageHandler rn;
 
   /**
   GNUNET_CLIENT_MessageHandler rn;
 
   /**
-   * Closure for "rn".
+   * Closure for @e rn.
    */
   void *rn_cls;
 };
    */
   void *rn_cls;
 };
@@ -171,7 +169,7 @@ struct GNUNET_CLIENT_Connection
   GNUNET_CLIENT_MessageHandler receiver_handler;
 
   /**
   GNUNET_CLIENT_MessageHandler receiver_handler;
 
   /**
-   * Closure for receiver_handler.
+   * Closure for @e receiver_handler.
    */
   void *receiver_handler_cls;
 
    */
   void *receiver_handler_cls;
 
@@ -181,26 +179,11 @@ struct GNUNET_CLIENT_Connection
    */
   struct GNUNET_CLIENT_TransmitHandle *th;
 
    */
   struct GNUNET_CLIENT_TransmitHandle *th;
 
-  /**
-   * Handler for service test completion (NULL unless in service_test)
-   */
-  GNUNET_SCHEDULER_Task test_cb;
-
-  /**
-   * Deadline for calling 'test_cb'.
-   */
-  struct GNUNET_TIME_Absolute test_deadline;
-
   /**
    * If we are re-trying and are delaying to do so,
    * handle to the scheduled task managing the delay.
    */
   /**
    * If we are re-trying and are delaying to do so,
    * handle to the scheduled task managing the delay.
    */
-  GNUNET_SCHEDULER_TaskIdentifier receive_task;
-
-  /**
-   * Closure for test_cb (NULL unless in service_test)
-   */
-  void *test_cb_cls;
+  struct GNUNET_SCHEDULER_Task * receive_task;
 
   /**
    * Buffer for received message.
 
   /**
    * Buffer for received message.
@@ -235,10 +218,17 @@ struct GNUNET_CLIENT_Connection
 
   /**
    * Are we currently busy doing receive-processing?
 
   /**
    * Are we currently busy doing receive-processing?
-   * GNUNET_YES if so, GNUNET_NO if not.
+   * #GNUNET_YES if so, #GNUNET_NO if not. #GNUNET_SYSERR
+   * if the connection has failed (but we may not have
+   * closed the handle itself yet).
    */
   int in_receive;
 
    */
   int in_receive;
 
+  /**
+   * Is this the first message we are sending to the service?
+   */
+  int first_message;
+
   /**
    * How often have we tried to connect?
    */
   /**
    * How often have we tried to connect?
    */
@@ -264,8 +254,8 @@ try_unixpath (const char *service_name,
   struct sockaddr_un s_un;
 
   unixpath = NULL;
   struct sockaddr_un s_un;
 
   unixpath = NULL;
-  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && 
-      (0 < strlen (unixpath)))     
+  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (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))
   {
     /* We have a non-NULL unixpath, need to validate it */
     if (strlen (unixpath) >= sizeof (s_un.sun_path))
@@ -276,6 +266,8 @@ try_unixpath (const char *service_name,
       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
       LOG (GNUNET_ERROR_TYPE_INFO,
           _("Using `%s' instead\n"), unixpath);
       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
       LOG (GNUNET_ERROR_TYPE_INFO,
           _("Using `%s' instead\n"), unixpath);
+      if (NULL == unixpath)
+       return NULL;
     }
     connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath);
     if (NULL != connection)
     }
     connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath);
     if (NULL != connection)
@@ -293,11 +285,12 @@ try_unixpath (const char *service_name,
 
 
 /**
 
 
 /**
- * Try connecting to the server using UNIX domain sockets.
+ * Test whether the configuration has proper values for connection
+ * (UNIXPATH || (PORT && HOSTNAME)).
  *
  * @param service_name name of service to connect to
  * @param cfg configuration to use
  *
  * @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
+ * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
  */
 static int
 test_service_configuration (const char *service_name,
  */
 static int
 test_service_configuration (const char *service_name,
@@ -309,8 +302,8 @@ test_service_configuration (const char *service_name,
 #if AF_UNIX
   char *unixpath = NULL;
 
 #if AF_UNIX
   char *unixpath = NULL;
 
-  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && 
-      (0 < strlen (unixpath)))     
+  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", &unixpath)) &&
+      (0 < strlen (unixpath)))
     ret = GNUNET_OK;
   GNUNET_free_non_null (unixpath);
 #endif
     ret = GNUNET_OK;
   GNUNET_free_non_null (unixpath);
 #endif
@@ -318,7 +311,7 @@ test_service_configuration (const char *service_name,
   if ( (GNUNET_YES ==
        GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) &&
        (GNUNET_OK ==
   if ( (GNUNET_YES ==
        GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) &&
        (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) && 
+       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",
        (port <= 65535) && (0 != port) &&
        (GNUNET_OK ==
        GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
@@ -340,12 +333,17 @@ test_service_configuration (const char *service_name,
  */
 static struct GNUNET_CONNECTION_Handle *
 do_connect (const char *service_name,
  */
 static struct GNUNET_CONNECTION_Handle *
 do_connect (const char *service_name,
-            const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int attempt)
+            const struct GNUNET_CONFIGURATION_Handle *cfg,
+           unsigned int attempt)
 {
   struct GNUNET_CONNECTION_Handle *connection;
   char *hostname;
   unsigned long long port;
 
 {
   struct GNUNET_CONNECTION_Handle *connection;
   char *hostname;
   unsigned long long port;
 
+  /* Never use a local source if a proxy is configured */
+  if (GNUNET_YES == GNUNET_SOCKS_check_service (service_name,cfg))
+    return GNUNET_SOCKS_do_connect (service_name,cfg);
+
   connection = NULL;
   if (0 == (attempt % 2))
   {
   connection = NULL;
   if (0 == (attempt % 2))
   {
@@ -389,7 +387,10 @@ do_connect (const char *service_name,
     /* if port is 0, try UNIX */
     connection = try_unixpath (service_name, cfg);
     if (NULL != connection)
     /* if port is 0, try UNIX */
     connection = try_unixpath (service_name, cfg);
     if (NULL != connection)
+    {
+      GNUNET_free_non_null (hostname);
       return connection;
       return connection;
+    }
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n",
          service_name);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n",
          service_name);
@@ -416,12 +417,13 @@ GNUNET_CLIENT_connect (const char *service_name,
   struct GNUNET_CLIENT_Connection *client;
   struct GNUNET_CONNECTION_Handle *connection;
 
   struct GNUNET_CLIENT_Connection *client;
   struct GNUNET_CONNECTION_Handle *connection;
 
-  if (GNUNET_OK != 
+  if (GNUNET_OK !=
       test_service_configuration (service_name,
                                  cfg))
     return NULL;
   connection = do_connect (service_name, cfg, 0);
       test_service_configuration (service_name,
                                  cfg))
     return NULL;
   connection = do_connect (service_name, cfg, 0);
-  client = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection));
+  client = GNUNET_new (struct GNUNET_CLIENT_Connection);
+  client->first_message = GNUNET_YES;
   client->attempts = 1;
   client->connection = connection;
   client->service_name = GNUNET_strdup (service_name);
   client->attempts = 1;
   client->connection = connection;
   client->service_name = GNUNET_strdup (service_name);
@@ -462,10 +464,10 @@ GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client)
     GNUNET_CONNECTION_destroy (client->connection);
     client->connection = NULL;
   }
     GNUNET_CONNECTION_destroy (client->connection);
     client->connection = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != client->receive_task)
+  if (NULL != client->receive_task)
   {
     GNUNET_SCHEDULER_cancel (client->receive_task);
   {
     GNUNET_SCHEDULER_cancel (client->receive_task);
-    client->receive_task = GNUNET_SCHEDULER_NO_TASK;
+    client->receive_task = NULL;
   }
   if (NULL != client->tag)
   {
   }
   if (NULL != client->tag)
   {
@@ -498,19 +500,23 @@ check_complete (struct GNUNET_CLIENT_Connection *client)
 
 /**
  * Callback function for data received from the network.  Note that
 
 /**
  * Callback function for data received from the network.  Note that
- * both "available" and "errCode" would be 0 if the read simply timed out.
+ * both @a available and @a errCode would be 0 if the read simply timed out.
  *
  * @param cls closure
  * @param buf pointer to received data
  *
  * @param cls closure
  * @param buf pointer to received data
- * @param available number of bytes availabe in "buf",
+ * @param available number of bytes availabe in @a buf,
  *        possibly 0 (on errors)
  * @param addr address of the sender
  *        possibly 0 (on errors)
  * @param addr address of the sender
- * @param addrlen size of addr
+ * @param addrlen size of @a addr
  * @param errCode value of errno (on errors receiving)
  */
 static void
  * @param errCode value of errno (on errors receiving)
  */
 static void
-receive_helper (void *cls, const void *buf, size_t available,
-                const struct sockaddr *addr, socklen_t addrlen, int errCode)
+receive_helper (void *cls,
+                const void *buf,
+                size_t available,
+                const struct sockaddr *addr,
+                socklen_t addrlen,
+                int errCode)
 {
   struct GNUNET_CLIENT_Connection *client = cls;
   struct GNUNET_TIME_Relative remaining;
 {
   struct GNUNET_CLIENT_Connection *client = cls;
   struct GNUNET_TIME_Relative remaining;
@@ -520,18 +526,24 @@ receive_helper (void *cls, const void *buf, size_t available,
   GNUNET_assert (GNUNET_NO == client->msg_complete);
   GNUNET_assert (GNUNET_YES == client->in_receive);
   client->in_receive = GNUNET_NO;
   GNUNET_assert (GNUNET_NO == client->msg_complete);
   GNUNET_assert (GNUNET_YES == client->in_receive);
   client->in_receive = GNUNET_NO;
-  if ((0 == available) || (NULL == client->connection) || (0 != errCode))
+  if ( (0 == available) ||
+       (NULL == client->connection) ||
+       (0 != errCode) )
   {
     /* signal timeout! */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n",
   {
     /* signal timeout! */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n",
-         (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL",
+         (unsigned int) available,
+         NULL == client->connection ? "NULL" : "non-NULL",
          STRERROR (errCode));
          STRERROR (errCode));
+    /* remember failure */
+    client->in_receive = GNUNET_SYSERR;
     if (NULL != (receive_handler = client->receiver_handler))
     {
       receive_handler_cls = client->receiver_handler_cls;
       client->receiver_handler = NULL;
     if (NULL != (receive_handler = client->receiver_handler))
     {
       receive_handler_cls = client->receiver_handler_cls;
       client->receiver_handler = NULL;
-      receive_handler (receive_handler_cls, NULL);
+      receive_handler (receive_handler_cls,
+                       NULL);
     }
     return;
   }
     }
     return;
   }
@@ -547,11 +559,14 @@ receive_helper (void *cls, const void *buf, size_t available,
   check_complete (client);
   /* check for timeout */
   remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout);
   check_complete (client);
   /* check for timeout */
   remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout);
-  if (0 == remaining.rel_value)
+  if (0 == remaining.rel_value_us)
   {
     /* signal timeout! */
   {
     /* signal timeout! */
-    if (NULL != client->receiver_handler)
-      client->receiver_handler (client->receiver_handler_cls, NULL);
+    if (NULL != (receive_handler = client->receiver_handler))
+    {
+      client->receiver_handler = NULL;
+      receive_handler (client->receiver_handler_cls, NULL);
+    }
     return;
   }
   /* back to receive -- either for more data or to call callback! */
     return;
   }
   /* back to receive -- either for more data or to call callback! */
@@ -567,7 +582,8 @@ receive_helper (void *cls, const void *buf, size_t available,
  * @param tc scheduler context
  */
 static void
  * @param tc scheduler context
  */
 static void
-receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+receive_task (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_CLIENT_Connection *client = cls;
   GNUNET_CLIENT_MessageHandler handler = client->receiver_handler;
 {
   struct GNUNET_CLIENT_Connection *client = cls;
   GNUNET_CLIENT_MessageHandler handler = client->receiver_handler;
@@ -575,12 +591,25 @@ receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       (const struct GNUNET_MessageHeader *) client->received_buf;
   void *handler_cls = client->receiver_handler_cls;
   uint16_t msize = ntohs (cmsg->size);
       (const struct GNUNET_MessageHeader *) client->received_buf;
   void *handler_cls = client->receiver_handler_cls;
   uint16_t msize = ntohs (cmsg->size);
-  char mbuf[msize];
+  char mbuf[msize] GNUNET_ALIGN;
   struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
 
   struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u\n",
-       ntohs (cmsg->type), msize);
-  client->receive_task = GNUNET_SCHEDULER_NO_TASK;
+  client->receive_task = NULL;
+  if ( (GNUNET_SYSERR == client->in_receive) &&
+       (GNUNET_YES != client->msg_complete) )
+  {
+    /* Connection failure, signal to caller! */
+    client->receiver_handler = NULL;
+    if (NULL != handler)
+      handler (handler_cls,
+               NULL);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received message of type %u and size %u from %s service.\n",
+       ntohs (cmsg->type),
+       msize,
+       client->service_name);
   GNUNET_assert (GNUNET_YES == client->msg_complete);
   GNUNET_assert (client->received_pos >= msize);
   memcpy (msg, cmsg, msize);
   GNUNET_assert (GNUNET_YES == client->msg_complete);
   GNUNET_assert (client->received_pos >= msize);
   memcpy (msg, cmsg, msize);
@@ -600,62 +629,164 @@ receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *
  * @param client the service
  * @param handler function to call with the message
  *
  * @param client the service
  * @param handler function to call with the message
- * @param handler_cls closure for handler
+ * @param handler_cls closure for @a handler
  * @param timeout how long to wait until timing out
  */
 void
 GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
  * @param timeout how long to wait until timing out
  */
 void
 GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
-                       GNUNET_CLIENT_MessageHandler handler, void *handler_cls,
+                       GNUNET_CLIENT_MessageHandler handler,
+                      void *handler_cls,
                        struct GNUNET_TIME_Relative timeout)
 {
   if (NULL == client->connection)
   {
     /* already disconnected, fail instantly! */
                        struct GNUNET_TIME_Relative timeout)
 {
   if (NULL == client->connection)
   {
     /* already disconnected, fail instantly! */
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               "Client API violation for service `%s'\n",
+               client->service_name);
     GNUNET_break (0);           /* this should not happen in well-written code! */
     if (NULL != handler)
     GNUNET_break (0);           /* this should not happen in well-written code! */
     if (NULL != handler)
-      handler (handler_cls, NULL);
+      handler (handler_cls,
+               NULL);
     return;
   }
   client->receiver_handler = handler;
   client->receiver_handler_cls = handler_cls;
   client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
     return;
   }
   client->receiver_handler = handler;
   client->receiver_handler_cls = handler_cls;
   client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  if (GNUNET_YES == client->msg_complete)
+  if ( (GNUNET_YES == client->msg_complete) ||
+       (GNUNET_SYSERR == client->in_receive) )
   {
   {
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->receive_task);
+    GNUNET_assert (NULL == client->receive_task);
     client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, client);
     client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, client);
+    return;
   }
   }
-  else
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "calling GNUNET_CONNECTION_receive\n");
+  GNUNET_assert (GNUNET_NO == client->in_receive);
+  client->in_receive = GNUNET_YES;
+  GNUNET_CONNECTION_receive (client->connection,
+                             GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
+                             timeout,
+                             &receive_helper,
+                             client);
+}
+
+
+/**
+ * Handle for a test to check if a service is running.
+ */
+struct GNUNET_CLIENT_TestHandle
+{
+  /**
+   * Function to call with the result of the test.
+   */
+  GNUNET_CLIENT_TestResultCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Client connection we are using for the test, if any.
+   */
+  struct GNUNET_CLIENT_Connection *client;
+
+  /**
+   * Handle for the transmission request, if any.
+   */
+  struct GNUNET_CLIENT_TransmitHandle *th;
+
+  /**
+   * Deadline for calling @e cb.
+   */
+  struct GNUNET_TIME_Absolute test_deadline;
+
+  /**
+   * ID of task used for asynchronous operations.
+   */
+  struct GNUNET_SCHEDULER_Task * task;
+
+  /**
+   * Final result to report back (once known).
+   */
+  int result;
+};
+
+
+/**
+ * Abort testing for service.
+ *
+ * @param th test handle
+ */
+void
+GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th)
+{
+  if (NULL != th->th)
+  {
+    GNUNET_CLIENT_notify_transmit_ready_cancel (th->th);
+    th->th = NULL;
+  }
+  if (NULL != th->client)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "calling GNUNET_CONNECTION_receive\n");
-    GNUNET_assert (GNUNET_NO == client->in_receive);
-    client->in_receive = GNUNET_YES;
-    GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                               timeout, &receive_helper, client);
+    GNUNET_CLIENT_disconnect (th->client);
+    th->client = NULL;
   }
   }
+  if (NULL != th->task)
+  {
+    GNUNET_SCHEDULER_cancel (th->task);
+    th->task = NULL;
+  }
+  GNUNET_free (th);
 }
 
 
 /**
 }
 
 
 /**
- * Report service unavailable.
+ * Task that reports back the result by calling the callback
+ * and then cleans up.
+ *
+ * @param cls the `struct GNUNET_CLIENT_TestHandle`
+ * @param tc scheduler context
  */
 static void
  */
 static void
-service_test_error (GNUNET_SCHEDULER_Task task, void *task_cls)
+report_result (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  GNUNET_SCHEDULER_add_continuation (task, task_cls,
-                                     GNUNET_SCHEDULER_REASON_TIMEOUT);
+  struct GNUNET_CLIENT_TestHandle *th = cls;
+
+  th->task = NULL;
+  th->cb (th->cb_cls, th->result);
+  GNUNET_CLIENT_service_test_cancel (th);
+}
+
+
+/**
+ * Report service test result asynchronously back to callback.
+ *
+ * @param th test handle with the result and the callback
+ * @param result result to report
+ */
+static void
+service_test_report (struct GNUNET_CLIENT_TestHandle *th,
+                    int result)
+{
+  th->result = result;
+  th->task = GNUNET_SCHEDULER_add_now (&report_result,
+                                      th);
 }
 
 
 /**
  * Receive confirmation from test, service is up.
  *
 }
 
 
 /**
  * Receive confirmation from test, service is up.
  *
- * @param cls closure
+ * @param cls closure with the `struct GNUNET_CLIENT_TestHandle`
  * @param msg message received, NULL on timeout or fatal error
  */
 static void
  * @param msg message received, NULL on timeout or fatal error
  */
 static void
-confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+confirm_handler (void *cls,
+                 const struct GNUNET_MessageHeader *msg)
 {
 {
-  struct GNUNET_CLIENT_Connection *client = cls;
+  struct GNUNET_CLIENT_TestHandle *th = cls;
 
   /* We may want to consider looking at the reply in more
    * detail in the future, for example, is this the
 
   /* We may want to consider looking at the reply in more
    * detail in the future, for example, is this the
@@ -664,14 +795,12 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Received confirmation that service is running.\n");
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Received confirmation that service is running.\n");
-    GNUNET_SCHEDULER_add_continuation (client->test_cb, client->test_cb_cls,
-                                       GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+    service_test_report (th, GNUNET_YES);
   }
   else
   {
   }
   else
   {
-    service_test_error (client->test_cb, client->test_cb_cls);
+    service_test_report (th, GNUNET_NO);
   }
   }
-  GNUNET_CLIENT_disconnect (client);
 }
 
 
 }
 
 
@@ -679,81 +808,110 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
  * Send the 'TEST' message to the service.  If successful, prepare to
  * receive the reply.
  *
  * 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 cls the `struct GNUNET_CLIENT_TestHandle` of the test
+ * @param size number of bytes available in @a buf
  * @param buf where to write the message
  * @param buf where to write the message
- * @return number of bytes written to buf
+ * @return number of bytes written to @a buf
  */
 static size_t
 write_test (void *cls, size_t size, void *buf)
 {
  */
 static size_t
 write_test (void *cls, size_t size, void *buf)
 {
-  struct GNUNET_CLIENT_Connection *client = cls;
+  struct GNUNET_CLIENT_TestHandle *th = cls;
   struct GNUNET_MessageHeader *msg;
 
   struct GNUNET_MessageHeader *msg;
 
+  th->th = NULL;
   if (size < sizeof (struct GNUNET_MessageHeader))
   {
   if (size < sizeof (struct GNUNET_MessageHeader))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n"));
-    service_test_error (client->test_cb, client->test_cb_cls);
-    GNUNET_CLIENT_disconnect (client);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Failed to transmit TEST request.\n");
+    service_test_report (th, GNUNET_NO);
     return 0;                   /* client disconnected */
   }
     return 0;                   /* client disconnected */
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmitting `%s' request.\n",
+       "TEST");
   msg = (struct GNUNET_MessageHeader *) buf;
   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
   msg = (struct GNUNET_MessageHeader *) buf;
   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
-  GNUNET_CLIENT_receive (client, &confirm_handler, client,
+  GNUNET_CLIENT_receive (th->client,
+                        &confirm_handler, th,
                          GNUNET_TIME_absolute_get_remaining
                          GNUNET_TIME_absolute_get_remaining
-                         (client->test_deadline));
+                         (th->test_deadline));
   return sizeof (struct GNUNET_MessageHeader);
 }
 
 
 /**
   return sizeof (struct GNUNET_MessageHeader);
 }
 
 
 /**
- * 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.
+ * 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
  *
  * @param service name of the service to wait for
  * @param cfg configuration to use
  * @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))
- * @param task_cls closure for task
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel the test
  */
  */
-void
+struct GNUNET_CLIENT_TestHandle *
 GNUNET_CLIENT_service_test (const char *service,
                             const struct GNUNET_CONFIGURATION_Handle *cfg,
                             struct GNUNET_TIME_Relative timeout,
 GNUNET_CLIENT_service_test (const char *service,
                             const struct GNUNET_CONFIGURATION_Handle *cfg,
                             struct GNUNET_TIME_Relative timeout,
-                            GNUNET_SCHEDULER_Task task, void *task_cls)
+                            GNUNET_CLIENT_TestResultCallback cb,
+                           void *cb_cls)
 {
 {
+  struct GNUNET_CLIENT_TestHandle *th;
   char *hostname;
   unsigned long long port;
   struct GNUNET_NETWORK_Handle *sock;
   char *hostname;
   unsigned long long port;
   struct GNUNET_NETWORK_Handle *sock;
-  struct GNUNET_CLIENT_Connection *client;
 
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n",
+  th = GNUNET_new (struct GNUNET_CLIENT_TestHandle);
+  th->cb = cb;
+  th->cb_cls = cb_cls;
+  th->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Testing if service `%s' is running.\n",
        service);
 #ifdef AF_UNIX
   {
     /* probe UNIX support */
     struct sockaddr_un s_un;
        service);
 #ifdef AF_UNIX
   {
     /* probe UNIX support */
     struct sockaddr_un s_un;
-    size_t slen;
     char *unixpath;
     char *unixpath;
+    int abstract;
 
     unixpath = NULL;
 
     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 ((GNUNET_OK ==
+        GNUNET_CONFIGURATION_get_value_filename (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))
       {
         LOG (GNUNET_ERROR_TYPE_WARNING,
     {
       if (strlen (unixpath) >= sizeof (s_un.sun_path))
       {
         LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+             _("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);
       }
     }
              (unsigned long long) sizeof (s_un.sun_path));
        unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
         LOG (GNUNET_ERROR_TYPE_INFO,
              _("Using `%s' instead\n"), unixpath);
       }
     }
+#ifdef LINUX
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                     "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+#else
+    abstract = GNUNET_NO;
+#endif
+    if ((NULL != unixpath) && (GNUNET_YES != abstract))
+    {
+      if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (unixpath))
+        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                  "mkdir", unixpath);
+    }
     if (NULL != unixpath)
     {
       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
     if (NULL != unixpath)
     {
       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
@@ -761,30 +919,23 @@ GNUNET_CLIENT_service_test (const char *service,
       {
        memset (&s_un, 0, sizeof (s_un));
        s_un.sun_family = AF_UNIX;
       {
        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
+        strncpy (s_un.sun_path, unixpath, sizeof (s_un.sun_path) - 1);
+        if (GNUNET_YES == abstract)
+          s_un.sun_path[0] = '\0';
 #if HAVE_SOCKADDR_IN_SIN_LEN
 #if HAVE_SOCKADDR_IN_SIN_LEN
-       s_un.sun_len = (u_char) slen;
+        s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
 #endif
        if (GNUNET_OK !=
            GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un,
 #endif
        if (GNUNET_OK !=
            GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un,
-                                       slen))
+                                       sizeof (struct sockaddr_un)))
         {
          /* failed to bind => service must be running */
          GNUNET_free (unixpath);
          (void) GNUNET_NETWORK_socket_close (sock);
         {
          /* 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;
+         service_test_report (th, GNUNET_YES);
+         return th;
        }
        }
-       (void) GNUNET_NETWORK_socket_close (sock);        
+       (void) GNUNET_NETWORK_socket_close (sock);
         /* let's try IP */
       }
     }
         /* let's try IP */
       }
     }
@@ -801,8 +952,8 @@ GNUNET_CLIENT_service_test (const char *service,
                                               &hostname)))
   {
     /* UNIXPATH failed (if possible) AND IP failed => error */
                                               &hostname)))
   {
     /* UNIXPATH failed (if possible) AND IP failed => error */
-    service_test_error (task, task_cls);
-    return;
+    service_test_report (th, GNUNET_SYSERR);
+    return th;
   }
 
   if (0 == strcmp ("localhost", hostname)
   }
 
   if (0 == strcmp ("localhost", hostname)
@@ -831,9 +982,8 @@ GNUNET_CLIENT_service_test (const char *service,
         /* failed to bind => service must be running */
         GNUNET_free (hostname);
         (void) GNUNET_NETWORK_socket_close (sock);
         /* 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;
+        service_test_report (th, GNUNET_YES);
+        return th;
       }
       (void) GNUNET_NETWORK_socket_close (sock);
     }
       }
       (void) GNUNET_NETWORK_socket_close (sock);
     }
@@ -865,9 +1015,8 @@ GNUNET_CLIENT_service_test (const char *service,
         /* failed to bind => service must be running */
         GNUNET_free (hostname);
         (void) GNUNET_NETWORK_socket_close (sock);
         /* 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;
+        service_test_report (th, GNUNET_YES);
+        return th;
       }
       (void) GNUNET_NETWORK_socket_close (sock);
     }
       }
       (void) GNUNET_NETWORK_socket_close (sock);
     }
@@ -882,35 +1031,33 @@ GNUNET_CLIENT_service_test (const char *service,
   {
     /* all binds succeeded => claim service not running right now */
     GNUNET_free_non_null (hostname);
   {
     /* all binds succeeded => claim service not running right now */
     GNUNET_free_non_null (hostname);
-    service_test_error (task, task_cls);
-    return;
+    service_test_report (th, GNUNET_NO);
+    return th;
   }
   GNUNET_free_non_null (hostname);
 
   /* non-localhost, try 'connect' method */
   }
   GNUNET_free_non_null (hostname);
 
   /* non-localhost, try 'connect' method */
-  client = GNUNET_CLIENT_connect (service, cfg);
-  if (NULL == client)
+  th->client = GNUNET_CLIENT_connect (service, cfg);
+  if (NULL == th->client)
   {
     LOG (GNUNET_ERROR_TYPE_INFO,
   {
     LOG (GNUNET_ERROR_TYPE_INFO,
-         _("Could not connect to service `%s', must not be running.\n"),
+         _("Could not connect to service `%s', configuration broken.\n"),
          service);
          service);
-    service_test_error (task, task_cls);
-    return;
+    service_test_report (th, GNUNET_SYSERR);
+    return th;
   }
   }
-  client->test_cb = task;
-  client->test_cb_cls = task_cls;
-  client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
-  if (NULL == GNUNET_CLIENT_notify_transmit_ready (client,
-                                                  sizeof (struct GNUNET_MessageHeader),
-                                                  timeout, GNUNET_YES, &write_test,
-                                                  client))
+  th->th = GNUNET_CLIENT_notify_transmit_ready (th->client,
+                                               sizeof (struct GNUNET_MessageHeader),
+                                               timeout, GNUNET_YES,
+                                               &write_test, th);
+  if (NULL == th->th)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Failure to transmit request to service `%s'\n"), service);
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Failure to transmit request to service `%s'\n"), service);
-    service_test_error (task, task_cls);
-    GNUNET_CLIENT_disconnect (client);
-    return;
+    service_test_report (th, GNUNET_SYSERR);
+    return th;
   }
   }
+  return th;
 }
 
 
 }
 
 
@@ -919,10 +1066,10 @@ GNUNET_CLIENT_service_test (const char *service,
  * a transmission request.  Either pass it on to our
  * user or, if possible, retry.
  *
  * a transmission request.  Either pass it on to our
  * user or, if possible, retry.
  *
- * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
+ * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
  * @param size number of bytes available for transmission
  * @param buf where to write them
  * @param size number of bytes available for transmission
  * @param buf where to write them
- * @return number of bytes written to buf
+ * @return number of bytes written to @a buf
  */
 static size_t
 client_notify (void *cls, size_t size, void *buf);
  */
 static size_t
 client_notify (void *cls, size_t size, void *buf);
@@ -932,32 +1079,42 @@ client_notify (void *cls, size_t size, void *buf);
  * This task is run if we should re-try connection to the
  * service after a while.
  *
  * This task is run if we should re-try connection to the
  * service after a while.
  *
- * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request
+ * @param cls our `struct GNUNET_CLIENT_TransmitHandle` of the request
  * @param tc unused
  */
 static void
  * @param tc unused
  */
 static void
-client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+client_delayed_retry (void *cls,
+                     const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_CLIENT_TransmitHandle *th = cls;
   struct GNUNET_TIME_Relative delay;
 
 {
   struct GNUNET_CLIENT_TransmitHandle *th = cls;
   struct GNUNET_TIME_Relative delay;
 
-  th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+  th->reconnect_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  {
+    /* give up, was shutdown */
+    th->client->th = NULL;
+    th->notify (th->notify_cls, 0, NULL);
+    GNUNET_free (th);
+    return;
+  }
   th->client->connection =
   th->client->connection =
-      do_connect (th->client->service_name, th->client->cfg, th->client->attempts++);
+    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 */
   if (NULL == th->client->connection)
   {
     /* could happen if we're out of sockets */
-    delay =
-        GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining
-                                  (th->timeout), th->client->back_off);
-    th->client->back_off =
-        GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply
-                                  (th->client->back_off, 2),
-                                  GNUNET_TIME_UNIT_SECONDS);
+    delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (th->timeout),
+                                      th->client->back_off);
+    th->client->back_off = GNUNET_TIME_STD_BACKOFF (th->client->back_off);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
     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,
          MAX_ATTEMPTS - th->attempts_left,
-         (unsigned long long) delay.rel_value);
+         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
+    GNUNET_assert (NULL == th->th);
+    GNUNET_assert (NULL == th->reconnect_task);
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return;
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return;
@@ -982,32 +1139,39 @@ client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * Connection notifies us about failure or success of a transmission
  * request.  Either pass it on to our user or, if possible, retry.
  *
  * Connection notifies us about failure or success of a transmission
  * request.  Either pass it on to our user or, if possible, retry.
  *
- * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
+ * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
  * @param size number of bytes available for transmission
  * @param buf where to write them
  * @param size number of bytes available for transmission
  * @param buf where to write them
- * @return number of bytes written to buf
+ * @return number of bytes written to @a buf
  */
 static size_t
  */
 static size_t
-client_notify (void *cls, size_t size, void *buf)
+client_notify (void *cls,
+               size_t size,
+               void *buf)
 {
   struct GNUNET_CLIENT_TransmitHandle *th = cls;
   struct GNUNET_CLIENT_Connection *client = th->client;
   size_t ret;
   struct GNUNET_TIME_Relative delay;
 
 {
   struct GNUNET_CLIENT_TransmitHandle *th = cls;
   struct GNUNET_CLIENT_Connection *client = th->client;
   size_t ret;
   struct GNUNET_TIME_Relative delay;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "client_notify is running\n");
   th->th = NULL;
   client->th = NULL;
   if (NULL == buf)
   {
     delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
   th->th = NULL;
   client->th = NULL;
   if (NULL == buf)
   {
     delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
-    delay.rel_value /= 2;
-    if ((GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) ||
-        (delay.rel_value < 1))
+    delay.rel_value_us /= 2;
+    if ( (GNUNET_YES != th->auto_retry) ||
+         (0 == --th->attempts_left) ||
+         (delay.rel_value_us < 1)||
+         (0 != (GNUNET_SCHEDULER_get_reason() & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG,
            "Transmission failed %u times, giving up.\n",
            MAX_ATTEMPTS - th->attempts_left);
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG,
            "Transmission failed %u times, giving up.\n",
            MAX_ATTEMPTS - th->attempts_left);
-      GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL));
+      GNUNET_break (0 ==
+                    th->notify (th->notify_cls, 0, NULL));
       GNUNET_free (th);
       return 0;
     }
       GNUNET_free (th);
       return 0;
     }
@@ -1019,7 +1183,7 @@ client_notify (void *cls, size_t size, void *buf)
     {
       GNUNET_CONNECTION_receive_cancel (client->connection);
       client->in_receive = GNUNET_NO;
     {
       GNUNET_CONNECTION_receive_cancel (client->connection);
       client->in_receive = GNUNET_NO;
-    }    
+    }
     GNUNET_CONNECTION_destroy (client->connection);
     client->connection = NULL;
     delay = GNUNET_TIME_relative_min (delay, client->back_off);
     GNUNET_CONNECTION_destroy (client->connection);
     client->connection = NULL;
     delay = GNUNET_TIME_relative_min (delay, client->back_off);
@@ -1028,10 +1192,12 @@ client_notify (void *cls, size_t size, void *buf)
                                   (client->back_off, 2),
                                   GNUNET_TIME_UNIT_SECONDS);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
                                   (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,
          MAX_ATTEMPTS - th->attempts_left,
-         (unsigned long long) delay.rel_value);
+         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
     client->th = th;
     client->th = th;
+    GNUNET_assert (NULL == th->reconnect_task);
+    GNUNET_assert (NULL == th->th);
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return 0;
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return 0;
@@ -1039,14 +1205,22 @@ client_notify (void *cls, size_t size, void *buf)
   GNUNET_assert (size >= th->size);
   ret = th->notify (th->notify_cls, size, buf);
   GNUNET_free (th);
   GNUNET_assert (size >= th->size);
   ret = th->notify (th->notify_cls, size, buf);
   GNUNET_free (th);
+  if (sizeof (struct GNUNET_MessageHeader) <= ret)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Transmitting message of type %u and size %u to %s service.\n",
+         ntohs (((struct GNUNET_MessageHeader *) buf)->type),
+         ntohs (((struct GNUNET_MessageHeader *) buf)->size),
+         client->service_name);
+  }
   return ret;
 }
 
 
 /**
  * Ask the client to call us once the specified number of bytes
   return ret;
 }
 
 
 /**
  * Ask the client to call us once the specified number of bytes
- * are free in the transmission buffer.  May call the notify
- * method immediately if enough space is available.
+ * are free in the transmission buffer.  Will never call the @a notify
+ * callback in this task, but always first go into the scheduler.
  *
  * @param client connection to the service
  * @param size number of bytes to send
  *
  * @param client connection to the service
  * @param size number of bytes to send
@@ -1058,7 +1232,7 @@ client_notify (void *cls, size_t size, void *buf)
  *        if the caller does not care about temporary connection errors,
  *        for example because the protocol is stateless
  * @param notify function to call
  *        if the caller does not care about temporary connection errors,
  *        for example because the protocol is stateless
  * @param notify function to call
- * @param notify_cls closure for notify
+ * @param notify_cls closure for @a notify
  * @return NULL if our buffer will never hold size bytes,
  *         a handle if the notify callback was queued (can be used to cancel)
  */
  * @return NULL if our buffer will never hold size bytes,
  *         a handle if the notify callback was queued (can be used to cancel)
  */
@@ -1067,8 +1241,8 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
                                      size_t size,
                                      struct GNUNET_TIME_Relative timeout,
                                      int auto_retry,
                                      size_t size,
                                      struct GNUNET_TIME_Relative timeout,
                                      int auto_retry,
-                                     GNUNET_CONNECTION_TransmitReadyNotify
-                                     notify, void *notify_cls)
+                                     GNUNET_CONNECTION_TransmitReadyNotify notify,
+                                    void *notify_cls)
 {
   struct GNUNET_CLIENT_TransmitHandle *th;
 
 {
   struct GNUNET_CLIENT_TransmitHandle *th;
 
@@ -1076,30 +1250,36 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
   {
     /* If this breaks, you most likley called this function twice without waiting
      * for completion or canceling the request */
   {
     /* If this breaks, you most likley called this function twice without waiting
      * for completion or canceling the request */
-    GNUNET_break (0);
+    GNUNET_assert (0);
     return NULL;
   }
     return NULL;
   }
-  th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle));
+  th = GNUNET_new (struct GNUNET_CLIENT_TransmitHandle);
   th->client = client;
   th->size = size;
   th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   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;
   client->th = th;
   if (NULL == client->connection)
   {
   th->notify = notify;
   th->notify_cls = notify_cls;
   th->attempts_left = MAX_ATTEMPTS;
   client->th = th;
   if (NULL == client->connection)
   {
+    GNUNET_assert (NULL == th->th);
+    GNUNET_assert (NULL == th->reconnect_task);
     th->reconnect_task =
     th->reconnect_task =
-        GNUNET_SCHEDULER_add_delayed (client->back_off, &client_delayed_retry,
+        GNUNET_SCHEDULER_add_delayed (client->back_off,
+                                      &client_delayed_retry,
                                       th);
                                       th);
-
   }
   else
   {
   }
   else
   {
-    th->th =
-        GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, timeout,
-                                                 &client_notify, th);
+    th->th = GNUNET_CONNECTION_notify_transmit_ready (client->connection,
+                                                      size,
+                                                      timeout,
+                                                      &client_notify,
+                                                      th);
     if (NULL == th->th)
     {
       GNUNET_break (0);
     if (NULL == th->th)
     {
       GNUNET_break (0);
@@ -1118,14 +1298,13 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
  * @param th handle from the original request.
  */
 void
  * @param th handle from the original request.
  */
 void
-GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle
-                                            *th)
+GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle *th)
 {
 {
-  if (GNUNET_SCHEDULER_NO_TASK != th->reconnect_task)
+  if (NULL != th->reconnect_task)
   {
     GNUNET_assert (NULL == th->th);
     GNUNET_SCHEDULER_cancel (th->reconnect_task);
   {
     GNUNET_assert (NULL == th->th);
     GNUNET_SCHEDULER_cancel (th->reconnect_task);
-    th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+    th->reconnect_task = NULL;
   }
   else
   {
   }
   else
   {
@@ -1139,17 +1318,19 @@ GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle
 
 /**
  * Function called to notify a client about the socket
 
 /**
  * Function called to notify a client about the socket
- * begin ready to queue the message.  "buf" will be
- * NULL and "size" zero if the socket was closed for
+ * begin ready to queue the message.  @a buf will be
+ * NULL and @a size zero if the socket was closed for
  * writing in the meantime.
  *
  * writing in the meantime.
  *
- * @param cls closure of type "struct TransmitGetResponseContext*"
- * @param size number of bytes available in buf
+ * @param cls closure of type `struct TransmitGetResponseContext *`
+ * @param size number of bytes available in @a buf
  * @param buf where the callee should write the message
  * @param buf where the callee should write the message
- * @return number of bytes written to buf
+ * @return number of bytes written to @a buf
  */
 static size_t
  */
 static size_t
-transmit_for_response (void *cls, size_t size, void *buf)
+transmit_for_response (void *cls,
+                      size_t size,
+                      void *buf)
 {
   struct TransmitGetResponseContext *tc = cls;
   uint16_t msize;
 {
   struct TransmitGetResponseContext *tc = cls;
   uint16_t msize;
@@ -1159,7 +1340,7 @@ transmit_for_response (void *cls, size_t size, void *buf)
   if (NULL == buf)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   if (NULL == buf)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         _("Could not submit request, not expecting to receive a response.\n"));
+         "Could not submit request, not expecting to receive a response.\n");
     if (NULL != tc->rn)
       tc->rn (tc->rn_cls, NULL);
     GNUNET_free (tc);
     if (NULL != tc->rn)
       tc->rn (tc->rn_cls, NULL);
     GNUNET_free (tc);
@@ -1167,7 +1348,9 @@ transmit_for_response (void *cls, size_t size, void *buf)
   }
   GNUNET_assert (size >= msize);
   memcpy (buf, tc->hdr, msize);
   }
   GNUNET_assert (size >= msize);
   memcpy (buf, tc->hdr, msize);
-  GNUNET_CLIENT_receive (tc->client, tc->rn, tc->rn_cls,
+  GNUNET_CLIENT_receive (tc->client,
+                         tc->rn,
+                         tc->rn_cls,
                          GNUNET_TIME_absolute_get_remaining (tc->timeout));
   GNUNET_free (tc);
   return msize;
                          GNUNET_TIME_absolute_get_remaining (tc->timeout));
   GNUNET_free (tc);
   return msize;
@@ -1191,8 +1374,8 @@ transmit_for_response (void *cls, size_t size, void *buf)
  *        if the caller does not care about temporary connection errors,
  *        for example because the protocol is stateless
  * @param rn function to call with the response
  *        if the caller does not care about temporary connection errors,
  *        for example because the protocol is stateless
  * @param rn function to call with the response
- * @param rn_cls closure for rn
- * @return GNUNET_OK on success, GNUNET_SYSERR if a request
+ * @param rn_cls closure for @a rn
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if a request
  *         is already pending
  */
 int
  *         is already pending
  */
 int
@@ -1230,5 +1413,4 @@ GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *client
 }
 
 
 }
 
 
-
 /*  end of client.c */
 /*  end of client.c */