trying to fix #4003
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index c5542d200835a95d4084b98ba06903e361a2d4d5..ca5166600807bd841e1a0cee902636d25fbcbdc3 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.
  */
 
 /**
@@ -614,13 +614,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 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 ******************** */
 
 /**
@@ -1456,6 +1516,11 @@ enqueue (struct Plugin *plugin,
 {
   struct Session *session = udpw->session;
 
+  if (GNUNET_YES == session->in_destroy)
+  {
+    GNUNET_break (0);
+    return;
+  }
   if (plugin->bytes_in_buffer + udpw->msg_size > INT64_MAX)
   {
     GNUNET_break (0);
@@ -1896,7 +1961,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
@@ -1975,6 +2040,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,
@@ -1994,11 +2065,12 @@ read_process_ack (struct Plugin *plugin,
   }
   if (NULL == s->frag_ctx)
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "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;
   }
@@ -2012,12 +2084,6 @@ read_process_ack (struct Plugin *plugin,
        GNUNET_i2s (&udp_ack->sender));
   s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute (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,
@@ -2174,7 +2240,10 @@ udp_disconnect_session (void *cls,
     fragmented_message_done (s->frag_ctx,
                              GNUNET_SYSERR);
   }
-
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
+                                                       &s->target,
+                                                       s));
   frc.rc = NULL;
   frc.udp_addr = s->address->address;
   frc.udp_addr_len = s->address->address_length;
@@ -2193,6 +2262,7 @@ udp_disconnect_session (void *cls,
       GNUNET_free (d_ctx);
     }
   }
+  s->in_destroy = GNUNET_YES;
   next = plugin->ipv4_queue_head;
   while (NULL != (udpw = next))
   {
@@ -2221,13 +2291,6 @@ udp_disconnect_session (void *cls,
       GNUNET_free (udpw);
     }
   }
-  notify_session_monitor (s->plugin,
-                          s,
-                          GNUNET_TRANSPORT_SS_DONE);
-  plugin->env->session_end (plugin->env->cls,
-                            s->address,
-                            s);
-
   if ( (NULL != s->frag_ctx) &&
        (NULL != s->frag_ctx->cont) )
   {
@@ -2242,23 +2305,18 @@ udp_disconnect_session (void *cls,
                        s->frag_ctx->payload_size,
                        s->frag_ctx->on_wire_size);
   }
-
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
-                                                       &s->target,
-                                                       s));
+  notify_session_monitor (s->plugin,
+                          s,
+                          GNUNET_TRANSPORT_SS_DONE);
+  plugin->env->session_end (plugin->env->cls,
+                            s->address,
+                            s);
   GNUNET_STATISTICS_set (plugin->env->stats,
                          "# UDP sessions active",
                          GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
                          GNUNET_NO);
-  if (s->rc > 0)
-  {
-    s->in_destroy = GNUNET_YES;
-  }
-  else
-  {
+  if (0 == s->rc)
     free_session (s);
-  }
   return GNUNET_OK;
 }
 
@@ -2418,7 +2476,7 @@ udp_plugin_get_session (void *cls,
 {
   struct Plugin *plugin = cls;
   struct Session *s;
-  enum GNUNET_ATS_Network_Type network_type;
+  enum GNUNET_ATS_Network_Type network_type = GNUNET_ATS_NET_UNSPECIFIED;
   const struct IPv4UdpAddress *udp_v4;
   const struct IPv6UdpAddress *udp_v6;
 
@@ -2636,7 +2694,11 @@ ack_proc (void *cls,
   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,
@@ -2667,7 +2729,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,
@@ -2853,6 +2914,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,
@@ -2865,6 +2933,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",
@@ -2985,13 +3057,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)
@@ -3165,11 +3236,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);
@@ -3181,6 +3252,8 @@ udp_select_send (struct Plugin *plugin,
                                          udpw->msg_size,
                                          a,
                                          slen);
+    dequeue (plugin,
+             udpw);
     if (GNUNET_SYSERR == sent)
     {
       /* Failure */
@@ -3225,8 +3298,6 @@ udp_select_send (struct Plugin *plugin,
                 udpw,
                 GNUNET_OK);
     }
-    dequeue (plugin,
-             udpw);
     notify_session_monitor (plugin,
                             udpw->session,
                             GNUNET_TRANSPORT_SS_UPDATE);
@@ -3255,8 +3326,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,
@@ -3284,12 +3356,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);
@@ -3530,7 +3604,8 @@ setup_sockets (struct Plugin *plugin,
                                      addrlens,
                                      &udp_nat_port_map_callback,
                                      NULL,
-                                     plugin);
+                                     plugin,
+                                     plugin->sockv4);
   return sockets_created;
 }
 
@@ -3751,7 +3826,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;
@@ -3874,6 +3950,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);