remove output
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index fa90d16c1267e3cc16bb0a5b15b25cda8f4d0c4b..be19c5de3005ae5c1259859153051267d4149b62 100644 (file)
@@ -42,6 +42,7 @@
 
 #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
 
+#define PLUGIN_NAME "udp"
 
 /**
  * Number of messages we can defragment in parallel.  We only really
  */
 #define UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG 128
 
+/**
+ * Running pretty printers: head
+ */
+static struct PrettyPrinterContext *ppc_dll_head;
+
+/**
+ * Running pretty printers: tail
+ */
+static struct PrettyPrinterContext *ppc_dll_tail;
+
 /**
  * Closure for 'append_port'.
  */
 struct PrettyPrinterContext
 {
+       /**
+        * DLL
+        */
+       struct PrettyPrinterContext *next;
+
+       /**
+        * DLL
+        */
+       struct PrettyPrinterContext *prev;
+
+       /**
+        * Timeout task
+        */
+       GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+       /**
+        * Resolver handle
+        */
+       struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
+
   /**
    * Function to call with the result.
    */
@@ -81,6 +112,17 @@ struct PrettyPrinterContext
    * Port to add after the IP address.
    */
   uint16_t port;
+
+  /**
+   * IPv6 address
+   */
+
+  int ipv6;
+
+  /**
+   * Options
+   */
+  uint32_t options;
 };
 
 
@@ -141,6 +183,8 @@ struct Session
   unsigned int rc;
 
   int in_destroy;
+
+  int inbound;
 };
 
 
@@ -383,6 +427,12 @@ struct UDP_ACK_Message
 
 };
 
+/**
+ * Address options
+ */
+static uint32_t myoptions;
+
+
 /**
  * Encapsulation of all of the state of the plugin.
  */
@@ -506,11 +556,14 @@ udp_address_to_string (void *cls, const void *addr, size_t addrlen)
   const struct IPv6UdpAddress *t6;
   int af;
   uint16_t port;
+  uint32_t options;
 
+  options = 0;
   if (addrlen == sizeof (struct IPv6UdpAddress))
   {
     t6 = addr;
     af = AF_INET6;
+    options = ntohl (t6->options);
     port = ntohs (t6->u6_port);
     memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
     sb = &a6;
@@ -519,18 +572,24 @@ udp_address_to_string (void *cls, const void *addr, size_t addrlen)
   {
     t4 = addr;
     af = AF_INET;
+    options = ntohl (t4->options);
     port = ntohs (t4->u4_port);
     memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
     sb = &a4;
   }
+  else if (addrlen == 0)
+       {
+               GNUNET_snprintf (rbuf, sizeof (rbuf), "%s", TRANSPORT_SESSION_INBOUND_STRING);
+               return rbuf;
+       }
   else
   {
-    GNUNET_break_op (0);
     return NULL;
   }
   inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
-  GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u",
-                   buf, port);
+
+  GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
+                   PLUGIN_NAME, options, buf, port);
   return rbuf;
 }
 
@@ -552,29 +611,63 @@ udp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
     void **buf, size_t *added)
 {
   struct sockaddr_storage socket_address;
-  
-  if ((NULL == addr) || (0 == addrlen))
+  char *address;
+  char *plugin;
+  char *optionstr;
+  uint32_t options;
+
+  /* Format tcp.options.address:port */
+  address = NULL;
+  plugin = NULL;
+  optionstr = NULL;
+  options = 0;
+  if ((NULL == addr) || (addrlen == 0))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
   if ('\0' != addr[addrlen - 1])
   {
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
   if (strlen (addr) != addrlen - 1)
   {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  plugin = GNUNET_strdup (addr);
+  optionstr = strchr (plugin, '.');
+  if (NULL == optionstr)
+  {
+    GNUNET_break (0);
+    GNUNET_free (plugin);
     return GNUNET_SYSERR;
   }
+  optionstr[0] = '\0';
+  optionstr ++;
+  options = atol (optionstr);
+  address = strchr (optionstr, '.');
+  if (NULL == address)
+  {
+    GNUNET_break (0);
+    GNUNET_free (plugin);
+    return GNUNET_SYSERR;
+  }
+  address[0] = '\0';
+  address ++;
 
-  if (GNUNET_OK != GNUNET_STRINGS_to_address_ip (addr, strlen (addr),
-                                                &socket_address))
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_to_address_ip (address, strlen (address),
+                                   &socket_address))
   {
+    GNUNET_break (0);
+    GNUNET_free (plugin);
     return GNUNET_SYSERR;
   }
 
+  GNUNET_free (plugin);
+
   switch (socket_address.ss_family)
   {
   case AF_INET:
@@ -582,6 +675,7 @@ udp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
       struct IPv4UdpAddress *u4;
       struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
       u4 = GNUNET_malloc (sizeof (struct IPv4UdpAddress));
+      u4->options =  htonl (options);
       u4->ipv4_addr = in4->sin_addr.s_addr;
       u4->u4_port = in4->sin_port;
       *buf = u4;
@@ -593,6 +687,7 @@ udp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
       struct IPv6UdpAddress *u6;
       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
       u6 = GNUNET_malloc (sizeof (struct IPv6UdpAddress));
+      u6->options =  htonl (options);
       u6->ipv6_addr = in6->sin6_addr;
       u6->u6_port = in6->sin6_port;
       *buf = u6;
@@ -606,6 +701,23 @@ udp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
 }
 
 
+void
+ppc_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+       struct PrettyPrinterContext *ppc = cls;
+       /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PPC %p was not removed!\n", ppc); */
+       ppc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+       if (NULL != ppc->resolver_handle)
+       {
+               GNUNET_RESOLVER_request_cancel (ppc->resolver_handle);
+               ppc->resolver_handle = NULL;
+       }
+
+       GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, ppc);
+       GNUNET_free (ppc);
+}
+
+
 /**
  * Append our port and forward the result.
  *
@@ -616,20 +728,39 @@ static void
 append_port (void *cls, const char *hostname)
 {
   struct PrettyPrinterContext *ppc = cls;
+  struct PrettyPrinterContext *cur;
   char *ret;
-
+       /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PPC callback: %p `%s'\n",ppc, hostname); */
   if (hostname == NULL)
   {
     ppc->asc (ppc->asc_cls, NULL);
+    GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, ppc);
+    GNUNET_SCHEDULER_cancel (ppc->timeout_task);
+    ppc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    ppc->resolver_handle = NULL;
+       /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PPC %p was removed!\n", ppc); */
     GNUNET_free (ppc);
     return;
   }
-  GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
+  for (cur = ppc_dll_head; (NULL != cur); cur = cur->next)
+  {
+       if (cur == ppc)
+               break;
+  }
+  if (NULL == cur)
+  {
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid callback for PPC %p \n", ppc);
+       return;
+  }
+
+  if (GNUNET_YES == ppc->ipv6)
+    GNUNET_asprintf (&ret, "%s.%u.[%s]:%d", PLUGIN_NAME, ppc->options, hostname, ppc->port);
+  else
+    GNUNET_asprintf (&ret, "%s.%u.%s:%d", PLUGIN_NAME, ppc->options, hostname, ppc->port);
   ppc->asc (ppc->asc_cls, ret);
   GNUNET_free (ret);
 }
 
-
 /**
  * Convert the transports address to a nice, human-readable
  * format.
@@ -660,7 +791,9 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
   const struct IPv4UdpAddress *u4;
   const struct IPv6UdpAddress *u6;
   uint16_t port;
+  uint32_t options;
 
+  options = 0;
   if (addrlen == sizeof (struct IPv6UdpAddress))
   {
     u6 = addr;
@@ -672,6 +805,7 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
     a6.sin6_port = u6->u6_port;
     memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof (struct in6_addr));
     port = ntohs (u6->u6_port);
+    options = ntohl (u6->options);
     sb = &a6;
     sbs = sizeof (a6);
   }
@@ -686,12 +820,13 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
     a4.sin_port = u4->u4_port;
     a4.sin_addr.s_addr = u4->ipv4_addr;
     port = ntohs (u4->u4_port);
+    options = ntohl (u4->options);
     sb = &a4;
     sbs = sizeof (a4);
   }
   else if (0 == addrlen)
   {
-    asc (asc_cls, "<inbound connection>");
+    asc (asc_cls, TRANSPORT_SESSION_INBOUND_STRING);
     asc (asc_cls, NULL);
     return;
   }
@@ -706,7 +841,17 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
   ppc->asc = asc;
   ppc->asc_cls = asc_cls;
   ppc->port = port;
-  GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+  ppc->options = options;
+  if (addrlen == sizeof (struct IPv6UdpAddress))
+    ppc->ipv6 = GNUNET_YES;
+  else
+    ppc->ipv6 = GNUNET_NO;
+  ppc->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(timeout, 2),
+               &ppc_cancel_task, ppc);
+  GNUNET_CONTAINER_DLL_insert (ppc_dll_head, ppc_dll_tail, ppc);
+       /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PPC %p was created!\n", ppc); */
+  ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+
 }
 
 
@@ -923,7 +1068,6 @@ udp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
   if ((addrlen != sizeof (struct IPv4UdpAddress)) &&
       (addrlen != sizeof (struct IPv6UdpAddress)))
   {
-    GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
   if (addrlen == sizeof (struct IPv4UdpAddress))
@@ -1263,6 +1407,10 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
   case sizeof (struct IPv4UdpAddress):
     if (NULL == plugin->sockv4)
     {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Could not create session for peer `%s' address `%s': IPv4 is not enabled\n",
+           GNUNET_i2s(target),
+           udp_address_to_string(NULL, addr, addrlen));
       return NULL;
     }
     t4 = addr;
@@ -1280,6 +1428,10 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
   case sizeof (struct IPv6UdpAddress):
     if (NULL == plugin->sockv6)
     {
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           "Could not create session for peer `%s' address `%s': IPv6 is not enabled\n",
+           GNUNET_i2s(target),
+           udp_address_to_string(NULL, addr, addrlen));
       return NULL;
     }
     t6 = addr;
@@ -1297,7 +1449,10 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
     break;
   default:
     /* Must have a valid address to send to */
-    GNUNET_break_op (0);
+    GNUNET_STATISTICS_update (plugin->env->stats,
+                              gettext_noop
+                              ("# requests to create session with invalid address"),
+                              1, GNUNET_NO);
     return NULL;
   }
   s->addrlen = len;
@@ -1307,6 +1462,7 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
   s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
   s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
   s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
+  s->inbound = GNUNET_NO;
   start_session_timeout (s);
   return s;
 }
@@ -1357,6 +1513,21 @@ session_cmp_it (void *cls,
 }
 
 
+/**
+ * Function obtain the network type for a session
+ *
+ * @param cls closure ('struct Plugin*')
+ * @param session the session
+ * @return the network type in HBO or GNUNET_SYSERR
+ */
+static enum GNUNET_ATS_Network_Type
+udp_get_network (void *cls, 
+                struct Session *session)
+{
+  return ntohl (session->ats.value);
+}
+
+
 /**
  * Creates a new outbound session the transport service will use to send data to the
  * peer
@@ -1366,10 +1537,9 @@ session_cmp_it (void *cls,
  * @return the session or NULL of max connections exceeded
  */
 static struct Session *
-udp_plugin_get_session (void *cls,
-                  const struct GNUNET_HELLO_Address *address)
+udp_plugin_lookup_session (void *cls,
+                 const struct GNUNET_HELLO_Address *address)
 {
-  struct Session * s = NULL;
   struct Plugin * plugin = cls;
   struct IPv6UdpAddress * udp_a6;
   struct IPv4UdpAddress * udp_a4;
@@ -1382,7 +1552,11 @@ udp_plugin_get_session (void *cls,
       ((address->address_length != sizeof (struct IPv4UdpAddress)) &&
       (address->address_length != sizeof (struct IPv6UdpAddress))))
   {
-    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+       _("Trying to create session for address of unexpected length %u (should be %u or %u)\n"),
+       address->address_length,
+       sizeof (struct IPv4UdpAddress),
+       sizeof (struct IPv6UdpAddress));
     return NULL;
   }
 
@@ -1418,6 +1592,14 @@ udp_plugin_get_session (void *cls,
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res);
     return cctx.res;
   }
+  return NULL;
+}
+
+static struct Session *
+udp_plugin_create_session (void *cls,
+                  const struct GNUNET_HELLO_Address *address)
+{
+  struct Session * s = NULL;
 
   /* otherwise create new */
   s = create_session (plugin,
@@ -1425,6 +1607,8 @@ udp_plugin_get_session (void *cls,
       address->address,
       address->address_length,
       NULL, NULL);
+  if (NULL == s)
+       return NULL; /* protocol not supported or address invalid */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Creating new session %p for peer `%s' address `%s'\n",
        s,
@@ -1442,6 +1626,39 @@ udp_plugin_get_session (void *cls,
   return s;
 }
 
+
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+static struct Session *
+udp_plugin_get_session (void *cls,
+                  const struct GNUNET_HELLO_Address *address)
+{
+  struct Session * s = NULL;
+
+  if (NULL == address)
+  {
+       GNUNET_break (0);
+       return NULL;
+  }
+  if ((address->address_length != sizeof (struct IPv4UdpAddress)) &&
+               (address->address_length != sizeof (struct IPv6UdpAddress)))
+               return NULL;
+
+  /* otherwise create new */
+  if (NULL != (s = udp_plugin_lookup_session(cls, address)))
+       return s;
+  else
+       return udp_plugin_create_session (cls, address);
+}
+
+
 static void 
 enqueue (struct Plugin *plugin, struct UDP_MessageWrapper * udpw)
 {
@@ -1687,18 +1904,26 @@ udp_nat_port_map_callback (void *cls, int add_remove,
   {
   case AF_INET:
     GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+    memset (&u4, 0, sizeof (u4));
+    u4.options = htonl(myoptions);
     u4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
     u4.u4_port = ((struct sockaddr_in *) addr)->sin_port;
+    if (0 == ((struct sockaddr_in *) addr)->sin_port)
+       return;
     arg = &u4;
-    args = sizeof (u4);
+    args = sizeof (struct IPv4UdpAddress);
     break;
   case AF_INET6:
     GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+    memset (&u4, 0, sizeof (u4));
+    u6.options = htonl(myoptions);
+    if (0 == ((struct sockaddr_in6 *) addr)->sin6_port)
+       return;
     memcpy (&u6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
             sizeof (struct in6_addr));
     u6.u6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
     arg = &u6;
-    args = sizeof (u6);
+    args = sizeof (struct IPv6UdpAddress);
     break;
   default:
     GNUNET_break (0);
@@ -1735,13 +1960,13 @@ process_inbound_tokenized_messages (void *cls, void *client,
                                &si->sender,
                                hdr,
                                si->session,
-                               si->arg,
-                               si->args);
+                (GNUNET_YES == si->session->inbound) ? NULL : si->arg,
+                (GNUNET_YES == si->session->inbound) ? 0 : si->args);
 
   plugin->env->update_address_metrics (plugin->env->cls,
                                       &si->sender,
-                                      si->arg,
-                                      si->args,
+                                        (GNUNET_YES == si->session->inbound) ? NULL : si->arg,
+                                        (GNUNET_YES == si->session->inbound) ? 0 : si->args,
                                       si->session,
                                       &si->session->ats, 1);
 
@@ -1788,6 +2013,8 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg,
   {
   case AF_INET:
     GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in));
+    memset (&u4, 0, sizeof (u4));
+    u6.options = htonl (0);
     u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr;
     u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port;
     arg = &u4;
@@ -1795,6 +2022,8 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg,
     break;
   case AF_INET6:
     GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in6));
+    memset (&u6, 0, sizeof (u6));
+    u6.options = htonl (0);
     u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr;
     u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port;
     arg = &u6;
@@ -1810,7 +2039,15 @@ process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg,
        GNUNET_a2s (sender_addr, sender_addr_len));
 
   struct GNUNET_HELLO_Address * address = GNUNET_HELLO_address_allocate(&msg->sender, "udp", arg, args);
-  s = udp_plugin_get_session(plugin, address);
+  if (NULL == (s = udp_plugin_lookup_session (plugin, address)))
+  {
+               s = udp_plugin_create_session(plugin, address);
+               s->inbound = GNUNET_YES;
+         plugin->env->session_start (NULL, &address->peer, PLUGIN_NAME,
+                       (GNUNET_YES == s->inbound) ? NULL : address->address,
+                       (GNUNET_YES == s->inbound) ? 0 : address->address_length,
+                 s, NULL, 0);
+  }
   GNUNET_free (address);
 
   /* iterate over all embedded messages */
@@ -2804,7 +3041,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
     {
       LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid IPv6 address: `%s'\n"),
            bind6_address);
-      GNUNET_free_non_null (bind4_address);
       GNUNET_free (bind6_address);
       return NULL;
     }
@@ -2812,6 +3048,9 @@ libgnunet_plugin_transport_udp_init (void *cls)
   }
   GNUNET_free_non_null (bind6_address);
 
+  /* Initialize my flags */
+  myoptions = 0;
+
   /* Enable neighbour discovery */
   broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp",
                                             "BROADCAST");
@@ -2882,6 +3121,7 @@ libgnunet_plugin_transport_udp_init (void *cls)
   api->check_address = &udp_plugin_check_address;
   api->get_session = &udp_plugin_get_session;
   api->send = &udp_plugin_send;
+  api->get_network = &udp_get_network;
 
   return api;
 }
@@ -2916,6 +3156,8 @@ libgnunet_plugin_transport_udp_done (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
+  struct PrettyPrinterContext *cur;
+  struct PrettyPrinterContext *next;
 
   if (NULL == plugin)
   {
@@ -3002,6 +3244,17 @@ libgnunet_plugin_transport_udp_done (void *cls)
   GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &disconnect_and_free_it, plugin);
   GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions);
 
+  next = ppc_dll_head;
+  for (cur = next; NULL != cur; cur = next)
+  {
+       next = cur->next;
+       GNUNET_CONTAINER_DLL_remove (ppc_dll_head, ppc_dll_tail, cur);
+       GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
+       GNUNET_SCHEDULER_cancel (cur->timeout_task);
+       GNUNET_free (cur);
+       GNUNET_break (0);
+  }
+
   plugin->nat = NULL;
   GNUNET_free (plugin);
   GNUNET_free (api);