tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / util / client.c
index 337d0673452f003ea88ab30e99022750a1a5bc43..05e05a328b26161116eabf4c6f48e893109e8d13 100644 (file)
@@ -2,20 +2,20 @@
      This file is part of GNUnet.
      Copyright (C) 2001-2016 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
+     Affero General Public License for more details.
 
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
 #include "gnunet_socks.h"
 
 
-#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
+
+/**
+ * Timeout we use on TCP connect before trying another
+ * result from the DNS resolver.  Actual value used
+ * is this value divided by the number of address families.
+ * Default is 5s.
+ */
+#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
 
 
 /**
@@ -213,9 +222,6 @@ start_connect (void *cls);
 static void
 connect_fail_continuation (struct ClientState *cstate)
 {
-  LOG (GNUNET_ERROR_TYPE_WARNING,
-       "Failed to establish connection to `%s', no further addresses to try.\n",
-       cstate->service_name);
   GNUNET_break (NULL == cstate->ap_head);
   GNUNET_break (NULL == cstate->ap_tail);
   GNUNET_break (NULL == cstate->dns_active);
@@ -225,6 +231,11 @@ connect_fail_continuation (struct ClientState *cstate)
   // GNUNET_assert (NULL == cstate->proxy_handshake);
 
   cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
+       cstate->service_name,
+       GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
+                                               GNUNET_YES));
   cstate->retry_task
     = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
                                     &start_connect,
@@ -247,17 +258,32 @@ transmit_ready (void *cls)
   int notify_in_flight;
 
   cstate->send_task = NULL;
+  if (GNUNET_YES == cstate->in_destroy)
+    return;
   pos = (const char *) cstate->msg;
   len = ntohs (cstate->msg->size);
   GNUNET_assert (cstate->msg_off < len);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "message of type %u trying to send with socket %p (MQ: %p\n",
+       ntohs(cstate->msg->type),
+       cstate->sock,
+       cstate->mq);
+
  RETRY:
   ret = GNUNET_NETWORK_socket_send (cstate->sock,
                                     &pos[cstate->msg_off],
                                     len - cstate->msg_off);
   if (-1 == ret)
   {
-    if (EINTR == errno)
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Error during sending message of type %u\n",
+         ntohs(cstate->msg->type));
+    if (EINTR == errno){
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Retrying message of type %u\n",
+           ntohs(cstate->msg->type));
       goto RETRY;
+    }
     GNUNET_MQ_inject_error (cstate->mq,
                             GNUNET_MQ_ERROR_WRITE);
     return;
@@ -266,15 +292,21 @@ transmit_ready (void *cls)
   cstate->msg_off += ret;
   if (cstate->msg_off < len)
   {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "rescheduling message of type %u\n",
+         ntohs(cstate->msg->type));
     cstate->send_task
       = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                         cstate->sock,
                                         &transmit_ready,
                                         cstate);
-    if (notify_in_flight) 
+    if (notify_in_flight)
       GNUNET_MQ_impl_send_in_flight (cstate->mq);
     return;
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "sending message of type %u successful\n",
+       ntohs(cstate->msg->type));
   cstate->msg = NULL;
   GNUNET_MQ_impl_send_continue (cstate->mq);
 }
@@ -286,7 +318,9 @@ transmit_ready (void *cls)
  *
  * @param cls the `struct ClientState`
  * @param msg message we received.
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ * @return #GNUNET_OK on success,
+ *     #GNUNET_NO to stop further processing due to disconnect (no error)
+ *     #GNUNET_SYSERR to stop further processing due to error
  */
 static int
 recv_message (void *cls,
@@ -295,11 +329,16 @@ recv_message (void *cls,
   struct ClientState *cstate = cls;
 
   if (GNUNET_YES == cstate->in_destroy)
-    return GNUNET_SYSERR;
+    return GNUNET_NO;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received message of type %u and size %u from %s\n",
+       ntohs (msg->type),
+       ntohs (msg->size),
+       cstate->service_name);
   GNUNET_MQ_inject_message (cstate->mq,
                             msg);
   if (GNUNET_YES == cstate->in_destroy)
-    return GNUNET_SYSERR;
+    return GNUNET_NO;
   return GNUNET_OK;
 }
 
@@ -340,6 +379,22 @@ connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
 {
   struct ClientState *cstate = impl_state;
 
+  (void) mq;
+  if (NULL != cstate->dns_active)
+  {
+    GNUNET_RESOLVER_request_cancel (cstate->dns_active);
+    cstate->dns_active = NULL;
+  }
+  if (NULL != cstate->send_task)
+  {
+    GNUNET_SCHEDULER_cancel (cstate->send_task);
+    cstate->send_task = NULL;
+  }
+  if (NULL != cstate->retry_task)
+  {
+    GNUNET_SCHEDULER_cancel (cstate->retry_task);
+    cstate->retry_task = NULL;
+  }
   if (GNUNET_SYSERR == cstate->in_destroy)
   {
     /* defer destruction */
@@ -347,16 +402,18 @@ connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
     cstate->mq = NULL;
     return;
   }
-  if (NULL != cstate->dns_active)
-    GNUNET_RESOLVER_request_cancel (cstate->dns_active);
-  if (NULL != cstate->send_task)
-    GNUNET_SCHEDULER_cancel (cstate->send_task);
   if (NULL != cstate->recv_task)
+  {
     GNUNET_SCHEDULER_cancel (cstate->recv_task);
-  if (NULL != cstate->retry_task)
-    GNUNET_SCHEDULER_cancel (cstate->retry_task);
+    cstate->recv_task = NULL;
+  }
   if (NULL != cstate->sock)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "destroying socket: %p\n",
+         cstate->sock);
     GNUNET_NETWORK_socket_close (cstate->sock);
+  }
   cancel_aps (cstate);
   GNUNET_free (cstate->service_name);
   GNUNET_free_non_null (cstate->hostname);
@@ -489,8 +546,8 @@ try_unixpath (const char *service_name,
         s_un.sun_path[0] = '\0';
     }
 #endif
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    un.sun_len = (u_char) sizeof (struct sockaddr_un);
+#if HAVE_SOCKADDR_UN_SUN_LEN
+    s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
 #endif
     sock = GNUNET_NETWORK_socket_create (AF_UNIX,
                                          SOCK_STREAM,
@@ -508,6 +565,8 @@ try_unixpath (const char *service_name,
       GNUNET_free (unixpath);
       return sock;
     }
+    if (NULL != sock)
+      GNUNET_NETWORK_socket_close (sock);
   }
   GNUNET_free_non_null (unixpath);
 #endif
@@ -583,7 +642,7 @@ try_connect_using_address (void *cls,
 {
   struct ClientState *cstate = cls;
   struct AddressProbe *ap;
-  
+
   if (NULL == addr)
   {
     cstate->dns_active = NULL;
@@ -647,7 +706,7 @@ try_connect_using_address (void *cls,
   GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
                                cstate->ap_tail,
                                ap);
-  ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+  ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
                                             ap->sock,
                                             &connect_probe_continuation,
                                             ap);
@@ -679,6 +738,17 @@ test_service_configuration (const char *service_name,
                                                 &unixpath)) &&
       (0 < strlen (unixpath)))
     ret = GNUNET_OK;
+  else if ((GNUNET_OK ==
+            GNUNET_CONFIGURATION_have_value (cfg,
+                                             service_name,
+                                             "UNIXPATH")))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               service_name,
+                               "UNIXPATH",
+                               _("not a valid filename"));
+    return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
+  }
   GNUNET_free_non_null (unixpath);
 #endif
 
@@ -739,7 +809,7 @@ start_connect (void *cls)
     {
       connect_success_continuation (cstate);
       return;
-    }    
+    }
   }
   if ( (NULL == cstate->hostname) ||
        (0 == cstate->port) )
@@ -751,7 +821,7 @@ start_connect (void *cls)
   cstate->dns_active
     = GNUNET_RESOLVER_ip_get (cstate->hostname,
                              AF_UNSPEC,
-                              GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+                              CONNECT_RETRY_TIMEOUT,
                               &try_connect_using_address,
                              cstate);
 }
@@ -771,13 +841,19 @@ connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
 {
   struct ClientState *cstate = impl_state;
 
+  (void) mq;
   /* only one message at a time allowed */
   GNUNET_assert (NULL == cstate->msg);
   GNUNET_assert (NULL == cstate->send_task);
   cstate->msg = msg;
   cstate->msg_off = 0;
   if (NULL == cstate->sock)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "message of type %u waiting for socket\n",
+         ntohs(msg->type));
     return; /* still waiting for connection */
+  }
   cstate->send_task
     = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                       cstate->sock,
@@ -798,6 +874,7 @@ connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
 {
   struct ClientState *cstate = impl_state;
 
+  (void) mq;
   GNUNET_assert (NULL != cstate->msg);
   GNUNET_assert (0 == cstate->msg_off);
   cstate->msg = NULL;
@@ -821,7 +898,7 @@ connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
  * @return the message queue, NULL on error
  */
 struct GNUNET_MQ_Handle *
-GNUNET_CLIENT_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg,
+GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
                       const char *service_name,
                       const struct GNUNET_MQ_MessageHandler *handlers,
                       GNUNET_MQ_ErrorHandler error_handler,
@@ -875,4 +952,4 @@ GNUNET_CLIENT_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg,
   return cstate->mq;
 }
 
-/* end of client_new.c */
+/* end of client.c */