[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r10867: timeout and retry schedules for fetching bridge descriptors (in tor/trunk: doc src/or)



Author: arma
Date: 2007-07-18 06:06:03 -0400 (Wed, 18 Jul 2007)
New Revision: 10867

Modified:
   tor/trunk/doc/TODO
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerlist.c
Log:
timeout and retry schedules for fetching bridge descriptors


Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-07-18 09:23:23 UTC (rev 10866)
+++ tor/trunk/doc/TODO	2007-07-18 10:06:03 UTC (rev 10867)
@@ -238,7 +238,7 @@
           manually listed in the torrc.
           D and some mechanism for specifying that we want to stop using
             a given bridge in this cache.
-      - timeout and retry schedules for fetching bridge descriptors
+      o timeout and retry schedules for fetching bridge descriptors
       - give extend_info_t a router_purpose again
       o react faster to download networkstatuses after the first bridge
         descriptor arrives
@@ -247,7 +247,7 @@
     - Bridges operators (rudimentary version)
       - Ability to act as dir cache without a dir port.
       o Bridges publish to bridge authorities
-      - Fix BEGIN_DIR so that you connect to bridge of which you only
+      o Fix BEGIN_DIR so that you connect to bridge of which you only
         know IP (and optionally fingerprint), and then use BEGIN_DIR to learn
         more about it.
       - look at server_mode() and decide if it always applies to bridges too.

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2007-07-18 09:23:23 UTC (rev 10866)
+++ tor/trunk/src/or/circuitbuild.c	2007-07-18 10:06:03 UTC (rev 10867)
@@ -2668,6 +2668,7 @@
   uint32_t addr;
   uint16_t port;
   char identity[DIGEST_LEN];
+  download_status_t fetch_status;
 } bridge_info_t;
 
 /** A list of known bridges. */
@@ -2697,23 +2698,30 @@
 }
 #endif
 
-/** Return 1 if <b>ri</b> is one of our known bridges (either by
- * comparing keys if possible, else by comparing addr/port). */
-int
-routerinfo_is_a_bridge(routerinfo_t *ri)
+/** Return a bridge pointer if <b>ri</b> is one of our known bridges
+ * (either by comparing keys if possible, else by comparing addr/port).
+ * Else return NULL. */
+static bridge_info_t *
+routerinfo_get_configured_bridge(routerinfo_t *ri)
 {
   SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
     {
       if (tor_digest_is_zero(bridge->identity) &&
           bridge->addr == ri->addr && bridge->port == ri->or_port)
-        return 1;
+        return bridge;
       if (!memcmp(bridge->identity, ri->cache_info.identity_digest,
                   DIGEST_LEN))
-        return 1;
+        return bridge;
     });
-  return 0;
+  return NULL;
 }
 
+int
+routerinfo_is_a_configured_bridge(routerinfo_t *ri)
+{
+  return routerinfo_get_configured_bridge(ri) ? 1 : 0;
+}
+
 /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
  * is set, it tells us the identity key too. */
 void
@@ -2729,11 +2737,34 @@
   smartlist_add(bridge_list, b);
 }
 
+/** Schedule the next fetch for <b>bridge</b>, based on
+ * some retry schedule. */
+static void
+bridge_fetch_status_increment(bridge_info_t *bridge, time_t now)
+{
+  switch (bridge->fetch_status.n_download_failures) {
+    case 0: bridge->fetch_status.next_attempt_at = now+60*15; break;
+    case 1: bridge->fetch_status.next_attempt_at = now+60*15; break;
+    default: bridge->fetch_status.next_attempt_at = now+60*60; break;
+  }
+  if (bridge->fetch_status.n_download_failures < 10)
+    bridge->fetch_status.n_download_failures++;
+}
+
+/** We just got a new descriptor for <b>bridge</b>. Reschedule the
+ * next fetch for a long time from <b>now</b>. */
+static void
+bridge_fetch_status_arrived(bridge_info_t *bridge, time_t now)
+{
+  bridge->fetch_status.next_attempt_at = now+60*60;
+  bridge->fetch_status.n_download_failures = 0;
+}
+
 /** For each bridge in our list for which we don't currently have a
  * descriptor, fetch a new copy of its descriptor -- either directly
  * from the bridge or via a bridge authority. */
 void
-fetch_bridge_descriptors(void)
+fetch_bridge_descriptors(time_t now)
 {
   char address_buf[INET_NTOA_BUF_LEN+1];
   struct in_addr in;
@@ -2746,8 +2777,12 @@
 
   SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
     {
-      if (router_get_by_digest(bridge->identity))
-        continue; /* we've already got one. great. */
+      if (bridge->fetch_status.next_attempt_at >= now)
+        continue; /* don't bother, no need to retry yet */
+
+     /* schedule another fetch as if this one failed, in case it does */
+      bridge_fetch_status_increment(bridge, now);
+
       in.s_addr = htonl(bridge->addr);
       tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
 
@@ -2792,16 +2827,22 @@
   tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
   if (get_options()->UseBridges) {
     int first = !any_bridge_descriptors_known();
+    bridge_info_t *bridge = routerinfo_get_configured_bridge(ri);
+    time_t now = time(NULL);
     ri->is_running = 1;
+
+    /* it's here; schedule its re-fetch for a long time from now. */
+    bridge_fetch_status_arrived(bridge, now);
+
     add_an_entry_guard(ri, 1);
     log_notice(LD_DIR, "new bridge descriptor '%s'", ri->nickname);
     if (first)
-      routerlist_retry_directory_downloads(time(NULL));
+      routerlist_retry_directory_downloads(now);
   }
 }
 
 /** Return 1 if any of our entry guards have descriptors that
- * are marked with purpose 'bridge'. Else return 0.
+ * are marked with purpose 'bridge' and are running. Else return 0.
  *
  * We use this function to decide if we're ready to start building
  * circuits through our bridges, or if we need to wait until the
@@ -2810,19 +2851,30 @@
 any_bridge_descriptors_known(void)
 {
   return choose_random_entry(NULL)!=NULL ? 1 : 0;
+}
+
 #if 0
+/** Return 1 if we have at least one descriptor for a bridge and
+ * all descriptors we know are down. Else return 0. */
+int
+all_bridges_down(void)
+{
   routerinfo_t *ri;
+  int any_known = 0;
   if (!entry_guards)
     entry_guards = smartlist_create();
   SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
     {
       ri = router_get_by_digest(e->identity);
-      if (ri && ri->purpose == ROUTER_PURPOSE_BRIDGE)
-        return 1;
+      if (ri && ri->purpose == ROUTER_PURPOSE_BRIDGE) {
+        any_known = 1;
+        if (ri->is_running)
+          return 0; /* some bridge is both known and running */
+      }
     });
-  return 0;
+  return any_known;
+}
 #endif
-}
 
 /** Release all storage held by the list of entry guards and related
  * memory structs. */

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2007-07-18 09:23:23 UTC (rev 10866)
+++ tor/trunk/src/or/main.c	2007-07-18 10:06:03 UTC (rev 10867)
@@ -881,16 +881,16 @@
 
   if (time_to_try_getting_descriptors < now) {
     /* XXXX  Maybe we should do this every 10sec when not enough info,
-     * and every 60sec when we have enough info -NM */
+     * and every 60sec when we have enough info -NM Great idea -RD */
     update_router_descriptor_downloads(now);
     update_extrainfo_downloads(now);
+    if (options->UseBridges)
+      fetch_bridge_descriptors(now);
     time_to_try_getting_descriptors = now + DESCRIPTOR_RETRY_INTERVAL;
   }
 
   if (time_to_reset_descriptor_failures < now) {
     router_reset_descriptor_download_failures();
-    if (options->UseBridges)
-      fetch_bridge_descriptors(); /* XXX get this its own retry schedule -RD */
     time_to_reset_descriptor_failures =
       now + DESCRIPTOR_FAILURE_RESET_INTERVAL;
   }

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-07-18 09:23:23 UTC (rev 10866)
+++ tor/trunk/src/or/or.h	2007-07-18 10:06:03 UTC (rev 10867)
@@ -2231,15 +2231,16 @@
 void entry_guards_update_state(or_state_t *state);
 int getinfo_helper_entry_guards(control_connection_t *conn,
                                 const char *question, char **answer);
-void entry_guards_free_all(void);
 
 void clear_bridge_list(void);
-int routerinfo_is_a_bridge(routerinfo_t *ri);
+int routerinfo_is_a_configured_bridge(routerinfo_t *ri);
 void bridge_add_from_config(uint32_t addr, uint16_t port, char *digest);
-void fetch_bridge_descriptors(void);
+void fetch_bridge_descriptors(time_t now);
 void learned_bridge_descriptor(routerinfo_t *ri);
 int any_bridge_descriptors_known(void);
 
+void entry_guards_free_all(void);
+
 /********************************* circuitlist.c ***********************/
 
 circuit_t * _circuit_get_global_list(void);

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2007-07-18 09:23:23 UTC (rev 10866)
+++ tor/trunk/src/or/routerlist.c	2007-07-18 10:06:03 UTC (rev 10867)
@@ -2413,7 +2413,7 @@
      * we are receiving in response to a fetch. */
 
     if (!signed_desc_digest_is_recognized(&router->cache_info) &&
-        !routerinfo_is_a_bridge(router)) {
+        !routerinfo_is_a_configured_bridge(router)) {
       /* We asked for it, so some networkstatus must have listed it when we
        * did.  Save it if we're a cache in case somebody else asks for it. */
       log_info(LD_DIR,