-fix NPE
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index 2e7e2acfa6b0522d4ad27d583ffce782726ad2b0..af1b412c2987a754c4bfc03fad18f09bb33fedbe 100644 (file)
@@ -14,8 +14,8 @@
 
  You should have received a copy of the GNU General Public License
  along with GNUnet; see the file COPYING.  If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
  */
 
 /**
@@ -151,7 +151,7 @@ struct PrettyPrinterContext
 /**
  * Session with another peer.
  */
-struct Session
+struct GNUNET_ATS_Session
 {
   /**
    * Which peer is this session for?
@@ -174,9 +174,11 @@ struct Session
   struct GNUNET_TIME_Relative flow_delay_for_other_peer;
 
   /**
-   * Desired delay for next sending we received from other peer
+   * Desired delay for transmissions we received from other peer.
+   * Adjusted to be per fragment (UDP_MTU), even though on the
+   * wire it was for "full messages".
    */
-  struct GNUNET_TIME_Absolute flow_delay_from_other_peer;
+  struct GNUNET_TIME_Relative flow_delay_from_other_peer;
 
   /**
    * Session timeout task
@@ -188,6 +190,11 @@ struct Session
    */
   struct GNUNET_TIME_Absolute timeout;
 
+  /**
+   * What time did we last transmit?
+   */
+  struct GNUNET_TIME_Absolute last_transmit_time;
+
   /**
    * expected delay for ACKs
    */
@@ -317,7 +324,7 @@ struct UDP_FragmentationContext
   /**
    * The session this fragmentation context belongs to
    */
-  struct Session *session;
+  struct GNUNET_ATS_Session *session;
 
   /**
    * Function to call upon completion of the transmission.
@@ -329,6 +336,18 @@ struct UDP_FragmentationContext
    */
   void *cont_cls;
 
+  /**
+   * Start time.
+   */
+  struct GNUNET_TIME_Absolute start_time;
+
+  /**
+   * Transmission time for the next fragment.  Incremented by
+   * the "flow_delay_from_other_peer" for each fragment when
+   * we setup the fragments.
+   */
+  struct GNUNET_TIME_Absolute next_frag_time;
+
   /**
    * Message timeout
    */
@@ -371,7 +390,7 @@ struct UDP_MessageWrapper
   /**
    * Session this message belongs to
    */
-  struct Session *session;
+  struct GNUNET_ATS_Session *session;
 
   /**
    * DLL of messages, previous element
@@ -418,6 +437,17 @@ struct UDP_MessageWrapper
    */
   struct UDP_FragmentationContext *frag_ctx;
 
+  /**
+   * Message enqueue time.
+   */
+  struct GNUNET_TIME_Absolute start_time;
+
+  /**
+   * Desired transmission time for this message, based on the
+   * flow limiting information we got from the other peer.
+   */
+  struct GNUNET_TIME_Absolute transmission_time;
+
   /**
    * Message timeout.
    */
@@ -476,7 +506,7 @@ GNUNET_NETWORK_STRUCT_END
  */
 static void
 notify_session_monitor (struct Plugin *plugin,
-                        struct Session *session,
+                        struct GNUNET_ATS_Session *session,
                         enum GNUNET_TRANSPORT_SessionState state)
 {
   struct GNUNET_TRANSPORT_SessionInfo info;
@@ -508,7 +538,7 @@ notify_session_monitor (struct Plugin *plugin,
  *
  * @param cls the `struct Plugin` with the monitor callback (`sic`)
  * @param peer peer we send information about
- * @param value our `struct Session` to send information about
+ * @param value our `struct GNUNET_ATS_Session` to send information about
  * @return #GNUNET_OK (continue to iterate)
  */
 static int
@@ -517,7 +547,7 @@ send_session_info_iter (void *cls,
                         void *value)
 {
   struct Plugin *plugin = cls;
-  struct Session *session = value;
+  struct GNUNET_ATS_Session *session = value;
 
   notify_session_monitor (plugin,
                           session,
@@ -572,7 +602,7 @@ udp_plugin_setup_monitor (void *cls,
  * @param s session to free
  */
 static void
-free_session (struct Session *s)
+free_session (struct GNUNET_ATS_Session *s)
 {
   if (NULL != s->address)
   {
@@ -614,13 +644,73 @@ udp_query_keepalive_factor (void *cls)
  * @return the network type
  */
 static enum GNUNET_ATS_Network_Type
-udp_get_network (void *cls,
-                 struct Session *session)
+udp_plugin_get_network (void *cls,
+                        struct GNUNET_ATS_Session *session)
 {
   return session->scope;
 }
 
 
+/**
+ * Function obtain the network type for an address.
+ *
+ * @param cls closure (`struct Plugin *`)
+ * @param address the address
+ * @return the network type
+ */
+static enum GNUNET_ATS_Network_Type
+udp_plugin_get_network_for_address (void *cls,
+                                    const struct GNUNET_HELLO_Address *address)
+{
+  struct Plugin *plugin = cls;
+  size_t addrlen;
+  struct sockaddr_in a4;
+  struct sockaddr_in6 a6;
+  const struct IPv4UdpAddress *u4;
+  const struct IPv6UdpAddress *u6;
+  const void *sb;
+  size_t sbs;
+
+  addrlen = address->address_length;
+  if (addrlen == sizeof(struct IPv6UdpAddress))
+  {
+    GNUNET_assert (NULL != address->address); /* make static analysis happy */
+    u6 = address->address;
+    memset (&a6, 0, sizeof(a6));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    a6.sin6_len = sizeof (a6);
+#endif
+    a6.sin6_family = AF_INET6;
+    a6.sin6_port = u6->u6_port;
+    memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr));
+    sb = &a6;
+    sbs = sizeof(a6);
+  }
+  else if (addrlen == sizeof(struct IPv4UdpAddress))
+  {
+    GNUNET_assert (NULL != address->address); /* make static analysis happy */
+    u4 = address->address;
+    memset (&a4, 0, sizeof(a4));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    a4.sin_len = sizeof (a4);
+#endif
+    a4.sin_family = AF_INET;
+    a4.sin_port = u4->u4_port;
+    a4.sin_addr.s_addr = u4->ipv4_addr;
+    sb = &a4;
+    sbs = sizeof(a4);
+  }
+  else
+  {
+    GNUNET_break (0);
+    return GNUNET_ATS_NET_UNSPECIFIED;
+  }
+  return plugin->env->get_address_type (plugin->env->cls,
+                                        sb,
+                                        sbs);
+}
+
+
 /* ******************* Event loop ******************** */
 
 /**
@@ -668,9 +758,26 @@ schedule_select_v4 (struct Plugin *plugin)
     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));
+                                            GNUNET_TIME_absolute_get_remaining (udpw->transmission_time));
     if (NULL != plugin->select_task_v4)
       GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
+    if (NULL != plugin->ipv4_queue_head)
+    {
+      if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Calculated flow delay for UDPv4 at %s\n",
+                    GNUNET_STRINGS_relative_time_to_string (min_delay,
+                                                            GNUNET_YES));
+      }
+      else
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Calculated flow delay for UDPv4 at %s\n",
+                    GNUNET_STRINGS_relative_time_to_string (min_delay,
+                                                            GNUNET_YES));
+      }
+    }
     plugin->select_task_v4
       = GNUNET_SCHEDULER_add_read_net (min_delay,
                                        plugin->sockv4,
@@ -697,9 +804,26 @@ schedule_select_v6 (struct Plugin *plugin)
     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));
+                                            GNUNET_TIME_absolute_get_remaining (udpw->transmission_time));
     if (NULL != plugin->select_task_v6)
       GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
+    if (NULL != plugin->ipv6_queue_head)
+    {
+      if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Calculated flow delay for UDPv6 at %s\n",
+                    GNUNET_STRINGS_relative_time_to_string (min_delay,
+                                                            GNUNET_YES));
+      }
+      else
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Calculated flow delay for UDPv6 at %s\n",
+                    GNUNET_STRINGS_relative_time_to_string (min_delay,
+                                                            GNUNET_YES));
+      }
+    }
     plugin->select_task_v6
       = GNUNET_SCHEDULER_add_read_net (min_delay,
                                        plugin->sockv6,
@@ -1226,12 +1350,12 @@ udp_nat_port_map_callback (void *cls,
 /**
  * Closure for #session_cmp_it().
  */
-struct SessionCompareContext
+struct GNUNET_ATS_SessionCompareContext
 {
   /**
    * Set to session matching the address.
    */
-  struct Session *res;
+  struct GNUNET_ATS_Session *res;
 
   /**
    * Address we are looking for.
@@ -1243,9 +1367,9 @@ struct SessionCompareContext
 /**
  * Find a session with a matching address.
  *
- * @param cls the `struct SessionCompareContext *`
+ * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
  * @param key peer identity (unused)
- * @param value the `struct Session *`
+ * @param value the `struct GNUNET_ATS_Session *`
  * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
  */
 static int
@@ -1253,8 +1377,8 @@ session_cmp_it (void *cls,
                 const struct GNUNET_PeerIdentity *key,
                 void *value)
 {
-  struct SessionCompareContext *cctx = cls;
-  struct Session *s = value;
+  struct GNUNET_ATS_SessionCompareContext *cctx = cls;
+  struct GNUNET_ATS_Session *s = value;
 
   if (0 == GNUNET_HELLO_address_cmp (s->address,
                                      cctx->address))
@@ -1276,14 +1400,14 @@ session_cmp_it (void *cls,
  * @param address the address we should locate the session by
  * @return the session if it exists, or NULL if it is not found
  */
-static struct Session *
+static struct GNUNET_ATS_Session *
 udp_plugin_lookup_session (void *cls,
                            const struct GNUNET_HELLO_Address *address)
 {
   struct Plugin *plugin = cls;
   const struct IPv6UdpAddress *udp_a6;
   const struct IPv4UdpAddress *udp_a4;
-  struct SessionCompareContext cctx;
+  struct GNUNET_ATS_SessionCompareContext cctx;
 
   if (NULL == address->address)
   {
@@ -1349,7 +1473,7 @@ udp_plugin_lookup_session (void *cls,
  * @param s session to reschedule timeout activity for
  */
 static void
-reschedule_session_timeout (struct Session *s)
+reschedule_session_timeout (struct GNUNET_ATS_Session *s)
 {
   if (GNUNET_YES == s->in_destroy)
     return;
@@ -1371,7 +1495,7 @@ reschedule_session_timeout (struct Session *s)
 static void
 udp_plugin_update_session_timeout (void *cls,
                                    const struct GNUNET_PeerIdentity *peer,
-                                   struct Session *session)
+                                   struct GNUNET_ATS_Session *session)
 {
   struct Plugin *plugin = cls;
 
@@ -1402,7 +1526,7 @@ static void
 dequeue (struct Plugin *plugin,
          struct UDP_MessageWrapper *udpw)
 {
-  struct Session *session = udpw->session;
+  struct GNUNET_ATS_Session *session = udpw->session;
 
   if (plugin->bytes_in_buffer < udpw->msg_size)
   {
@@ -1454,7 +1578,7 @@ static void
 enqueue (struct Plugin *plugin,
          struct UDP_MessageWrapper *udpw)
 {
-  struct Session *session = udpw->session;
+  struct GNUNET_ATS_Session *session = udpw->session;
 
   if (GNUNET_YES == session->in_destroy)
   {
@@ -1520,10 +1644,11 @@ fragmented_message_done (struct UDP_FragmentationContext *frag_ctx,
                          int result)
 {
   struct Plugin *plugin = frag_ctx->plugin;
-  struct Session *s = frag_ctx->session;
+  struct GNUNET_ATS_Session *s = frag_ctx->session;
   struct UDP_MessageWrapper *udpw;
   struct UDP_MessageWrapper *tmp;
   size_t overhead;
+  struct GNUNET_TIME_Relative delay;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "%p: Fragmented message removed with result %s\n",
@@ -1534,6 +1659,22 @@ fragmented_message_done (struct UDP_FragmentationContext *frag_ctx,
     overhead = frag_ctx->on_wire_size - frag_ctx->payload_size;
   else
     overhead = frag_ctx->on_wire_size;
+  delay = GNUNET_TIME_absolute_get_duration (frag_ctx->start_time);
+  if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Fragmented message acknowledged after %s\n",
+                GNUNET_STRINGS_relative_time_to_string (delay,
+                                                        GNUNET_YES));
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Fragmented message acknowledged after %s\n",
+                GNUNET_STRINGS_relative_time_to_string (delay,
+                                                        GNUNET_YES));
+  }
+
   if (NULL != frag_ctx->cont)
     frag_ctx->cont (frag_ctx->cont_cls,
                     &s->target,
@@ -1693,7 +1834,7 @@ enqueue_fragment (void *cls,
   struct UDP_FragmentationContext *frag_ctx = cls;
   struct Plugin *plugin = frag_ctx->plugin;
   struct UDP_MessageWrapper *udpw;
-  struct Session *session = frag_ctx->session;
+  struct GNUNET_ATS_Session *session = frag_ctx->session;
   size_t msg_len = ntohs (msg->size);
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1705,6 +1846,11 @@ enqueue_fragment (void *cls,
   udpw->msg_size = msg_len;
   udpw->payload_size = msg_len; /* FIXME: minus fragment overhead */
   udpw->timeout = frag_ctx->timeout;
+  udpw->start_time = frag_ctx->start_time;
+  udpw->transmission_time = frag_ctx->next_frag_time;
+  frag_ctx->next_frag_time
+    = GNUNET_TIME_absolute_add (frag_ctx->next_frag_time,
+                                session->flow_delay_from_other_peer);
   udpw->frag_ctx = frag_ctx;
   udpw->qc = &qc_fragment_sent;
   udpw->qc_cls = plugin;
@@ -1735,6 +1881,7 @@ qc_message_sent (void *cls,
 {
   struct Plugin *plugin = cls;
   size_t overhead;
+  struct GNUNET_TIME_Relative delay;
 
   if (udpw->msg_size >= udpw->payload_size)
     overhead = udpw->msg_size - udpw->payload_size;
@@ -1742,11 +1889,28 @@ qc_message_sent (void *cls,
     overhead = udpw->msg_size;
 
   if (NULL != udpw->cont)
+  {
+    delay = GNUNET_TIME_absolute_get_duration (udpw->start_time);
+    if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Message sent via UDP with delay of %s\n",
+                  GNUNET_STRINGS_relative_time_to_string (delay,
+                                                          GNUNET_YES));
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Message sent via UDP with delay of %s\n",
+                  GNUNET_STRINGS_relative_time_to_string (delay,
+                                                          GNUNET_YES));
+    }
     udpw->cont (udpw->cont_cls,
                 &udpw->session->target,
                 result,
                 udpw->payload_size,
                 overhead);
+  }
   if (GNUNET_OK == result)
   {
     GNUNET_STATISTICS_update (plugin->env->stats,
@@ -1817,7 +1981,7 @@ qc_message_sent (void *cls,
  */
 static ssize_t
 udp_plugin_send (void *cls,
-                 struct Session *s,
+                 struct GNUNET_ATS_Session *s,
                  const char *msgbuf,
                  size_t msgbuf_size,
                  unsigned int priority,
@@ -1881,7 +2045,12 @@ udp_plugin_send (void *cls,
     udpw->msg_buf = (char *) &udpw[1];
     udpw->msg_size = udpmlen; /* message size with UDP overhead */
     udpw->payload_size = msgbuf_size; /* message size without UDP overhead */
+    udpw->start_time = GNUNET_TIME_absolute_get ();
     udpw->timeout = GNUNET_TIME_relative_to_absolute (to);
+    udpw->transmission_time = s->last_transmit_time;
+    s->last_transmit_time
+      = GNUNET_TIME_absolute_add (s->last_transmit_time,
+                                  s->flow_delay_from_other_peer);
     udpw->cont = cont;
     udpw->cont_cls = cont_cls;
     udpw->frag_ctx = NULL;
@@ -1901,7 +2070,7 @@ udp_plugin_send (void *cls,
                               GNUNET_NO);
     GNUNET_STATISTICS_update (plugin->env->stats,
                               "# UDP, unfragmented bytes payload queued total",
-                              udpw->payload_size,
+                              msgbuf_size,
                               GNUNET_NO);
   }
   else
@@ -1917,6 +2086,8 @@ udp_plugin_send (void *cls,
     frag_ctx->session = s;
     frag_ctx->cont = cont;
     frag_ctx->cont_cls = cont_cls;
+    frag_ctx->start_time = GNUNET_TIME_absolute_get ();
+    frag_ctx->next_frag_time = s->last_transmit_time;
     frag_ctx->timeout = GNUNET_TIME_relative_to_absolute (to);
     frag_ctx->payload_size = msgbuf_size; /* unfragmented message size without UDP overhead */
     frag_ctx->on_wire_size = 0; /* bytes with UDP and fragmentation overhead */
@@ -1929,6 +2100,7 @@ udp_plugin_send (void *cls,
                                                      &enqueue_fragment,
                                                      frag_ctx);
     s->frag_ctx = frag_ctx;
+    s->last_transmit_time = frag_ctx->next_frag_time;
     GNUNET_STATISTICS_update (plugin->env->stats,
                               "# UDP, fragmented messages active",
                               1,
@@ -1970,7 +2142,7 @@ read_process_ack (struct Plugin *plugin,
   const struct GNUNET_MessageHeader *ack;
   const struct UDP_ACK_Message *udp_ack;
   struct GNUNET_HELLO_Address *address;
-  struct Session *s;
+  struct GNUNET_ATS_Session *s;
   struct GNUNET_TIME_Relative flow_delay;
 
   if (ntohs (msg->size)
@@ -1980,6 +2152,12 @@ read_process_ack (struct Plugin *plugin,
     return;
   }
   udp_ack = (const struct UDP_ACK_Message *) msg;
+  ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
+  if (ntohs (ack->size) != ntohs (msg->size) - sizeof(struct UDP_ACK_Message))
+  {
+    GNUNET_break_op(0);
+    return;
+  }
   address = GNUNET_HELLO_address_allocate (&udp_ack->sender,
                                            PLUGIN_NAME,
                                            udp_addr,
@@ -1999,11 +2177,12 @@ read_process_ack (struct Plugin *plugin,
   }
   if (NULL == s->frag_ctx)
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
-         "Fragmentation context of address %s for ACK not found\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+         "Fragmentation context of address %s for ACK (%s) not found\n",
          udp_address_to_string (plugin,
                                 address->address,
-                                address->address_length));
+                                address->address_length),
+         GNUNET_FRAGMENT_print_ack (ack));
     GNUNET_HELLO_address_free (address);
     return;
   }
@@ -2015,14 +2194,13 @@ read_process_ack (struct Plugin *plugin,
        GNUNET_STRINGS_relative_time_to_string (flow_delay,
                                                GNUNET_YES),
        GNUNET_i2s (&udp_ack->sender));
-  s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute (flow_delay);
+  /* Flow delay is for the reassembled packet, however, our delay
+     is per packet, so we need to adjust: */
+  flow_delay = GNUNET_TIME_relative_divide (flow_delay,
+                                            1 + (s->frag_ctx->payload_size /
+                                                 UDP_MTU));
+  s->flow_delay_from_other_peer = flow_delay;
 
-  ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
-  if (ntohs (ack->size) != ntohs (msg->size) - sizeof(struct UDP_ACK_Message))
-  {
-    GNUNET_break_op(0);
-    return;
-  }
 
   if (GNUNET_OK !=
       GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag,
@@ -2068,7 +2246,7 @@ struct FindReceiveContext
   /**
    * Session associated with this context.
    */
-  struct Session *session;
+  struct GNUNET_ATS_Session *session;
 
   /**
    * Address to find.
@@ -2119,7 +2297,7 @@ find_receive_context (void *cls,
  * to the service.
  *
  * @param cls the `struct Plugin *`
- * @param client the `struct Session *`
+ * @param client the `struct GNUNET_ATS_Session *`
  * @param hdr the actual message
  * @return #GNUNET_OK (always)
  */
@@ -2129,7 +2307,7 @@ process_inbound_tokenized_messages (void *cls,
                                     const struct GNUNET_MessageHeader *hdr)
 {
   struct Plugin *plugin = cls;
-  struct Session *session = client;
+  struct GNUNET_ATS_Session *session = client;
 
   if (GNUNET_YES == session->in_destroy)
     return GNUNET_OK;
@@ -2153,7 +2331,7 @@ process_inbound_tokenized_messages (void *cls,
  */
 static int
 udp_disconnect_session (void *cls,
-                        struct Session *s)
+                        struct GNUNET_ATS_Session *s)
 {
   struct Plugin *plugin = cls;
   struct UDP_MessageWrapper *udpw;
@@ -2308,14 +2486,14 @@ udp_disconnect (void *cls,
 /**
  * Session was idle, so disconnect it.
  *
- * @param cls the `struct Session` to time out
+ * @param cls the `struct GNUNET_ATS_Session` to time out
  * @param tc scheduler context
  */
 static void
 session_timeout (void *cls,
                  const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct Session *s = cls;
+  struct GNUNET_ATS_Session *s = cls;
   struct Plugin *plugin = s->plugin;
   struct GNUNET_TIME_Relative left;
 
@@ -2355,22 +2533,23 @@ session_timeout (void *cls,
  * @param network_type network type the address belongs to
  * @return NULL on error, otherwise session handle
  */
-static struct Session *
+static struct GNUNET_ATS_Session *
 udp_plugin_create_session (void *cls,
                            const struct GNUNET_HELLO_Address *address,
                            enum GNUNET_ATS_Network_Type network_type)
 {
   struct Plugin *plugin = cls;
-  struct Session *s;
+  struct GNUNET_ATS_Session *s;
 
-  s = GNUNET_new (struct Session);
+  s = GNUNET_new (struct GNUNET_ATS_Session);
   s->plugin = plugin;
   s->address = GNUNET_HELLO_address_copy (address);
   s->target = address->peer;
+  s->last_transmit_time = GNUNET_TIME_absolute_get ();
   s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
                                                               250);
   s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
-  s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
+  s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
   s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
   s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
   s->timeout_task = GNUNET_SCHEDULER_add_delayed (UDP_SESSION_TIME_OUT,
@@ -2409,13 +2588,13 @@ udp_plugin_create_session (void *cls,
  * @param address the address
  * @return the session or NULL of max connections exceeded
  */
-static struct Session *
+static struct GNUNET_ATS_Session *
 udp_plugin_get_session (void *cls,
                         const struct GNUNET_HELLO_Address *address)
 {
   struct Plugin *plugin = cls;
-  struct Session *s;
-  enum GNUNET_ATS_Network_Type network_type;
+  struct GNUNET_ATS_Session *s;
+  enum GNUNET_ATS_Network_Type network_type = GNUNET_ATS_NET_UNSPECIFIED;
   const struct IPv4UdpAddress *udp_v4;
   const struct IPv6UdpAddress *udp_v6;
 
@@ -2490,7 +2669,7 @@ process_udp_message (struct Plugin *plugin,
                      size_t udp_addr_len,
                      enum GNUNET_ATS_Network_Type network_type)
 {
-  struct Session *s;
+  struct GNUNET_ATS_Session *s;
   struct GNUNET_HELLO_Address *address;
 
   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
@@ -2627,13 +2806,17 @@ ack_proc (void *cls,
   struct UDP_ACK_Message *udp_ack;
   uint32_t delay;
   struct UDP_MessageWrapper *udpw;
-  struct Session *s;
+  struct GNUNET_ATS_Session *s;
   struct GNUNET_HELLO_Address *address;
 
   if (GNUNET_NO == rc->have_sender)
   {
     /* tried to defragment but never succeeded, hence will not ACK */
-    GNUNET_break_op (0);
+    /* This can happen if we just lost msgs */
+    GNUNET_STATISTICS_update (plugin->env->stats,
+                              "# UDP, fragments discarded without ACK",
+                              1,
+                              GNUNET_NO);
     return;
   }
   address = GNUNET_HELLO_address_allocate (&rc->sender,
@@ -2664,7 +2847,6 @@ ack_proc (void *cls,
     delay = s->flow_delay_for_other_peer.rel_value_us;
   else
     delay = UINT32_MAX;
-
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending ACK to `%s' including delay of %s\n",
        udp_address_to_string (plugin,
@@ -2676,6 +2858,7 @@ ack_proc (void *cls,
   udpw->msg_size = msize;
   udpw->payload_size = 0;
   udpw->session = s;
+  udpw->start_time = GNUNET_TIME_absolute_get ();
   udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
   udpw->msg_buf = (char *) &udpw[1];
   udpw->qc = &ack_message_sent;
@@ -2850,6 +3033,13 @@ udp_select_read (struct Plugin *plugin,
     /* Connection failure or something. Not a protocol violation. */
     return;
   }
+
+  /* Check if this is a STUN packet */
+  if (GNUNET_NAT_is_valid_stun_packet (plugin->nat,
+                                       (uint8_t *)buf,
+                                       size))
+    return; /* was STUN, do not process further */
+
   if (size < sizeof(struct GNUNET_MessageHeader))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -2862,6 +3052,10 @@ udp_select_read (struct Plugin *plugin,
     GNUNET_break_op (0);
     return;
   }
+
+
+
+
   msg = (const struct GNUNET_MessageHeader *) buf;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "UDP received %u-byte message from `%s' type %u\n",
@@ -2967,7 +3161,7 @@ remove_timeout_messages_and_select (struct Plugin *plugin,
 {
   struct UDP_MessageWrapper *udpw;
   struct GNUNET_TIME_Relative remaining;
-  struct Session *session;
+  struct GNUNET_ATS_Session *session;
   int removed;
 
   removed = GNUNET_NO;
@@ -2982,13 +3176,12 @@ remove_timeout_messages_and_select (struct Plugin *plugin,
     if (GNUNET_TIME_UNIT_ZERO.rel_value_us == remaining.rel_value_us)
     {
       /* Message timed out */
-      udpw->qc (udpw->qc_cls,
-                udpw,
-                GNUNET_SYSERR);
-      /* Remove message */
       removed = GNUNET_YES;
       dequeue (plugin,
                udpw);
+      udpw->qc (udpw->qc_cls,
+                udpw,
+                GNUNET_SYSERR);
       GNUNET_free (udpw);
 
       if (sock == plugin->sockv4)
@@ -3011,8 +3204,8 @@ remove_timeout_messages_and_select (struct Plugin *plugin,
     }
     else
     {
-      /* Message did not time out, check flow delay */
-      remaining = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer);
+      /* Message did not time out, check transmission time */
+      remaining = GNUNET_TIME_absolute_get_remaining (udpw->transmission_time);
       if (0 == remaining.rel_value_us)
       {
         /* this message is not delayed */
@@ -3162,11 +3355,11 @@ udp_select_send (struct Plugin *plugin,
     else
     {
       GNUNET_break (0);
+      dequeue (plugin,
+               udpw);
       udpw->qc (udpw->qc_cls,
                 udpw,
                 GNUNET_SYSERR);
-      dequeue (plugin,
-               udpw);
       notify_session_monitor (plugin,
                               udpw->session,
                               GNUNET_TRANSPORT_SS_UPDATE);
@@ -3178,6 +3371,11 @@ udp_select_send (struct Plugin *plugin,
                                          udpw->msg_size,
                                          a,
                                          slen);
+    udpw->session->last_transmit_time
+      = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
+                                  udpw->session->last_transmit_time);
+    dequeue (plugin,
+             udpw);
     if (GNUNET_SYSERR == sent)
     {
       /* Failure */
@@ -3222,8 +3420,6 @@ udp_select_send (struct Plugin *plugin,
                 udpw,
                 GNUNET_OK);
     }
-    dequeue (plugin,
-             udpw);
     notify_session_monitor (plugin,
                             udpw->session,
                             GNUNET_TRANSPORT_SS_UPDATE);
@@ -3252,8 +3448,9 @@ udp_plugin_select_v4 (void *cls,
   plugin->select_task_v4 = NULL;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
+  if (NULL == plugin->sockv4)
+    return;
   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,
@@ -3281,12 +3478,14 @@ udp_plugin_select_v6 (void *cls,
   plugin->select_task_v6 = NULL;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
+  if (NULL == plugin->sockv6)
+    return;
   if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
-       (NULL != plugin->sockv6) &&
        (GNUNET_NETWORK_fdset_isset (tc->read_ready,
                                     plugin->sockv6)) )
     udp_select_read (plugin,
                      plugin->sockv6);
+
   udp_select_send (plugin,
                    plugin->sockv6);
   schedule_select_v6 (plugin);
@@ -3527,7 +3726,8 @@ setup_sockets (struct Plugin *plugin,
                                      addrlens,
                                      &udp_nat_port_map_callback,
                                      NULL,
-                                     plugin);
+                                     plugin,
+                                     plugin->sockv4);
   return sockets_created;
 }
 
@@ -3748,7 +3948,8 @@ 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;
+  api->get_network = &udp_plugin_get_network;
+  api->get_network_for_address = &udp_plugin_get_network_for_address;
   api->update_session_timeout = &udp_plugin_update_session_timeout;
   api->setup_monitor = &udp_plugin_setup_monitor;
   return api;
@@ -3871,6 +4072,11 @@ libgnunet_plugin_transport_udp_done (void *cls)
                                  plugin->ppc_dll_tail,
                                  cur);
     GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
+    if (NULL != cur->timeout_task)
+    {
+      GNUNET_SCHEDULER_cancel (cur->timeout_task);
+      cur->timeout_task = NULL;
+    }
     GNUNET_free (cur);
   }
   GNUNET_free (plugin);