expand GNUNET_OS_ProjectData API to also enable de-duplcation of logic for --help
[oweals/gnunet.git] / src / util / client.c
index c222a0ff7f94a3863f69a3c96653aaa61ad3b196..d87be74f6d943c1bfdc072906ca6fe8a523b3919 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001-2013 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
@@ -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
-     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.
 */
 
 /**
@@ -29,6 +29,7 @@
 #include "platform.h"
 #include "gnunet_protocols.h"
 #include "gnunet_util_lib.h"
+#include "gnunet_socks.h"
 
 
 /**
@@ -70,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.
    */
-  GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
 
   /**
    * Timeout for the operation overall.
@@ -182,7 +183,7 @@ struct GNUNET_CLIENT_Connection
    * If we are re-trying and are delaying to do so,
    * handle to the scheduled task managing the delay.
    */
-  GNUNET_SCHEDULER_TaskIdentifier receive_task;
+  struct GNUNET_SCHEDULER_Task * receive_task;
 
   /**
    * Buffer for received message.
@@ -217,7 +218,9 @@ struct GNUNET_CLIENT_Connection
 
   /**
    * 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;
 
@@ -337,6 +340,10 @@ do_connect (const char *service_name,
   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))
   {
@@ -457,10 +464,10 @@ GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client)
     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);
-    client->receive_task = GNUNET_SCHEDULER_NO_TASK;
+    client->receive_task = NULL;
   }
   if (NULL != client->tag)
   {
@@ -504,8 +511,12 @@ check_complete (struct GNUNET_CLIENT_Connection *client)
  * @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;
@@ -515,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;
-  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",
-         (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL",
+         (unsigned int) available,
+         NULL == client->connection ? "NULL" : "non-NULL",
          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;
-      receive_handler (receive_handler_cls, NULL);
+      receive_handler (receive_handler_cls,
+                       NULL);
     }
     return;
   }
@@ -565,7 +582,8 @@ receive_helper (void *cls, const void *buf, size_t available,
  * @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;
@@ -576,12 +594,22 @@ receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   char mbuf[msize] GNUNET_ALIGN;
   struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
 
+  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);
-  client->receive_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (GNUNET_YES == client->msg_complete);
   GNUNET_assert (client->received_pos >= msize);
   memcpy (msg, cmsg, msize);
@@ -613,27 +641,34 @@ GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
   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)
-      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);
-  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);
+    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);
-  }
+  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);
 }
 
 
@@ -670,7 +705,7 @@ struct GNUNET_CLIENT_TestHandle
   /**
    * ID of task used for asynchronous operations.
    */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+  struct GNUNET_SCHEDULER_Task * task;
 
   /**
    * Final result to report back (once known).
@@ -697,10 +732,10 @@ GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th)
     GNUNET_CLIENT_disconnect (th->client);
     th->client = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != th->task)
+  if (NULL != th->task)
   {
     GNUNET_SCHEDULER_cancel (th->task);
-    th->task = GNUNET_SCHEDULER_NO_TASK;
+    th->task = NULL;
   }
   GNUNET_free (th);
 }
@@ -719,7 +754,7 @@ report_result (void *cls,
 {
   struct GNUNET_CLIENT_TestHandle *th = cls;
 
-  th->task = GNUNET_SCHEDULER_NO_TASK;
+  th->task = NULL;
   th->cb (th->cb_cls, th->result);
   GNUNET_CLIENT_service_test_cancel (th);
 }
@@ -748,7 +783,8 @@ service_test_report (struct GNUNET_CLIENT_TestHandle *th,
  * @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_TestHandle *th = cls;
 
@@ -1033,7 +1069,7 @@ GNUNET_CLIENT_service_test (const char *service,
  * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
  * @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);
@@ -1053,7 +1089,7 @@ client_delayed_retry (void *cls,
   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 */
@@ -1077,7 +1113,8 @@ client_delayed_retry (void *cls,
          "Transmission failed %u times, trying again in %s.\n",
          MAX_ATTEMPTS - th->attempts_left,
          GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == th->reconnect_task);
+    GNUNET_assert (NULL == th->th);
+    GNUNET_assert (NULL == th->reconnect_task);
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th);
     return;
@@ -1108,7 +1145,9 @@ client_delayed_retry (void *cls,
  * @return number of bytes written to @a buf
  */
 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;
@@ -1123,14 +1162,16 @@ client_notify (void *cls, size_t size, void *buf)
   {
     delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
     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)))
+    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);
-      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;
     }
@@ -1155,7 +1196,8 @@ client_notify (void *cls, size_t size, void *buf)
          MAX_ATTEMPTS - th->attempts_left,
          GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
     client->th = th;
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == th->reconnect_task);
+    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;
@@ -1208,7 +1250,7 @@ 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 */
-    GNUNET_break (0);
+    GNUNET_assert (0);
     return NULL;
   }
   th = GNUNET_new (struct GNUNET_CLIENT_TransmitHandle);
@@ -1224,18 +1266,20 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
   client->th = th;
   if (NULL == client->connection)
   {
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == th->reconnect_task);
+    GNUNET_assert (NULL == th->th);
+    GNUNET_assert (NULL == th->reconnect_task);
     th->reconnect_task =
         GNUNET_SCHEDULER_add_delayed (client->back_off,
                                       &client_delayed_retry,
                                       th);
-
   }
   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);
@@ -1256,11 +1300,11 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
 void
 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);
-    th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+    th->reconnect_task = NULL;
   }
   else
   {
@@ -1278,7 +1322,7 @@ GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle
  * NULL and @a size zero if the socket was closed for
  * writing in the meantime.
  *
- * @param cls closure of type "struct TransmitGetResponseContext*"
+ * @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
  * @return number of bytes written to @a buf
@@ -1296,7 +1340,7 @@ transmit_for_response (void *cls,
   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);
@@ -1304,7 +1348,9 @@ transmit_for_response (void *cls,
   }
   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;