remove output
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index b6d4b3f30a63dc9f2640b2d2782443e01b7657e6..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.
  */
@@ -442,7 +492,7 @@ schedule_select (struct Plugin *plugin)
   struct GNUNET_TIME_Relative min_delay;
   struct UDP_MessageWrapper *udpw;
 
-  if (NULL != plugin->sockv4)
+  if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4))
   {
     /* Find a message ready to send:
      * Flow delay from other peer is expired or not set (0) */
@@ -464,7 +514,7 @@ schedule_select (struct Plugin *plugin)
                                   (0 == min_delay.rel_value) ? plugin->ws_v4 : NULL,
                                   &udp_plugin_select, plugin);  
   }
-  if (NULL != plugin->sockv6)
+  if ((GNUNET_YES == plugin->enable_ipv6) && (NULL != plugin->sockv6))
   {
     min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
     for (udpw = plugin->ipv6_queue_head; NULL != udpw; udpw = udpw->next)
@@ -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 */
@@ -2495,7 +2732,7 @@ udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  */
 static int
 setup_sockets (struct Plugin *plugin, 
-              const struct sockaddr_in6 *bind_v6, 
+              const struct sockaddr_in6 *bind_v6,
               const struct sockaddr_in *bind_v4)
 {
   int tries;
@@ -2515,6 +2752,7 @@ setup_sockets (struct Plugin *plugin,
     plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0);
     if (NULL == plugin->sockv6)
     {
+       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
       LOG (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n");
       plugin->enable_ipv6 = GNUNET_NO;
     }
@@ -2530,38 +2768,36 @@ setup_sockets (struct Plugin *plugin,
       else
        serverAddrv6.sin6_addr = in6addr_any;
 
-      if (0 == plugin->port)
-       /* autodetect */
-       serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
+      if (0 == plugin->port) /* autodetect */
+               serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
       else
-       serverAddrv6.sin6_port = htons (plugin->port);
+               serverAddrv6.sin6_port = htons (plugin->port);
       addrlen = sizeof (struct sockaddr_in6);
       serverAddr = (struct sockaddr *) &serverAddrv6;
 
       tries = 0;
       while (tries < 10)
       {
-       LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 `%s'\n",
-            GNUNET_a2s (serverAddr, addrlen));
-       
-       /* binding */
-       if (GNUNET_OK == GNUNET_NETWORK_socket_bind (plugin->sockv6, serverAddr, addrlen))
-         break;
-       eno = errno;
-       if (0 != plugin->port)
-         {
-           tries = 10; /* fail */
-           break; /* bind failed on specific port */
-         }
-       
-       /* autodetect */
-       serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
-       tries ++;
+               LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 `%s'\n",
+                                GNUNET_a2s (serverAddr, addrlen));
+               /* binding */
+               if (GNUNET_OK == GNUNET_NETWORK_socket_bind (plugin->sockv6,
+                                                            serverAddr, addrlen, 0))
+                       break;
+               eno = errno;
+               if (0 != plugin->port)
+               {
+                               tries = 10; /* fail */
+                               break; /* bind failed on specific port */
+               }
+               /* autodetect */
+               serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
+               tries ++;
       }
-      
       if (tries >= 10)
       {
         GNUNET_NETWORK_socket_close (plugin->sockv6);
+        plugin->enable_ipv6 = GNUNET_NO;
         plugin->sockv6 = NULL;
       }
 
@@ -2590,7 +2826,8 @@ setup_sockets (struct Plugin *plugin,
   if (NULL == plugin->sockv4)
   {
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
-    return sockets_created;
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv4 since it is not supported on this system!\n");
+    plugin->enable_ipv4 = GNUNET_NO;
   }
   else
   {
@@ -2618,16 +2855,17 @@ setup_sockets (struct Plugin *plugin,
     while (tries < 10)
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv4 `%s'\n",
-          GNUNET_a2s (serverAddr, addrlen));
+                       GNUNET_a2s (serverAddr, addrlen));
       
       /* binding */
-      if (GNUNET_OK == GNUNET_NETWORK_socket_bind (plugin->sockv4, serverAddr, addrlen))
-       break;
+      if (GNUNET_OK == GNUNET_NETWORK_socket_bind (plugin->sockv4,
+                                                   serverAddr, addrlen, 0))
+               break;
       eno = errno;
       if (0 != plugin->port)
       {
-       tries = 10; /* fail */
-       break; /* bind failed on specific port */
+               tries = 10; /* fail */
+               break; /* bind failed on specific port */
       }
       
       /* autodetect */
@@ -2638,14 +2876,14 @@ setup_sockets (struct Plugin *plugin,
     if (tries >= 10)
     {
       GNUNET_NETWORK_socket_close (plugin->sockv4);
+      plugin->enable_ipv4 = GNUNET_NO;
       plugin->sockv4 = NULL;
     }
     
     if (plugin->sockv4 != NULL)
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG,
-          "IPv4 socket created on port %s\n",
-          GNUNET_a2s (serverAddr, addrlen));
+               "IPv4 socket created on port %s\n", GNUNET_a2s (serverAddr, addrlen));
       addrs[sockets_created] = (struct sockaddr *) &serverAddrv4;
       addrlens[sockets_created] = sizeof (struct sockaddr_in);
       sockets_created++;
@@ -2653,25 +2891,31 @@ setup_sockets (struct Plugin *plugin,
     else
     {            
       LOG (GNUNET_ERROR_TYPE_ERROR,
-          "Failed to bind UDP socket to %s: %s\n",
-          GNUNET_a2s (serverAddr, addrlen),
-          STRERROR (eno));
+               "Failed to bind UDP socket to %s: %s\n",
+               GNUNET_a2s (serverAddr, addrlen), STRERROR (eno));
     }
   }
   
+  if (0 == sockets_created)
+  {
+               LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
+               return 0; /* No sockets created, return */
+  }
+
   /* Create file descriptors */
-  plugin->rs_v4 = GNUNET_NETWORK_fdset_create ();
-  plugin->ws_v4 = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_zero (plugin->rs_v4);
-  GNUNET_NETWORK_fdset_zero (plugin->ws_v4);
-  if (NULL != plugin->sockv4)
+  if (plugin->enable_ipv4 == GNUNET_YES)
   {
-    GNUNET_NETWORK_fdset_set (plugin->rs_v4, plugin->sockv4);
-    GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4);
+                       plugin->rs_v4 = GNUNET_NETWORK_fdset_create ();
+                       plugin->ws_v4 = GNUNET_NETWORK_fdset_create ();
+                       GNUNET_NETWORK_fdset_zero (plugin->rs_v4);
+                       GNUNET_NETWORK_fdset_zero (plugin->ws_v4);
+                       if (NULL != plugin->sockv4)
+                       {
+                               GNUNET_NETWORK_fdset_set (plugin->rs_v4, plugin->sockv4);
+                               GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4);
+                       }
   }
 
-  if (0 == sockets_created)
-    LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
   if (plugin->enable_ipv6 == GNUNET_YES)
   {
     plugin->rs_v6 = GNUNET_NETWORK_fdset_create ();
@@ -2684,8 +2928,7 @@ setup_sockets (struct Plugin *plugin,
       GNUNET_NETWORK_fdset_set (plugin->ws_v6, plugin->sockv6);
     }
   }
-  if (0 == sockets_created)
-    return 0;
+
   schedule_select (plugin);
   plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
                            GNUNET_NO, plugin->port,
@@ -2737,7 +2980,7 @@ libgnunet_plugin_transport_udp_init (void *cls)
     return api;
   }
 
-  GNUNET_assertNULL != env->stats);
+  GNUNET_assert (NULL != env->stats);
 
   /* Get port number: port == 0 : autodetect a port,
    *                                                                                           > 0 : use this port,
@@ -2762,9 +3005,7 @@ libgnunet_plugin_transport_udp_init (void *cls)
   if ((GNUNET_YES ==
        GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "nat",
                                              "DISABLEV6")))
-  {
     enable_v6 = GNUNET_NO;
-  }
   else
     enable_v6 = GNUNET_YES;
 
@@ -2785,6 +3026,7 @@ libgnunet_plugin_transport_udp_init (void *cls)
     }
     have_bind4 = GNUNET_YES;
   }
+  GNUNET_free_non_null (bind4_address);
   have_bind6 = GNUNET_NO;
   memset (&serverAddrv6, 0, sizeof (serverAddrv6));
   if (GNUNET_YES ==
@@ -2799,12 +3041,15 @@ 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;
     }
     have_bind6 = GNUNET_YES;
   }
+  GNUNET_free_non_null (bind6_address);
+
+  /* Initialize my flags */
+  myoptions = 0;
 
   /* Enable neighbour discovery */
   broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp",
@@ -2834,51 +3079,50 @@ libgnunet_plugin_transport_udp_init (void *cls)
   }
 
   p = GNUNET_malloc (sizeof (struct Plugin));
-
-  GNUNET_BANDWIDTH_tracker_init (&p->tracker,
-                                 GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30);
-  p->sessions = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
-  p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, p);
   p->port = port;
   p->aport = aport;
   p->broadcast_interval = interval;
   p->enable_ipv6 = enable_v6;
+  p->enable_ipv4 = GNUNET_YES; /* default */
   p->env = env;
-
+  p->sessions = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, p);
+  GNUNET_BANDWIDTH_tracker_init (&p->tracker,
+                                 GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30);
   plugin = p;
-  api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
-  api->cls = p;
-  api->send = NULL;
-  api->disconnect = &udp_disconnect;
-  api->address_pretty_printer = &udp_plugin_address_pretty_printer;
-  api->address_to_string = &udp_address_to_string;
-  api->string_to_address = &udp_string_to_address;
-  api->check_address = &udp_plugin_check_address;
-  api->get_session = &udp_plugin_get_session;
-  api->send = &udp_plugin_send;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting up sockets\n");
   res = setup_sockets (p, (GNUNET_YES == have_bind6) ? &serverAddrv6 : NULL,
-                      (GNUNET_YES == have_bind4) ? &serverAddrv4 : NULL);
+                                                                               (GNUNET_YES == have_bind4) ? &serverAddrv4 : NULL);
   if ((res == 0) || ((p->sockv4 == NULL) && (p->sockv6 == NULL)))
   {
-    /* FIXME: memory leaks here! (i.e. p->mst, sessions, defrag_ctxs, etc.) */
     LOG (GNUNET_ERROR_TYPE_ERROR,
         _("Failed to create network sockets, plugin failed\n"));
+    GNUNET_CONTAINER_multihashmap_destroy (p->sessions);
+    GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
+    GNUNET_SERVER_mst_destroy (p->mst);
     GNUNET_free (p);
-    GNUNET_free (api);
     return NULL;
   }
-
-  if (broadcast == GNUNET_YES)
+  else if (broadcast == GNUNET_YES)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n");
     setup_broadcast (p, &serverAddrv6, &serverAddrv4);
   }
 
-  GNUNET_free_non_null (bind4_address);
-  GNUNET_free_non_null (bind6_address);
+  api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+  api->cls = p;
+  api->send = NULL;
+  api->disconnect = &udp_disconnect;
+  api->address_pretty_printer = &udp_plugin_address_pretty_printer;
+  api->address_to_string = &udp_address_to_string;
+  api->string_to_address = &udp_string_to_address;
+  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;
 }
 
@@ -2912,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)
   {
@@ -2932,24 +3178,29 @@ libgnunet_plugin_transport_udp_done (void *cls)
   }
 
   /* Closing sockets */
-  if (plugin->sockv4 != NULL)
+  if (GNUNET_YES ==plugin->enable_ipv4)
   {
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4));
-    plugin->sockv4 = NULL;
+               if (plugin->sockv4 != NULL)
+               {
+                       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4));
+                       plugin->sockv4 = NULL;
+               }
+               GNUNET_NETWORK_fdset_destroy (plugin->rs_v4);
+               GNUNET_NETWORK_fdset_destroy (plugin->ws_v4);
   }
-  GNUNET_NETWORK_fdset_destroy (plugin->rs_v4);
-  GNUNET_NETWORK_fdset_destroy (plugin->ws_v4);
-
-  if (plugin->sockv6 != NULL)
+  if (GNUNET_YES ==plugin->enable_ipv6)
   {
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6));
-    plugin->sockv6 = NULL;
+               if (plugin->sockv6 != NULL)
+               {
+                       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6));
+                       plugin->sockv6 = NULL;
 
-    GNUNET_NETWORK_fdset_destroy (plugin->rs_v6);
-    GNUNET_NETWORK_fdset_destroy (plugin->ws_v6);
+                       GNUNET_NETWORK_fdset_destroy (plugin->rs_v6);
+                       GNUNET_NETWORK_fdset_destroy (plugin->ws_v6);
+               }
   }
-
-  GNUNET_NAT_unregister (plugin->nat);
+  if (NULL != plugin->nat)
+       GNUNET_NAT_unregister (plugin->nat);
 
   if (plugin->defrag_ctxs != NULL)
   {
@@ -2993,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);