remove output
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index 078946f0a561bbc777b84c69b8f80875cc6c5b0c..be19c5de3005ae5c1259859153051267d4149b62 100644 (file)
  */
 #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.
    */
@@ -153,6 +183,8 @@ struct Session
   unsigned int rc;
 
   int in_destroy;
+
+  int inbound;
 };
 
 
@@ -545,9 +577,13 @@ udp_address_to_string (void *cls, const void *addr, size_t addrlen)
     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);
@@ -626,6 +662,7 @@ udp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
                                    &socket_address))
   {
     GNUNET_break (0);
+    GNUNET_free (plugin);
     return GNUNET_SYSERR;
   }
 
@@ -664,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.
  *
@@ -674,14 +728,31 @@ 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;
   }
+  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
@@ -690,7 +761,6 @@ append_port (void *cls, const char *hostname)
   GNUNET_free (ret);
 }
 
-
 /**
  * Convert the transports address to a nice, human-readable
  * format.
@@ -756,7 +826,7 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
   }
   else if (0 == addrlen)
   {
-    asc (asc_cls, "<inbound connection>");
+    asc (asc_cls, TRANSPORT_SESSION_INBOUND_STRING);
     asc (asc_cls, NULL);
     return;
   }
@@ -776,7 +846,12 @@ udp_plugin_address_pretty_printer (void *cls, const char *type,
     ppc->ipv6 = GNUNET_YES;
   else
     ppc->ipv6 = GNUNET_NO;
-  GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+  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);
+
 }
 
 
@@ -993,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))
@@ -1333,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;
@@ -1350,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;
@@ -1367,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;
@@ -1377,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;
 }
@@ -1427,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
@@ -1436,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;
@@ -1492,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,
@@ -1499,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,
@@ -1516,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)
 {
@@ -1765,6 +1908,8 @@ udp_nat_port_map_callback (void *cls, int add_remove,
     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 (struct IPv4UdpAddress);
     break;
@@ -1772,6 +1917,8 @@ udp_nat_port_map_callback (void *cls, int add_remove,
     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;
@@ -1813,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);
 
@@ -1892,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 */
@@ -2966,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;
 }
@@ -3000,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)
   {
@@ -3086,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);