Browse Source

Preserve bridge download status across SETCONF, HUP

This code changes it so that we don't remove bridges immediately when
we start re-parsing our configuration.  Instead, we mark them all, and
remove all the marked ones after re-parsing our bridge lines.  As we
add a bridge, we see if it's already in the list.  If so, we just
unmark it.

This new behavior will lose the property we used to have that bridges
were in bridge_list in the same order in which they appeared in the
torrc.  I took a quick look through the code, and I'm pretty sure we
didn't actually depend on that anywhere.

This is for bug 3019; it's a fix on 0.2.0.3-alpha.
Nick Mathewson 13 years ago
parent
commit
2b9c5ee301
4 changed files with 61 additions and 12 deletions
  1. 4 0
      changes/bug3019
  2. 50 7
      src/or/circuitbuild.c
  3. 5 4
      src/or/circuitbuild.h
  4. 2 1
      src/or/config.c

+ 4 - 0
changes/bug3019

@@ -0,0 +1,4 @@
+  o Minor bugfixes:
+    - Do not reset the bridge descriptor download status every time we
+      re-parse our configuration or get a configuration change.  Fixes
+      bug 3019; bugfix on Tor 0.2.0.3-alpha.

+ 50 - 7
src/or/circuitbuild.c

@@ -4471,6 +4471,9 @@ typedef struct {
   tor_addr_t addr;
   /** TLS port for the bridge. */
   uint16_t port;
+  /** Boolean: We are re-parsing our bridge list, and we are going to remove
+   * this one if we don't find it in the list of configured bridges. */
+  unsigned marked_for_removal : 1;
   /** Expected identity digest, or all zero bytes if we don't know what the
    * digest should be. */
   char identity[DIGEST_LEN];
@@ -4479,11 +4482,39 @@ typedef struct {
 } bridge_info_t;
 
 /** A list of configured bridges. Whenever we actually get a descriptor
- * for one, we add it as an entry guard. */
+ * for one, we add it as an entry guard.  Note that the order of bridges
+ * in this list does not necessarily correspond to the order of bridges
+ * in the torrc. */
 static smartlist_t *bridge_list = NULL;
 
-/** Initialize the bridge list to empty, creating it if needed. */
+/** Mark every entry of the bridge list to be removed on our next call to
+ * sweep_bridge_list unless it has first been un-marked. */
+void
+mark_bridge_list(void)
+{
+  if (!bridge_list)
+    bridge_list = smartlist_create();
+  SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
+                    b->marked_for_removal = 1);
+}
+
+/** Remove every entry of the bridge list that was marked with
+ * mark_bridge_list if it has not subsequently been un-marked. */
 void
+sweep_bridge_list(void)
+{
+  if (!bridge_list)
+    bridge_list = smartlist_create();
+  SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
+    if (b->marked_for_removal) {
+      SMARTLIST_DEL_CURRENT(bridge_list, b);
+      tor_free(b);
+    }
+  } SMARTLIST_FOREACH_END(b);
+}
+
+/** Initialize the bridge list to empty, creating it if needed. */
+static void
 clear_bridge_list(void)
 {
   if (!bridge_list)
@@ -4496,7 +4527,8 @@ clear_bridge_list(void)
  * (either by comparing keys if possible, else by comparing addr/port).
  * Else return NULL. */
 static bridge_info_t *
-get_configured_bridge_by_addr_port_digest(tor_addr_t *addr, uint16_t port,
+get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
+                                          uint16_t port,
                                           const char *digest)
 {
   if (!bridge_list)
@@ -4537,7 +4569,8 @@ routerinfo_is_a_configured_bridge(routerinfo_t *ri)
  * If it was a bridge, and we still don't know its digest, record it.
  */
 void
-learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest)
+learned_router_identity(const tor_addr_t *addr, uint16_t port,
+                        const char *digest)
 {
   bridge_info_t *bridge =
     get_configured_bridge_by_addr_port_digest(addr, port, digest);
@@ -4549,11 +4582,20 @@ learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest)
 }
 
 /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
- * is set, it tells us the identity key too. */
+ * is set, it tells us the identity key too.  If we already had the
+ * bridge in our list, unmark it, and don't actually add anything new. */
 void
-bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest)
+bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+                       const char *digest)
 {
-  bridge_info_t *b = tor_malloc_zero(sizeof(bridge_info_t));
+  bridge_info_t *b;
+
+  if ((b = get_configured_bridge_by_addr_port_digest(addr, port, digest))) {
+    b->marked_for_removal = 0;
+    return;
+  }
+
+  b = tor_malloc_zero(sizeof(bridge_info_t));
   tor_addr_copy(&b->addr, addr);
   b->port = port;
   if (digest)
@@ -4561,6 +4603,7 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest)
   b->fetch_status.schedule = DL_SCHED_BRIDGE;
   if (!bridge_list)
     bridge_list = smartlist_create();
+
   smartlist_add(bridge_list, b);
 }
 

+ 5 - 4
src/or/circuitbuild.h

@@ -62,12 +62,13 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
                                 const char *question, char **answer,
                                 const char **errmsg);
 
-void clear_bridge_list(void);
+void mark_bridge_list(void);
+void sweep_bridge_list(void);
 int routerinfo_is_a_configured_bridge(routerinfo_t *ri);
-void
-learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest);
+void learned_router_identity(const tor_addr_t *addr, uint16_t port,
+                             const char *digest);
 void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
-                            char *digest);
+                            const char *digest);
 void retry_bridge_descriptor_fetch_directly(const char *digest);
 void fetch_bridge_descriptors(or_options_t *options, time_t now);
 void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);

+ 2 - 1
src/or/config.c

@@ -1172,7 +1172,7 @@ options_act(or_options_t *old_options)
     return -1;
 
   if (options->Bridges) {
-    clear_bridge_list();
+    mark_bridge_list();
     for (cl = options->Bridges; cl; cl = cl->next) {
       if (parse_bridge_line(cl->value, 0)<0) {
         log_warn(LD_BUG,
@@ -1180,6 +1180,7 @@ options_act(or_options_t *old_options)
         return -1;
       }
     }
+    sweep_bridge_list();
   }
 
   if (running_tor && rend_config_services(options, 0)<0) {