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

[or-cvs] [tor/master] Generate all the flavors of consensuses when building consensuses.



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Tue, 22 Sep 2009 16:52:51 -0400
Subject: Generate all the flavors of consensuses when building consensuses.
Commit: d9c71816b15af4325fb8ab9befa8600185d9aa90

---
 src/or/directory.c |    2 +-
 src/or/dirvote.c   |  338 +++++++++++++++++++++++++++++++++++-----------------
 src/or/or.h        |    9 +-
 3 files changed, 235 insertions(+), 114 deletions(-)

diff --git a/src/or/directory.c b/src/or/directory.c
index 19ef635..0feddcb 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2618,7 +2618,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
       const char *item;
       tor_assert(!current); /* we handle current consensus specially above,
                              * since it wants to be spooled. */
-      if ((item = dirvote_get_pending_consensus()))
+      if ((item = dirvote_get_pending_consensus(FLAV_NS)))
         smartlist_add(items, (char*)item);
     } else if (!current && !strcmp(url, "consensus-signatures")) {
       /* XXXX the spec says that we should implement
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 1bdf4cc..e361102 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -11,15 +11,21 @@
  * \brief Functions to compute directory consensus, and schedule voting.
  **/
 
-static int dirvote_add_signatures_to_pending_consensus(
+typedef struct pending_consensus_t pending_consensus_t;
+
+static int dirvote_add_signatures_to_all_pending_consensuses(
                        const char *detached_signatures_body,
                        const char **msg_out);
+static int dirvote_add_signatures_to_pending_consensus(
+                       pending_consensus_t *pc,
+                       ns_detached_signatures_t *sigs,
+                       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);
 static int dirvote_perform_vote(void);
 static void dirvote_clear_votes(int all_votes);
-static int dirvote_compute_consensus(void);
+static int dirvote_compute_consensuses(void);
 static int dirvote_publish_consensus(void);
 static char *make_consensus_method_list(int low, int high, const char *sep);
 
@@ -1480,6 +1486,44 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
   return r;
 }
 
+/** DOCDOC */
+static char *
+networkstatus_format_signatures(networkstatus_t *consensus)
+{
+  smartlist_t *elements;
+  char buf[4096];
+  char *result = NULL;
+  int n_sigs = 0;
+
+  elements = smartlist_create();
+
+  SMARTLIST_FOREACH_BEGIN(consensus->voters, networkstatus_voter_info_t *, v) {
+    SMARTLIST_FOREACH_BEGIN(v->sigs, document_signature_t *, sig) {
+      char sk[HEX_DIGEST_LEN+1];
+      char id[HEX_DIGEST_LEN+1];
+      if (!sig->signature || sig->bad_signature || sig->alg != DIGEST_SHA1)
+        continue;
+      ++n_sigs;
+      base16_encode(sk, sizeof(sk), sig->signing_key_digest, DIGEST_LEN);
+      base16_encode(id, sizeof(id), sig->identity_digest, DIGEST_LEN);
+      tor_snprintf(buf, sizeof(buf),
+                   "directory-signature %s %s\n-----BEGIN SIGNATURE-----\n",
+                   id, sk);
+      smartlist_add(elements, tor_strdup(buf));
+      base64_encode(buf, sizeof(buf), sig->signature, sig->signature_len);
+      strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
+      smartlist_add(elements, tor_strdup(buf));
+    } SMARTLIST_FOREACH_END(sig);
+  } SMARTLIST_FOREACH_END(v);
+
+  result = smartlist_join_strings(elements, "", 0, NULL);
+  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
+  smartlist_free(elements);
+  if (!n_sigs)
+    tor_free(result);
+  return result;
+}
+
 /** Return a newly allocated string holding the detached-signatures document
  * corresponding to the signatures on <b>consensus</b>. */
 char *
@@ -1488,7 +1532,6 @@ networkstatus_get_detached_signatures(networkstatus_t *consensus)
   smartlist_t *elements;
   char buf[4096];
   char *result = NULL;
-  int n_sigs = 0;
   tor_assert(consensus);
   tor_assert(consensus->type == NS_TYPE_CONSENSUS);
 
@@ -1514,30 +1557,17 @@ networkstatus_get_detached_signatures(networkstatus_t *consensus)
     smartlist_add(elements, tor_strdup(buf));
   }
 
-  SMARTLIST_FOREACH_BEGIN(consensus->voters, networkstatus_voter_info_t *, v) {
-    SMARTLIST_FOREACH_BEGIN(v->sigs, document_signature_t *, sig) {
-      char sk[HEX_DIGEST_LEN+1];
-      char id[HEX_DIGEST_LEN+1];
-      if (!sig->signature || sig->bad_signature || sig->alg != DIGEST_SHA1)
-        continue;
-      ++n_sigs;
-      base16_encode(sk, sizeof(sk), sig->signing_key_digest, DIGEST_LEN);
-      base16_encode(id, sizeof(id), sig->identity_digest, DIGEST_LEN);
-      tor_snprintf(buf, sizeof(buf),
-                   "directory-signature %s %s\n-----BEGIN SIGNATURE-----\n",
-                   id, sk);
-      smartlist_add(elements, tor_strdup(buf));
-      base64_encode(buf, sizeof(buf), sig->signature, sig->signature_len);
-      strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
-      smartlist_add(elements, tor_strdup(buf));
-    } SMARTLIST_FOREACH_END(sig);
-  } SMARTLIST_FOREACH_END(v);
+  {
+    char *sigs = networkstatus_format_signatures(consensus);
+    if (!sigs)
+      goto err;
+    smartlist_add(elements, sigs);
+  }
 
   result = smartlist_join_strings(elements, "", 0, NULL);
+ err:
   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
   smartlist_free(elements);
-  if (!n_sigs)
-    tor_free(result);
   return result;
 }
 
@@ -1744,7 +1774,7 @@ dirvote_act(or_options_t *options, time_t now)
   if (voting_schedule.voting_ends < now &&
       !voting_schedule.have_built_consensus) {
     log_notice(LD_DIR, "Time to compute a consensus.");
-    dirvote_compute_consensus();
+    dirvote_compute_consensuses();
     /* XXXX We will want to try again later if we haven't got enough
      * votes yet.  Implement this if it turns out to ever happen. */
     voting_schedule.have_built_consensus = 1;
@@ -1781,14 +1811,22 @@ static smartlist_t *pending_vote_list = NULL;
 /** List of pending_vote_t for the previous vote.  After we've used them to
  * build a consensus, the votes go here for the next period. */
 static smartlist_t *previous_vote_list = NULL;
-/** The body of the consensus that we're currently building.  Once we
- * have it built, it goes into dirserv.c */
-static char *pending_consensus_body = NULL;
+
+/** DOCDOC*/
+struct pending_consensus_t {
+  /** The body of the consensus that we're currently building.  Once we
+   * have it built, it goes into dirserv.c */
+  char *body;
+  /** The parsed in-progress consensus document. */
+  networkstatus_t *consensus;
+};
+
+static pending_consensus_t pending_consensuses[N_CONSENSUS_FLAVORS];
+
 /** The detached signatures for the consensus that we're currently
  * building. */
 static char *pending_consensus_signatures = NULL;
-/** The parsed in-progress consensus document. */
-static networkstatus_t *pending_consensus = NULL;
+
 /** List of ns_detached_signatures_t: hold signatures that get posted to us
  * before we have generated the consensus on our own. */
 static smartlist_t *pending_consensus_signature_list = NULL;
@@ -1882,15 +1920,39 @@ dirvote_fetch_missing_votes(void)
 static void
 dirvote_fetch_missing_signatures(void)
 {
-  if (!pending_consensus)
+  int need_any = 0;
+  int i;
+  for (i=0; i < N_CONSENSUS_FLAVORS; ++i) {
+    networkstatus_t *consensus = pending_consensuses[i].consensus;
+    if (!consensus ||
+        networkstatus_check_consensus_signature(consensus, -1) == 1) {
+      /* We have no consensus, or we have one that's signed by everybody. */
+      continue;
+    }
+    need_any = 1;
+  }
+  if (!need_any)
     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);
 }
 
+/** DOCDOC */
+static void
+dirvote_clear_pending_consensuses(void)
+{
+  int i;
+  for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
+    pending_consensus_t *pc = &pending_consensuses[i];
+    tor_free(pc->body);
+    if (pc->consensus) {
+      networkstatus_vote_free(pc->consensus);
+      pc->consensus = NULL;
+    }
+  }
+}
+
 /** Drop all currently pending votes, consensus, and detached signatures. */
 static void
 dirvote_clear_votes(int all_votes)
@@ -1928,12 +1990,8 @@ dirvote_clear_votes(int all_votes)
                       tor_free(cp));
     smartlist_clear(pending_consensus_signature_list);
   }
-  tor_free(pending_consensus_body);
   tor_free(pending_consensus_signatures);
-  if (pending_consensus) {
-    networkstatus_vote_free(pending_consensus);
-    pending_consensus = NULL;
-  }
+  dirvote_clear_pending_consensuses();
 }
 
 /** Return a newly allocated string containing the hex-encoded v3 authority
@@ -2121,7 +2179,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
  * pending_consensus: it won't be ready to be published until we have
  * everybody else's signatures collected too. (V3 Authority only) */
 static int
-dirvote_compute_consensus(void)
+dirvote_compute_consensuses(void)
 {
   /* Have we got enough votes to try? */
   int n_votes, n_voters;
@@ -2129,6 +2187,10 @@ dirvote_compute_consensus(void)
   char *consensus_body = NULL, *signatures = NULL, *votefile;
   networkstatus_t *consensus = NULL;
   authority_cert_t *my_cert;
+  pending_consensus_t pending[N_CONSENSUS_FLAVORS];
+  int flav;
+
+  memset(pending, 0, sizeof(pending));
 
   if (!pending_vote_list)
     pending_vote_list = smartlist_create();
@@ -2168,6 +2230,7 @@ dirvote_compute_consensus(void)
     char legacy_dbuf[DIGEST_LEN];
     crypto_pk_env_t *legacy_sign=NULL;
     char *legacy_id_digest = NULL;
+    int n_generated = 0;
     if (get_options()->V3AuthUseLegacyKey) {
       authority_cert_t *cert = get_my_v3_legacy_cert();
       legacy_sign = get_my_v3_legacy_signing_key();
@@ -2176,40 +2239,59 @@ dirvote_compute_consensus(void)
         legacy_id_digest = legacy_dbuf;
       }
     }
-    consensus_body = networkstatus_compute_consensus(
+
+    for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) {
+      const char *flavor_name = networkstatus_get_flavor_name(flav);
+      consensus_body = networkstatus_compute_consensus(
         votes, n_voters,
         my_cert->identity_key,
         get_my_v3_authority_signing_key(), legacy_id_digest, legacy_sign,
-        FLAV_NS);
-  }
-  if (!consensus_body) {
-    log_warn(LD_DIR, "Couldn't generate a consensus at all!");
-    goto err;
-  }
-  consensus = networkstatus_parse_vote_from_string(consensus_body, NULL,
-                                                   NS_TYPE_CONSENSUS);
-  if (!consensus) {
-    log_warn(LD_DIR, "Couldn't parse consensus we generated!");
-    goto err;
+        flav);
+
+      if (!consensus_body) {
+        log_warn(LD_DIR, "Couldn't generate a %s consensus at all!",
+                 flavor_name);
+        continue;
+      }
+      consensus = networkstatus_parse_vote_from_string(consensus_body, NULL,
+                                                       NS_TYPE_CONSENSUS);
+      if (!consensus) {
+        log_warn(LD_DIR, "Couldn't parse %s consensus we generated!",
+                 flavor_name);
+        tor_free(consensus_body);
+        continue;
+      }
+
+      /* 'Check' our own signature, to mark it valid. */
+      networkstatus_check_consensus_signature(consensus, -1);
+
+      pending[flav].body = consensus_body;
+      pending[flav].consensus = consensus;
+      n_generated++;
+      consensus_body = NULL;
+      consensus = NULL;
+    }
+    if (!n_generated) {
+      log_warn(LD_DIR, "Couldn't generate any consensus flavors at all.");
+      goto err;
+    }
   }
-  /* 'Check' our own signature, to mark it valid. */
-  networkstatus_check_consensus_signature(consensus, -1);
 
-  signatures = networkstatus_get_detached_signatures(consensus);
+  /* XXXX NMNM NM NM wrong. */
+  signatures =
+    networkstatus_get_detached_signatures(pending[FLAV_NS].consensus);
+
   if (!signatures) {
     log_warn(LD_DIR, "Couldn't extract signatures.");
     goto err;
   }
 
-  tor_free(pending_consensus_body);
-  pending_consensus_body = consensus_body;
+  dirvote_clear_pending_consensuses();
+  memcpy(pending_consensuses, pending, sizeof(pending));
+
   tor_free(pending_consensus_signatures);
   pending_consensus_signatures = signatures;
 
-  if (pending_consensus)
-    networkstatus_vote_free(pending_consensus);
-  pending_consensus = consensus;
-
   if (pending_consensus_signature_list) {
     int n_sigs = 0;
     /* we may have gotten signatures for this consensus before we built
@@ -2217,7 +2299,7 @@ dirvote_compute_consensus(void)
     SMARTLIST_FOREACH(pending_consensus_signature_list, char *, sig,
       {
         const char *msg = NULL;
-        int r = dirvote_add_signatures_to_pending_consensus(sig, &msg);
+        int r = dirvote_add_signatures_to_all_pending_consensuses(sig, &msg);
         if (r >= 0)
           n_sigs += r;
         else
@@ -2253,79 +2335,61 @@ dirvote_compute_consensus(void)
 }
 
 /** Helper: we just got the <b>detached_signatures_body</b> sent to us as
- * signatures on the currently pending consensus.  Add them to the consensus
+ * signatures on the currently pending consensus.  Add them to <b>pc</b>
  * as appropriate.  Return the number of signatures added. (?) */
 static int
 dirvote_add_signatures_to_pending_consensus(
-                       const char *detached_signatures_body,
+                       pending_consensus_t *pc,
+                       ns_detached_signatures_t *sigs,
                        const char **msg_out)
 {
-  ns_detached_signatures_t *sigs = NULL;
+  const char *flavor_name;
   int r = -1;
 
-  tor_assert(detached_signatures_body);
-  tor_assert(msg_out);
-
   /* Only call if we have a pending consensus right now. */
-  tor_assert(pending_consensus);
-  tor_assert(pending_consensus_body);
+  tor_assert(pc->consensus);
+  tor_assert(pc->body);
   tor_assert(pending_consensus_signatures);
 
+  flavor_name = networkstatus_get_flavor_name(pc->consensus->flavor);
   *msg_out = NULL;
 
-  if (!(sigs = networkstatus_parse_detached_signatures(
-                               detached_signatures_body, NULL))) {
-    *msg_out = "Couldn't parse detached signatures.";
-    goto err;
-  }
-
   {
-    smartlist_t *sig_list = strmap_get(sigs->signatures,
-                    networkstatus_get_flavor_name(pending_consensus->flavor));
-    log_info(LD_DIR, "Have %d signatures for adding to consensus.",
-             sig_list ? smartlist_len(sig_list) : 0);
+    smartlist_t *sig_list = strmap_get(sigs->signatures, flavor_name);
+    log_info(LD_DIR, "Have %d signatures for adding to %s consensus.",
+             sig_list ? smartlist_len(sig_list) : 0, flavor_name);
   }
-  r = networkstatus_add_detached_signatures(pending_consensus,
-                                            sigs, msg_out);
+  r = networkstatus_add_detached_signatures(pc->consensus, sigs, msg_out);
   log_info(LD_DIR,"Added %d signatures to consensus.", r);
 
   if (r >= 1) {
-    char *new_detached =
-      networkstatus_get_detached_signatures(pending_consensus);
-    const char *src;
+    char *new_signatures =
+      networkstatus_format_signatures(pc->consensus);
     char *dst, *dst_end;
     size_t new_consensus_len;
-    if (!new_detached) {
+    if (!new_signatures) {
       *msg_out = "No signatures to add";
       goto err;
     }
     new_consensus_len =
-      strlen(pending_consensus_body) + strlen(new_detached) + 1;
-    pending_consensus_body = tor_realloc(pending_consensus_body,
-                                         new_consensus_len);
-    dst_end = pending_consensus_body + new_consensus_len;
-    dst = strstr(pending_consensus_body, "directory-signature ");
+      strlen(pc->body) + strlen(new_signatures) + 1;
+    pc->body = tor_realloc(pc->body, new_consensus_len);
+    dst_end = pc->body + new_consensus_len;
+    dst = strstr(pc->body, "directory-signature ");
     tor_assert(dst);
-    src = strstr(new_detached, "directory-signature ");
-    tor_assert(src);
-    strlcpy(dst, src, dst_end-dst);
+    strlcpy(dst, new_signatures, dst_end-dst);
 
     /* We remove this block once it has failed to crash for a while.  But
      * unless it shows up in profiles, we're probably better leaving it in,
      * just in case we break detached signature processing at some point. */
     {
-      ns_detached_signatures_t *sigs =
-        networkstatus_parse_detached_signatures(new_detached, NULL);
       networkstatus_t *v = networkstatus_parse_vote_from_string(
-                                             pending_consensus_body, NULL,
+                                             pc->body, NULL,
                                              NS_TYPE_CONSENSUS);
-      tor_assert(sigs);
-      ns_detached_signatures_free(sigs);
       tor_assert(v);
       networkstatus_vote_free(v);
     }
     tor_free(pending_consensus_signatures);
-    pending_consensus_signatures = new_detached;
     *msg_out = "Signatures added";
   } else if (r == 0) {
     *msg_out = "Signatures ignored";
@@ -2338,8 +2402,62 @@ dirvote_add_signatures_to_pending_consensus(
   if (!*msg_out)
     *msg_out = "Unrecognized error while adding detached signatures.";
  done:
+  return r;
+}
+
+static int
+dirvote_add_signatures_to_all_pending_consensuses(
+                       const char *detached_signatures_body,
+                       const char **msg_out)
+{
+  int r=0, i, n_added = 0, errors = 0;
+  ns_detached_signatures_t *sigs;
+  tor_assert(detached_signatures_body);
+  tor_assert(msg_out);
+
+  if (!(sigs = networkstatus_parse_detached_signatures(
+                               detached_signatures_body, NULL))) {
+    *msg_out = "Couldn't parse detached signatures.";
+    goto err;
+  }
+
+  for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
+    int res;
+    pending_consensus_t *pc = &pending_consensuses[i];
+    if (!pc->consensus)
+      continue;
+    res = dirvote_add_signatures_to_pending_consensus(pc, sigs, msg_out);
+    if (res < 0)
+      errors++;
+    else
+      n_added += res;
+  }
+
+  if (errors) {
+    r = -1;
+    goto err;
+  }
+
+  /* Still not right XXXX NM NM*/
+  if (pending_consensuses[FLAV_NS].consensus) {
+    char *new_detached = networkstatus_get_detached_signatures(
+                           pending_consensuses[FLAV_NS].consensus);
+    if (new_detached) {
+      tor_free(pending_consensus_signatures);
+      pending_consensus_signatures = new_detached;
+    }
+  }
+
+  r = n_added;
+  goto done;
+ err:
+  if (!*msg_out)
+    *msg_out = "Unrecognized error while adding detached signatures.";
+ done:
   if (sigs)
     ns_detached_signatures_free(sigs);
+  /* XXXX NM Check how return is used.  We can now have an error *and*
+     signatures added. */
   return r;
 }
 
@@ -2352,10 +2470,10 @@ dirvote_add_signatures(const char *detached_signatures_body,
                        const char *source,
                        const char **msg)
 {
-  if (pending_consensus) {
+  if (pending_consensuses[FLAV_NS].consensus) {
     log_notice(LD_DIR, "Got a signature from %s. "
                        "Adding it to the pending consensus.", source);
-    return dirvote_add_signatures_to_pending_consensus(
+    return dirvote_add_signatures_to_all_pending_consensuses(
                                      detached_signatures_body, msg);
   } else {
     log_notice(LD_DIR, "Got a signature from %s. "
@@ -2375,13 +2493,16 @@ static int
 dirvote_publish_consensus(void)
 {
   /* Can we actually publish it yet? */
-  if (!pending_consensus ||
-      networkstatus_check_consensus_signature(pending_consensus, 1)<0) {
+  if (!pending_consensuses[FLAV_NS].consensus ||
+      networkstatus_check_consensus_signature(
+                              pending_consensuses[FLAV_NS].consensus, 1)<0) {
     log_warn(LD_DIR, "Not enough info to publish pending consensus");
     return -1;
   }
 
-  if (networkstatus_set_current_consensus(pending_consensus_body, 0))
+  /* XXXXXX NMNMNM */
+  if (networkstatus_set_current_consensus(
+                              pending_consensuses[FLAV_NS].body, 0))
     log_warn(LD_DIR, "Error publishing consensus");
   else
     log_notice(LD_DIR, "Consensus published.");
@@ -2400,12 +2521,8 @@ dirvote_free_all(void)
   smartlist_free(previous_vote_list);
   previous_vote_list = NULL;
 
-  tor_free(pending_consensus_body);
+  dirvote_clear_pending_consensuses();
   tor_free(pending_consensus_signatures);
-  if (pending_consensus) {
-    networkstatus_vote_free(pending_consensus);
-    pending_consensus = NULL;
-  }
   if (pending_consensus_signature_list) {
     /* now empty as a result of clear_pending_votes. */
     smartlist_free(pending_consensus_signature_list);
@@ -2419,9 +2536,10 @@ dirvote_free_all(void)
 
 /** Return the body of the consensus that we're currently trying to build. */
 const char *
-dirvote_get_pending_consensus(void)
+dirvote_get_pending_consensus(consensus_flavor_t flav)
 {
-  return pending_consensus_body;
+  tor_assert(((int)flav) >= 0 && flav < N_CONSENSUS_FLAVORS);
+  return pending_consensuses[flav].body;
 }
 
 /** Return the signatures that we know for the consensus that we're currently
diff --git a/src/or/or.h b/src/or/or.h
index e2050ec..b8ccac9 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1688,10 +1688,13 @@ typedef enum {
 
 /** DOCDOC */
 typedef enum {
-  FLAV_NS,
-  FLAV_MICRODESC,
+  FLAV_NS = 0,
+  FLAV_MICRODESC = 1,
 } consensus_flavor_t;
 
+/** DOCDOC */
+#define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1)
+
 /** A common structure to hold a v3 network status vote, or a v3 network
  * status consensus. */
 typedef struct networkstatus_t {
@@ -3863,7 +3866,7 @@ int dirvote_add_signatures(const char *detached_signatures_body,
                            const char **msg_out);
 
 /* Item access */
-const char *dirvote_get_pending_consensus(void);
+const char *dirvote_get_pending_consensus(consensus_flavor_t flav);
 const char *dirvote_get_pending_detached_signatures(void);
 #define DGV_BY_ID 1
 #define DGV_INCLUDE_PENDING 2
-- 
1.5.6.5