[or-cvs] r11575: V3 authority work: fetch missing votes and/or signatures as (in tor/trunk: . doc src/or)

nickm at seul.org nickm at seul.org
Sat Sep 22 06:06:06 UTC 2007


Author: nickm
Date: 2007-09-22 02:06:05 -0400 (Sat, 22 Sep 2007)
New Revision: 11575

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/dirvote.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerlist.c
   tor/trunk/src/or/routerparse.c
   tor/trunk/src/or/test.c
Log:
 r15279 at catbus:  nickm | 2007-09-22 02:00:06 -0400
 V3 authority work: fetch missing votes and/or signatures as needed.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r15279] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/ChangeLog	2007-09-22 06:06:05 UTC (rev 11575)
@@ -1,3 +1,8 @@
+Changes in version 0.2.0.8-alpha - 2007-??-??
+  o Major features (directory authorities):
+    - When an authority is missing votes or signatures, it now tries to fetch
+      them.
+
 Changes in version 0.2.0.7-alpha - 2007-09-21
   o New directory authorities:
     - Set up moria1 and tor26 as the first v3 directory authorities. See

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/doc/TODO	2007-09-22 06:06:05 UTC (rev 11575)
@@ -59,8 +59,8 @@
             . Code to retry download.
         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.
+        o Push/pull documents as appropriate.
+          o Pull votes and signatures if we don't get them.
         - Cache votes and signatures on disk?
           o Code to keep consensus docs in limbo if they don't have
             have enough signatures.

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/directory.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -297,6 +297,8 @@
       break;
     case DIR_PURPOSE_FETCH_STATUS_VOTE:
     case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
+      type = V3_AUTHORITY;
+      break;
     case DIR_PURPOSE_FETCH_CONSENSUS:
     case DIR_PURPOSE_FETCH_CERTIFICATE:
       type = V3_AUTHORITY;
@@ -377,6 +379,32 @@
   }
 }
 
+/** As directory_get_from_dirserver, but initiates a request to <i>every</i>
+ * directory authority other than ourself.  Only for use by authorities when
+ * searching for missing information while voting. */
+void
+directory_get_from_all_authorities(uint8_t dir_purpose,
+                                   uint8_t router_purpose,
+                                   const char *resource)
+{
+  tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
+             dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
+
+  SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
+                    trusted_dir_server_t *, ds,
+    {
+      routerstatus_t *rs;
+      if (router_digest_is_me(ds->digest))
+        continue;
+      if (!(ds->type & V3_AUTHORITY))
+        continue;
+      rs = &ds->fake_status.status;
+      /* XXXX020 should this ever tunnel via tor? */
+      directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
+                                              0, resource, NULL, 0);
+    });
+}
+
 /** Launch a new connection to the directory server <b>status</b> to
  * upload or download a server or rendezvous
  * descriptor. <b>dir_purpose</b> determines what
@@ -727,7 +755,7 @@
       httpcommand = "GET";
       len = strlen(resource)+32;
       url = tor_malloc(len);
-      tor_snprintf(url, len, "/tor/status-vote/next/%s", resource);
+      tor_snprintf(url, len, "/tor/status-vote/next/%s.z", resource);
       break;
     case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
       tor_assert(!resource);
@@ -1318,7 +1346,7 @@
     /*XXXX020*/;
   }
   if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
-    log_info(LD_DIR,"Received aurhority certificatess (size %d) from server "
+    log_info(LD_DIR,"Received authority certificatess (size %d) from server "
              "'%s:%d'",(int) body_len, conn->_base.address, conn->_base.port);
     if (status_code != 200) {
       log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
@@ -1336,10 +1364,38 @@
     }
   }
   if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
-    /*XXXX020*/;
+    const char *msg;
+    int st;
+    log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
+             (int) body_len, conn->_base.address, conn->_base.port);
+    if (status_code != 200) {
+      log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
+             "Received http status code %d (%s) from server "
+             "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
+             status_code, escaped(reason), conn->_base.address,
+             conn->_base.port, conn->requested_resource);
+      tor_free(body); tor_free(headers); tor_free(reason);
+      return -1;
+    }
+    if (!dirvote_add_vote(body, &msg, &st)) {
+      log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
+    } else {
+      log_info(LD_DIR, "Added vote(s) successfully.");
+    }
   }
   if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
-    /*XXXX020*/;
+    log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
+             (int) body_len, conn->_base.address, conn->_base.port);
+    if (status_code != 200) {
+      log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
+        "Received http status code %d (%s) from server "
+        "'%s:%d' while fetching \"/tor/status-vote/consensus-signatures.z\".",
+             status_code, escaped(reason), conn->_base.address,
+             conn->_base.port);
+      tor_free(body); tor_free(headers); tor_free(reason);
+      return -1;
+    }
+    dirvote_add_signatures(body);
   }
 
   if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/dirserv.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -2198,7 +2198,7 @@
 
   {
     networkstatus_vote_t *v;
-    if (!(v = networkstatus_parse_vote_from_string(status, 1))) {
+    if (!(v = networkstatus_parse_vote_from_string(status, NULL, 1))) {
       log_err(LD_BUG,"Generated a networkstatus vote we couldn't parse: "
               "<<%s>>", status);
       goto err;

Modified: tor/trunk/src/or/dirvote.c
===================================================================
--- tor/trunk/src/or/dirvote.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/dirvote.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -17,7 +17,11 @@
                        const char *detached_signatures_body,
                        const char **msg_out);
 static char *list_v3_auth_ids(void);
+static void dirvote_fetch_missing_votes(void);
+static void dirvote_fetch_missing_signatures(void);
 
+/* XXXX020 lots of the functions here could be made static. Do so. */
+
 /* =====
  * Voting and consensus generation
  * ===== */
@@ -641,7 +645,7 @@
 
   {
     networkstatus_vote_t *c;
-    if (!(c = networkstatus_parse_vote_from_string(result, 0))) {
+    if (!(c = networkstatus_parse_vote_from_string(result, NULL, 0))) {
       log_err(LD_BUG,"Generated a networkstatus consensus we couldn't "
               "parse.");
       tor_free(result);
@@ -686,7 +690,8 @@
 }
 
 /** Given a v3 networkstatus consensus in <b>consensus</b>, check every
- * as-yet-unchecked signature on <b>consensus</b>.  Return 0 if there are
+ * as-yet-unchecked signature on <b>consensus</b>.  Return 1 if there is a
+ * signature from every recognized authority on it, 0 if there are
  * enough good signatures from recognized authorities on it, -1 if we might
  * get enough good signatures by fetching missing certificates, and -2
  * otherwise.  Log messages at INFO or WARN: if <b>warn</b> is over 1, warn
@@ -701,7 +706,8 @@
   int n_bad = 0;
   int n_unknown = 0;
   int n_no_signature = 0;
-  int n_required = get_n_authorities(V3_AUTHORITY)/2 + 1;
+  int n_v3_authorities = get_n_authorities(V3_AUTHORITY);
+  int n_required = n_v3_authorities/2 + 1;
   smartlist_t *need_certs_from = smartlist_create();
   smartlist_t *unrecognized = smartlist_create();
   smartlist_t *missing_authorities = smartlist_create();
@@ -786,7 +792,9 @@
   smartlist_free(need_certs_from);
   smartlist_free(missing_authorities);
 
-  if (n_good >= n_required)
+  if (n_good == n_v3_authorities)
+    return 1;
+  else if (n_good >= n_required)
     return 0;
   else if (n_good + n_missing_key >= n_required)
     return -1;
@@ -1076,11 +1084,15 @@
 
   /* True iff we have generated and distributed our vote. */
   int have_voted;
+  /* DOCDOC */
+  int have_fetched_missing_votes;
   /* True iff we have built a consensus and sent the signatures around. */
   int have_built_consensus;
+  /* DOCDOC */
+  int have_fetched_missing_signatures;
   /* True iff we have published our consensus. */
   int have_published_consensus;
-} voting_schedule = {0,0,0,0,0,0,0,0,0};
+} voting_schedule = {0,0,0,0,0,0,0,0,0,0,0};
 
 /** Set voting_schedule to hold the timing for the next vote we should be
  * doing. */
@@ -1143,7 +1155,12 @@
     dirvote_perform_vote();
     voting_schedule.have_voted = 1;
   }
-  /* XXXX020 after a couple minutes here, start trying to fetch votes. */
+  if (voting_schedule.fetch_missing_votes < now &&
+      !voting_schedule.have_fetched_missing_votes) {
+    log_notice(LD_DIR, "Time to fetch any votes that we're missing.");
+    dirvote_fetch_missing_votes();
+    voting_schedule.have_fetched_missing_votes = 1;
+  }
   if (voting_schedule.voting_ends < now &&
       !voting_schedule.have_built_consensus) {
     log_notice(LD_DIR, "Time to compute a consensus.");
@@ -1152,6 +1169,12 @@
      * votes yet. */
     voting_schedule.have_built_consensus = 1;
   }
+  if (voting_schedule.fetch_missing_signatures < now &&
+      !voting_schedule.have_fetched_missing_signatures) {
+    log_notice(LD_DIR, "Time to fetch any signatures that we're missing.");
+    dirvote_fetch_missing_signatures();
+    voting_schedule.have_fetched_missing_signatures = 1;
+  }
   if (voting_schedule.interval_starts < now &&
       !voting_schedule.have_published_consensus) {
     log_notice(LD_DIR, "Time to publish the consensus.");
@@ -1216,6 +1239,53 @@
   log_notice(LD_DIR, "Vote posted.");
 }
 
+/** DOCDOC */
+static void
+dirvote_fetch_missing_votes(void)
+{
+  smartlist_t *missing_fps = smartlist_create();
+  char *resource;
+
+  SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
+                    trusted_dir_server_t *, ds,
+    {
+      if ((ds->type & V3_AUTHORITY))
+        continue;
+      if (!dirvote_get_vote(ds->v3_identity_digest)) {
+        char *cp = tor_malloc(HEX_DIGEST_LEN+1);
+        base16_encode(cp, HEX_DIGEST_LEN+1, ds->v3_identity_digest,
+                      DIGEST_LEN);
+        smartlist_add(missing_fps, cp);
+      }
+    });
+
+  if (!smartlist_len(missing_fps)) {
+    smartlist_free(missing_fps);
+    return;
+  }
+  log_notice(LOG_NOTICE, "We're missing votes from %d authorities. Asking "
+             "every other authority for a copy.", smartlist_len(missing_fps));
+  resource = smartlist_join_strings(missing_fps, "+", 0, NULL);
+  directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE,
+                                     0, resource);
+  tor_free(resource);
+  SMARTLIST_FOREACH(missing_fps, char *, cp, tor_free(cp));
+  smartlist_free(missing_fps);
+}
+
+/** DOCDOC */
+static void
+dirvote_fetch_missing_signatures(void)
+{
+  if (!pending_consensus)
+    return;
+  if (networkstatus_check_consensus_signature(pending_consensus, -1) == 1)
+    return; /* we have a signature from everybody. */
+
+  directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES,
+                                     0, NULL);
+}
+
 /** Drop all currently pending votes, consensus, and detached signatures. */
 void
 dirvote_clear_pending_votes(void)
@@ -1271,6 +1341,8 @@
   networkstatus_voter_info_t *vi;
   trusted_dir_server_t *ds;
   pending_vote_t *pending_vote = NULL;
+  const char *end_of_vote = NULL;
+  int any_failed = 0;
   tor_assert(vote_body);
   tor_assert(msg_out);
   tor_assert(status_out);
@@ -1280,7 +1352,8 @@
     pending_vote_list = smartlist_create();
   *msg_out = NULL;
 
-  vote = networkstatus_parse_vote_from_string(vote_body, 1);
+ again:
+  vote = networkstatus_parse_vote_from_string(vote_body, &end_of_vote, 1);
   if (!vote) {
     *msg_out = "Unable to parse vote";
     goto err;
@@ -1325,7 +1398,7 @@
     goto err;
   }
 
-  /* Now see whether we already have a vote from this authority.*/
+  /* Now see whether we already h<ave a vote from this authority.*/
   SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
       if (! memcmp(v->vote->cert->cache_info.identity_digest,
                    vote->cert->cache_info.identity_digest,
@@ -1359,17 +1432,29 @@
                                            vote->published);
   pending_vote->vote = vote;
   smartlist_add(pending_vote_list, pending_vote);
+
+  if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version "))
+    goto again;
+
+  if (any_failed)
+    goto err;
+
   if (!*status_out)
     *status_out = 200;
   *msg_out = "ok";
+
   return pending_vote;
  err:
+  any_failed = 1;
   if (vote)
     networkstatus_vote_free(vote);
   if (!*msg_out)
     *msg_out = "Error adding vote";
   if (!*status_out)
     *status_out = 400;
+
+  if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version "))
+    goto again;
   return NULL;
 }
 
@@ -1414,7 +1499,7 @@
     log_warn(LD_DIR, "Couldn't generate a consensus at all!");
     goto err;
   }
-  consensus = networkstatus_parse_vote_from_string(consensus_body, 0);
+  consensus = networkstatus_parse_vote_from_string(consensus_body, NULL, 0);
   if (!consensus) {
     log_warn(LD_DIR, "Couldn't parse consensus we generated!");
     goto err;
@@ -1526,7 +1611,7 @@
       ns_detached_signatures_t *sigs =
         networkstatus_parse_detached_signatures(new_detached, NULL);
       networkstatus_vote_t *v = networkstatus_parse_vote_from_string(
-                                                 pending_consensus_body, 0);
+                                             pending_consensus_body, NULL, 0);
       tor_assert(sigs);
       ns_detached_signatures_free(sigs);
       tor_assert(v);

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/or.h	2007-09-22 06:06:05 UTC (rev 11575)
@@ -2769,6 +2769,9 @@
 void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
                                   const char *resource,
                                   int retry_if_no_servers);
+void directory_get_from_all_authorities(uint8_t dir_purpose,
+                                        uint8_t router_purpose,
+                                        const char *resource);
 void directory_initiate_command_routerstatus(routerstatus_t *status,
                                              uint8_t dir_purpose,
                                              uint8_t router_purpose,
@@ -3662,7 +3665,8 @@
 
 networkstatus_t *networkstatus_parse_from_string(const char *s);
 networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
-                                                           int is_vote);
+                                                          const char **eos_out,
+                                                          int is_vote);
 ns_detached_signatures_t *networkstatus_parse_detached_signatures(
                                           const char *s, const char *eos);
 

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/routerlist.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -284,8 +284,8 @@
   trusted_dirs_flush_certs_to_disk();
 
   if (consensus_waiting_for_certs) {
-    if (!networkstatus_check_consensus_signature(
-                                    consensus_waiting_for_certs, 0)) {
+    if (networkstatus_check_consensus_signature(
+                                    consensus_waiting_for_certs, 0)<0) {
       if (!networkstatus_set_current_consensus(
                                  consensus_waiting_for_certs_body, 0, 1)) {
         tor_free(consensus_waiting_for_certs_body);
@@ -4081,7 +4081,7 @@
   networkstatus_vote_t *c;
   int r;
   /* Make sure it's parseable. */
-  c = networkstatus_parse_vote_from_string(consensus, 0);
+  c = networkstatus_parse_vote_from_string(consensus, NULL, 0);
   if (!c) {
     log_warn(LD_DIR, "Unable to parse networkstatus consensus");
     return -1;

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/routerparse.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -1790,7 +1790,8 @@
  * networkstatus consensus (if <b>is_vote</b> is false) from <b>s</b>, and
  * return the result.  Return NULL on failure. */
 networkstatus_vote_t *
-networkstatus_parse_vote_from_string(const char *s, int is_vote)
+networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
+                                     int is_vote)
 {
   smartlist_t *tokens = smartlist_create();
   smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
@@ -2026,7 +2027,10 @@
 
   /* Parse footer; check signature. */
   footer_tokens = smartlist_create();
-  end_of_footer = s + strlen(s);
+  if ((end_of_footer = strstr(s, "\nnetwork-status-version ")))
+    ++end_of_footer;
+  else
+    end_of_footer = s + strlen(s);
   if (tokenize_string(s, end_of_footer, footer_tokens,
                       networkstatus_vote_footer_token_table)) {
     log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
@@ -2092,6 +2096,9 @@
 
   /* XXXX020 check dates for plausibility.  ??? */
 
+  if (eos_out)
+    *eos_out = end_of_footer;
+
   goto done;
  err:
   if (ns)

Modified: tor/trunk/src/or/test.c
===================================================================
--- tor/trunk/src/or/test.c	2007-09-22 05:46:51 UTC (rev 11574)
+++ tor/trunk/src/or/test.c	2007-09-22 06:06:05 UTC (rev 11575)
@@ -2520,7 +2520,7 @@
   /* dump the vote and try to parse it. */
   v1_text = format_networkstatus_vote(sign_skey_1, vote);
   test_assert(v1_text);
-  v1 = networkstatus_parse_vote_from_string(v1_text, 1);
+  v1 = networkstatus_parse_vote_from_string(v1_text, NULL, 1);
   test_assert(v1);
 
   /* Make sure the parsed thing was right. */
@@ -2604,7 +2604,7 @@
   /* generate and parse. */
   v2_text = format_networkstatus_vote(sign_skey_2, vote);
   test_assert(v2_text);
-  v2 = networkstatus_parse_vote_from_string(v2_text, 1);
+  v2 = networkstatus_parse_vote_from_string(v2_text, NULL, 1);
   test_assert(v2);
   /* Check that flags come out right.*/
   cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
@@ -2639,7 +2639,7 @@
 
   v3_text = format_networkstatus_vote(sign_skey_3, vote);
   test_assert(v3_text);
-  v3 = networkstatus_parse_vote_from_string(v3_text, 1);
+  v3 = networkstatus_parse_vote_from_string(v3_text, NULL, 1);
   test_assert(v3);
 
   /* Compute a consensus as voter 3. */
@@ -2650,7 +2650,7 @@
                                                    cert3->identity_key,
                                                    sign_skey_3);
   test_assert(consensus_text);
-  con = networkstatus_parse_vote_from_string(consensus_text, 0);
+  con = networkstatus_parse_vote_from_string(consensus_text, NULL, 0);
   test_assert(con);
   //log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
   //           v1_text, v2_text, v3_text);
@@ -2759,8 +2759,8 @@
                                                       sign_skey_1);
     test_assert(consensus_text2);
     test_assert(consensus_text3);
-    con2 = networkstatus_parse_vote_from_string(consensus_text2, 0);
-    con3 = networkstatus_parse_vote_from_string(consensus_text3, 0);
+    con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL, 0);
+    con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL, 0);
     test_assert(con2);
     test_assert(con3);
 



More information about the tor-commits mailing list