-some fixes for monkey
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index 45387cfc827eedbc4487d7be9862feec02821d58..1520bf2840e59b6c9db62995d409dfb1a7ea1bce 100644 (file)
@@ -348,6 +348,51 @@ static void
 stop_session_timeout (struct Session *s);
 
 
+/**
+ * (re)schedule select tasks for this plugin.
+ *
+ * @param plugin plugin to reschedule
+ */
+static void
+schedule_select (struct Plugin *plugin)
+{
+  struct GNUNET_TIME_Relative min_delay;
+  struct UDPMessageWrapper *udpw;
+
+  if (NULL != plugin->sockv4)
+  {
+    min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
+    for (udpw = plugin->ipv4_queue_head; NULL != udpw; udpw = udpw->next)
+      min_delay = GNUNET_TIME_relative_min (min_delay,
+                                           GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer));
+    
+    if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+      GNUNET_SCHEDULER_cancel(plugin->select_task);
+    plugin->select_task =
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                  (0 == min_delay.rel_value) ? GNUNET_TIME_UNIT_FOREVER_REL : min_delay,
+                                  plugin->rs_v4,
+                                  (0 == min_delay.rel_value) ? plugin->ws_v4 : NULL,
+                                  &udp_plugin_select, plugin);  
+  }
+  if (NULL != plugin->sockv6)
+  {
+    min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
+    for (udpw = plugin->ipv6_queue_head; NULL != udpw; udpw = udpw->next)
+      min_delay = GNUNET_TIME_relative_min (min_delay,
+                                           GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer));
+    
+    if (GNUNET_SCHEDULER_NO_TASK != plugin->select_task_v6)
+      GNUNET_SCHEDULER_cancel(plugin->select_task_v6);
+    plugin->select_task_v6 =
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                  (0 == min_delay.rel_value) ? GNUNET_TIME_UNIT_FOREVER_REL : min_delay,
+                                  plugin->rs_v6,
+                                  (0 == min_delay.rel_value) ? plugin->ws_v6 : NULL,
+                                  &udp_plugin_select_v6, plugin);
+  }
+}
+
 
 /**
  * Function called for a quick conversion of the binary address to
@@ -690,7 +735,7 @@ free_session (struct Session *s)
  * to close a session due to a disconnect or failure to
  * establish a connection.
  *
- * @param session session to close down
+ * @param s session to close down
  */
 static void
 disconnect_session (struct Session *s)
@@ -704,7 +749,7 @@ disconnect_session (struct Session *s)
          s,
          GNUNET_i2s (&s->target),
          GNUNET_a2s (s->sock_addr, s->addrlen));
-  stop_session_timeout(s);
+  stop_session_timeout (s);
   next = plugin->ipv4_queue_head;
   while (NULL != (udpw = next))
   {
@@ -764,7 +809,7 @@ disconnect_session (struct Session *s)
  * @return GNUNET_OK (continue to iterate)
  */
 static int
-disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value)
+disconnect_and_free_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   disconnect_session(value);
   return GNUNET_OK;
@@ -792,6 +837,79 @@ udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
 }
 
 
+/**
+ * Session was idle, so disconnect it
+ */
+static void
+session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_assert (NULL != cls);
+  struct Session *s = cls;
+
+  s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Session %p was idle for %llu ms, disconnecting\n",
+              s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+  /* call session destroy function */
+  disconnect_session (s);
+}
+
+
+/**
+ * Start session timeout
+ */
+static void
+start_session_timeout (struct Session *s)
+{
+  GNUNET_assert (NULL != s);
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
+  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+                                                   &session_timeout,
+                                                   s);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Timeout for session %p set to %llu ms\n",
+              s,  (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+}
+
+
+/**
+ * Increment session timeout due to activity
+ */
+static void
+reschedule_session_timeout (struct Session *s)
+{
+  GNUNET_assert (NULL != s);
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
+
+  GNUNET_SCHEDULER_cancel (s->timeout_task);
+  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+                                                   &session_timeout,
+                                                   s);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Timeout rescheduled for session %p set to %llu ms\n",
+              s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+}
+
+
+/**
+ * Cancel timeout
+ */
+static void
+stop_session_timeout (struct Session *s)
+{
+  GNUNET_assert (NULL != s);
+
+  if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (s->timeout_task);
+    s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Timeout stopped for session %p canceled\n",
+                s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+  }
+}
+
+
 static struct Session *
 create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
                 const void *addr, size_t addrlen,
@@ -846,23 +964,18 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
     GNUNET_break_op (0);
     return NULL;
   }
-
   s->addrlen = len;
   s->target = *target;
   s->sock_addr = (const struct sockaddr *) &s[1];
-  s->flow_delay_for_other_peer = GNUNET_TIME_relative_get_zero();
-  s->flow_delay_from_other_peer = GNUNET_TIME_absolute_get_zero();
   s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS;
-
-  start_session_timeout(s);
-
+  start_session_timeout (s);
   return s;
 }
 
 
 static int
 session_cmp_it (void *cls,
-               const GNUNET_HashCode * key,
+               const struct GNUNET_HashCode * key,
                void *value)
 {
   struct SessionCompareContext * cctx = cls;
@@ -1038,14 +1151,12 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg)
   struct FragmentationContext *frag_ctx = cls;
   struct Plugin *plugin = frag_ctx->plugin;
   struct UDPMessageWrapper * udpw;
-  struct Session *s;
   size_t msg_len = ntohs (msg->size);
-
   LOG (GNUNET_ERROR_TYPE_DEBUG, 
        "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper));
   udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msg_len);
   udpw->session = frag_ctx->session;
-  s = udpw->session;
   udpw->udp = (char *) &udpw[1];
 
   udpw->msg_size = msg_len;
@@ -1055,39 +1166,7 @@ enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg)
   udpw->frag_ctx = frag_ctx;
   memcpy (udpw->udp, msg, msg_len);
   enqueue (plugin, udpw);
-
-  if (s->addrlen == sizeof (struct sockaddr_in))
-  {
-    if (plugin->with_v4_ws == GNUNET_NO)
-    {
-      if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
-        GNUNET_SCHEDULER_cancel(plugin->select_task);
-
-      plugin->select_task =
-          GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                       GNUNET_TIME_UNIT_FOREVER_REL,
-                                       plugin->rs_v4,
-                                       plugin->ws_v4,
-                                       &udp_plugin_select, plugin);
-      plugin->with_v4_ws = GNUNET_YES;
-    }
-  }
-  else if (s->addrlen == sizeof (struct sockaddr_in6))
-  {
-    if (plugin->with_v6_ws == GNUNET_NO)
-    {
-      if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
-        GNUNET_SCHEDULER_cancel(plugin->select_task_v6);
-
-      plugin->select_task_v6 =
-          GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                       GNUNET_TIME_UNIT_FOREVER_REL,
-                                       plugin->rs_v6,
-                                       plugin->ws_v6,
-                                       &udp_plugin_select_v6, plugin);
-      plugin->with_v6_ws = GNUNET_YES;
-    }
-  }
+  schedule_select (plugin);
 }
 
 
@@ -1154,6 +1233,14 @@ udp_plugin_send (void *cls,
        GNUNET_i2s (&s->target),
        GNUNET_a2s(s->sock_addr, s->addrlen));
   
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                            "# bytes currently in UDP buffers",
+                            msgbuf_size, GNUNET_NO);
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                            "# bytes payload asked to transmit via UDP",
+                            msgbuf_size, GNUNET_NO);
+
+
   /* Message */
   udp = (struct UDPMessage *) mbuf;
   udp->header.size = htons (mlen);
@@ -1174,13 +1261,12 @@ udp_plugin_send (void *cls,
     udpw->frag_ctx = NULL;
     memcpy (udpw->udp, udp, sizeof (struct UDPMessage));
     memcpy (&udpw->udp[sizeof (struct UDPMessage)], msgbuf, msgbuf_size);
-
     enqueue (plugin, udpw);
   }
   else
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "UDP has to fragment message \n");
+         "UDP has to fragment message\n");
     if  (s->frag_ctx != NULL)
       return GNUNET_SYSERR;
     memcpy (&udp[1], msgbuf, msgbuf_size);
@@ -1202,40 +1288,7 @@ udp_plugin_send (void *cls,
 
     s->frag_ctx = frag_ctx;
   }
-
-  if (s->addrlen == sizeof (struct sockaddr_in))
-  {
-    if (plugin->with_v4_ws == GNUNET_NO)
-    {
-      if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
-        GNUNET_SCHEDULER_cancel(plugin->select_task);
-
-      plugin->select_task =
-          GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                       GNUNET_TIME_UNIT_FOREVER_REL,
-                                       plugin->rs_v4,
-                                       plugin->ws_v4,
-                                       &udp_plugin_select, plugin);
-      plugin->with_v4_ws = GNUNET_YES;
-    }
-  }
-  else if (s->addrlen == sizeof (struct sockaddr_in6))
-  {
-    if (plugin->with_v6_ws == GNUNET_NO)
-    {
-      if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
-        GNUNET_SCHEDULER_cancel(plugin->select_task_v6);
-
-      plugin->select_task_v6 =
-        GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                     GNUNET_TIME_UNIT_FOREVER_REL,
-                                     plugin->rs_v6,
-                                     plugin->ws_v6,
-                                     &udp_plugin_select_v6, plugin);
-      plugin->with_v6_ws = GNUNET_YES;
-    }
-  }
-
+  schedule_select (plugin);
   return mlen;
 }
 
@@ -1282,7 +1335,7 @@ udp_nat_port_map_callback (void *cls, int add_remove,
     return;
   }
   /* modify our published address list */
-  plugin->env->notify_address (plugin->env->cls, add_remove, arg, args);
+  plugin->env->notify_address (plugin->env->cls, add_remove, arg, args, "udp");
 }
 
 
@@ -1316,7 +1369,7 @@ process_inbound_tokenized_messages (void *cls, void *client,
                                &si->sender,
                                hdr,
                                (const struct GNUNET_ATS_Information *) &ats, 2,
-                               NULL,
+                               si->session,
                                si->arg,
                                si->args);
   si->session->flow_delay_for_other_peer = delay;
@@ -1466,7 +1519,7 @@ struct LookupContext
 
 
 static int
-lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value)
+lookup_session_by_addr_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct LookupContext *l_ctx = cls;
   struct Session * s = value;
@@ -1521,14 +1574,10 @@ ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg)
                                                                      sockaddr_in6)),
        delay);
   udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msize);
-  udpw->cont = NULL;
-  udpw->cont_cls = NULL;
-  udpw->frag_ctx = NULL;
   udpw->msg_size = msize;
   udpw->session = s;
-  udpw->timeout = GNUNET_TIME_absolute_get_forever();
+  udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
   udpw->udp = (char *)&udpw[1];
-
   udp_ack = (struct UDP_ACK_Message *) udpw->udp;
   udp_ack->header.size = htons ((uint16_t) msize);
   udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK);
@@ -1750,8 +1799,15 @@ udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock)
   memset (&addr, 0, sizeof (addr));
   size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof (buf),
                                       (struct sockaddr *) &addr, &fromlen);
-
-  if (size < sizeof (struct GNUNET_MessageHeader))
+#if MINGW
+  /* On SOCK_DGRAM UDP sockets recvfrom might fail with a
+   * WSAECONNRESET error to indicate that previous sendto() (???)
+   * on this socket has failed.
+   */
+  if ( (-1 == size) && (ECONNRESET == errno) )
+    return;
+#endif
+  if ( (-1 == size) || (size < sizeof (struct GNUNET_MessageHeader)))
   {
     GNUNET_break_op (0);
     return;
@@ -1768,6 +1824,10 @@ udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock)
     return;
   }
 
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                            "# bytes received via UDP",
+                            size, GNUNET_NO);
+
   switch (ntohs (msg->type))
   {
   case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
@@ -1800,6 +1860,7 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
   size_t slen;
   struct GNUNET_TIME_Absolute max;
   struct UDPMessageWrapper *udpw = NULL;
+  static int network_down_error;
 
   if (sock == plugin->sockv4)
   {
@@ -1818,7 +1879,7 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
   const struct sockaddr * sa = udpw->session->sock_addr;
   slen = udpw->session->addrlen;
 
-  max = GNUNET_TIME_absolute_max(udpw->timeout, GNUNET_TIME_absolute_get());
+  max = GNUNET_TIME_absolute_max (udpw->timeout, GNUNET_TIME_absolute_get());
 
   while (udpw != NULL)
   {
@@ -1831,7 +1892,7 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
         LOG (GNUNET_ERROR_TYPE_DEBUG,
             "Fragmented message for peer `%s' with size %u timed out\n",
             GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send);
-        udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag);
+        udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy (udpw->frag_ctx->frag);
         GNUNET_free (udpw->frag_ctx);
         udpw->session->frag_ctx = NULL;
       }
@@ -1891,24 +1952,39 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
     const struct GNUNET_ATS_Information type = plugin->env->get_address_type
         (plugin->env->cls,sa, slen);
 
-    if ((GNUNET_ATS_NET_WAN == type.value) &&
+    if (((GNUNET_ATS_NET_LAN == ntohl(type.value)) || (GNUNET_ATS_NET_WAN == ntohl(type.value))) &&
         ((ENETUNREACH == errno) || (ENETDOWN == errno)))
     {
-      /* "Network unreachable" or "Network down" */
-      /*
-       * This indicates that this system is IPv6 enabled, but does not
-       * have a valid global IPv6 address assigned
-       */
-       LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-           _("UDP could not message to `%s': `%s'. "
+      if ((network_down_error == GNUNET_NO) && (slen == sizeof (struct sockaddr_in)))
+      {
+        /* IPv4: "Network unreachable" or "Network down"
+         *
+         * This indicates we do not have connectivity
+         */
+        LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+            _("UDP could not transmit message to `%s': "
+              "Network seems down, please check your network configuration\n"),
+            GNUNET_a2s (sa, slen));
+      }
+      if ((network_down_error == GNUNET_NO) && (slen == sizeof (struct sockaddr_in6)))
+      {
+        /* IPv6: "Network unreachable" or "Network down"
+         *
+         * This indicates that this system is IPv6 enabled, but does not
+         * have a valid global IPv6 address assigned or we do not have
+         * connectivity
+         */
+
+       LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+           _("UDP could not transmit message to `%s': "
             "Please check your network configuration and disable IPv6 if your "
             "connection does not have a global IPv6 address\n"),
-           GNUNET_a2s (sa, slen),
-           STRERROR (errno));
+          GNUNET_a2s (sa, slen));
+      }
     }
     else
     {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
+      LOG (GNUNET_ERROR_TYPE_WARNING,
          "UDP could not transmit %u-byte message to `%s': `%s'\n",
          (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen),
          STRERROR (errno));
@@ -1918,12 +1994,20 @@ udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
   else
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "UDP transmitted %u-byte message to `%s' (%d: %s)\n",
-         (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent,
+         "UDP transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
+         (unsigned int) (udpw->msg_size), GNUNET_i2s(&udpw->session->target) ,GNUNET_a2s (sa, slen), (int) sent,
          (sent < 0) ? STRERROR (errno) : "ok");
+    GNUNET_STATISTICS_update (plugin->env->stats,
+                              "# bytes transmitted via UDP",
+                              sent, GNUNET_NO);
     call_continuation(udpw, GNUNET_OK);
+    network_down_error = GNUNET_NO;
   }
 
+  GNUNET_STATISTICS_update (plugin->env->stats,
+                            "# bytes currently in UDP buffers",
+                            -udpw->msg_size, GNUNET_NO);
+
   if (sock == plugin->sockv4)
     GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
   else if (sock == plugin->sockv6)
@@ -1949,38 +2033,18 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct Plugin *plugin = cls;
 
   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
-  plugin->with_v4_ws = GNUNET_NO;
-
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
-  {
-    if ((NULL != plugin->sockv4) &&
-      (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4)))
-        udp_select_read (plugin, plugin->sockv4);
-
-  }
-
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
-  {
-    if ((NULL != plugin->sockv4) && (plugin->ipv4_queue_head != NULL) &&
-      (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv4)))
-      {
-        udp_select_send (plugin, plugin->sockv4);
-      }
-  }
-
-  if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (plugin->select_task);
-  plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   GNUNET_TIME_UNIT_FOREVER_REL,
-                                   plugin->rs_v4,
-                                   (plugin->ipv4_queue_head != NULL) ? plugin->ws_v4 : NULL,
-                                   &udp_plugin_select, plugin);
-  if (plugin->ipv4_queue_head != NULL)
-    plugin->with_v4_ws = GNUNET_YES;
-  else
-    plugin->with_v4_ws = GNUNET_NO;
+  if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
+       (NULL != plugin->sockv4) &&
+       (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4)) )
+    udp_select_read (plugin, plugin->sockv4);
+  if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
+       (NULL != plugin->sockv4) && 
+       (NULL != plugin->ipv4_queue_head) &&
+       (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv4)) )
+    udp_select_send (plugin, plugin->sockv4);   
+  schedule_select (plugin);
 }
 
 
@@ -1998,36 +2062,17 @@ udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct Plugin *plugin = cls;
 
   plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK;
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
-
-  plugin->with_v6_ws = GNUNET_NO;
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
-  {
-    if ((NULL != plugin->sockv6) &&
-      (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6)))
-        udp_select_read (plugin, plugin->sockv6);
-  }
-
-  if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
-  {
-    if ((NULL != plugin->sockv6) && (plugin->ipv6_queue_head != NULL) &&
-      (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv6)))
-      {
-        udp_select_send (plugin, plugin->sockv6);
-      }
-  }
-  if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
-  plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   GNUNET_TIME_UNIT_FOREVER_REL,
-                                   plugin->rs_v6,
-                                   (plugin->ipv6_queue_head != NULL) ? plugin->ws_v6 : NULL,
-                                   &udp_plugin_select_v6, plugin);
-  if (plugin->ipv6_queue_head != NULL)
-    plugin->with_v6_ws = GNUNET_YES;
-  else
-    plugin->with_v6_ws = GNUNET_NO;
+  if ( ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) &&
+       (NULL != plugin->sockv6) &&
+       (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6)) )
+    udp_select_read (plugin, plugin->sockv6);
+  if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
+       (NULL != plugin->sockv6) && (plugin->ipv6_queue_head != NULL) &&
+       (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv6)) )    
+    udp_select_send (plugin, plugin->sockv6);
+  schedule_select (plugin);
 }
 
 
@@ -2143,17 +2188,8 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct
     GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4);
   }
 
-  if (sockets_created == 0)
+  if (0 == sockets_created)
     LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
-
-  plugin->select_task =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   GNUNET_TIME_UNIT_FOREVER_REL,
-                                   plugin->rs_v4,
-                                   NULL,
-                                   &udp_plugin_select, plugin);
-  plugin->with_v4_ws = GNUNET_NO;
-
   if (plugin->enable_ipv6 == GNUNET_YES)
   {
     plugin->rs_v6 = GNUNET_NETWORK_fdset_create ();
@@ -2165,16 +2201,8 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct
       GNUNET_NETWORK_fdset_set (plugin->rs_v6, plugin->sockv6);
       GNUNET_NETWORK_fdset_set (plugin->ws_v6, plugin->sockv6);
     }
-
-    plugin->select_task_v6 =
-        GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                     GNUNET_TIME_UNIT_FOREVER_REL,
-                                     plugin->rs_v6,
-                                     NULL,
-                                     &udp_plugin_select_v6, plugin);
-    plugin->with_v6_ws = GNUNET_NO;
   }
-
+  schedule_select (plugin);
   plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
                            GNUNET_NO, plugin->port,
                            sockets_created,
@@ -2184,82 +2212,6 @@ setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct
   return sockets_created;
 }
 
-/**
- * Session was idle, so disconnect it
- */
-static void
-session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  GNUNET_assert (NULL != cls);
-  struct Session *s = cls;
-
-  s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n",
-      s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
-
-  /* call session destroy function */
-  disconnect_session(s);
-
-}
-
-/**
- * Start session timeout
- */
-static void
-start_session_timeout (struct Session *s)
-{
-  GNUNET_assert (NULL != s);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
-
-  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                                                   &session_timeout,
-                                                   s);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n",
-      s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
-}
-
-/**
- * Increment session timeout due to activity
- */
-static void
-reschedule_session_timeout (struct Session *s)
-{
-  GNUNET_assert (NULL != s);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
-
-  GNUNET_SCHEDULER_cancel (s->timeout_task);
-  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                                                   &session_timeout,
-                                                   s);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n",
-      s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
-}
-
-/**
- * Cancel timeout
- */
-static void
-stop_session_timeout (struct Session *s)
-{
-  GNUNET_assert (NULL != s);
-
-  if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (s->timeout_task);
-    s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n",
-      s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n",
-      s);
-  }
-}
 
 /**
  * The exported method. Makes the core api available via a global and
@@ -2281,6 +2233,7 @@ libgnunet_plugin_transport_udp_init (void *cls)
   unsigned long long enable_v6;
   char * bind4_address;
   char * bind6_address;
+  char * fancy_interval;
   struct GNUNET_TIME_Relative interval;
   struct sockaddr_in serverAddrv4;
   struct sockaddr_in6 serverAddrv6;
@@ -2369,11 +2322,19 @@ libgnunet_plugin_transport_udp_init (void *cls)
   if (broadcast == GNUNET_SYSERR)
     broadcast = GNUNET_NO;
 
-  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-udp",
-                                           "BROADCAST_INTERVAL", &interval))
+  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp",
+                                           "BROADCAST_INTERVAL", &fancy_interval))
   {
     interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
   }
+  else
+  {
+     if (GNUNET_SYSERR == GNUNET_STRINGS_fancy_time_to_relative(fancy_interval, &interval))
+     {
+       interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
+     }
+     GNUNET_free (fancy_interval);
+  }
 
   /* Maximum datarate */
   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
@@ -2467,7 +2428,6 @@ libgnunet_plugin_transport_udp_done (void *cls)
   }
 
   stop_broadcast (plugin);
-
   if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
   {
     GNUNET_SCHEDULER_cancel (plugin->select_task);