-trying to fix #2391: limit connect rate from topology
authorChristian Grothoff <christian@grothoff.org>
Fri, 1 Jun 2012 11:34:21 +0000 (11:34 +0000)
committerChristian Grothoff <christian@grothoff.org>
Fri, 1 Jun 2012 11:34:21 +0000 (11:34 +0000)
src/topology/gnunet-daemon-topology.c

index a9dbd3573bd2a03997f05a52071918ad74031127..15ca9f87b48e7631e86d5d62b03d47f130a05ef9 100644 (file)
 #include "gnunet_util_lib.h"
 
 
+/**
+ * Minimum required delay between calls to GNUNET_TRANSPORT_try_connect.
+ */
+#define MAX_CONNECT_FREQUENCY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
+
 /**
  * For how long do we blacklist a peer after a failed connection
  * attempt?  This is the baseline factor which is then multiplied by
@@ -121,6 +126,11 @@ struct Peer
    */
   GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
 
+  /**
+   * Task for issuing GNUNET_TRANSPORT_try_connect for this peer.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task;
+
   /**
    * ID of task we use to clear peers from the greylist.
    */
@@ -187,6 +197,11 @@ static struct GNUNET_STATISTICS_Handle *stats;
  */
 static struct GNUNET_TRANSPORT_Blacklist *blacklist;
 
+/**
+ * When can we next ask transport to create a connection?
+ */
+static struct GNUNET_TIME_Absolute next_connect_attempt;
+
 /**
  * Task scheduled to try to add peers.
  */
@@ -312,6 +327,8 @@ free_peer (void *cls, const GNUNET_HashCode * pid, void *value)
     GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
   if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
+  if (pos->attempt_connect_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
   if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
   GNUNET_free_non_null (pos->hello);
@@ -378,6 +395,50 @@ attempt_connect (struct Peer *pos)
 }
 
 
+/**
+ * Try to connect to the specified peer.
+ *
+ * @param pos peer to connect to
+ */
+static void
+do_attempt_connect (void *cls,
+                   const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Peer *pos = cls;
+  struct GNUNET_TIME_Relative delay;
+
+  pos->attempt_connect_task = GNUNET_SCHEDULER_NO_TASK;
+  if (GNUNET_YES == pos->is_connected)
+    return;
+  delay = GNUNET_TIME_absolute_get_remaining (next_connect_attempt);
+  if (delay.rel_value > 0)
+  {
+    pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (delay,
+                                                             &do_attempt_connect,
+                                                             pos);
+    return;
+  }
+  next_connect_attempt = GNUNET_TIME_relative_to_absolute (MAX_CONNECT_FREQUENCY_DELAY);
+  attempt_connect (pos);
+}
+
+
+/**
+ * Schedule a task to try to connect to the specified peer.
+ *
+ * @param pos peer to connect to
+ */
+static void
+schedule_attempt_connect (struct Peer *pos)
+{
+  if (GNUNET_SCHEDULER_NO_TASK != pos->attempt_connect_task)
+    return;
+  pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_connect_attempt),
+                                                           &do_attempt_connect,
+                                                           pos);
+}
+
+
 /**
  * Discard peer entries for greylisted peers
  * where the greylisting has expired.
@@ -395,7 +456,7 @@ remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until);
   if (rem.rel_value == 0)
   {
-    attempt_connect (pos);
+    schedule_attempt_connect (pos);
   }
   else
   {
@@ -685,7 +746,7 @@ try_add_peers (void *cls, const GNUNET_HashCode * pid, void *value)
 {
   struct Peer *pos = value;
 
-  attempt_connect (pos);
+  schedule_attempt_connect (pos);
   return GNUNET_YES;
 }
 
@@ -705,6 +766,7 @@ add_peer_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_CONTAINER_multihashmap_iterate (peers, &try_add_peers, NULL);
 }
 
+
 /**
  * Method called whenever a peer disconnects.
  *
@@ -910,7 +972,7 @@ process_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s'\n",
               GNUNET_i2s (peer));
-  attempt_connect (pos);
+  schedule_attempt_connect (pos);
 }