Fixed 5528: TCP *communicator* bindto option should support DNS names, and 6013:...
authort3sserakt <t3ss@posteo.de>
Fri, 12 Jun 2020 10:51:46 +0000 (12:51 +0200)
committert3sserakt <t3ss@posteo.de>
Fri, 12 Jun 2020 10:51:46 +0000 (12:51 +0200)
src/transport/Makefile.am
src/transport/gnunet-communicator-tcp.c
src/transport/test_communicator_tcp_basic_peer1.conf
src/transport/test_communicator_tcp_basic_peer2.conf
src/transport/transport-testing2.c
src/util/resolver_api.c

index 02e87da0f62ae328525fae66e4af0a45e8b9d3ae..eadb601efde308299c0d83d20d2418ad798c4334 100644 (file)
@@ -669,13 +669,13 @@ TESTS += \
   test_transport_api_timeout_udp \
   test_transport_api_udp_nat \
   test_transport_api_reliability_udp \
-test_quota_compliance_udp \
-test_communicator_basic-unix \
-test_communicator_basic-tcp \
-test_communicator_basic-udp \
-test_communicator_rekey-tcp \
-test_communicator_rekey-udp \
-test_communicator_backchannel-udp
+  test_quota_compliance_udp \
+  test_communicator_basic-unix \
+  test_communicator_basic-tcp \
+  test_communicator_basic-udp \
+  test_communicator_rekey-tcp \
+  test_communicator_rekey-udp \
+  test_communicator_backchannel-udp
 endif
 endif
 
index 7f70c55df731098e880f6db2165d61cfd42f2bdb..e25cdf13916ace68b0c07b0ed817e5bd7b5e6f82 100644 (file)
 #include "gnunet_nt_lib.h"
 #include "gnunet_nat_service.h"
 #include "gnunet_statistics_service.h"
+#include "gnunet_ats_transport_service.h"
+#include "transport.h"
 #include "gnunet_transport_communication_service.h"
-
+#include "gnunet_resolver_service.h"
 /**
  * How long do we believe our addresses to remain up (before
  * the other peer should revalidate).
@@ -253,6 +255,21 @@ struct TCPFinish
 
 GNUNET_NETWORK_STRUCT_END
 
+/**
+ * Struct to use as closure.
+ */
+struct ListenTask
+{
+  /**
+   * ID of listen task
+   */
+  struct GNUNET_SCHEDULER_Task *listen_task;
+
+  /**
+   * Listen socket.
+   */
+  struct GNUNET_NETWORK_Handle *listen_sock;
+};
 
 /**
  * Handle for a queue.
@@ -264,6 +281,16 @@ struct Queue
    */
   struct GNUNET_PeerIdentity target;
 
+  /**
+   * ID of listen task
+   */
+  struct GNUNET_SCHEDULER_Task *listen_task;
+
+  /**
+   * Listen socket.
+   */
+  struct GNUNET_NETWORK_Handle *listen_sock;
+
   /**
    * socket that we transmit all data with on this queue
    */
@@ -448,6 +475,16 @@ struct ProtoQueue
    */
   struct ProtoQueue *prev;
 
+  /**
+   * ID of listen task
+   */
+  struct GNUNET_SCHEDULER_Task *listen_task;
+
+  /**
+   * Listen socket.
+   */
+  struct GNUNET_NETWORK_Handle *listen_sock;
+
   /**
    * socket that we transmit all data with on this queue
    */
@@ -485,11 +522,61 @@ struct ProtoQueue
   size_t ibuf_off;
 };
 
+/**
+ * In case of port only configuration we like to bind to ipv4 and ipv6 addresses.
+ */
+struct PortOnlyIpv4Ipv6
+{
+  /**
+   * Ipv4 address we like to bind to.
+   */
+  struct sockaddr *addr_ipv4;
+
+  /**
+   * Length of ipv4 address.
+   */
+  socklen_t *addr_len_ipv4;
+
+  /**
+   * Ipv6 address we like to bind to.
+   */
+  struct sockaddr *addr_ipv6;
+
+  /**
+   * Length of ipv6 address.
+   */
+  socklen_t *addr_len_ipv6;
+
+};
 
 /**
- * ID of listen task
+ * DLL to store the addresses we like to register at NAT service.
  */
-static struct GNUNET_SCHEDULER_Task *listen_task;
+struct Addresses
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct Addresses *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct Addresses *prev;
+
+  /**
+   * Address we like to register at NAT service.
+   */
+  struct sockaddr *addr;
+
+  /**
+   * Length of address we like to register at NAT service.
+   */
+  socklen_t addr_len;
+
+};
+
+
 
 /**
  * Maximum queue length before we stop reading towards the transport service.
@@ -511,11 +598,6 @@ static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
  */
 static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
 
-/**
- * Listen socket.
- */
-static struct GNUNET_NETWORK_Handle *listen_sock;
-
 /**
  * Our public key.
  */
@@ -556,6 +638,25 @@ static struct ProtoQueue *proto_head;
  */
 static struct ProtoQueue *proto_tail;
 
+/**
+ * Handle for DNS lookup of bindto address
+ */
+struct GNUNET_RESOLVER_RequestHandle *resolve_request_handle;
+
+/**
+ * Head of DLL with addresses we like to register at NAT servcie.
+ */
+struct Addresses *addrs_head;
+
+/**
+ * Head of DLL with addresses we like to register at NAT servcie.
+ */
+struct Addresses *addrs_tail;
+
+/**
+ * Number of addresses in the DLL for register at NAT service.
+ */
+int addrs_lens;
 
 /**
  * We have been notified that our listen socket has something to
@@ -579,6 +680,10 @@ static void
 queue_destroy (struct Queue *queue)
 {
   struct GNUNET_MQ_Handle *mq;
+  struct ListenTask *lt;
+  lt = GNUNET_new (struct ListenTask);
+  lt->listen_sock = queue->listen_sock;
+  lt->listen_task = queue->listen_task;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Disconnecting queue for peer `%s'\n",
@@ -618,11 +723,13 @@ queue_destroy (struct Queue *queue)
     queue->destroyed = GNUNET_YES;
   else
     GNUNET_free (queue);
-  if (NULL == listen_task)
-    listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 listen_sock,
-                                                 &listen_cb,
-                                                 NULL);
+
+  if (NULL == lt->listen_task)
+    lt->listen_task = GNUNET_SCHEDULER_add_read_net (
+      GNUNET_TIME_UNIT_FOREVER_REL,
+      lt->listen_sock,
+      &listen_cb,
+      lt);
 }
 
 
@@ -1063,7 +1170,8 @@ queue_read (void *cls)
        However, we have to take into account that the plaintext buffer may have
        already contained data and not jumpt too far ahead in the ciphertext.
        If there is no rekey and the last message is incomplete (max > total),
-       it is safe to keep the decryption so we shift by 'max' */if (GNUNET_YES == queue->rekeyed)
+       it is safe to keep the decryption so we shift by 'max' */
+    if (GNUNET_YES == queue->rekeyed)
     {
       max = total - old_pread_off;
       queue->rekeyed = GNUNET_NO;
@@ -1095,143 +1203,276 @@ queue_read (void *cls)
   queue_finish (queue);
 }
 
+/**
+ * Convert a `struct sockaddr_in6 to a `struct sockaddr *`
+ *
+ * @param[out] sock_len set to the length of the address.
+ * @param v6 The sockaddr_in6 to be converted.
+ * @return The struct sockaddr *.
+ */
+static struct sockaddr *
+tcp_address_to_sockaddr_numeric_v6 (socklen_t *sock_len, struct sockaddr_in6 v6,
+                                    unsigned int port)
+{
+  struct sockaddr *in;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "1 address %s\n",
+              GNUNET_a2s (in, *sock_len));
+
+  v6.sin6_family = AF_INET6;
+  v6.sin6_port = htons ((uint16_t) port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
+#endif
+  in = GNUNET_memdup (&v6, sizeof(v6));
+  *sock_len = sizeof(struct sockaddr_in6);
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "address %s\n",
+              GNUNET_a2s (in, *sock_len));
+
+  return in;
+}
 
 /**
- * Convert TCP bind specification to a `struct sockaddr *`
+ * Convert a `struct sockaddr_in4 to a `struct sockaddr *`
  *
- * @param bindto bind specification to convert
- * @param[out] sock_len set to the length of the address
- * @return converted bindto specification
+ * @param[out] sock_len set to the length of the address.
+ * @param v4 The sockaddr_in4 to be converted.
+ * @return The struct sockaddr *.
  */
 static struct sockaddr *
-tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
+tcp_address_to_sockaddr_numeric_v4 (socklen_t *sock_len, struct sockaddr_in v4,
+                                    unsigned int port)
 {
   struct sockaddr *in;
-  unsigned int port;
-  char dummy[2];
-  char *colon;
+
+  v4.sin_family = AF_INET;
+  v4.sin_port = htons ((uint16_t) port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  v4.sin_len = sizeof(struct sockaddr_in);
+#endif
+  in = GNUNET_memdup (&v4, sizeof(v4));
+  *sock_len = sizeof(struct sockaddr_in);
+  return in;
+}
+
+/**
+ * Convert TCP bind specification to a `struct PortOnlyIpv4Ipv6  *`
+ *
+ * @param bindto bind specification to convert.
+ * @return The converted bindto specification.
+ */
+static struct PortOnlyIpv4Ipv6 *
+tcp_address_to_sockaddr_port_only (const char *bindto, unsigned int *port)
+{
+  struct PortOnlyIpv4Ipv6 *po;
+  struct sockaddr_in *i4;
+  struct sockaddr_in6 *i6;
+  socklen_t sock_len_ipv4;
+  socklen_t sock_len_ipv6;
+
+  /* interpreting value as just a PORT number */
+  if (*port > UINT16_MAX)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "BINDTO specification `%s' invalid: value too large for port\n",
+                bindto);
+    return NULL;
+  }
+
+  po = GNUNET_new (struct PortOnlyIpv4Ipv6);
+
+  if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
+      (GNUNET_YES ==
+       GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                             COMMUNICATOR_CONFIG_SECTION,
+                                             "DISABLE_V6")))
+  {
+    i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
+    po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
+                                                        *port);
+    po->addr_len_ipv4 = &sock_len_ipv4;
+  }
+  else
+  {
+
+    i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
+    po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
+                                                        *port);
+    po->addr_len_ipv4 = &sock_len_ipv4;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "3.5 address %s\n",
+                GNUNET_a2s (po->addr_ipv4, sock_len_ipv4));
+
+    i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
+    po->addr_ipv6 = tcp_address_to_sockaddr_numeric_v6 (&sock_len_ipv6, *i6,
+                                                        *port);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "3 address %s\n",
+                GNUNET_a2s (po->addr_ipv6, sock_len_ipv6));
+
+    po->addr_len_ipv6 = &sock_len_ipv6;
+  }
+  return po;
+}
+
+/**
+ * This Method extracts the address part of the BINDTO string.
+ *
+ * @param bindto String we extract the address part from.
+ * @return The extracted address string.
+ */
+static char *
+extract_address (const char *bindto)
+{
+
+  char *start;
+  char *token;
   char *cp;
+  char *rest = NULL;
 
-  if (1 == sscanf (bindto, "%u%1s", &port, dummy))
+  if (NULL == bindto)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "bindto is NULL\n");
+
+  cp = GNUNET_strdup (bindto);
+  start = cp;
+  if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
   {
-    /* interpreting value as just a PORT number */
-    if (port > UINT16_MAX)
+    start++;   /* skip over '['*/
+    cp[strlen (cp) - 1] = '\0';  /* eat ']'*/
+  }
+  else {
+    token = strtok_r (cp, "]", &rest);
+    if (strlen (bindto) == strlen (token))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "BINDTO specification `%s' invalid: value too large for port\n",
-                  bindto);
-      return NULL;
+      token = strtok_r (cp, ":", &rest);
     }
-    if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
-        (GNUNET_YES ==
-         GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                               COMMUNICATOR_CONFIG_SECTION,
-                                               "DISABLE_V6")))
+    else
     {
-      struct sockaddr_in *i4;
+      token++;
+      return token;
+    }
+  }
 
-      i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
-      i4->sin_family = AF_INET;
-      i4->sin_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      i4->sin_len = sizeof(sizeof(struct sockaddr_in));
-#endif
-      *sock_len = sizeof(struct sockaddr_in);
-      in = (struct sockaddr *) i4;
+  // GNUNET_free(cp);
+
+  return start;
+}
+
+/**
+ * This Method extracts the port part of the BINDTO string.
+ *
+ * @param addr_and_port String we extract the port from.
+ * @return The extracted port as unsigned int.
+ */
+static unsigned int
+extract_port (const char *addr_and_port)
+{
+  unsigned int port;
+  char dummy[2];
+  char *token;
+  char *addr;
+  char *colon;
+  char *cp;
+  char *rest = NULL;
+
+  if (NULL != addr_and_port)
+  {
+    cp = GNUNET_strdup (addr_and_port);
+    token = strtok_r (cp, "]", &rest);
+    if (strlen (addr_and_port) == strlen (token))
+    {
+      colon = strrchr (cp, ':');
+      if (NULL == colon)
+      {
+        return 0;
+      }
+      addr = colon;
+      addr++;
     }
     else
     {
-      struct sockaddr_in6 *i6;
-
-      i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
-      i6->sin6_family = AF_INET6;
-      i6->sin6_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      i6->sin6_len = sizeof(sizeof(struct sockaddr_in6));
-#endif
-      *sock_len = sizeof(struct sockaddr_in6);
-      in = (struct sockaddr *) i6;
+      token = strtok_r (NULL, "]", &rest);
+      if (NULL == token)
+      {
+        return 0;
+      }
+      else
+      {
+        addr = token;
+        addr++;
+      }
     }
-    return in;
-  }
-  cp = GNUNET_strdup (bindto);
-  colon = strrchr (cp, ':');
-  if (NULL != colon)
-  {
-    /* interpet value after colon as port */
-    *colon = '\0';
-    colon++;
-    if (1 == sscanf (colon, "%u%1s", &port, dummy))
+
+
+    if (1 == sscanf (addr, "%u%1s", &port, dummy))
     {
       /* interpreting value as just a PORT number */
       if (port > UINT16_MAX)
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "BINDTO specification `%s' invalid: value too large for port\n",
-                    bindto);
-        GNUNET_free (cp);
-        return NULL;
+                    "Port `%u' invalid: value too large for port\n",
+                    port);
+        // GNUNET_free (cp);
+        return 0;
       }
     }
     else
     {
-      GNUNET_log (
-        GNUNET_ERROR_TYPE_ERROR,
-        "BINDTO specification `%s' invalid: last ':' not followed by number\n",
-        bindto);
-      GNUNET_free (cp);
-      return NULL;
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "BINDTO specification invalid: last ':' not followed by number\n");
+      // GNUNET_free (cp);
+      return 0;
     }
   }
   else
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "return 0\n");
     /* interpret missing port as 0, aka pick any free one */
     port = 0;
   }
-  {
-    /* try IPv4 */
-    struct sockaddr_in v4;
 
-    if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
-    {
-      v4.sin_family = AF_INET;
-      v4.sin_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      v4.sin_len = sizeof(struct sockaddr_in);
-#endif
-      in = GNUNET_memdup (&v4, sizeof(v4));
-      *sock_len = sizeof(v4);
-      GNUNET_free (cp);
-      return in;
-    }
+
+  return port;
+}
+
+/**
+ * Convert TCP bind specification to a `struct sockaddr *`
+ *
+ * @param bindto bind specification to convert
+ * @param[out] sock_len set to the length of the address
+ * @return converted bindto specification
+ */
+static struct sockaddr *
+tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
+{
+  struct sockaddr *in;
+  unsigned int port;
+  struct sockaddr_in v4;
+  struct sockaddr_in6 v6;
+  const char *start;
+
+  // cp = GNUNET_strdup (bindto);
+  start = extract_address (bindto);
+
+  if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
+  {
+    // colon = strrchr (cp, ':');
+    port = extract_port (bindto);
+    in = tcp_address_to_sockaddr_numeric_v4 (sock_len, v4, port);
   }
+  else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
   {
-    /* try IPv6 */
-    struct sockaddr_in6 v6;
-    const char *start;
-
-    start = cp;
-    if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
-    {
-      start++;   /* skip over '[' */
-      cp[strlen (cp) - 1] = '\0';  /* eat ']' */
-    }
-    if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
-    {
-      v6.sin6_family = AF_INET6;
-      v6.sin6_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
-#endif
-      in = GNUNET_memdup (&v6, sizeof(v6));
-      *sock_len = sizeof(v6);
-      GNUNET_free (cp);
-      return in;
-    }
+    // colon = strrchr (cp, ':');
+    port = extract_port (bindto);
+    in = tcp_address_to_sockaddr_numeric_v6 (sock_len, v6, port);
   }
-  /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
-  GNUNET_free (cp);
-  return NULL;
+
+  return in;
 }
 
 
@@ -1667,6 +1908,16 @@ decrypt_and_check_tc (struct Queue *queue,
 static void
 free_proto_queue (struct ProtoQueue *pq)
 {
+  if (NULL != pq->listen_task)
+  {
+    GNUNET_SCHEDULER_cancel (pq->listen_task);
+    pq->listen_task = NULL;
+  }
+  if (NULL != pq->listen_sock)
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pq->listen_sock));
+    pq->listen_sock = NULL;
+  }
   GNUNET_NETWORK_socket_close (pq->sock);
   GNUNET_free (pq->address);
   GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
@@ -1739,6 +1990,8 @@ proto_read_kx (void *cls)
   queue->address = pq->address; /* steals reference */
   queue->address_len = pq->address_len;
   queue->target = tc.sender;
+  queue->listen_task = pq->listen_task;
+  queue->listen_sock = pq->listen_sock;
   queue->sock = pq->sock;
   start_initial_kx_out (queue);
   boot_queue (queue, GNUNET_TRANSPORT_CS_INBOUND);
@@ -1762,7 +2015,7 @@ proto_read_kx (void *cls)
  * read. Do the read and reschedule this function to be called again
  * once more is available.
  *
- * @param cls NULL
+ * @param cls ListenTask with listening socket and task
  */
 static void
 listen_cb (void *cls)
@@ -1771,20 +2024,23 @@ listen_cb (void *cls)
   socklen_t addrlen;
   struct GNUNET_NETWORK_Handle *sock;
   struct ProtoQueue *pq;
+  struct ListenTask *lt;
 
-  listen_task = NULL;
-  GNUNET_assert (NULL != listen_sock);
+  lt = cls;
+
+  lt->listen_task = NULL;
+  GNUNET_assert (NULL != lt->listen_sock);
   addrlen = sizeof(in);
   memset (&in, 0, sizeof(in));
-  sock = GNUNET_NETWORK_socket_accept (listen_sock,
+  sock = GNUNET_NETWORK_socket_accept (lt->listen_sock,
                                        (struct sockaddr*) &in,
                                        &addrlen);
   if ((NULL == sock) && ((EMFILE == errno) || (ENFILE == errno)))
     return; /* system limit reached, wait until connection goes down */
-  listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                               listen_sock,
-                                               &listen_cb,
-                                               NULL);
+  lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                   lt->listen_sock,
+                                                   &listen_cb,
+                                                   lt);
   if ((NULL == sock) && ((EAGAIN == errno) || (ENOBUFS == errno)))
     return;
   if (NULL == sock)
@@ -1884,7 +2140,6 @@ queue_read_kx (void *cls)
     queue->read_task = GNUNET_SCHEDULER_add_now (&queue_read, queue);
 }
 
-
 /**
  * Function called by the transport service to initialize a
  * message queue given address information about another peer.
@@ -1924,6 +2179,13 @@ mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
   path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
   in = tcp_address_to_sockaddr (path, &in_len);
 
+  if (NULL == in)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to setup TCP socket address\n");
+    return GNUNET_SYSERR;
+  }
+
   sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, IPPROTO_TCP);
   if (NULL == sock)
   {
@@ -1967,7 +2229,6 @@ mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
   return GNUNET_OK;
 }
 
-
 /**
  * Iterator over all message queues to clean up.
  *
@@ -2005,16 +2266,6 @@ do_shutdown (void *cls)
     GNUNET_NAT_unregister (nat);
     nat = NULL;
   }
-  if (NULL != listen_task)
-  {
-    GNUNET_SCHEDULER_cancel (listen_task);
-    listen_task = NULL;
-  }
-  if (NULL != listen_sock)
-  {
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (listen_sock));
-    listen_sock = NULL;
-  }
   GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
   GNUNET_CONTAINER_multipeermap_destroy (queue_map);
   if (NULL != ch)
@@ -2087,6 +2338,10 @@ nat_address_cb (void *cls,
   char *my_addr;
   struct GNUNET_TRANSPORT_AddressIdentifier *ai;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "1 nat_address %s\n",
+              GNUNET_a2s (addr, addrlen));
+
   if (GNUNET_YES == add_remove)
   {
     enum GNUNET_NetworkType nt;
@@ -2112,80 +2367,53 @@ nat_address_cb (void *cls,
   }
 }
 
-
 /**
- * Setup communicator and launch network interactions.
+ * This method launch network interactions for each address we like to bind to.
  *
- * @param cls NULL (always)
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
+ * @param addr The address we will listen to.
+ * @param in_len The length of the address we will listen to.
+ * @return GNUNET_SYSERR in case of error. GNUNET_OK in case we are successfully listen to the address.
  */
-static void
-run (void *cls,
-     char *const *args,
-     const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle *c)
+static int
+init_socket (const struct sockaddr *addr,
+             socklen_t in_len)
 {
-  char *bindto;
-  struct sockaddr *in;
-  socklen_t in_len;
   struct sockaddr_storage in_sto;
   socklen_t sto_len;
+  struct GNUNET_NETWORK_Handle *listen_sock;
+  struct ListenTask *lt;
 
-  (void) cls;
-  cfg = c;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg,
-                                             COMMUNICATOR_CONFIG_SECTION,
-                                             "BINDTO",
-                                             &bindto))
-  {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                               COMMUNICATOR_CONFIG_SECTION,
-                               "BINDTO");
-    return;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg,
-                                             COMMUNICATOR_CONFIG_SECTION,
-                                             "MAX_QUEUE_LENGTH",
-                                             &max_queue_length))
-    max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (cfg,
-                                           COMMUNICATOR_CONFIG_SECTION,
-                                           "REKEY_INTERVAL",
-                                           &rekey_interval))
-    rekey_interval = DEFAULT_REKEY_INTERVAL;
-
-  in = tcp_address_to_sockaddr (bindto, &in_len);
-  if (NULL == in)
+  if (NULL == addr)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to setup TCP socket address with path `%s'\n",
-                bindto);
-    GNUNET_free (bindto);
-    return;
+                "Address is NULL.\n");
+    return GNUNET_SYSERR;
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "4 address %s\n",
+              GNUNET_a2s (addr, in_len));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "address %s\n",
+              GNUNET_a2s (addr, in_len));
+
   listen_sock =
-    GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, IPPROTO_TCP);
+    GNUNET_NETWORK_socket_create (addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
   if (NULL == listen_sock)
   {
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
-    GNUNET_free (in);
-    GNUNET_free (bindto);
-    return;
+    return GNUNET_SYSERR;
   }
-  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, in, in_len))
+
+  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, addr, in_len))
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "bind", bindto);
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
     GNUNET_NETWORK_socket_close (listen_sock);
     listen_sock = NULL;
-    GNUNET_free (in);
-    GNUNET_free (bindto);
-    return;
+    return GNUNET_SYSERR;
   }
+
   if (GNUNET_OK !=
       GNUNET_NETWORK_socket_listen (listen_sock,
                                     5))
@@ -2194,69 +2422,311 @@ run (void *cls,
                          "listen");
     GNUNET_NETWORK_socket_close (listen_sock);
     listen_sock = NULL;
-    GNUNET_free (in);
-    GNUNET_free (bindto);
+    return GNUNET_SYSERR;
   }
+
   /* We might have bound to port 0, allowing the OS to figure it out;
      thus, get the real IN-address from the socket */
   sto_len = sizeof(in_sto);
+
   if (0 != getsockname (GNUNET_NETWORK_get_fd (listen_sock),
                         (struct sockaddr *) &in_sto,
                         &sto_len))
   {
-    memcpy (&in_sto, in, in_len);
+    memcpy (&in_sto, addr, in_len);
     sto_len = in_len;
   }
-  GNUNET_free (in);
-  GNUNET_free (bindto);
-  in = (struct sockaddr *) &in_sto;
+
+  addr = (struct sockaddr *) &in_sto;
   in_len = sto_len;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Bound to `%s'\n",
               GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
   stats = GNUNET_STATISTICS_create ("C-TCP", cfg);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
-  is = GNUNET_NT_scanner_init ();
-  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
+
+  if (NULL == is)
+    is = GNUNET_NT_scanner_init ();
+
+  if (NULL == my_private_key)
+    my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
   if (NULL == my_private_key)
   {
     GNUNET_log (
       GNUNET_ERROR_TYPE_ERROR,
       _ (
         "Transport service is lacking key configuration settings. Exiting.\n"));
+    GNUNET_RESOLVER_request_cancel (resolve_request_handle);
     GNUNET_SCHEDULER_shutdown ();
-    return;
+    return GNUNET_SYSERR;
   }
   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
   /* start listening */
-  listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                               listen_sock,
-                                               &listen_cb,
-                                               NULL);
-  queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
-  ch = GNUNET_TRANSPORT_communicator_connect (cfg,
-                                              COMMUNICATOR_CONFIG_SECTION,
-                                              COMMUNICATOR_ADDRESS_PREFIX,
-                                              GNUNET_TRANSPORT_CC_RELIABLE,
-                                              &mq_init,
-                                              NULL,
-                                              &enc_notify_cb,
-                                              NULL);
+
+  lt = GNUNET_new (struct ListenTask);
+  lt->listen_sock = listen_sock;
+
+  lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                   listen_sock,
+                                                   &listen_cb,
+                                                   lt);
+
+  if (NULL == queue_map)
+    queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
+
+  if (NULL == ch )
+    ch = GNUNET_TRANSPORT_communicator_connect (cfg,
+                                                COMMUNICATOR_CONFIG_SECTION,
+                                                COMMUNICATOR_ADDRESS_PREFIX,
+                                                GNUNET_TRANSPORT_CC_RELIABLE,
+                                                &mq_init,
+                                                NULL,
+                                                &enc_notify_cb,
+                                                NULL);
+
   if (NULL == ch)
   {
     GNUNET_break (0);
+    GNUNET_RESOLVER_request_cancel (resolve_request_handle);
     GNUNET_SCHEDULER_shutdown ();
-    return;
+    return GNUNET_SYSERR;
+  }
+
+  return GNUNET_OK;
+
+}
+
+/**
+ * This method reads from the DLL addrs_head to register them at the NAT service.
+ */
+static void
+nat_register ()
+{
+
+  struct sockaddr **saddrs;
+  socklen_t *saddr_lens;
+  int i;
+  struct Addresses *pos;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "nat here\n");
+
+  i = 0;
+  saddrs = GNUNET_malloc ((addrs_lens + 1) * sizeof(struct sockaddr *));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "2 nat here\n");
+
+  saddr_lens = GNUNET_malloc ((addrs_lens + 1) * sizeof(socklen_t));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "3 nat here\n");
+
+  for (pos = addrs_head; NULL != pos; pos = pos->next)
+  {
+
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "5 nat here\n");
+
+    saddr_lens[i] = addrs_head->addr_len;
+    saddrs[i] = GNUNET_malloc (saddr_lens[i]);
+    saddrs[i] = addrs_head->addr;
+
+    i++;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "6 nat here\n");
+
   }
+
   nat = GNUNET_NAT_register (cfg,
                              COMMUNICATOR_CONFIG_SECTION,
                              IPPROTO_TCP,
-                             1 /* one address */,
-                             (const struct sockaddr **) &in,
-                             &in_len,
+                             addrs_lens,
+                             (const struct sockaddr **) saddrs,
+                             saddr_lens,
                              &nat_address_cb,
                              NULL /* FIXME: support reversal: #5529 */,
                              NULL /* closure */);
+
+  if (NULL == nat)
+  {
+    GNUNET_break (0);
+    GNUNET_RESOLVER_request_cancel (resolve_request_handle);
+    GNUNET_SCHEDULER_shutdown ();
+  }
+}
+
+/**
+ * This method adds addresses to the DLL, that are later register at the NAT service.
+ */
+static void
+add_addr (struct sockaddr *in, socklen_t in_len)
+{
+
+  struct Addresses *saddrs;
+
+  saddrs = GNUNET_new (struct Addresses);
+  saddrs->addr = in;
+  saddrs->addr_len = in_len;
+  GNUNET_CONTAINER_DLL_insert (addrs_head, addrs_tail, saddrs);
+  addrs_lens++;
+}
+
+/**
+ * This method is the callback called by the resolver API, and wraps method init_socket.
+ *
+ * @param cls The port we will bind to.
+ * @param addr The address we will bind to.
+ * @param in_len The length of the address we will bind to.
+ */
+static void
+init_socket_resolv (void *cls,
+                    const struct sockaddr *addr,
+                    socklen_t in_len)
+{
+  struct sockaddr_in *v4;
+  struct sockaddr_in6 *v6;
+  struct sockaddr *in;
+  unsigned int *port;
+
+  port = cls;
+  if (NULL  != addr)
+  {
+    if (AF_INET == addr->sa_family)
+    {
+      v4 = (struct sockaddr_in *) addr;
+      in = tcp_address_to_sockaddr_numeric_v4 (&in_len, *v4, *port);// _global);
+      add_addr (in, in_len);
+    }
+    else if (AF_INET6 == addr->sa_family)
+    {
+      v6 = (struct sockaddr_in6 *) addr;
+      in = tcp_address_to_sockaddr_numeric_v6 (&in_len, *v6, *port);// _global);
+      add_addr (in, in_len);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Address family %u not suitable (not AF_INET %u nor AF_INET6 %u \n",
+                  addr->sa_family,
+                  AF_INET,
+                  AF_INET6);
+      return;
+    }
+    init_socket (in,
+                 in_len);
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Address is NULL. This might be an error or the resolver finished resolving.\n");
+    nat_register ();
+  }
+}
+
+/**
+ * Setup communicator and launch network interactions.
+ *
+ * @param cls NULL (always)
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  char *bindto;
+  struct sockaddr *in;
+  socklen_t in_len;
+  struct sockaddr_in v4;
+  struct sockaddr_in6 v6;
+  char *start;
+  unsigned int port;
+  char dummy[2];
+  char *rest = NULL;
+  struct PortOnlyIpv4Ipv6 *po;
+
+  (void) cls;
+  cfg = c;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             COMMUNICATOR_CONFIG_SECTION,
+                                             "BINDTO",
+                                             &bindto))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               COMMUNICATOR_CONFIG_SECTION,
+                               "BINDTO");
+    return;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (cfg,
+                                             COMMUNICATOR_CONFIG_SECTION,
+                                             "MAX_QUEUE_LENGTH",
+                                             &max_queue_length))
+    max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (cfg,
+                                           COMMUNICATOR_CONFIG_SECTION,
+                                           "REKEY_INTERVAL",
+                                           &rekey_interval))
+    rekey_interval = DEFAULT_REKEY_INTERVAL;
+
+
+  // cp = GNUNET_strdup (bindto);
+  start = extract_address (bindto);
+
+  if (1 == sscanf (bindto, "%u%1s", &port, dummy))
+  {
+    po = tcp_address_to_sockaddr_port_only (bindto, &port);
+
+    if (NULL != &po->addr_ipv4)
+    {
+      init_socket (po->addr_ipv4, *po->addr_len_ipv4);
+      add_addr (po->addr_ipv4, *po->addr_len_ipv4);
+    }
+
+    if (NULL != &po->addr_ipv6)
+    {
+      init_socket (po->addr_ipv6, *po->addr_len_ipv6);
+      add_addr (po->addr_ipv6, *po->addr_len_ipv6);
+    }
+
+    nat_register ();
+  }
+  else if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
+  {
+    port = extract_port (bindto);
+
+    in = tcp_address_to_sockaddr_numeric_v4 (&in_len, v4, port);
+    init_socket (in, in_len);
+    add_addr (in, in_len);
+    nat_register ();
+  }
+  else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
+  {
+    port = extract_port (bindto);
+    in = tcp_address_to_sockaddr_numeric_v6 (&in_len, v6, port);
+    init_socket (in, in_len);
+    add_addr (in, in_len);
+    nat_register ();
+  }
+  else
+  {
+    port = extract_port (bindto);
+
+    resolve_request_handle = GNUNET_RESOLVER_ip_get (strtok_r (bindto, ":",
+                                                               &rest),
+                                                     AF_UNSPEC,
+                                                     GNUNET_TIME_UNIT_MINUTES,
+                                                     &init_socket_resolv,
+                                                     &port);
+  }
+  GNUNET_free (bindto);
 }
 
 
index fc08af1ee510894d844b58afd0a2920f2b5f57d9..d0293ff512532514ea35d2808d3316dd86e1d33f 100644 (file)
@@ -18,14 +18,17 @@ UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
 
 [nat]
 UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
-ENABLE_IPSCAN = YES
 
 [communicator-unix]
 UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
 
 [communicator-tcp]
 BINDTO = 60002
-DISABLE_V6 = YES
+DISABLE_V6 = NO
 
 [communicator-udp]
 BINDTO = 60002
+
+[resolver]
+PORT = 62089
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
index 4197df00d51984db9070bf0744f4c73d9b35de5f..5b90505472c8376e70b4484ab2ecd23e765856ea 100644 (file)
@@ -25,7 +25,11 @@ UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
 
 [communicator-tcp]
 BINDTO = 60003
-DISABLE_V6 = YES
+DISABLE_V6 = NO
 
 [communicator-udp]
 BINDTO = 60003
+
+[resolver]
+PORT = 62090
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
index e85e46b1156461e5ba6abda555fe6eaef1ba5790..0dc1bb33156fd59b91b310ed94c0724341525b74 100644 (file)
@@ -108,6 +108,11 @@ struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
    */
   struct GNUNET_OS_Process *nat_proc;
 
+  /**
+   * resolver service process
+   */
+  struct GNUNET_OS_Process *resolver_proc;
+
   /**
    * @brief Task that will be run on shutdown to stop and clean communicator
    */
@@ -877,11 +882,11 @@ shutdown_process (struct GNUNET_OS_Process *proc)
   if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Error shutting down communicator with SIGERM, trying SIGKILL\n");
+         "Error shutting down process with SIGERM, trying SIGKILL\n");
     if (0 != GNUNET_OS_process_kill (proc, SIGKILL))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
-           "Error shutting down communicator with SIGERM and SIGKILL\n");
+           "Error shutting down process with SIGERM and SIGKILL\n");
     }
   }
   GNUNET_OS_process_destroy (proc);
@@ -942,6 +947,45 @@ shutdown_nat (void *cls)
   shutdown_process (proc);
 }
 
+/**
+ * @brief Task run at shutdown to kill the resolver process
+ *
+ * @param cls Closure - Process of communicator
+ */
+static void
+shutdown_resolver (void *cls)
+{
+  struct GNUNET_OS_Process *proc = cls;
+  shutdown_process (proc);
+}
+
+static void
+resolver_start (struct
+                GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
+{
+  char *binary;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n");
+  binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
+  tc_h->resolver_proc = GNUNET_OS_start_process (GNUNET_YES,
+                                                 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                                 NULL,
+                                                 NULL,
+                                                 NULL,
+                                                 binary,
+                                                 "gnunet-service-resolver",
+                                                 "-c",
+                                                 tc_h->cfg_filename,
+                                                 NULL);
+  if (NULL == tc_h->resolver_proc)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!");
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n");
+  GNUNET_free (binary);
+
+}
 
 /**
  * @brief Start NAT
@@ -1037,6 +1081,8 @@ GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
   transport_communicator_start (tc_h);
   /* Start NAT */
   nat_start (tc_h);
+  /* Start resolver service */
+  resolver_start (tc_h);
   /* Schedule start communicator */
   communicator_start (tc_h,
                       binary_name);
@@ -1051,6 +1097,7 @@ GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
   shutdown_communicator (tc_h->c_proc);
   shutdown_service (tc_h->sh);
   shutdown_nat (tc_h->nat_proc);
+  shutdown_resolver (tc_h->resolver_proc);
   GNUNET_CONFIGURATION_destroy (tc_h->cfg);
   GNUNET_free (tc_h);
 }
index a1e30bbd451b5f262994dbac9c7b71dba2410995..d38c700e46a29cbf846c94ecca9de2571c3bf7e3 100644 (file)
@@ -152,7 +152,7 @@ struct GNUNET_RESOLVER_RequestHandle
   /**
    * Has this request been transmitted to the service?
    * #GNUNET_YES if transmitted
-   * #GNUNET_YES if not transmitted
+   * #GNUNET_NO if not transmitted
    * #GNUNET_SYSERR when request was canceled
    */
   int was_transmitted;