bugfixes and redesigning scheduler API
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 3e696827f20c247338acfec2288fee427a8d35ca..efe53e0215388c90c214f377540e225ca77e5ed1 100644 (file)
 
 /**
  * How long until a HELLO verification attempt should time out?
+ * Must be rather small, otherwise a partially successful HELLO
+ * validation (some addresses working) might not be available
+ * before a client's request for a connection fails for good.
+ * Besides, if a single request to an address takes a long time,
+ * then the peer is unlikely worthwhile anyway.
  */
-#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
 
 /**
  * How often do we re-add (cheaper) plugins to our list of plugins
@@ -692,6 +697,11 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
       msize = ntohs (msg->size);
       if (msize + tsize > size)
         break;
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Transmitting message of type %u to client.\n",
+                 ntohs (msg->type));
+#endif
       client->message_queue_head = q->next;
       if (q->next == NULL)
         client->message_queue_tail = NULL;
@@ -700,9 +710,9 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
       GNUNET_free (q);
       client->message_count--;
     }
-  GNUNET_assert (tsize > 0);
   if (NULL != q)
     {
+      GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
       th = GNUNET_SERVER_notify_transmit_ready (client->client,
                                                 msize,
                                                 GNUNET_TIME_UNIT_FOREVER_REL,
@@ -743,6 +753,7 @@ transmit_to_client (struct TransportClient *client,
     }
   client->message_count++;
   msize = ntohs (msg->size);
+  GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
   memcpy (&q[1], msg, msize);
   /* append to message queue */
@@ -1207,9 +1218,6 @@ update_addresses (struct TransportPlugin *plugin, int fresh)
   if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
     plugin->address_update_task
       = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
-                                      GNUNET_NO,
-                                      GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                      GNUNET_SCHEDULER_NO_TASK,
                                       min_remaining,
                                       &expire_address_task, plugin);
 
@@ -1451,6 +1459,7 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct ValidationList *pos;
   struct ValidationList *prev;
   struct GNUNET_TIME_Absolute now;
+  struct GNUNET_TIME_Absolute first;
   struct GNUNET_HELLO_Message *hello;
   struct GNUNET_PeerIdentity pid;
   struct NeighbourList *n;
@@ -1506,16 +1515,19 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   /* finally, reschedule cleanup if needed; list is
      ordered by timeout, so we need the last element... */
-  pos = pending_validations;
-  while ((pos != NULL) && (pos->next != NULL))
-    pos = pos->next;
-  if (NULL != pos)
-    GNUNET_SCHEDULER_add_delayed (sched,
-                                  GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_TASK,
-                                  GNUNET_TIME_absolute_get_remaining
-                                  (pos->timeout), &cleanup_validation, NULL);
+  if (NULL != pending_validations)
+    {
+      first = pending_validations->timeout;
+      pos = pending_validations;
+      while (pos != NULL) 
+       {
+         first = GNUNET_TIME_absolute_min (first, pos->timeout);
+         pos = pos->next;
+       }
+      GNUNET_SCHEDULER_add_delayed (sched,
+                                   GNUNET_TIME_absolute_get_remaining (first),
+                                   &cleanup_validation, NULL);
+    }
 }
 
 
@@ -1543,7 +1555,7 @@ plugin_env_notify_validation (void *cls,
                              uint32_t challenge,
                              const char *sender_addr)
 {
-  int all_done;
+  unsigned int not_done;
   int matched;
   struct ValidationList *pos;
   struct ValidationAddress *va;
@@ -1570,7 +1582,7 @@ plugin_env_notify_validation (void *cls,
                  GNUNET_i2s(peer));
       return;
     }
-  all_done = GNUNET_YES;
+  not_done = 0;
   matched = GNUNET_NO;
   va = pos->addresses;
   while (va != NULL)
@@ -1579,7 +1591,10 @@ plugin_env_notify_validation (void *cls,
        {
 #if DEBUG_TRANSPORT
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Confirmed validity of peer address.\n");
+                     "Confirmed validity of address, peer `%4s' has address `%s'.\n",
+                     GNUNET_i2s (peer),
+                     GNUNET_a2s ((const struct sockaddr*) &va[1], 
+                                 va->addr_len));
 #endif
          GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
                      _("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
@@ -1591,7 +1606,7 @@ plugin_env_notify_validation (void *cls,
          matched = GNUNET_YES;
        }        
       if (va->ok != GNUNET_YES)
-        all_done = GNUNET_NO;
+        not_done++;
       va = va->next;
     }
   if (GNUNET_NO == matched)
@@ -1602,15 +1617,29 @@ plugin_env_notify_validation (void *cls,
                   ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
                   "PONG", "PING");
     }
-  if (GNUNET_YES == all_done)
+  if (0 == not_done)
     {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "All addresses validated, will now construct `%s' for `%4s'.\n",
+                 "HELLO",
+                 GNUNET_i2s (peer));
+#endif
       pos->timeout.value = 0;
-      GNUNET_SCHEDULER_add_delayed (sched,
-                                    GNUNET_NO,
-                                    GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                    GNUNET_SCHEDULER_NO_TASK,
-                                    GNUNET_TIME_UNIT_ZERO,
-                                    &cleanup_validation, NULL);
+      GNUNET_SCHEDULER_add_with_priority (sched,
+                                         GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                         &cleanup_validation, NULL);
+    }
+  else
+    {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
+                 not_done,
+                 "PONG",
+                 "HELLO",
+                 GNUNET_i2s (peer));
+#endif
     }
 }
 
@@ -1731,14 +1760,21 @@ check_hello_validated (void *cls,
   GNUNET_assert (GNUNET_OK ==
                 GNUNET_HELLO_get_id (chvc->hello,
                                      &apeer));
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Ready to validate addresses from `%s' message for peer `%4s'\n",
+             "HELLO", GNUNET_i2s (&apeer));
+#endif
   va = chvc->e->addresses;
   while (va != NULL)
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Establishing `%s' connection to validate `%s' of `%4s'\n",
+                  "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
                   va->transport_name,
                   "HELLO",
+                 GNUNET_a2s ((const struct sockaddr*) &va[1], 
+                             va->addr_len),
                  GNUNET_i2s (&apeer));
 #endif
       tp = find_transport (va->transport_name);
@@ -1753,14 +1789,9 @@ check_hello_validated (void *cls,
         va->ok = GNUNET_SYSERR;
       va = va->next;
     }
-  if (chvc->e->next == NULL)
-    GNUNET_SCHEDULER_add_delayed (sched,
-                                  GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_TASK,
-                                  GNUNET_TIME_absolute_get_remaining
-                                  (chvc->e->timeout), &cleanup_validation,
-                                  NULL);
+  GNUNET_SCHEDULER_add_delayed (sched,
+                               GNUNET_TIME_absolute_get_remaining (chvc->e->timeout), 
+                               &cleanup_validation, NULL);
   GNUNET_free (chvc);
 }
 
@@ -2005,9 +2036,6 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
   n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
   add_plugins (n);
   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                  GNUNET_NO,
-                                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                                  GNUNET_SCHEDULER_NO_TASK,
                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                   &neighbour_timeout_task, n);
   transmit_to_peer (NULL, 0,
@@ -2024,6 +2052,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
  * reducing the rate at which they read from the socket
  * and generally forward to our receive callback.
  *
+ * @param cls the "struct TransportPlugin *" we gave to the plugin
  * @param plugin_context value to pass to this plugin
  *        to respond to the given peer (use is optional,
  *        but may speed up processing)
@@ -2118,9 +2147,7 @@ plugin_env_receive (void *cls,
   n->peer_timeout =
     GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
   n->timeout_task =
-    GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_TASK,
+    GNUNET_SCHEDULER_add_delayed (sched, 
                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                   &neighbour_timeout_task, n);
   update_quota (n);
@@ -2178,7 +2205,8 @@ plugin_env_receive (void *cls,
         }
       GNUNET_free (im);
     }
-  GNUNET_assert (NULL != service_context->neighbour);
+  GNUNET_assert ( (service_context == NULL) ||
+                 (NULL != service_context->neighbour) );
   return service_context;
 }
 
@@ -2543,6 +2571,42 @@ client_disconnect_notification (void *cls,
 }
 
 
+/**
+ * Function called when the service shuts down.  Unloads our plugins.
+ *
+ * @param cls closure, unused
+ * @param tc task context (unused)
+ */
+static void
+unload_plugins (void *cls, 
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct TransportPlugin *plug;
+  struct AddressList *al;
+
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Transport service is unloading plugins...\n");
+#endif
+  while (NULL != (plug = plugins))
+    {
+      plugins = plug->next;
+      GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
+      GNUNET_free (plug->lib_name);
+      GNUNET_free (plug->short_name);
+      while (NULL != (al = plug->addresses))
+        {
+          plug->addresses = al->next;
+          GNUNET_free (al);
+        }
+      GNUNET_free (plug);
+    }
+  if (my_private_key != NULL)
+    GNUNET_CRYPTO_rsa_key_free (my_private_key);
+  GNUNET_free_non_null (our_hello);
+}
+
+
 /**
  * Initiate transport service.
  *
@@ -2617,6 +2681,9 @@ run (void *cls,
         }
       GNUNET_free (plugs);
     }
+  GNUNET_SCHEDULER_add_delayed (sched,
+                                GNUNET_TIME_UNIT_FOREVER_REL,
+                                &unload_plugins, NULL);
   if (no_transports)
     refresh_hello ();
 #if DEBUG_TRANSPORT
@@ -2628,43 +2695,6 @@ run (void *cls,
 }
 
 
-/**
- * Function called when the service shuts
- * down.  Unloads our plugins.
- *
- * @param cls closure
- * @param cfg configuration to use
- */
-static void
-unload_plugins (void *cls, 
-               const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct TransportPlugin *plug;
-  struct AddressList *al;
-
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transport service is unloading plugins...\n");
-#endif
-  while (NULL != (plug = plugins))
-    {
-      plugins = plug->next;
-      GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
-      GNUNET_free (plug->lib_name);
-      GNUNET_free (plug->short_name);
-      while (NULL != (al = plug->addresses))
-        {
-          plug->addresses = al->next;
-          GNUNET_free (al);
-        }
-      GNUNET_free (plug);
-    }
-  if (my_private_key != NULL)
-    GNUNET_CRYPTO_rsa_key_free (my_private_key);
-  GNUNET_free_non_null (our_hello);
-}
-
-
 /**
  * The main function for the transport service.
  *
@@ -2679,7 +2709,7 @@ main (int argc, char *const *argv)
          GNUNET_SERVICE_run (argc,
                              argv,
                              "transport",
-                             &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
+                             &run, NULL)) ? 0 : 1;
 }
 
 /* end of gnunet-service-transport.c */