ソースを参照

r15049@catbus: nickm | 2007-09-11 16:05:50 -0400
When we get a consensus for which we are missing the right certificates, keep it around pending more certificates; do not just drop it.


svn:r11430

Nick Mathewson 18 年 前
コミット
e73fb2f102
4 ファイル変更95 行追加19 行削除
  1. 3 3
      doc/TODO
  2. 5 3
      src/or/dirvote.c
  3. 2 1
      src/or/or.h
  4. 85 12
      src/or/routerlist.c

+ 3 - 3
doc/TODO

@@ -53,12 +53,12 @@ Things we'd like to do in 0.2.0.x:
           o Download as needed.
             o Code to download
             . Code to retry download.
-        . Code to generate consensus from a list of votes
-          * Detect whether votes are really all for the same period.
+        o Code to generate consensus from a list of votes
+          o Detect whether votes are really all for the same period.
         . Push/pull documents as appropriate.
           - Pull votes and signatures if we don't get them.
         - Cache votes and signatures on disk.
-          - Code to keep consensus docs in limbo if they don't have
+          o Code to keep consensus docs in limbo if they don't have
             have enough signatures.
         o Have clients know which authorities are v3 authorities, and what
           their keys are.

+ 5 - 3
src/or/dirvote.c

@@ -735,7 +735,7 @@ networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
 /** Given a v3 networkstatus consensus in <b>consensus</b>, check every
  * as-yet-unchecked signature on <b>consensus.  Return 0 if there are enough
  * good signatures from recognized authorities on it, and -1 otherwise.
- * DOCDOC warn. */
+ * DOCDOC warn. DOCDOC -2 rerturn. */
 int
 networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
                                         int warn)
@@ -832,8 +832,10 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
 
   if (n_good >= n_required)
     return 0;
-  else
+  else if (n_good + n_missing_key >= n_required)
     return -1;
+  else
+    return -2;
 }
 
 /** Given a consensus vote <b>target</b> and a list of
@@ -1681,7 +1683,7 @@ dirvote_publish_consensus(void)
     return -1;
   }
 
-  if (networkstatus_set_current_consensus(pending_consensus_body, 0))
+  if (networkstatus_set_current_consensus(pending_consensus_body, 0, 0))
     log_warn(LD_DIR, "Error publishing consensus");
   else
     log_warn(LD_DIR, "Consensus published.");

+ 2 - 1
src/or/or.h

@@ -3550,7 +3550,8 @@ local_routerstatus_t *router_get_combined_status_by_descriptor_digest(
 int router_reload_consensus_networkstatus(void);
 networkstatus_vote_t *networkstatus_get_latest_consensus(void);
 networkstatus_vote_t *networkstatus_get_live_consensus(time_t now);
-int networkstatus_set_current_consensus(const char *consensus, int from_cache);
+int networkstatus_set_current_consensus(const char *consensus, int from_cache,
+                                        int was_waiting_for_certs);
 
 //routerstatus_t *routerstatus_get_by_hexdigest(const char *hexdigest);
 int should_delay_dir_fetches(or_options_t *options);

+ 85 - 12
src/or/routerlist.c

@@ -65,9 +65,14 @@ static routerlist_t *routerlist = NULL;
  * about.  This list is kept sorted by published_on. */
 static smartlist_t *networkstatus_list = NULL;
 
-/** Most recently received v3 consensus network status. */
+/** Most recently received and validated v3 consensus network status. */
 static networkstatus_vote_t *current_consensus = NULL;
 
+/** A v3 consensus networkstatus that we've received, but which we don't
+ * have enough certificates to be happy about. */
+static networkstatus_vote_t *consensus_waiting_for_certs = NULL;
+static char *consensus_waiting_for_certs_body = NULL;
+
 /** Global list of local_routerstatus_t for each router, known or unknown.
  * Kept sorted by digest. */
 static smartlist_t *routerstatus_list = NULL;
@@ -184,14 +189,26 @@ router_reload_consensus_networkstatus(void)
   tor_snprintf(filename,sizeof(filename),"%s"PATH_SEPARATOR"cached-consensus",
                get_options()->DataDirectory);
   s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
-  if (!s)
-    return 0;
+  if (s) {
+    if (networkstatus_set_current_consensus(s, 1, 0)) {
+      log_warn(LD_FS, "Couldn't load consensus networkstatus from \"%s\"",
+               filename);
+    }
+    tor_free(s);
+  }
 
-  if (networkstatus_set_current_consensus(s, 1)) {
-    log_warn(LD_FS, "Couldn't load consensus networkstatus from \"%s\"",
-             filename);
+  tor_snprintf(filename,sizeof(filename),
+               "%s"PATH_SEPARATOR"unverified-consensus",
+               get_options()->DataDirectory);
+  s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
+  if (s) {
+    if (networkstatus_set_current_consensus(s, 1, 1)) {
+      log_warn(LD_FS, "Couldn't load consensus networkstatus from \"%s\"",
+               filename);
+    }
+    tor_free(s);
   }
-  tor_free(s);
+
   return 0;
 }
 
@@ -266,6 +283,16 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store)
 
   trusted_dirs_flush_certs_to_disk();
 
+  if (consensus_waiting_for_certs) {
+    if (!networkstatus_check_consensus_signature(
+                                    consensus_waiting_for_certs, 0)) {
+      if (!networkstatus_set_current_consensus(
+                                 consensus_waiting_for_certs_body, 0, 1)) {
+        tor_free(consensus_waiting_for_certs_body);
+      }
+    }
+  }
+
   return 0;
 }
 
@@ -2501,6 +2528,15 @@ routerlist_free_all(void)
   if (named_server_map) {
     strmap_free(named_server_map, _tor_free);
   }
+  if (current_consensus) {
+    networkstatus_vote_free(current_consensus);
+    current_consensus = NULL;
+  }
+  if (consensus_waiting_for_certs) {
+    networkstatus_vote_free(current_consensus);
+    current_consensus = NULL;
+  }
+  tor_free(consensus_waiting_for_certs_body);
 }
 
 /** Free all storage held by the routerstatus object <b>rs</b>. */
@@ -4027,9 +4063,11 @@ networkstatus_get_live_consensus(time_t now)
 
 /** DOCDOC */
 int
-networkstatus_set_current_consensus(const char *consensus, int from_cache)
+networkstatus_set_current_consensus(const char *consensus, int from_cache,
+                                    int was_waiting_for_certs)
 {
   networkstatus_vote_t *c;
+  int r;
   /* Make sure it's parseable. */
   c = networkstatus_parse_vote_from_string(consensus, 0);
   if (!c) {
@@ -4038,15 +4076,50 @@ networkstatus_set_current_consensus(const char *consensus, int from_cache)
   }
 
   /* Make sure it's signed enough. */
-  if (networkstatus_check_consensus_signature(c, 1)<0) {
-    log_warn(LD_DIR, "Not enough good signatures on networkstatus consensus");
-    networkstatus_vote_free(c);
-    return -1;
+  if ((r=networkstatus_check_consensus_signature(c, 1))<0) {
+    if (r == -1 && !was_waiting_for_certs) {
+      /* Okay, so it _might_ be signed enough if we get more certificates. */
+      if (!was_waiting_for_certs)
+        log_notice(LD_DIR, "Not enough certificates to check networkstatus "
+                   "consensus");
+      if (!current_consensus ||
+          c->valid_after > current_consensus->valid_after) {
+        if (consensus_waiting_for_certs)
+          networkstatus_vote_free(consensus_waiting_for_certs);
+        tor_free(consensus_waiting_for_certs_body);
+        consensus_waiting_for_certs = c;
+        consensus_waiting_for_certs_body = tor_strdup(consensus);
+        if (!from_cache) {
+          or_options_t *options = get_options();
+          char filename[512];
+          tor_snprintf(filename, sizeof(filename),
+                       "%s"PATH_SEPARATOR"unverified-consensus",
+                       options->DataDirectory);
+          write_str_to_file(filename, consensus, 0);
+        }
+        /* XXXX020 trigger the certificate download. */
+      }
+      return -1;
+    } else {
+      if (!was_waiting_for_certs)
+        log_warn(LD_DIR, "Not enough good signatures on networkstatus "
+                 "consensus");
+      networkstatus_vote_free(c);
+      return -1;
+    }
   }
 
   if (current_consensus)
     networkstatus_vote_free(current_consensus);
 
+  if (consensus_waiting_for_certs &&
+      consensus_waiting_for_certs->valid_after <= c->valid_after) {
+    networkstatus_vote_free(consensus_waiting_for_certs);
+    consensus_waiting_for_certs = NULL;
+    if (consensus != consensus_waiting_for_certs_body)
+      tor_free(consensus_waiting_for_certs_body);
+  }
+
   current_consensus = c;
 
   if (!from_cache) {