-makefile for new test_stream_local (commented)
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
index 181817602941a4876ff2e7348ece775f6f802924..9b8fafe33230c1ac6e33875c9d8e8228da024c92 100644 (file)
@@ -59,6 +59,8 @@
 
 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 
+#define FAST_RECONNECT_RATE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
+
 #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 
 #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
@@ -264,6 +266,12 @@ struct NeighbourMapEntry
    */
   struct GNUNET_HELLO_Address *address;
 
+  /**
+   * Address we currently use.
+   */
+  struct GNUNET_HELLO_Address *fast_reconnect_address;
+
+
   /**
    * Identity of this neighbour.
    */
@@ -322,6 +330,11 @@ struct NeighbourMapEntry
    */
   GNUNET_SCHEDULER_TaskIdentifier ats_suggest;
 
+  /**
+   * Delay for ATS request
+   */
+  GNUNET_SCHEDULER_TaskIdentifier ats_request;
+
   /**
    * Task the resets the peer state after due to an pending
    * unsuccessful connection setup
@@ -347,7 +360,16 @@ struct NeighbourMapEntry
    * Did we sent an KEEP_ALIVE message and are we expecting a response?
    */
   int expect_latency_response;
+
+  /**
+   * Was the address used successfully
+   */
   int address_state;
+
+  /**
+   * Fast reconnect attempts for identical address
+   */
+  unsigned int fast_reconnect_attempts;
 };
 
 
@@ -499,7 +521,6 @@ reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
               GNUNET_i2s (&n->id), n, print_state(n->state), "S_NOT_CONNECTED", __LINE__);
 
   n->state = S_NOT_CONNECTED;
-  GNUNET_break (0);
 
   /* destroying address */
   if (n->address != NULL)
@@ -922,7 +943,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
     GNUNET_assert (NULL != n->address);
     if (n->address_state == USED)
     {
-      GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+      GST_validation_set_address_use (n->address, n->session, GNUNET_NO, __LINE__);
       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
       n->address_state = UNUSED;
     }
@@ -982,6 +1003,12 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
     GNUNET_SCHEDULER_cancel (n->ats_suggest);
     n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
   }
+  if (n->ats_request != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (n->ats_request);
+    n->ats_request = GNUNET_SCHEDULER_NO_TASK;
+  }
+
   if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
   {
     GNUNET_SCHEDULER_cancel (n->timeout_task);
@@ -992,6 +1019,11 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
     GNUNET_SCHEDULER_cancel (n->transmission_task);
     n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
   }
+  if (NULL != n->fast_reconnect_address)
+  {
+    GNUNET_HELLO_address_free (n->fast_reconnect_address);
+    n->fast_reconnect_address = NULL;
+  }
   if (NULL != n->address)
   {
     GNUNET_HELLO_address_free (n->address);
@@ -1017,6 +1049,8 @@ neighbour_timeout_task (void *cls,
   struct NeighbourMapEntry *n = cls;
 
   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer`%4s' disconnected due to timeout\n",
+              GNUNET_i2s (&n->id));
 
   GNUNET_STATISTICS_update (GST_stats,
                             gettext_noop
@@ -1100,10 +1134,14 @@ ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "ATS did not suggested address to connect to peer `%s'\n",
               GNUNET_i2s (&n->id));
 
+  GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# ATS address suggestions failed"), 1,
+                            GNUNET_NO);
+
+
   disconnect_neighbour (n);
 }
 
@@ -1213,6 +1251,18 @@ send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
 }
 
 
+static void
+ats_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct NeighbourMapEntry *n = cls;
+  n->ats_request = GNUNET_SCHEDULER_NO_TASK;
+
+  n->ats_suggest =
+    GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
+                                  n);
+}
+
+
 /**
  * We tried to switch addresses with an peer already connected. If it failed,
  * we should tell ATS to not use this address anymore (until it is re-validated).
@@ -1247,20 +1297,42 @@ send_switch_address_continuation (void *cls,
   GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT));
   if (GNUNET_YES != success)
   {
-#if DEBUG_TRANSPORT
+
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Failed to switch connected peer `%s' to address '%s' session %X, asking ATS for new address \n",
-                GNUNET_i2s (&n->id), GST_plugins_a2s (cc->address), cc->session);
-#endif
+                "Failed to switch connected peer `%s' in state %s to address '%s' session %X, asking ATS for new address \n",
+                GNUNET_i2s (&n->id), print_state(n->state), GST_plugins_a2s (cc->address), cc->session);
+
     GNUNET_assert (strlen (cc->address->transport_name) > 0);
     GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
 
     if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+    {
       GNUNET_SCHEDULER_cancel (n->ats_suggest);
-    n->ats_suggest =
+      n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
+    }
+
+    if (n->state == S_FAST_RECONNECT)
+    {
+      if (GNUNET_SCHEDULER_NO_TASK == n->ats_request)
+      {
+        /* Throtteled ATS request for fast reconnect */
+        struct GNUNET_TIME_Relative delay = GNUNET_TIME_relative_multiply(FAST_RECONNECT_RATE, n->fast_reconnect_attempts);
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Fast reconnect attempt %u failed, delay ATS request for %llu ms\n", n->fast_reconnect_attempts, delay.rel_value);
+        n->ats_request =
+            GNUNET_SCHEDULER_add_delayed (delay,
+                                          ats_request,
+                                          n);
+      }
+    }
+    else
+    {
+      /* Immediate ATS request for connected peers */
+      n->ats_suggest =
         GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
                                       n);
-    GNUNET_ATS_suggest_address (GST_ats, &n->id);
+      GNUNET_ATS_suggest_address (GST_ats, &n->id);
+    }
     GNUNET_HELLO_address_free (cc->address);
     GNUNET_free (cc);
     return;
@@ -1271,7 +1343,7 @@ send_switch_address_continuation (void *cls,
   case S_CONNECTED:
     if (n->address_state == FRESH)
     {
-      GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES);
+      GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES,  __LINE__);
       GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
       if (cc->session != n->session)
         GNUNET_break (0);
@@ -1292,7 +1364,7 @@ send_switch_address_continuation (void *cls,
 
     if (n->address_state == FRESH)
     {
-      GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES);
+      GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES,  __LINE__);
       GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
       GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
       n->address_state = USED;
@@ -1444,18 +1516,32 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     GNUNET_SCHEDULER_cancel (n->ats_suggest);
     n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
   }
-  /* do not switch addresses just update quotas */
-/*
+
+
   if (n->state == S_FAST_RECONNECT)
   {
-    if (0 == GNUNET_HELLO_address_cmp(address, n->address))
+    /* Throtteled fast reconnect */
+
+    if (NULL == n->fast_reconnect_address)
+    {
+      n->fast_reconnect_address = GNUNET_HELLO_address_copy (address);
+
+    }
+    else if (0 == GNUNET_HELLO_address_cmp(address, n->fast_reconnect_address))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "FAST RECONNECT to peer `%s' and  address '%s' with identical ADDRESS\n",
-                  GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
+      n->fast_reconnect_attempts ++;
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "FAST RECONNECT to peer `%s' and address '%s' with identical address attempt %u\n",
+                GNUNET_i2s (&n->id), GST_plugins_a2s (address), n->fast_reconnect_attempts);
     }
   }
-*/
+  else
+  {
+    n->fast_reconnect_attempts = 0;
+  }
+
+  /* do not switch addresses just update quotas */
   if ((n->state == S_CONNECTED) && (NULL != n->address) &&
       (0 == GNUNET_HELLO_address_cmp (address, n->address)) &&
       (n->session == session))
@@ -1472,7 +1558,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     GNUNET_assert (NULL != n->address);
     if (n->address_state == USED)
     {
-      GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+      GST_validation_set_address_use (n->address, n->session, GNUNET_NO,  __LINE__);
       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
       n->address_state = UNUSED;
     }
@@ -1496,7 +1582,24 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
   /* Obtain an session for this address from plugin */
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
   papi = GST_plugins_find (address->transport_name);
-  GNUNET_assert (papi != NULL);
+
+  if (papi == NULL)
+  {
+    /* we don't have the plugin for this address */
+    GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
+
+    if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+      GNUNET_SCHEDULER_cancel (n->ats_suggest);
+    n->ats_suggest =  GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
+                                      ats_suggest_cancel,
+                                      n);
+    GNUNET_ATS_suggest_address (GST_ats, &n->id);
+    GNUNET_HELLO_address_free (n->address);
+    n->address = NULL;
+    n->session = NULL;
+    return GNUNET_NO;
+  }
+
   if (session == NULL)
   {
     n->session = papi->get_session (papi->cls, address);
@@ -1786,9 +1889,10 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
   {
     if (n->address_state == USED)
     {
-      GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+      GST_validation_set_address_use (n->address, n->session, GNUNET_NO,  __LINE__);
       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
       n->address_state = UNUSED;
+
     }
   }
 
@@ -2453,7 +2557,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
 
   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
   {
-    GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
+    GST_validation_set_address_use (n->address, n->session, GNUNET_YES,  __LINE__);
     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
     n->address_state = USED;
   }
@@ -2540,7 +2644,7 @@ GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
 
   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
   {
-    GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
+    GST_validation_set_address_use (n->address, n->session, GNUNET_YES,  __LINE__);
     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
     n->address_state = USED;
   }