[or-cvs] r11957: Implement v3 networkstatus client code. Remove v2 networksta (in tor/trunk: . doc src/or)

nickm at seul.org nickm at seul.org
Mon Oct 15 23:15:25 UTC 2007


Author: nickm
Date: 2007-10-15 19:15:24 -0400 (Mon, 15 Oct 2007)
New Revision: 11957

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/src/or/control.c
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/dirvote.c
   tor/trunk/src/or/hibernate.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/networkstatus.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerlist.c
   tor/trunk/src/or/routerparse.c
Log:
 r15806 at catbus:  nickm | 2007-10-15 19:14:57 -0400
 Implement v3 networkstatus client code.  Remove v2 networkstatus client code, except as needed for caches to fetch and serve v2 networkstatues and the routers they list.



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

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/ChangeLog	2007-10-15 23:15:24 UTC (rev 11957)
@@ -1,4 +1,9 @@
 Changes in version 0.2.0.9-alpha - 2007-10-??
+  o Major features (v3 directory system):
+    - Clients now download v3 consensus networkstatus documents instead
+      of v2 networkstatus documents.  Clients and caches now their opinions
+      about routers on these consensus documents.  Clients only download
+      router descriptors listed in the consensus.
 
   o Major bugfixes:
     - Stop publishing a new server descriptor just because we HUP or

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/doc/TODO	2007-10-15 23:15:24 UTC (rev 11957)
@@ -69,8 +69,29 @@
         - Enable for non-caches
       - Code to use v3 networkstatus documents once clients are
         fetching them
-        - Implement
-        - Enable
+        o Make everybody download v3 networkstatus docs.
+        o Make clients not download v2 networkstatus docs.
+        o Make everybody download routerdescs based on v3 networkstatus
+          docs.
+        o Change definition of "have enough information to build circuits"
+        o Base version sanity check on v3 ns.
+        o Change routerstatus_get_by_* to use v3 networkstatus docs.
+        o Make download_status_get_by_descriptor_digest() use v2
+          networkstatus docs too.
+        o Eliminate routerstatus_list.
+        o Make routers_update_all_from_networkstatus() [or equivalent]
+          get called at the right time.
+        o Make  routersstatus_list_update_from_consensus_networkstatus()
+          get renamed and called.
+        o When setting a new consensus, copy the extra fields out of the
+          old consensus (if any).
+        o Update named-server-map as appropriate.
+        - Fix all XXXX020s.
+        - Sort out need_to_mirror
+        - Work hard to make sure clients never look at v2 networkstatus docs.
+        - Check in old_routers before fetching a router status. You never
+          know if we'll flap...
+
       - Controller support
         - GETINFO to get consensus
         - Event when new consensus arrives

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/control.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -1609,34 +1609,39 @@
                    check_whether_orport_reachable() ? 1 : 0,
                    check_whether_dirport_reachable() ? 1 : 0);
     } else if (!strcmpstart(question, "status/version/")) {
-      combined_version_status_t st;
       int is_server = server_mode(get_options());
-      char *recommended;
-      recommended = compute_recommended_versions(time(NULL),
-                                                 !is_server, VERSION, &st);
+      networkstatus_vote_t *c = networkstatus_get_latest_consensus();
+      version_status_t status;
+      const char *recommended;
+      if (c) {
+        recommended = is_server ? c->server_versions : c->client_versions;
+        status = tor_version_is_obsolete(VERSION, recommended);
+      } else {
+        recommended = "?";
+        status = VS_UNKNOWN;
+      }
+
       if (!strcmp(question, "status/version/recommended")) {
-        *answer = recommended;
+        *answer = tor_strdup(recommended);
         return 0;
       }
-      tor_free(recommended);
       if (!strcmp(question, "status/version/current")) {
-        switch (st.consensus)
+        switch (status)
           {
           case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break;
           case VS_OLD: *answer = tor_strdup("obsolete"); break;
           case VS_NEW: *answer = tor_strdup("new"); break;
           case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break;
           case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break;
+          case VS_UNKNOWN: *answer = tor_strdup("unknown"); break;
           default: tor_fragile_assert();
           }
-      } else if (!strcmp(question, "status/version/num-versioning")) {
+      } else if (!strcmp(question, "status/version/num-versioning") ||
+                 !strcmp(question, "status/version/num-concurring")) {
+        /*XXXX020 deprecate.*/
         char s[33];
-        tor_snprintf(s, sizeof(s), "%d", st.n_versioning);
+        tor_snprintf(s, sizeof(s), "%d", get_n_authorities(V3_AUTHORITY));
         *answer = tor_strdup(s);
-      } else if (!strcmp(question, "status/version/num-concurring")) {
-        char s[33];
-        tor_snprintf(s, sizeof(s), "%d", st.n_concurring);
-        *answer = tor_strdup(s);
       }
     } else {
       return 0;

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/directory.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -178,7 +178,7 @@
       return 1;
   }
   if (is_authority) {
-    routerstatus_t *rs = router_get_combined_status_by_digest(identity_digest);
+    routerstatus_t *rs = router_get_consensus_status_by_id(identity_digest);
     if (rs && rs->version_supports_extrainfo_upload)
       return 1;
   }
@@ -1232,7 +1232,7 @@
              "'%s:%d'. I'll try again soon.",
              status_code, escaped(reason), conn->_base.address,
              conn->_base.port);
-    if ((rs = router_get_combined_status_by_digest(conn->identity_digest)))
+    if ((rs = router_get_consensus_status_by_id(conn->identity_digest)))
       rs->last_dir_503_at = now;
     if ((ds = router_get_trusteddirserver_by_digest(conn->identity_digest)))
       ds->fake_status.last_dir_503_at = now;
@@ -1387,7 +1387,7 @@
       if (next)
         next[1] = '\0';
       /* learn from it, and then remove it from 'which' */
-      if (router_set_networkstatus(cp, now, source, which)<0)
+      if (router_set_networkstatus_v2(cp, now, source, which)<0)
         break;
       if (next) {
         next[1] = 'n';
@@ -1426,6 +1426,8 @@
       networkstatus_consensus_download_failed(0);
       return -1;
     }
+    routers_update_all_from_networkstatus(now); /*launches router downloads*/
+    directory_info_has_arrived(now, 0);
     log_info(LD_DIR, "Successfully loaded consensus.");
   }
   if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
@@ -2790,10 +2792,7 @@
       if (sd)
         dls = &sd->ei_dl_status;
     } else {
-      routerstatus_t *rs =
-        router_get_combined_status_by_descriptor_digest(digest);
-      if (rs)
-        dls = &rs->dl_status;
+      dls = router_get_dl_status_by_descriptor_digest(digest);
     }
     if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
       continue;

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/dirserv.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -2380,12 +2380,12 @@
   }
 
   {
-    networkstatus_t *ns;
-    if (!(ns = networkstatus_parse_from_string(status))) {
+    networkstatus_v2_t *ns;
+    if (!(ns = networkstatus_v2_parse_from_string(status))) {
       log_err(LD_BUG,"Generated a networkstatus we couldn't parse.");
       goto done;
     }
-    networkstatus_free(ns);
+    networkstatus_v2_free(ns);
   }
 
   {
@@ -2395,7 +2395,7 @@
     *ns_ptr = new_cached_dir(status, now);
     status = NULL; /* So it doesn't get double-freed. */
     the_v2_networkstatus_is_dirty = 0;
-    router_set_networkstatus((*ns_ptr)->dir, now, NS_GENERATED, NULL);
+    router_set_networkstatus_v2((*ns_ptr)->dir, now, NS_GENERATED, NULL);
     r = *ns_ptr;
   }
 

Modified: tor/trunk/src/or/dirvote.c
===================================================================
--- tor/trunk/src/or/dirvote.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/dirvote.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -67,6 +67,8 @@
 
     smartlist_free(ns->routerstatus_list);
   }
+  if (ns->desc_digest_map)
+    digestmap_free(ns->desc_digest_map, NULL);
 
   memset(ns, 11, sizeof(*ns));
   tor_free(ns);

Modified: tor/trunk/src/or/hibernate.c
===================================================================
--- tor/trunk/src/or/hibernate.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/hibernate.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -547,7 +547,6 @@
 
 /* This rounds 0 up to 1000, but that's actually a feature. */
 #define ROUND_UP(x) (((x) + 0x3ff) & ~0x3ff)
-#define BW_ACCOUNTING_VERSION 1
 /** Save all our bandwidth tracking information to disk. Return 0 on
  * success, -1 on failure. */
 int

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/main.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -995,9 +995,10 @@
      * update all the descriptors' running status. */
     /* purge obsolete entries */
     routerlist_remove_old_routers();
-    networkstatus_list_clean(now);
-    networkstatus_list_update_recent(now);
-    routers_update_all_from_networkstatus(now);
+    networkstatus_v2_list_clean(now);
+#if 0
+    networkstatus_v2_list_update_recent(now);
+#endif
 
     /* Also, once per minute, check whether we want to download any
      * networkstatus documents.
@@ -1339,6 +1340,14 @@
   stats_prev_global_read_bucket = global_read_bucket;
   stats_prev_global_write_bucket = global_write_bucket;
 
+  if (trusted_dirs_reload_certs())
+    return -1;
+  if (router_reload_v2_networkstatus()) {
+    return -1;
+  }
+  if (router_reload_consensus_networkstatus()) {
+    return -1;
+  }
   /* load the routers file, or assign the defaults. */
   if (router_reload_router_list()) {
     return -1;
@@ -1346,12 +1355,6 @@
   /* load the networkstatuses. (This launches a download for new routers as
    * appropriate.)
    */
-  if (router_reload_networkstatus()) {
-    return -1;
-  }
-  if (router_reload_consensus_networkstatus()) {
-    return -1;
-  }
   now = time(NULL);
   directory_info_has_arrived(now, 1);
 

Modified: tor/trunk/src/or/networkstatus.c
===================================================================
--- tor/trunk/src/or/networkstatus.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/networkstatus.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -12,21 +12,17 @@
 
 #include "or.h"
 
-/** Global list of routerstatus_t for each router, known or unknown.
- * Kept sorted by digest. */
-static smartlist_t *routerstatus_list = NULL;
-/** Map from descriptor digest to a member of routerstatus_list: used to
- * update download status when a download fails. */
-static digestmap_t *routerstatus_by_desc_digest_map = NULL;
-/** True iff any element of routerstatus_list has changed since the last
- * time we called routers_update_all_from_networkstatus().*/
-static int routerstatus_list_has_changed = 0;
+/** XXXXX020 are all these still needed */
+
+/** DOCDOC */
+static digestmap_t *v2_download_status_map = NULL;
+
 /** Map from lowercase nickname to digest of named server, if any. */
 static strmap_t *named_server_map = NULL;
 
-/** Global list of all of the current network_status documents that we know
+/** Global list of all of the current v2 network_status documents that we know
  * about.  This list is kept sorted by published_on. */
-static smartlist_t *networkstatus_list = NULL;
+static smartlist_t *networkstatus_v2_list = NULL;
 
 /** Most recently received and validated v3 consensus network status. */
 static networkstatus_vote_t *current_consensus = NULL;
@@ -36,9 +32,9 @@
 static networkstatus_vote_t *consensus_waiting_for_certs = NULL;
 static char *consensus_waiting_for_certs_body = NULL;
 
-/** True iff any member of networkstatus_list has changed since the last time
- * we called routerstatus_list_update_from_networkstatus(). */
-static int networkstatus_list_has_changed = 0;
+/** True iff any member of networkstatus_v2_list has changed since the last
+ * time we called routerstatus_list_update_from_networkstatus(). */
+static int networkstatus_v2_list_has_changed = 0;
 
 /** The last time we tried to download a networkstatus, or 0 for "never".  We
  * use this to rate-limit download attempts for directory caches (including
@@ -64,16 +60,18 @@
  * listed by the authorities  */
 static int have_warned_about_new_version = 0;
 
-static int have_tried_downloading_all_statuses(int n_failures);
+static void routerstatus_list_update_from_v2_networkstatus(void);
+static void routerstatus_list_update_named_server_map(void);
 
 /** DOCDOC */
 void
 networkstatus_reset_warnings(void)
 {
-  if (!routerstatus_list)
-    routerstatus_list = smartlist_create();
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-                    rs->name_lookup_warned = 0);
+  if (current_consensus) {
+    SMARTLIST_FOREACH(current_consensus->routerstatus_list,
+                      routerstatus_t *, rs,
+                      rs->name_lookup_warned = 0);
+  }
 
   if (!warned_conflicts)
     warned_conflicts = smartlist_create();
@@ -85,18 +83,47 @@
   have_warned_about_new_version = 0;
 }
 
+/** Reset the descriptor download failure count on all networkstatus docs, so
+ * that we can retry any long-failed documents immediately.
+ */
+void
+networkstatus_reset_download_failures(void)
+{
+  const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
+  SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
+     SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
+       {
+         if (!router_get_by_descriptor_digest(rs->descriptor_digest))
+           rs->need_to_mirror = 1;
+       }));;
+
+  download_status_reset(&consensus_dl_status);
+  if (v2_download_status_map) {
+    digestmap_iter_t *iter;
+    digestmap_t *map = v2_download_status_map;
+    const char *key;
+    void *val;
+    download_status_t *dls;
+    for (iter = digestmap_iter_init(map); !digestmap_iter_done(iter); ) {
+      digestmap_iter_get(iter, &key, &val);
+      dls = val;
+      download_status_reset(dls);
+    }
+  }
+}
+
 /** Repopulate our list of network_status_t objects from the list cached on
  * disk.  Return 0 on success, -1 on failure. */
 int
-router_reload_networkstatus(void)
+router_reload_v2_networkstatus(void)
 {
   char filename[512];
   smartlist_t *entries;
   struct stat st;
   char *s;
   tor_assert(get_options()->DataDirectory);
-  if (!networkstatus_list)
-    networkstatus_list = smartlist_create();
+  if (!networkstatus_v2_list)
+    networkstatus_v2_list = smartlist_create();
 
   tor_snprintf(filename,sizeof(filename),"%s"PATH_SEPARATOR"cached-status",
                get_options()->DataDirectory);
@@ -114,7 +141,8 @@
                    get_options()->DataDirectory, fn);
       s = read_file_to_str(filename, 0, &st);
       if (s) {
-        if (router_set_networkstatus(s, st.st_mtime, NS_FROM_CACHE, NULL)<0) {
+        if (router_set_networkstatus_v2(s, st.st_mtime, NS_FROM_CACHE,
+                                        NULL)<0) {
           log_warn(LD_FS, "Couldn't load networkstatus from \"%s\"",filename);
         }
         tor_free(s);
@@ -122,7 +150,7 @@
     });
   SMARTLIST_FOREACH(entries, char *, fn, tor_free(fn));
   smartlist_free(entries);
-  networkstatus_list_clean(time(NULL));
+  networkstatus_v2_list_clean(time(NULL));
   routers_update_all_from_networkstatus(time(NULL));
   return 0;
 }
@@ -171,7 +199,7 @@
 
 /** Free all storage held by the networkstatus object <b>ns</b>. */
 void
-networkstatus_free(networkstatus_t *ns)
+networkstatus_v2_free(networkstatus_v2_t *ns)
 {
   tor_free(ns->source_address);
   tor_free(ns->contact);
@@ -205,9 +233,9 @@
 /** Helper for smartlist_sort: Compare two networkstatus objects by
  * publication date. */
 static int
-_compare_networkstatus_published_on(const void **_a, const void **_b)
+_compare_networkstatus_v2_published_on(const void **_a, const void **_b)
 {
-  const networkstatus_t *a = *_a, *b = *_b;
+  const networkstatus_v2_t *a = *_a, *b = *_b;
   if (a->published_on < b->published_on)
     return -1;
   else if (a->published_on > b->published_on)
@@ -222,7 +250,7 @@
 static int
 add_networkstatus_to_cache(const char *s,
                            networkstatus_source_t source,
-                           networkstatus_t *ns)
+                           networkstatus_v2_t *ns)
 {
   if (source != NS_FROM_CACHE) {
     char *fn = networkstatus_get_cache_filename(ns->identity_digest);
@@ -265,10 +293,10 @@
  * invoked after this function succeeds.
  */
 int
-router_set_networkstatus(const char *s, time_t arrived_at,
+router_set_networkstatus_v2(const char *s, time_t arrived_at,
             networkstatus_source_t source, smartlist_t *requested_fingerprints)
 {
-  networkstatus_t *ns;
+  networkstatus_v2_t *ns;
   int i, found;
   time_t now;
   int skewed = 0;
@@ -277,7 +305,10 @@
   char fp[HEX_DIGEST_LEN+1];
   char published[ISO_TIME_LEN+1];
 
-  ns = networkstatus_parse_from_string(s);
+  if (!dirserver_mode(get_options()))
+    return 0; /* Don't bother storing it. */
+
+  ns = networkstatus_v2_parse_from_string(s);
   if (!ns) {
     log_warn(LD_DIR, "Couldn't parse network status.");
     return -1;
@@ -289,7 +320,7 @@
     log_info(LD_DIR, "Network status was signed, but not by an authoritative "
              "directory we recognize.");
     if (!dirserver_mode(get_options())) {
-      networkstatus_free(ns);
+      networkstatus_v2_free(ns);
       return 0;
     }
     source_desc = fp;
@@ -315,13 +346,13 @@
     skewed = 1;
   }
 
-  if (!networkstatus_list)
-    networkstatus_list = smartlist_create();
+  if (!networkstatus_v2_list)
+    networkstatus_v2_list = smartlist_create();
 
   if ( (source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) &&
        router_digest_is_me(ns->identity_digest)) {
     /* Don't replace our own networkstatus when we get it from somebody else.*/
-    networkstatus_free(ns);
+    networkstatus_v2_free(ns);
     return 0;
   }
 
@@ -351,20 +382,20 @@
                "We do not recognize authority (%s) but we are willing "
                "to cache it.", fp);
       add_networkstatus_to_cache(s, source, ns);
-      networkstatus_free(ns);
+      networkstatus_v2_free(ns);
     }
     return 0;
   }
 
   found = 0;
-  for (i=0; i < smartlist_len(networkstatus_list); ++i) {
-    networkstatus_t *old_ns = smartlist_get(networkstatus_list, i);
+  for (i=0; i < smartlist_len(networkstatus_v2_list); ++i) {
+    networkstatus_v2_t *old_ns = smartlist_get(networkstatus_v2_list, i);
 
     if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
       if (!memcmp(old_ns->networkstatus_digest,
                   ns->networkstatus_digest, DIGEST_LEN)) {
         /* Same one we had before. */
-        networkstatus_free(ns);
+        networkstatus_v2_free(ns);
         tor_assert(trusted_dir);
         log_info(LD_DIR,
                  "Not replacing network-status from %s (published %s); "
@@ -391,12 +422,12 @@
                  " we have a newer one (published %s) for this authority.",
                  trusted_dir->description, published,
                  old_published);
-        networkstatus_free(ns);
+        networkstatus_v2_free(ns);
         download_status_failed(&trusted_dir->v2_ns_dl_status, 0);
         return 0;
       } else {
-        networkstatus_free(old_ns);
-        smartlist_set(networkstatus_list, i, ns);
+        networkstatus_v2_free(old_ns);
+        smartlist_set(networkstatus_v2_list, i, ns);
         found = 1;
         break;
       }
@@ -408,7 +439,7 @@
   }
 
   if (!found)
-    smartlist_add(networkstatus_list, ns);
+    smartlist_add(networkstatus_v2_list, ns);
 
   SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
     {
@@ -421,36 +452,35 @@
            ((source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) ?
              "downloaded from":"generated for"),
            trusted_dir->description, published);
-  networkstatus_list_has_changed = 1;
+  networkstatus_v2_list_has_changed = 1;
   router_dir_info_changed();
 
-  smartlist_sort(networkstatus_list, _compare_networkstatus_published_on);
+  smartlist_sort(networkstatus_v2_list,
+                 _compare_networkstatus_v2_published_on);
 
   if (!skewed)
     add_networkstatus_to_cache(s, source, ns);
 
-  networkstatus_list_update_recent(now);
-
   return 0;
 }
 
 /** Remove all very-old network_status_t objects from memory and from the
  * disk cache. */
 void
-networkstatus_list_clean(time_t now)
+networkstatus_v2_list_clean(time_t now)
 {
   int i;
-  if (!networkstatus_list)
+  if (!networkstatus_v2_list)
     return;
 
-  for (i = 0; i < smartlist_len(networkstatus_list); ++i) {
-    networkstatus_t *ns = smartlist_get(networkstatus_list, i);
+  for (i = 0; i < smartlist_len(networkstatus_v2_list); ++i) {
+    networkstatus_v2_t *ns = smartlist_get(networkstatus_v2_list, i);
     char *fname = NULL;
     if (ns->published_on + MAX_NETWORKSTATUS_AGE > now)
       continue;
     /* Okay, this one is too old.  Remove it from the list, and delete it
      * from the cache. */
-    smartlist_del(networkstatus_list, i--);
+    smartlist_del(networkstatus_v2_list, i--);
     fname = networkstatus_get_cache_filename(ns->identity_digest);
     if (file_status(fname) == FN_FILE) {
       log_info(LD_DIR, "Removing too-old networkstatus in %s", fname);
@@ -460,7 +490,7 @@
     if (dirserver_mode(get_options())) {
       dirserv_set_cached_networkstatus_v2(NULL, ns->identity_digest, 0);
     }
-    networkstatus_free(ns);
+    networkstatus_v2_free(ns);
     router_dir_info_changed();
   }
 
@@ -470,7 +500,8 @@
   dirserv_clear_old_v1_info(now);
 }
 
-/** Helper for bsearching a list of routerstatus_t pointers.*/
+/** Helper for bsearching a list of routerstatus_t pointers: compare a
+ * digest in the key to the identity digest of a routerstatus_t. */
 static int
 _compare_digest_to_routerstatus_entry(const void *_key, const void **_member)
 {
@@ -482,78 +513,106 @@
 /** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
  * NULL if none was found. */
 routerstatus_t *
-networkstatus_find_entry(networkstatus_t *ns, const char *digest)
+networkstatus_v2_find_entry(networkstatus_v2_t *ns, const char *digest)
 {
   return smartlist_bsearch(ns->entries, digest,
                            _compare_digest_to_routerstatus_entry);
 }
 
+/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
+ * NULL if none was found. */
+routerstatus_t *
+networkstatus_vote_find_entry(networkstatus_vote_t *ns, const char *digest)
+{
+  return smartlist_bsearch(ns->routerstatus_list, digest,
+                           _compare_digest_to_routerstatus_entry);
+}
+
 /** DOCDOC */
 const smartlist_t *
 networkstatus_get_v2_list(void)
 {
-  if (!networkstatus_list)
-    networkstatus_list = smartlist_create();
-  return networkstatus_list;
+  if (!networkstatus_v2_list)
+    networkstatus_v2_list = smartlist_create();
+  return networkstatus_v2_list;
 }
 
-/** DOCDOC list of routerstatus_t */
-const smartlist_t *
-networkstatus_get_all_statuses(void)
+/** Return the consensus view of the status of the router whose current
+ * <i>descriptor</i> digest is <b>digest</b>, or NULL if no such router is
+ * known. */
+routerstatus_t *
+router_get_consensus_status_by_descriptor_digest(const char *digest)
 {
-  if (!routerstatus_list)
-    routerstatus_list = smartlist_create();
-  return routerstatus_list;
+  if (!current_consensus) return NULL;
+  if (!current_consensus->desc_digest_map) {
+    digestmap_t * m = current_consensus->desc_digest_map = digestmap_new();
+    SMARTLIST_FOREACH(current_consensus->routerstatus_list,
+                      routerstatus_t *, rs,
+     {
+       digestmap_set(m, rs->descriptor_digest, rs);
+     });
+  }
+  return digestmap_get(current_consensus->desc_digest_map, digest);
 }
 
+/** DOCDOC */
+download_status_t *
+router_get_dl_status_by_descriptor_digest(const char *d)
+{
+  routerstatus_t *rs;
+  if ((rs = router_get_consensus_status_by_descriptor_digest(d)))
+    return &rs->dl_status;
+  if (v2_download_status_map)
+    return digestmap_get(v2_download_status_map, d);
+
+  return NULL;
+}
+
 /** Return the consensus view of the status of the router whose identity
  * digest is <b>digest</b>, or NULL if we don't know about any such router. */
 routerstatus_t *
-router_get_combined_status_by_digest(const char *digest)
+router_get_consensus_status_by_id(const char *digest)
 {
-  if (!routerstatus_list)
+  if (!current_consensus)
     return NULL;
-  return smartlist_bsearch(routerstatus_list, digest,
+  return smartlist_bsearch(current_consensus->routerstatus_list, digest,
                            _compare_digest_to_routerstatus_entry);
 }
 
-/** Return the consensus view of the status of the router whose current
- * <i>descriptor</i> digest is <b>digest</b>, or NULL if no such router is
- * known. */
-routerstatus_t *
-router_get_combined_status_by_descriptor_digest(const char *digest)
-{
-  if (!routerstatus_by_desc_digest_map)
-    return NULL;
-  return digestmap_get(routerstatus_by_desc_digest_map, digest);
-}
-
 /** Given a nickname (possibly verbose, possibly a hexadecimal digest), return
  * the corresponding routerstatus_t, or NULL if none exists.  Warn the
  * user if <b>warn_if_unnamed</b> is set, and they have specified a router by
  * nickname, but the Named flag isn't set for that router. */
 routerstatus_t *
-router_get_combined_status_by_nickname(const char *nickname,
+router_get_consensus_status_by_nickname(const char *nickname,
                                        int warn_if_unnamed)
 {
   char digest[DIGEST_LEN];
   routerstatus_t *best=NULL;
   smartlist_t *matches=NULL;
+  const char *named_id=NULL;
 
-  if (!routerstatus_list || !nickname)
+  if (!current_consensus || !nickname)
     return NULL;
 
   if (nickname[0] == '$') {
     if (base16_decode(digest, DIGEST_LEN, nickname+1, strlen(nickname))<0)
       return NULL;
-    return router_get_combined_status_by_digest(digest);
+    return networkstatus_vote_find_entry(current_consensus, digest);
   } else if (strlen(nickname) == HEX_DIGEST_LEN &&
        (base16_decode(digest, DIGEST_LEN, nickname+1, strlen(nickname))==0)) {
-    return router_get_combined_status_by_digest(digest);
+    return networkstatus_vote_find_entry(current_consensus, digest);
   }
 
+  if (named_server_map)
+    named_id = strmap_get_lc(named_server_map, nickname);
+  if (named_id)
+    return networkstatus_vote_find_entry(current_consensus, named_id);
+
+  /*XXXX020 is this behavior really what we want? */
   matches = smartlist_create();
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, lrs,
+  SMARTLIST_FOREACH(current_consensus->routerstatus_list,
+                    routerstatus_t *, lrs,
     {
       if (!strcasecmp(lrs->nickname, nickname)) {
         if (lrs->is_named) {
@@ -606,27 +665,6 @@
   return strmap_get_lc(named_server_map, nickname);
 }
 
-#if 0
-/** Find a routerstatus_t that corresponds to <b>hexdigest</b>, if
- * any. Prefer ones that belong to authorities. */
-routerstatus_t *
-routerstatus_get_by_hexdigest(const char *hexdigest)
-{
-  char digest[DIGEST_LEN];
-  routerstatus_t *rs;
-  trusted_dir_server_t *ds;
-
-  if (strlen(hexdigest) < HEX_DIGEST_LEN ||
-      base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
-    return NULL;
-  if ((ds = router_get_trusteddirserver_by_digest(digest)))
-    return &ds->fake_status;
-  if ((rs = router_get_combined_status_by_digest(digest)))
-    return rs;
-  return NULL;
-}
-#endif
-
 /** How frequently do directory authorities re-download fresh networkstatus
  * documents? */
 #define AUTHORITY_NS_CACHE_INTERVAL (5*60)
@@ -693,143 +731,11 @@
   }
 }
 
-/** How long (in seconds) does a client wait after getting a network status
- * before downloading the next in sequence? */
-#define NETWORKSTATUS_CLIENT_DL_INTERVAL (30*60)
-/** How many times do we allow a networkstatus download to fail before we
- * assume that the authority isn't publishing? */
-#define NETWORKSTATUS_N_ALLOWABLE_FAILURES 3
-/** We are not a directory cache or authority.  Update our network-status list
- * by launching a new directory fetch for enough network-status documents "as
- * necessary".  See function comments for implementation details.
- */
-static void
-update_v2_networkstatus_client_downloads(time_t now)
-{
-  int n_live = 0, n_dirservers, n_running_dirservers, needed = 0;
-  int fetch_latest = 0;
-  int most_recent_idx = -1;
-  trusted_dir_server_t *most_recent = NULL;
-  time_t most_recent_received = 0;
-  char *resource, *cp;
-  size_t resource_len;
-  smartlist_t *missing;
-  const smartlist_t *trusted_dir_servers = router_get_trusted_dir_servers();
-
-  if (connection_get_by_type_purpose(CONN_TYPE_DIR,
-                                     DIR_PURPOSE_FETCH_NETWORKSTATUS))
-    return;
-
-  /* This is a little tricky.  We want to download enough network-status
-   * objects so that we have all of them under
-   * NETWORKSTATUS_MAX_AGE publication time.  We want to download a new
-   * *one* if the most recent one's publication time is under
-   * NETWORKSTATUS_CLIENT_DL_INTERVAL.
-   */
-  if (!get_n_authorities(V2_AUTHORITY))
-    return;
-  n_dirservers = n_running_dirservers = 0;
-  missing = smartlist_create();
-  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
-     {
-       networkstatus_t *ns = networkstatus_get_by_digest(ds->digest);
-       if (!(ds->type & V2_AUTHORITY))
-         continue;
-       ++n_dirservers;
-       if (!download_status_is_ready(&ds->v2_ns_dl_status, now,
-                                     NETWORKSTATUS_N_ALLOWABLE_FAILURES))
-         continue;
-       ++n_running_dirservers;
-       if (ns && ns->published_on > now-NETWORKSTATUS_MAX_AGE)
-         ++n_live;
-       else
-         smartlist_add(missing, ds->digest);
-       if (ns && (!most_recent || ns->received_on > most_recent_received)) {
-         most_recent_idx = ds_sl_idx; /* magic variable from FOREACH */
-         most_recent = ds;
-         most_recent_received = ns->received_on;
-       }
-     });
-
-  /* Also, download at least 1 every NETWORKSTATUS_CLIENT_DL_INTERVAL. */
-  if (!smartlist_len(missing) &&
-      most_recent_received < now-NETWORKSTATUS_CLIENT_DL_INTERVAL) {
-    log_info(LD_DIR, "Our most recent network-status document (from %s) "
-             "is %d seconds old; downloading another.",
-             most_recent?most_recent->description:"nobody",
-             (int)(now-most_recent_received));
-    fetch_latest = 1;
-    needed = 1;
-  } else if (smartlist_len(missing)) {
-    log_info(LD_DIR, "For %d/%d running directory servers, we have %d live"
-             " network-status documents. Downloading %d.",
-             n_running_dirservers, n_dirservers, n_live,
-             smartlist_len(missing));
-    needed = smartlist_len(missing);
-  } else {
-    smartlist_free(missing);
-    return;
-  }
-
-  /* If no networkstatus was found, choose a dirserver at random as "most
-   * recent". */
-  if (most_recent_idx<0)
-    most_recent_idx = crypto_rand_int(smartlist_len(trusted_dir_servers));
-
-  if (fetch_latest) {
-    int i;
-    int n_failed = 0;
-    for (i = most_recent_idx + 1; 1; ++i) {
-      trusted_dir_server_t *ds;
-      if (i >= smartlist_len(trusted_dir_servers))
-        i = 0;
-      ds = smartlist_get(trusted_dir_servers, i);
-      if (!(ds->type & V2_AUTHORITY))
-        continue;
-      if (n_failed >= n_dirservers) {
-        log_info(LD_DIR, "All authorities have failed. Not trying any.");
-        smartlist_free(missing);
-        return;
-      }
-      if (ds->v2_ns_dl_status.n_download_failures >
-          NETWORKSTATUS_N_ALLOWABLE_FAILURES) {
-        ++n_failed;
-        continue;
-      }
-      smartlist_add(missing, ds->digest);
-      break;
-    }
-  }
-
-  /* Build a request string for all the resources we want. */
-  resource_len = smartlist_len(missing) * (HEX_DIGEST_LEN+1) + 6;
-  resource = tor_malloc(resource_len);
-  memcpy(resource, "fp/", 3);
-  cp = resource+3;
-  smartlist_sort_digests(missing);
-  needed = smartlist_len(missing);
-  SMARTLIST_FOREACH(missing, const char *, d,
-    {
-      base16_encode(cp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
-      cp += HEX_DIGEST_LEN;
-      --needed;
-      if (needed)
-        *cp++ = '+';
-    });
-  memcpy(cp, ".z", 3);
-  directory_get_from_dirserver(DIR_PURPOSE_FETCH_NETWORKSTATUS,
-                               ROUTER_PURPOSE_GENERAL, resource, 1);
-  tor_free(resource);
-  smartlist_free(missing);
-}
-
 /** DOCDOC */
 static void
 update_consensus_networkstatus_downloads(time_t now)
 {
   or_options_t *options = get_options();
-  if (!options->DirPort) /*XXXX020 remove this. */
-    return;
   if (time_to_download_next_consensus > now)
     return;
   if (authdir_mode_v3(options))
@@ -902,8 +808,6 @@
     return;
   if (dirserver_mode(options))
     update_v2_networkstatus_cache_downloads(now);
-  else
-    update_v2_networkstatus_client_downloads(now);
   update_consensus_networkstatus_downloads(now);
   if (consensus_waiting_for_certs)
     authority_certs_fetch_missing(consensus_waiting_for_certs, now);
@@ -912,10 +816,10 @@
 }
 
 /** Return the network status with a given identity digest. */
-networkstatus_t *
-networkstatus_get_by_digest(const char *digest)
+networkstatus_v2_t *
+networkstatus_v2_get_by_digest(const char *digest)
 {
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+  SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
     {
       if (!memcmp(ns->identity_digest, digest, DIGEST_LEN))
         return ns;
@@ -944,6 +848,46 @@
     return NULL;
 }
 
+/** DOCDOC */
+static void
+networkstatus_copy_old_consensus_info(networkstatus_vote_t *new_c,
+                                      const networkstatus_vote_t *old_c)
+{
+  int idx = 0;
+  const routerstatus_t *rs_old;
+  if (old_c == new_c)
+    return;
+  if (!smartlist_len(old_c->routerstatus_list))
+    return;
+
+  rs_old = smartlist_get(old_c->routerstatus_list, idx);
+  SMARTLIST_FOREACH(new_c->routerstatus_list, routerstatus_t *, rs_new,
+  {
+    int r;
+    while ((r = memcmp(rs_old->identity_digest, rs_new->identity_digest,
+                       DIGEST_LEN))<0) {
+      if (idx == smartlist_len(old_c->routerstatus_list))
+        goto done;
+      rs_old = smartlist_get(old_c->routerstatus_list, ++idx);
+    }
+    if (r>0)
+      continue;
+    /* Okay, so we're looking at the same identity. */
+    rs_new->name_lookup_warned = rs_old->name_lookup_warned;
+    rs_new->last_dir_503_at = rs_old->last_dir_503_at;
+
+    if (!memcmp(rs_old->descriptor_digest, rs_new->descriptor_digest,
+                DIGEST_LEN)) {
+      /* And the same descriptor too! */
+      rs_new->need_to_mirror = rs_old->need_to_mirror; /*XXXX020 NM ????? */
+      memcpy(&rs_new->dl_status, &rs_old->dl_status,sizeof(download_status_t));
+    }
+  });
+
+ done:
+  return;
+}
+
 /** Try to replace the current cached v3 networkstatus with the one in
  * <b>consensus</b>.  If we don't have enough certificates to validate it,
  * store it in consensus_waiting_for_certs and launch a certificate fetch.
@@ -1006,8 +950,10 @@
   if (r != 1)
     authority_certs_fetch_missing(c, now);
 
-  if (current_consensus)
+  if (current_consensus) {
+    networkstatus_copy_old_consensus_info(c, current_consensus);
     networkstatus_vote_free(current_consensus);
+  }
 
   if (consensus_waiting_for_certs &&
       consensus_waiting_for_certs->valid_after <= c->valid_after) {
@@ -1021,6 +967,7 @@
 
   update_consensus_networkstatus_fetch_time(now);
   dirvote_recalculate_timing(now);
+  routerstatus_list_update_named_server_map();
 
   if (!from_cache) {
     or_options_t *options = get_options();
@@ -1034,6 +981,8 @@
   if (dirserver_mode(get_options()))
     dirserv_set_cached_networkstatus_v3(consensus, c->valid_after);
 
+  router_dir_info_changed();
+
   return 0;
 }
 
@@ -1052,16 +1001,6 @@
   }
 }
 
-/** How many times do we have to fail at getting a networkstatus we can't find
- * before we're willing to believe it's okay to set up router statuses? */
-#define N_NS_ATTEMPTS_TO_SET_ROUTERS 4
-/** How many times do we have to fail at getting a networkstatus we can't find
- * before we're willing to believe it's okay to check our version? */
-#define N_NS_ATTEMPTS_TO_CHECK_VERSION 4
-/** We believe networkstatuses more recent than this when they tell us that
- * our server is broken, invalid, obsolete, etc. */
-#define SELF_OPINION_INTERVAL (90*60)
-
 /** If the network-status list has changed since the last time we called this
  * function, update the status of every routerinfo from the network-status
  * list.
@@ -1069,541 +1008,105 @@
 void
 routers_update_all_from_networkstatus(time_t now)
 {
-  /*XXXX020 Change this function to look at the consensus. */
   routerinfo_t *me;
   routerlist_t *rl = router_get_routerlist();
-  if (!networkstatus_list ||
-      (!networkstatus_list_has_changed && !routerstatus_list_has_changed))
-    return;
+  networkstatus_vote_t *consensus = networkstatus_get_live_consensus(now);
 
   router_dir_info_changed();
 
-  if (networkstatus_list_has_changed)
-    routerstatus_list_update_from_networkstatus(now);
+  if (networkstatus_v2_list_has_changed) {
+    routerstatus_list_update_from_v2_networkstatus();
+    networkstatus_v2_list_has_changed = 0;
+  }
 
-  routers_update_status_from_networkstatus(rl->routers, 0);
+  routers_update_status_from_consensus_networkstatus(rl->routers, 0);
+  SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri,
+                    ri->routerlist_index = ri_sl_idx);
+  entry_guards_compute_status();
 
   me = router_get_my_routerinfo();
-  if (me && !have_warned_about_invalid_status &&
-      have_tried_downloading_all_statuses(N_NS_ATTEMPTS_TO_SET_ROUTERS)) {
-    int n_recent = 0, n_listing = 0, n_valid = 0, n_named = 0, n_naming = 0;
-    routerstatus_t *rs;
-    SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-    {
-      if (ns->received_on + SELF_OPINION_INTERVAL < now)
-        continue;
-      ++n_recent;
-      if (ns->binds_names)
-        ++n_naming;
-      if (!(rs = networkstatus_find_entry(ns, me->cache_info.identity_digest)))
-        continue;
-      ++n_listing;
-      if (rs->is_valid)
-        ++n_valid;
-      if (rs->is_named)
-        ++n_named;
-    });
+  if (me && consensus && !have_warned_about_invalid_status) {
+    routerstatus_t *rs = networkstatus_vote_find_entry(consensus,
+                                        me->cache_info.identity_digest);
 
-    if (n_listing) {
-      if (n_valid <= n_listing/2)  {
-        log_info(LD_GENERAL,
-                 "%d/%d recent statements from directory authorities list us "
-                 "as unapproved. Are you misconfigured?",
-                 n_listing-n_valid, n_listing);
-        have_warned_about_invalid_status = 1;
-      } else if (n_naming && !n_named) {
-        log_info(LD_GENERAL, "0/%d name-binding directory authorities "
-                 "recognize your nickname. Please consider sending your "
-                 "nickname and identity fingerprint to the tor-ops.",
-                 n_naming);
-        have_warned_about_invalid_status = 1;
-      }
+    if (!rs) {
+      log_info(LD_GENERAL, "The latest consensus does not list us."
+               "Are you misconfigured?");
+      have_warned_about_invalid_status = 1;
+    } else if (!rs->is_named) {
+      /*XXXX020 this isn't a correct warning. */
+      log_info(LD_GENERAL,  "The directory authorities do not recognize "
+               "your nickname. Please consider sending your "
+               "nickname and identity fingerprint to the tor-ops.");
+      have_warned_about_invalid_status = 1;
     }
   }
 
-  entry_guards_compute_status();
-
-  if (!have_warned_about_old_version &&
-      have_tried_downloading_all_statuses(N_NS_ATTEMPTS_TO_CHECK_VERSION)) {
-    combined_version_status_t st;
+  if (consensus && !have_warned_about_old_version) {
     int is_server = server_mode(get_options());
-    char *recommended;
+    version_status_t status;
+    const char *recommended = is_server ?
+      consensus->server_versions : consensus->client_versions;
+    status = tor_version_is_obsolete(VERSION, recommended);
 
-    recommended = compute_recommended_versions(now, !is_server, VERSION, &st);
-
-    if (st.n_versioning) {
-      if (st.consensus == VS_RECOMMENDED) {
-        log_info(LD_GENERAL, "%d/%d statements from version-listing "
-                 "directory authorities say my version is ok.",
-                 st.n_concurring, st.n_versioning);
-      } else if (st.consensus == VS_NEW || st.consensus == VS_NEW_IN_SERIES) {
-        if (!have_warned_about_new_version) {
-          log_notice(LD_GENERAL, "This version of Tor (%s) is newer than any "
-                 "recommended version%s, according to %d/%d version-listing "
-                 "network statuses. Versions recommended by more than %d "
-                 "authorit%s are: %s",
-                 VERSION,
-                 st.consensus == VS_NEW_IN_SERIES ? " in its series" : "",
-                 st.n_concurring, st.n_versioning, st.n_versioning/2,
-                 st.n_versioning/2 > 1 ? "ies" : "y", recommended);
-          have_warned_about_new_version = 1;
-          control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
-                 "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
-                 VERSION, "NEW", recommended);
-        }
-      } else {
-        log_warn(LD_GENERAL, "Please upgrade! "
-                 "This version of Tor (%s) is %s, according to %d/%d version-"
-                 "listing network statuses. Versions recommended by "
-                 "at least %d authorit%s are: %s",
-                 VERSION,
-                 st.consensus == VS_OLD ? "obsolete" : "not recommended",
-                 st.n_concurring, st.n_versioning, st.n_versioning/2,
-                 st.n_versioning/2 > 1 ? "ies" : "y", recommended);
-        have_warned_about_old_version = 1;
+    if (status == VS_RECOMMENDED) {
+      log_info(LD_GENERAL, "The directory authorities say my version is ok.");
+    } else if (status == VS_NEW || status == VS_NEW_IN_SERIES) {
+      if (!have_warned_about_new_version) {
+        log_notice(LD_GENERAL, "This version of Tor (%s) is newer than any "
+                   "recommended version%s, according to the directory "
+                   "authorities. Recommended versions are: %s",
+                   VERSION,
+                   status == VS_NEW_IN_SERIES ? " in its series" : "",
+                   recommended);
+        have_warned_about_new_version = 1;
         control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
-                 "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
-                 VERSION, st.consensus == VS_OLD ? "OLD" : "UNRECOMMENDED",
-                 recommended);
+                                     "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
+                                     VERSION, "NEW", recommended);
       }
-    }
-    tor_free(recommended);
-  }
-
-  routerstatus_list_has_changed = 0;
-}
-
-/** Allow any network-status newer than this to influence our view of who's
- * running. */
-#define DEFAULT_RUNNING_INTERVAL (60*60)
-/** If possible, always allow at least this many network-statuses to influence
- * our view of who's running. */
-#define MIN_TO_INFLUENCE_RUNNING 3
-
-/** Change the is_recent field of each member of networkstatus_list so that
- * all members more recent than DEFAULT_RUNNING_INTERVAL are recent, and
- * at least the MIN_TO_INFLUENCE_RUNNING most recent members are recent, and no
- * others are recent.  Set networkstatus_list_has_changed if anything happened.
- */
-void
-networkstatus_list_update_recent(time_t now)
-{
-  /*XXXX020 Nuke this function. */
-  int n_statuses, n_recent, changed, i;
-  char published[ISO_TIME_LEN+1];
-
-  if (!networkstatus_list)
-    return;
-
-  n_statuses = smartlist_len(networkstatus_list);
-  n_recent = 0;
-  changed = 0;
-  for (i=n_statuses-1; i >= 0; --i) {
-    networkstatus_t *ns = smartlist_get(networkstatus_list, i);
-    trusted_dir_server_t *ds =
-      router_get_trusteddirserver_by_digest(ns->identity_digest);
-    const char *src = ds?ds->description:ns->source_address;
-    if (n_recent < MIN_TO_INFLUENCE_RUNNING ||
-        ns->published_on + DEFAULT_RUNNING_INTERVAL > now) {
-      if (!ns->is_recent) {
-        format_iso_time(published, ns->published_on);
-        log_info(LD_DIR,
-                 "Networkstatus from %s (published %s) is now \"recent\"",
-                 src, published);
-        changed = 1;
-      }
-      ns->is_recent = 1;
-      ++n_recent;
     } else {
-      if (ns->is_recent) {
-        format_iso_time(published, ns->published_on);
-        log_info(LD_DIR,
-                 "Networkstatus from %s (published %s) is "
-                 "no longer \"recent\"",
-                 src, published);
-        changed = 1;
-        ns->is_recent = 0;
-      }
+      log_warn(LD_GENERAL, "Please upgrade! "
+               "This version of Tor (%s) is %s, according to the directory "
+               "authorities. Recommended versions are: %s",
+               VERSION,
+               status == VS_OLD ? "obsolete" : "not recommended",
+               recommended);
+      have_warned_about_old_version = 1;
+      control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
+           "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
+           VERSION, status == VS_OLD ? "OLD" : "UNRECOMMENDED",
+           recommended);
     }
   }
-  if (changed) {
-    networkstatus_list_has_changed = 1;
-    router_dir_info_changed();
-  }
 }
 
-/** Helper for routerstatus_list_update_from_networkstatus: remember how many
- * authorities recommend a given descriptor digest. */
-typedef struct {
-  routerstatus_t *rs;
-  int count;
-} desc_digest_count_t;
-
-/** Update our view of router status (as stored in routerstatus_list) from the
- * current set of network status documents (as stored in networkstatus_list).
- * Do nothing unless the network status list has changed since the last time
- * this function was called.
- */
-void
-routerstatus_list_update_from_networkstatus(time_t now)
+/** DOCDOC */
+static void
+routerstatus_list_update_from_v2_networkstatus(void)
 {
-  /* XXXX020 nuke this function.  It serves no point in v3 */
-  or_options_t *options = get_options();
-  int n_trusted, n_statuses, n_recent = 0, n_naming = 0;
-  int n_listing_bad_exits = 0, n_listing_bad_directories = 0;
-  int i, j, warned;
-  int *index, *size;
-  networkstatus_t **networkstatus;
-  smartlist_t *result, *changed_list;
-  strmap_t *name_map;
-  char conflict[DIGEST_LEN]; /* Sentinel value */
-  desc_digest_count_t *digest_counts = NULL;
-
-  /* compute which network statuses will have a vote now */
-  networkstatus_list_update_recent(now);
-  router_dir_info_changed();
-
-  if (!networkstatus_list_has_changed)
+  digestmap_t *dl_status;
+  if (!networkstatus_v2_list)
     return;
-  if (!networkstatus_list)
-    networkstatus_list = smartlist_create();
-  if (!routerstatus_list)
-    routerstatus_list = smartlist_create();
-  if (!warned_conflicts)
-    warned_conflicts = smartlist_create();
+  if (!v2_download_status_map)
+    v2_download_status_map = digestmap_new();
 
-  n_statuses = smartlist_len(networkstatus_list);
-  n_trusted = get_n_authorities(V2_AUTHORITY);
-
-  if (n_statuses <= n_trusted/2) {
-    /* Not enough statuses to adjust status. */
-    log_info(LD_DIR,
-             "Not enough statuses to update router status list. (%d/%d)",
-             n_statuses, n_trusted);
-    return;
-  }
-
-  log_info(LD_DIR, "Rebuilding router status list.");
-
-  index = tor_malloc(sizeof(int)*n_statuses);
-  size = tor_malloc(sizeof(int)*n_statuses);
-  networkstatus = tor_malloc(sizeof(networkstatus_t *)*n_statuses);
-  for (i = 0; i < n_statuses; ++i) {
-    index[i] = 0;
-    networkstatus[i] = smartlist_get(networkstatus_list, i);
-    size[i] = smartlist_len(networkstatus[i]->entries);
-    if (networkstatus[i]->binds_names)
-      ++n_naming;
-    if (networkstatus[i]->is_recent)
-      ++n_recent;
-    if (networkstatus[i]->lists_bad_exits)
-      ++n_listing_bad_exits;
-    if (networkstatus[i]->lists_bad_directories)
-      ++n_listing_bad_directories;
-  }
-
-  /** Iterate over all entries in all networkstatuses, and build
-   * name_map as a map from lc nickname to identity digest.  If there
-   * is a conflict on that nickname, map the lc nickname to conflict.
-   */
-  name_map = strmap_new();
-  /* Clear the global map... */
-  if (named_server_map)
-    strmap_free(named_server_map, _tor_free);
-  named_server_map = strmap_new();
-  memset(conflict, 0xff, sizeof(conflict));
-  for (i = 0; i < n_statuses; ++i) {
-    if (!networkstatus[i]->binds_names)
-      continue;
-    SMARTLIST_FOREACH(networkstatus[i]->entries, routerstatus_t *, rs,
+  dl_status = digestmap_new();
+  SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
+  {
+    SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
     {
-      const char *other_digest;
-      if (!rs->is_named)
+      const char *d = rs->descriptor_digest;
+      download_status_t *s;
+      if (digestmap_get(dl_status, d))
         continue;
-      other_digest = strmap_get_lc(name_map, rs->nickname);
-      warned = smartlist_string_isin(warned_conflicts, rs->nickname);
-      if (!other_digest) {
-        strmap_set_lc(name_map, rs->nickname, rs->identity_digest);
-        strmap_set_lc(named_server_map, rs->nickname,
-                      tor_memdup(rs->identity_digest, DIGEST_LEN));
-        if (warned)
-          smartlist_string_remove(warned_conflicts, rs->nickname);
-      } else if (memcmp(other_digest, rs->identity_digest, DIGEST_LEN) &&
-                 other_digest != conflict) {
-        if (!warned) {
-          char *d;
-          int should_warn = authdir_mode(options);
-          char fp1[HEX_DIGEST_LEN+1];
-          char fp2[HEX_DIGEST_LEN+1];
-          base16_encode(fp1, sizeof(fp1), other_digest, DIGEST_LEN);
-          base16_encode(fp2, sizeof(fp2), rs->identity_digest, DIGEST_LEN);
-          log_fn(should_warn ? LOG_WARN : LOG_INFO, LD_DIR,
-                 "Naming authorities disagree about which key goes with %s. "
-                 "($%s vs $%s)",
-                 rs->nickname, fp1, fp2);
-          strmap_set_lc(name_map, rs->nickname, conflict);
-          d = strmap_remove_lc(named_server_map, rs->nickname);
-          tor_free(d);
-          smartlist_add(warned_conflicts, tor_strdup(rs->nickname));
-        }
-      } else {
-        if (warned)
-          smartlist_string_remove(warned_conflicts, rs->nickname);
+      if (!(s = digestmap_remove(v2_download_status_map, d))) {
+        s = tor_malloc_zero(sizeof(download_status_t));
       }
+      digestmap_set(dl_status, d, s);
     });
-  }
-
-  result = smartlist_create();
-  changed_list = smartlist_create();
-  digest_counts = tor_malloc_zero(sizeof(desc_digest_count_t)*n_statuses);
-
-  /* Iterate through all of the sorted routerstatus lists in lockstep.
-   * Invariants:
-   *  - For 0 <= i < n_statuses: index[i] is an index into
-   *    networkstatus[i]->entries, which has size[i] elements.
-   *  - For i1, i2, j such that 0 <= i1 < n_statuses, 0 <= i2 < n_statues, 0 <=
-   *    j < index[i1]: networkstatus[i1]->entries[j]->identity_digest <
-   *    networkstatus[i2]->entries[index[i2]]->identity_digest.
-   *
-   *    (That is, the indices are always advanced past lower digest before
-   *    higher.)
-   */
-  while (1) {
-    int n_running=0, n_named=0, n_valid=0, n_listing=0;
-    int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0, n_guard=0, n_bad_exit=0;
-    int n_bad_directory=0;
-    int n_version_known=0, n_supports_begindir=0;
-    int n_supports_extrainfo_upload=0;
-    int n_desc_digests=0, highest_count=0;
-    const char *the_name = NULL;
-    routerstatus_t *rs_out, *rs_old;
-    routerstatus_t *rs, *most_recent;
-    networkstatus_t *ns;
-    const char *lowest = NULL;
-
-    /* Find out which of the digests appears first. */
-    for (i = 0; i < n_statuses; ++i) {
-      if (index[i] < size[i]) {
-        rs = smartlist_get(networkstatus[i]->entries, index[i]);
-        if (!lowest || memcmp(rs->identity_digest, lowest, DIGEST_LEN)<0)
-          lowest = rs->identity_digest;
-      }
-    }
-    if (!lowest) {
-      /* We're out of routers. Great! */
-      break;
-    }
-    /* Okay. The routers at networkstatus[i]->entries[index[i]] whose digests
-     * match "lowest" are next in order. Iterate over them, incrementing those
-     * index[i] as we go. */
-    for (i = 0; i < n_statuses; ++i) {
-      if (index[i] >= size[i])
-        continue;
-      ns = networkstatus[i];
-      rs = smartlist_get(ns->entries, index[i]);
-      if (memcmp(rs->identity_digest, lowest, DIGEST_LEN))
-        continue;
-      /* At this point, we know that we're looking at a routersatus with
-       * identity "lowest".
-       */
-      ++index[i];
-      ++n_listing;
-      /* Should we name this router? Only if all the names from naming
-       * authorities match. */
-      if (rs->is_named && ns->binds_names) {
-        if (!the_name)
-          the_name = rs->nickname;
-        if (!strcasecmp(rs->nickname, the_name)) {
-          ++n_named;
-        } else if (strcmp(the_name,"**mismatch**")) {
-          char hd[HEX_DIGEST_LEN+1];
-          base16_encode(hd, HEX_DIGEST_LEN+1, rs->identity_digest, DIGEST_LEN);
-          if (! smartlist_string_isin(warned_conflicts, hd)) {
-            log_warn(LD_DIR,
-                     "Naming authorities disagree about nicknames for $%s "
-                     "(\"%s\" vs \"%s\")",
-                     hd, the_name, rs->nickname);
-            smartlist_add(warned_conflicts, tor_strdup(hd));
-          }
-          the_name = "**mismatch**";
-        }
-      }
-      /* Keep a running count of how often which descriptor digests
-       * appear. */
-      for (j = 0; j < n_desc_digests; ++j) {
-        if (!memcmp(rs->descriptor_digest,
-                    digest_counts[j].rs->descriptor_digest, DIGEST_LEN)) {
-          if (++digest_counts[j].count > highest_count)
-            highest_count = digest_counts[j].count;
-          goto found;
-        }
-      }
-      digest_counts[n_desc_digests].rs = rs;
-      digest_counts[n_desc_digests].count = 1;
-      if (!highest_count)
-        highest_count = 1;
-      ++n_desc_digests;
-    found:
-      /* Now tally up the easily-tallied flags. */
-      if (rs->is_valid)
-        ++n_valid;
-      if (rs->is_running && ns->is_recent)
-        ++n_running;
-      if (rs->is_exit)
-        ++n_exit;
-      if (rs->is_fast)
-        ++n_fast;
-      if (rs->is_possible_guard)
-        ++n_guard;
-      if (rs->is_stable)
-        ++n_stable;
-      if (rs->is_v2_dir)
-        ++n_v2_dir;
-      if (rs->is_bad_exit)
-        ++n_bad_exit;
-      if (rs->is_bad_directory)
-        ++n_bad_directory;
-      if (rs->version_known)
-        ++n_version_known;
-      if (rs->version_supports_begindir)
-        ++n_supports_begindir;
-      if (rs->version_supports_extrainfo_upload)
-        ++n_supports_extrainfo_upload;
-    }
-    /* Go over the descriptor digests and figure out which descriptor we
-     * want. */
-    most_recent = NULL;
-    for (i = 0; i < n_desc_digests; ++i) {
-      /* If any digest appears twice or more, ignore those that don't.*/
-      if (highest_count >= 2 && digest_counts[i].count < 2)
-        continue;
-      if (!most_recent ||
-          digest_counts[i].rs->published_on > most_recent->published_on)
-        most_recent = digest_counts[i].rs;
-    }
-    rs_out = tor_malloc_zero(sizeof(routerstatus_t));
-    memcpy(rs_out, most_recent, sizeof(routerstatus_t));
-    /* Copy status info about this router, if we had any before. */
-    if ((rs_old = router_get_combined_status_by_digest(lowest))) {
-      if (!memcmp(rs_out->descriptor_digest,
-                  most_recent->descriptor_digest, DIGEST_LEN)) {
-        rs_out->dl_status.n_download_failures =
-          rs_old->dl_status.n_download_failures;
-        rs_out->dl_status.next_attempt_at = rs_old->dl_status.next_attempt_at;
-      }
-      rs_out->name_lookup_warned = rs_old->name_lookup_warned;
-      rs_out->last_dir_503_at = rs_old->last_dir_503_at;
-    }
-    smartlist_add(result, rs_out);
-    log_debug(LD_DIR, "Router '%s' is listed by %d/%d directories, "
-              "named by %d/%d, validated by %d/%d, and %d/%d recent "
-              "directories think it's running.",
-              rs_out->nickname,
-              n_listing, n_statuses, n_named, n_naming, n_valid, n_statuses,
-              n_running, n_recent);
-    rs_out->is_named  = 0;
-    if (the_name && strcmp(the_name, "**mismatch**") && n_named > 0) {
-      const char *d = strmap_get_lc(name_map, the_name);
-      if (d && d != conflict)
-        rs_out->is_named = 1;
-      if (smartlist_string_isin(warned_conflicts, rs_out->nickname))
-        smartlist_string_remove(warned_conflicts, rs_out->nickname);
-    }
-    if (rs_out->is_named)
-      strlcpy(rs_out->nickname, the_name,
-              sizeof(rs_out->nickname));
-    rs_out->is_valid = n_valid > n_statuses/2;
-    rs_out->is_running = n_running > n_recent/2;
-    rs_out->is_exit = n_exit > n_statuses/2;
-    rs_out->is_fast = n_fast > n_statuses/2;
-    rs_out->is_possible_guard = n_guard > n_statuses/2;
-    rs_out->is_stable = n_stable > n_statuses/2;
-    rs_out->is_v2_dir = n_v2_dir > n_statuses/2;
-    rs_out->is_bad_exit = n_bad_exit > n_listing_bad_exits/2;
-    rs_out->is_bad_directory =
-      n_bad_directory > n_listing_bad_directories/2;
-    rs_out->version_known = n_version_known > 0;
-    rs_out->version_supports_begindir =
-      n_supports_begindir > n_version_known/2;
-    rs_out->version_supports_extrainfo_upload =
-      n_supports_extrainfo_upload > n_version_known/2;
-    if (!rs_old || memcmp(rs_old, rs_out, sizeof(routerstatus_t)))
-      smartlist_add(changed_list, rs_out);
-  }
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-                    routerstatus_free(rs));
-
-  smartlist_free(routerstatus_list);
-  routerstatus_list = result;
-
-  if (routerstatus_by_desc_digest_map)
-    digestmap_free(routerstatus_by_desc_digest_map, NULL);
-  routerstatus_by_desc_digest_map = digestmap_new();
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-                    digestmap_set(routerstatus_by_desc_digest_map,
-                                  rs->descriptor_digest,
-                                  rs));
-
-  tor_free(networkstatus);
-  tor_free(index);
-  tor_free(size);
-  tor_free(digest_counts);
-  strmap_free(name_map, NULL);
-
-  networkstatus_list_has_changed = 0;
-  routerstatus_list_has_changed = 1;
-
-  control_event_networkstatus_changed(changed_list);
-  smartlist_free(changed_list);
-}
-
-/** Given a list <b>routers</b> of routerinfo_t *, update each routers's
- * is_named, is_valid, and is_running fields according to our current
- * networkstatus_t documents. */  /* XXXX020 obsoleted by v3 */
-void
-routers_update_status_from_networkstatus(smartlist_t *routers,
-                                         int reset_failures)
-{
-  /*XXXX020 remove this. while function */
-  trusted_dir_server_t *ds;
-  routerstatus_t *rs;
-  or_options_t *options = get_options();
-  int authdir = authdir_mode_v2(options);
-  int namingdir = authdir && options->NamingAuthoritativeDir;
-
-  if (!routerstatus_list)
-    return;
-
-  SMARTLIST_FOREACH(routers, routerinfo_t *, router,
-  {
-    const char *digest = router->cache_info.identity_digest;
-    rs = router_get_combined_status_by_digest(digest);
-    ds = router_get_trusteddirserver_by_digest(digest);
-
-    if (!rs)
-      continue;
-
-    if (!namingdir)
-      router->is_named = rs->is_named;
-
-    if (!authdir) {
-      /* If we're not an authdir, believe others. */
-      router->is_valid = rs->is_valid;
-      router->is_running = rs->is_running;
-      router->is_fast = rs->is_fast;
-      router->is_stable = rs->is_stable;
-      router->is_possible_guard = rs->is_possible_guard;
-      router->is_exit = rs->is_exit;
-      router->is_bad_exit = rs->is_bad_exit;
-    }
-    if (router->is_running && ds) {
-      download_status_reset(&ds->v2_ns_dl_status);
-    }
-    if (reset_failures) {
-      download_status_reset(&rs->dl_status);
-    }
   });
-  router_dir_info_changed();
+  digestmap_free(v2_download_status_map, _tor_free);
+  v2_download_status_map = dl_status;
 }
 
 /** Update our view of router status (as stored in routerstatus_list) from the
@@ -1611,12 +1114,9 @@
  * Do nothing unless the network status list has changed since the last time
  * this function was called. DOCDOC
  */
-void
-routerstatus_list_update_from_consensus_networkstatus(time_t now)
+static void
+routerstatus_list_update_named_server_map(void)
 {
-  /* XXXX020 use this function */
-  (void)now;
-
   if (!current_consensus)
     return;
 
@@ -1630,19 +1130,6 @@
                    tor_memdup(rs->identity_digest, DIGEST_LEN));
       }
     });
-
-  if (routerstatus_by_desc_digest_map)
-    digestmap_free(routerstatus_by_desc_digest_map, NULL);
-  routerstatus_by_desc_digest_map = digestmap_new();
-  SMARTLIST_FOREACH(current_consensus->routerstatus_list, routerstatus_t *, rs,
-                    digestmap_set(routerstatus_by_desc_digest_map,
-                                  rs->descriptor_digest,
-                                  rs));
-
-  /* XXXX020 memcpy extra information from old consensus, somewhere. */
-
-  /* XXXX020 incorporate entries from v2 networkstatuses, for download
-   * purposees. */
 }
 
 /** Given a list <b>routers</b> of routerinfo_t *, update each routers's
@@ -1652,7 +1139,6 @@
 routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
                                                    int reset_failures)
 {
-  /*XXXX020 use this function */
   trusted_dir_server_t *ds;
   routerstatus_t *rs;
   or_options_t *options = get_options();
@@ -1712,27 +1198,6 @@
   router_dir_info_changed();
 }
 
-/** Return true iff we have downloaded, or attempted to download at least
- * n_failures times, a network status for each authority. */
-static int
-have_tried_downloading_all_statuses(int n_failures)
-{
-  smartlist_t *trusted_dir_servers = router_get_trusted_dir_servers();
-
-  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
-    {
-      if (!(ds->type & V2_AUTHORITY))
-        continue;
-      /* If we don't have the status, and we haven't failed to get the status,
-       * we haven't tried to get the status. */
-      if (!networkstatus_get_by_digest(ds->digest) &&
-          ds->v2_ns_dl_status.n_download_failures <= n_failures)
-        return 0;
-    });
-
-  return 1;
-}
-
 /** Generate networkstatus lines for a single routerstatus_t object, and
  * return the result in a newly allocated string.  Used only by controller
  * interface (for now.) */
@@ -1755,14 +1220,15 @@
   routerstatus_t *status;
   (void) conn;
 
-  if (!routerstatus_list) {
+  if (!current_consensus) {
     *answer = tor_strdup("");
     return 0;
   }
 
   if (!strcmp(question, "ns/all")) {
     smartlist_t *statuses = smartlist_create();
-    SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
+    SMARTLIST_FOREACH(current_consensus->routerstatus_list,
+                      routerstatus_t *, rs,
       {
         smartlist_add(statuses, networkstatus_getinfo_helper_single(rs));
       });
@@ -1775,9 +1241,9 @@
 
     if (base16_decode(d, DIGEST_LEN, question+6, strlen(question+6)))
       return -1;
-    status = router_get_combined_status_by_digest(d);
+    status = router_get_consensus_status_by_id(d);
   } else if (!strcmpstart(question, "ns/name/")) {
-    status = router_get_combined_status_by_nickname(question+8, 0);
+    status = router_get_consensus_status_by_nickname(question+8, 0);
   } else {
     return -1;
   }
@@ -1792,22 +1258,12 @@
 void
 networkstatus_free_all(void)
 {
-  if (networkstatus_list) {
-    SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-                      networkstatus_free(ns));
-    smartlist_free(networkstatus_list);
-    networkstatus_list = NULL;
+  if (networkstatus_v2_list) {
+    SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
+                      networkstatus_v2_free(ns));
+    smartlist_free(networkstatus_v2_list);
+    networkstatus_v2_list = NULL;
   }
-  if (routerstatus_list) {
-    SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-                      routerstatus_free(rs));
-    smartlist_free(routerstatus_list);
-    routerstatus_list = NULL;
-  }
-  if (routerstatus_by_desc_digest_map) {
-    digestmap_free(routerstatus_by_desc_digest_map, NULL);
-    routerstatus_by_desc_digest_map = NULL;
-  }
   if (current_consensus) {
     networkstatus_vote_free(current_consensus);
     current_consensus = NULL;

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/or.h	2007-10-15 23:15:24 UTC (rev 11957)
@@ -120,12 +120,6 @@
 #define cell_t tor_cell_t
 #endif
 
-/** Undefine this when it's time to stop generating v1 directories. */
-// #define FULL_V1_DIRECTORIES
-/** Undefine this when it's time to stop includeing bandwidth info in router
- * descriptors. */
-#define INCLUDE_BW_INFO_IN_ROUTERDESCS
-
 /** Length of longest allowable configured nickname. */
 #define MAX_NICKNAME_LEN 19
 /** Length of a router identity encoded as a hexadecimal digest, plus
@@ -172,8 +166,6 @@
 #define ROUTER_MAX_AGE_TO_PUBLISH (60*60*20)
 /** How old do we let a saved descriptor get before force-removing it? */
 #define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5)
-/** How old do we let a networkstatus get before ignoring it? */
-#define NETWORKSTATUS_MAX_AGE (60*60*24)
 
 /** Possible rules for generating circuit IDs on an OR connection. */
 typedef enum {
@@ -342,26 +334,24 @@
 #define DIR_PURPOSE_UPLOAD_RENDDESC 9
 /** A connection to a directory server: upload a v3 networkstatus vote. */
 #define DIR_PURPOSE_UPLOAD_VOTE 10
-/** A connection to a directory server: fetch a v3 networkstatus vote. */
-#define DIR_PURPOSE_FETCH_VOTE 11
 /** A connection to a directory server: upload a v3 consensus signature */
-#define DIR_PURPOSE_UPLOAD_SIGNATURES 12
+#define DIR_PURPOSE_UPLOAD_SIGNATURES 11
 /** A connection to a directory server: download one or more network-status
  * objects */
-#define DIR_PURPOSE_FETCH_STATUS_VOTE 13
+#define DIR_PURPOSE_FETCH_STATUS_VOTE 12
 /** A connection to a directory server: download one or more network-status
  * objects */
-#define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 14
+#define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 13
 /** A connection to a directory server: download one or more network-status
  * objects */
-#define DIR_PURPOSE_FETCH_CONSENSUS 15
+#define DIR_PURPOSE_FETCH_CONSENSUS 14
 /** A connection to a directory server: download one or more network-status
  * objects */
-#define DIR_PURPOSE_FETCH_CERTIFICATE 16
+#define DIR_PURPOSE_FETCH_CERTIFICATE 15
 
 /** Purpose for connection at a directory server. */
-#define DIR_PURPOSE_SERVER 17
-#define _DIR_PURPOSE_MAX 17
+#define DIR_PURPOSE_SERVER 16
+#define _DIR_PURPOSE_MAX 16
 
 #define _EXIT_PURPOSE_MIN 1
 /** This exit stream wants to do an ordinary connect. */
@@ -1274,7 +1264,7 @@
 #define MAX_ROUTERDESC_DOWNLOAD_FAILURES 8
 
 /** Contents of a v2 (non-consensus, non-vote) network status object. */
-typedef struct networkstatus_t {
+typedef struct networkstatus_v2_t {
   /** When did we receive the network-status document? */
   time_t received_on;
 
@@ -1312,7 +1302,7 @@
 
   smartlist_t *entries; /**< List of routerstatus_t*.   This list is kept
                          * sorted by identity_digest. */
-} networkstatus_t;
+} networkstatus_v2_t;
 
 /** The claim about a single router, make in a vote. */
 typedef struct vote_routerstatus_t {
@@ -1385,6 +1375,10 @@
    * the elements are vote_routerstatus_t; for a consensus, the elements
    * are routerstatus_t. */
   smartlist_t *routerstatus_list;
+
+  /** If present, a map from descriptor digest to elements of
+   * routerstatus_list. */
+  digestmap_t *desc_digest_map;
 } networkstatus_vote_t;
 
 /** A set of signatures for a networkstatus consensus.  All fields are as for
@@ -1466,7 +1460,6 @@
                                           * display. */
   char identity_digest[DIGEST_LEN]; /**< Hash of this router's identity key. */
   uint16_t port; /**< OR port. */
-//  uint8_t router_purpose; /**< General, controller, or bridge. */
   uint32_t addr; /**< IP address in host order. */
   crypto_pk_env_t *onion_key; /**< Current onionskin key. */
 } extend_info_t;
@@ -2310,7 +2303,6 @@
                                  crypto_pk_env_t *onion_key,
                                  uint32_t addr, uint16_t port);
 extend_info_t *extend_info_from_router(routerinfo_t *r);
-//extend_info_t *extend_info_from_routerstatus(routerstatus_t *s);
 extend_info_t *extend_info_dup(extend_info_t *info);
 void extend_info_free(extend_info_t *info);
 routerinfo_t *build_state_get_exit_router(cpath_build_state_t *state);
@@ -3058,52 +3050,43 @@
   VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
                        * in its series, but later recommended versions exist.
                        */
-  VS_UNRECOMMENDED=4 /**< This version is not recommended (general case). */
+  VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */
+  VS_UNKNOWN, /**< We have no idea. */
 } version_status_t;
 
-typedef struct combined_version_status_t {
-  /** How many networkstatuses claim to know about versions? */
-  int n_versioning;
-  /** What do the majority of networkstatuses believe about this version? */
-  enum version_status_t consensus;
-  /** How many networkstatuses constitute the majority? */
-  int n_concurring;
-} combined_version_status_t;
-
 void networkstatus_reset_warnings(void);
-int router_reload_networkstatus(void);
+void networkstatus_reset_download_failures(void);
+int router_reload_v2_networkstatus(void);
 int router_reload_consensus_networkstatus(void);
 void routerstatus_free(routerstatus_t *rs);
-void networkstatus_free(networkstatus_t *ns);
+void networkstatus_v2_free(networkstatus_v2_t *ns);
 char *networkstatus_get_cache_filename(const char *identity_digest);
-int router_set_networkstatus(const char *s, time_t arrived_at,
+int router_set_networkstatus_v2(const char *s, time_t arrived_at,
                              networkstatus_source_t source,
                              smartlist_t *requested_fingerprints);
-void networkstatus_list_clean(time_t now);
-routerstatus_t *networkstatus_find_entry(networkstatus_t *ns,
+void networkstatus_v2_list_clean(time_t now);
+routerstatus_t *networkstatus_v2_find_entry(networkstatus_v2_t *ns,
                                          const char *digest);
+routerstatus_t *networkstatus_vote_find_entry(networkstatus_vote_t *ns,
+                                              const char *digest);
 const smartlist_t *networkstatus_get_v2_list(void);
-const smartlist_t *networkstatus_get_all_statuses(void);
-routerstatus_t *router_get_combined_status_by_digest(const char *digest);
-routerstatus_t *router_get_combined_status_by_descriptor_digest(const char *d);
-routerstatus_t *router_get_combined_status_by_nickname(const char *nickname,
+download_status_t *router_get_dl_status_by_descriptor_digest(const char *d);
+routerstatus_t *router_get_consensus_status_by_id(const char *digest);
+routerstatus_t *router_get_consensus_status_by_descriptor_digest(
+                                                        const char *digest);
+routerstatus_t *router_get_consensus_status_by_nickname(const char *nickname,
                                                        int warn_if_unnamed);
 const char *networkstatus_get_router_digest_by_nickname(const char *nickname);
-routerstatus_t *routerstatus_get_by_hexdigest(const char *hexdigest);
 void networkstatus_consensus_download_failed(int status_code);
 int should_delay_dir_fetches(or_options_t *options);
 void update_networkstatus_downloads(time_t now);
-networkstatus_t *networkstatus_get_by_digest(const char *digest);
+networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest);
 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 was_waiting_for_certs);
 void networkstatus_note_certs_arrived(void);
 void routers_update_all_from_networkstatus(time_t now);
-void networkstatus_list_update_recent(time_t now);
-void routerstatus_list_update_from_networkstatus(time_t now);
-void routers_update_status_from_networkstatus(smartlist_t *routers,
-                                              int reset_failures);
 void routerstatus_list_update_from_consensus_networkstatus(time_t now);
 void routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
                                                         int reset_failures);
@@ -3628,9 +3611,6 @@
                        authority_type_t type);
 void clear_trusted_dir_servers(void);
 int any_trusted_dir_is_v1_authority(void);
-char *compute_recommended_versions(time_t now, int client,
-                                   const char *my_version,
-                                   combined_version_status_t *status_out);
 void update_router_descriptor_downloads(time_t now);
 void update_extrainfo_downloads(time_t now);
 int router_have_minimum_dir_info(void);
@@ -3695,7 +3675,6 @@
                                                     int assume_action);
 version_status_t tor_version_is_obsolete(const char *myversion,
                                          const char *versionlist);
-version_status_t version_status_join(version_status_t a, version_status_t b);
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_as_new_as(const char *platform, const char *cutoff);
 int tor_version_compare(tor_version_t *a, tor_version_t *b);
@@ -3703,7 +3682,7 @@
 void assert_addr_policy_ok(addr_policy_t *t);
 void dump_distinct_digest_count(int severity);
 
-networkstatus_t *networkstatus_parse_from_string(const char *s);
+networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s);
 networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
                                                           const char **eos_out,
                                                           int is_vote);

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/routerlist.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -468,6 +468,7 @@
   int r = -1;
   off_t offset = 0;
   smartlist_t *signed_descriptors = NULL;
+  int nocache=0;
 
   if (!force && !router_should_rebuild_store(store))
     return 0;
@@ -506,11 +507,9 @@
     }
   } else {
     SMARTLIST_FOREACH(routerlist->old_routers, signed_descriptor_t *, sd,
-                      if (desc_get_store(routerlist, sd) == store)
-                        smartlist_add(signed_descriptors, sd));
+                      smartlist_add(signed_descriptors, sd));
     SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
-                      if (router_get_store(routerlist, ri) == store)
-                        smartlist_add(signed_descriptors, &ri->cache_info));
+                      smartlist_add(signed_descriptors, &ri->cache_info));
   }
 
   smartlist_sort(signed_descriptors, _compare_signed_descriptors_by_age);
@@ -524,8 +523,10 @@
         log_warn(LD_BUG, "No descriptor available for router.");
         goto done;
       }
-      if (sd->do_not_cache)
+      if (sd->do_not_cache) {
+        ++nocache;
         continue;
+      }
       c = tor_malloc(sizeof(sized_chunk_t));
       c->bytes = body;
       c->len = sd->signed_descriptor_len + sd->annotations_len;
@@ -549,8 +550,10 @@
   }
 
   store->mmap = tor_mmap_file(fname);
-  if (! store->mmap)
+  if (! store->mmap) {
     log_warn(LD_FS, "Unable to mmap new descriptor file at '%s'.",fname);
+    //tor_assert(0);
+  }
 
   log_info(LD_DIR, "Reconstructing pointers into cache");
 
@@ -688,8 +691,6 @@
     return -1;
   if (router_reload_router_list_impl(&rl->extrainfo_store))
     return -1;
-  if (trusted_dirs_reload_certs())
-    return -1;
   return 0;
 }
 
@@ -844,8 +845,11 @@
   smartlist_t *trusted_direct, *trusted_tunnel;
   smartlist_t *overloaded_direct, *overloaded_tunnel;
   time_t now = time(NULL);
-  const smartlist_t *routerstatus_list = networkstatus_get_all_statuses();
+  const networkstatus_vote_t *consensus = networkstatus_get_latest_consensus();
 
+  if (!consensus)
+    return NULL;
+
   direct = smartlist_create();
   tunnel = smartlist_create();
   trusted_direct = smartlist_create();
@@ -854,7 +858,7 @@
   overloaded_tunnel = smartlist_create();
 
   /* Find all the running dirservers we know about. */
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, status,
+  SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, status,
   {
     int is_trusted;
     int is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
@@ -997,7 +1001,7 @@
       routerstatus_t *rs;
       dir->is_running = 1;
       download_status_reset(&dir->v2_ns_dl_status);
-      rs = router_get_combined_status_by_digest(dir->digest);
+      rs = router_get_consensus_status_by_id(dir->digest);
       if (rs && !rs->is_running) {
         rs->is_running = 1;
         rs->last_dir_503_at = 0;
@@ -1147,7 +1151,7 @@
       if (!must_be_running || router->is_running) {
         smartlist_add(sl,router);
       }
-    } else if (!router_get_combined_status_by_nickname(nick,1)) {
+    } else if (!router_get_consensus_status_by_nickname(nick,1)) {
       if (!warned) {
         log_fn(have_dir_info ? LOG_WARN : LOG_INFO, LD_CONFIG,
                "Nickname list includes '%s' which isn't a known router.",nick);
@@ -1714,6 +1718,8 @@
     return rimap_get(routerlist->identity_map, named_digest);
   }
 
+  /* If we reach this point, there's no canonical value for the nickname. */
+
   SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
   {
     if (!strcasecmp(router->nickname, nickname)) {
@@ -1742,7 +1748,7 @@
           char fp[HEX_DIGEST_LEN+1];
           if (strcasecmp(router->nickname, nickname))
             continue;
-          rs = router_get_combined_status_by_digest(
+          rs = router_get_consensus_status_by_id(
                                           router->cache_info.identity_digest);
           if (rs && !rs->name_lookup_warned) {
             rs->name_lookup_warned = 1;
@@ -1768,7 +1774,7 @@
       SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
       smartlist_free(fps);
     } else if (warn_if_unnamed) {
-      routerstatus_t *rs = router_get_combined_status_by_digest(
+      routerstatus_t *rs = router_get_consensus_status_by_id(
           best_match->cache_info.identity_digest);
       if (rs && !rs->name_lookup_warned) {
         char fp[HEX_DIGEST_LEN+1];
@@ -2134,15 +2140,6 @@
       smartlist_len(routerlist->old_routers), U64_PRINTF_ARG(olddescs));
 }
 
-/** Return the greatest number of routerdescs we'll hold for any given router.
- */
-static int
-max_descriptors_per_router(void)
-{
-  int n_authorities = get_n_v2_authorities();
-  return (n_authorities < 5) ? 5 : n_authorities;
-}
-
 /** Return non-zero if we have a lot of extra descriptors in our
  * routerlist, and should get rid of some of them. Else return 0.
  *
@@ -2154,8 +2151,12 @@
 static INLINE int
 routerlist_is_overfull(routerlist_t *rl)
 {
-  return smartlist_len(rl->old_routers) >
-    smartlist_len(rl->routers)*(max_descriptors_per_router()+1);
+  /*XXXX020 no longer wholly logical.*/
+  if (dirserver_mode(get_options())) {
+    return smartlist_len(rl->old_routers) > smartlist_len(rl->routers)*5;
+  } else {
+    return smartlist_len(rl->old_routers) > smartlist_len(rl->routers)*2;
+  }
 }
 
 static INLINE int
@@ -2541,7 +2542,7 @@
                "addresses reachable?");
     router->is_running = up;
   }
-  status = router_get_combined_status_by_digest(digest);
+  status = router_get_consensus_status_by_id(digest);
   if (status && status->is_running != up) {
     status->is_running = up;
     control_event_networkstatus_changed_single(status);
@@ -2574,8 +2575,8 @@
  * server or via the controller.)
  *
  * This function should be called *after*
- * routers_update_status_from_networkstatus; subsequently, you should call
- * router_rebuild_store and routerlist_descriptors_added.
+ * routers_update_status_from_consensus_networkstatus; subsequently, you
+ * should call router_rebuild_store and routerlist_descriptors_added.
  */
 int
 router_add_to_routerlist(routerinfo_t *router, const char **msg,
@@ -2590,7 +2591,9 @@
   int authdir_may_warn_about_unreachable_server =
     authdir && !from_cache && !from_fetch &&
     router_have_minimum_dir_info();
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
+  networkstatus_vote_t *consensus = networkstatus_get_latest_consensus();
+  const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
+  int in_consensus = 0;
 
   tor_assert(msg);
 
@@ -2644,16 +2647,38 @@
   }
 
   /* We no longer need a router with this descriptor digest. */
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+  SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
   {
     routerstatus_t *rs =
-      networkstatus_find_entry(ns, router->cache_info.identity_digest);
+      networkstatus_v2_find_entry(ns, router->cache_info.identity_digest);
     if (rs && !memcmp(rs->descriptor_digest,
                       router->cache_info.signed_descriptor_digest,
                       DIGEST_LEN))
       rs->need_to_mirror = 0;
   });
+  if (consensus) {
+    routerstatus_t *rs = networkstatus_vote_find_entry(consensus,
+                                        router->cache_info.identity_digest);
+    if (rs && !memcmp(rs->descriptor_digest,
+                      router->cache_info.signed_descriptor_digest,
+                      DIGEST_LEN)) {
+      in_consensus = 1;
+      rs->need_to_mirror = 0;
+    }
+  }
 
+  /*XXXX020 I had suspicions about whether this was correct, but now I
+   * can't remember why. :( -NM */
+  if (consensus && !in_consensus && !authdir_mode(get_options())) {
+    /* If it's not listed in the consensus, then don't consider replacing
+     * the latest router with it. */
+    if (!from_cache && should_cache_old_descriptors())
+      signed_desc_append_to_journal(&router->cache_info,
+                                    router_get_store(routerlist, router));
+    routerlist_insert_old(routerlist, router);
+    return -1;
+  }
+
   /* If we have a router with the same identity key, choose the newer one. */
   old_router = rimap_get(routerlist->identity_map,
                          router->cache_info.identity_digest);
@@ -2802,7 +2827,7 @@
 
   /* Check whether we need to do anything at all. */
   {
-    int mdpr = max_descriptors_per_router();
+    int mdpr = dirserver_mode(get_options()) ? 5 : 2;
     if (n <= mdpr)
       return;
     n_extra = n - mdpr;
@@ -2874,11 +2899,13 @@
   routerinfo_t *router;
   signed_descriptor_t *sd;
   digestmap_t *retain;
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
+  int dirserv = dirserver_mode(get_options());
+  const networkstatus_vote_t *consensus = networkstatus_get_latest_consensus();
+  const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
 
   trusted_dirs_remove_old_certs();
 
-  if (!routerlist || !networkstatus_list)
+  if (!routerlist || !consensus)
     return;
 
   routerlist_assert_ok(routerlist);
@@ -2886,7 +2913,8 @@
   retain = digestmap_new();
   cutoff = now - OLD_ROUTER_DESC_MAX_AGE;
   /* Build a list of all the descriptors that _anybody_ lists. */
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+  if (dirserv) {
+    SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
     {
       /* XXXX The inner loop here gets pretty expensive, and actually shows up
        * on some profiles.  It may be the reason digestmap_set shows up in
@@ -2900,22 +2928,21 @@
         if (rs->published_on >= cutoff)
           digestmap_set(retain, rs->descriptor_digest, (void*)1));
     });
+  }
 
-  {
-    /* Retain anything listed in the consensus. */
-    networkstatus_vote_t *ns = networkstatus_get_latest_consensus();
-    if (ns) {
-      SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs,
+  /* Retain anything listed in the consensus. */
+  if (consensus) {
+    SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
         if (rs->published_on >= cutoff)
           digestmap_set(retain, rs->descriptor_digest, (void*)1));
-    }
   }
 
   /* If we have a bunch of networkstatuses, we should consider pruning current
    * routers that are too old and that nobody recommends.  (If we don't have
    * enough networkstatuses, then we should get more before we decide to kill
    * routers.) */
-  if (smartlist_len(networkstatus_list) > get_n_v2_authorities() / 2) {
+  if (!dirserv ||
+      smartlist_len(networkstatus_v2_list) > get_n_v2_authorities() / 2) {
     cutoff = now - ROUTER_MAX_AGE;
     /* Remove too-old unrecommended members of routerlist->routers. */
     for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
@@ -2955,7 +2982,7 @@
    * total number doesn't approach max_descriptors_per_router()*len(router).
    */
   if (smartlist_len(routerlist->old_routers) <
-      smartlist_len(routerlist->routers) * (max_descriptors_per_router() - 1))
+      smartlist_len(routerlist->routers) * (dirserver_mode(get_options())?4:2))
     goto done;
 
   smartlist_sort(routerlist->old_routers, _compare_old_routers_by_identity);
@@ -3040,7 +3067,7 @@
 
   lst = smartlist_create();
   smartlist_add(lst, ri);
-  routers_update_status_from_networkstatus(lst, 0);
+  routers_update_status_from_consensus_networkstatus(lst, 0);
 
   if ((r=router_add_to_routerlist(ri, msg, 0, 0))<0) {
     /* we've already assigned to *msg now, and ri is already freed */
@@ -3086,7 +3113,7 @@
   router_parse_list_from_string(&s, eos, routers, saved_location, 0,
                                 allow_annotations, prepend_annotations);
 
-  routers_update_status_from_networkstatus(routers, !from_cache);
+  routers_update_status_from_consensus_networkstatus(routers, !from_cache);
 
   log_info(LD_DIR, "%d elements to add", smartlist_len(routers));
 
@@ -3171,16 +3198,26 @@
 signed_desc_digest_is_recognized(signed_descriptor_t *desc)
 {
   routerstatus_t *rs;
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
+  networkstatus_vote_t *consensus = networkstatus_get_latest_consensus();
+  int dirserv = dirserver_mode(get_options());
+  const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
 
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-  {
-    if (!(rs = networkstatus_find_entry(ns, desc->identity_digest)))
-      continue;
-    if (!memcmp(rs->descriptor_digest,
-                desc->signed_descriptor_digest, DIGEST_LEN))
+  if (consensus) {
+    rs = networkstatus_vote_find_entry(consensus, desc->identity_digest);
+    if (rs && !memcmp(rs->descriptor_digest,
+                      desc->signed_descriptor_digest, DIGEST_LEN))
       return 1;
-  });
+  }
+  if (dirserv && networkstatus_v2_list) {
+    SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
+    {
+      if (!(rs = networkstatus_v2_find_entry(ns, desc->identity_digest)))
+        continue;
+      if (!memcmp(rs->descriptor_digest,
+                  desc->signed_descriptor_digest, DIGEST_LEN))
+        return 1;
+    });
+  }
   return 0;
 }
 
@@ -3336,103 +3373,6 @@
   return 0;
 }
 
-/** Return a newly allocated string naming the versions of Tor recommended by
- * more than half the versioning networkstatuses. */
-char *
-compute_recommended_versions(time_t now, int client,
-                             const char *my_version,
-                             combined_version_status_t *status_out)
-{
-  int n_seen;
-  char *current;
-  smartlist_t *combined, *recommended;
-  int n_versioning, n_recommending;
-  char *result;
-  /** holds the compromise status taken among all non-recommending
-   * authorities */
-  version_status_t consensus = VS_RECOMMENDED;
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
-  (void) now; /* right now, we consider *all* statuses, regardless of age. */
-
-  tor_assert(my_version);
-  tor_assert(status_out);
-
-  memset(status_out, 0, sizeof(combined_version_status_t));
-
-  if (!networkstatus_list)
-    return tor_strdup("<none>");
-
-  combined = smartlist_create();
-  n_versioning = n_recommending = 0;
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-    {
-      const char *vers;
-      smartlist_t *versions;
-      version_status_t status;
-      if (! ns->recommends_versions)
-        continue;
-      n_versioning++;
-      vers = client ? ns->client_versions : ns->server_versions;
-      if (!vers)
-        continue;
-      versions = smartlist_create();
-      smartlist_split_string(versions, vers, ",",
-                             SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
-      sort_version_list(versions, 1);
-      smartlist_add_all(combined, versions);
-      smartlist_free(versions);
-
-      /* now, check _our_ version */
-      status = tor_version_is_obsolete(my_version, vers);
-      if (status == VS_RECOMMENDED)
-        n_recommending++;
-      consensus = version_status_join(status, consensus);
-    });
-
-  sort_version_list(combined, 0);
-
-  current = NULL;
-  n_seen = 0;
-  recommended = smartlist_create();
-  SMARTLIST_FOREACH(combined, char *, cp,
-    {
-      if (current && !strcmp(cp, current)) {
-        ++n_seen;
-      } else {
-        if (current)
-          log_info(LD_DIR,"version %s is recommended by %d authorities",
-                    current, n_seen);
-        if (n_seen > n_versioning/2 && current) {
-          smartlist_add(recommended, current);
-        }
-        n_seen = 1;
-        current = cp;
-      }
-    });
-  if (current)
-    log_info(LD_DIR,"version %s is recommended by %d authorities",
-             current, n_seen);
-  if (n_seen > n_versioning/2 && current)
-    smartlist_add(recommended, current);
-
-  result = smartlist_join_strings(recommended, ", ", 0, NULL);
-
-  SMARTLIST_FOREACH(combined, char *, cp, tor_free(cp));
-  smartlist_free(combined);
-  smartlist_free(recommended);
-
-  status_out->n_versioning = n_versioning;
-  if (n_recommending > n_versioning/2) {
-    status_out->consensus = VS_RECOMMENDED;
-    status_out->n_concurring = n_recommending;
-  } else {
-    status_out->consensus = consensus;
-    status_out->n_concurring = n_versioning - n_recommending;
-  }
-
-  return result;
-}
-
 /** DOCDOC */
 static void
 list_pending_downloads(digestmap_t *result,
@@ -3541,129 +3481,27 @@
   return 1;
 }
 
-/** Return new list of ID fingerprints for routers that we (as a client) would
- * like to download.
+/** Max amount of hashes to download per request.
+ * Since squid does not like URLs >= 4096 bytes we limit it to 96.
+ *   4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
+ *   4058/41 (40 for the hash and 1 for the + that separates them) => 98
+ *   So use 96 because it's a nice number.
  */
-static smartlist_t *
-router_list_client_downloadable(void)
-{
-  int n_downloadable = 0;
-  smartlist_t *downloadable = smartlist_create();
-  digestmap_t *downloading;
-  time_t now = time(NULL);
-  /* these are just used for logging */
-  int n_not_ready = 0, n_in_progress = 0, n_uptodate = 0, n_wouldnt_use = 0;
-  or_options_t *options = get_options();
-  const smartlist_t *routerstatus_list = networkstatus_get_all_statuses();
-
-  if (!smartlist_len(routerstatus_list))
-    return downloadable;
-
-  downloading = digestmap_new();
-  list_pending_descriptor_downloads(downloading, 0);
-
-  routerstatus_list_update_from_networkstatus(now);
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-  {
-    routerinfo_t *ri;
-    if (router_get_by_descriptor_digest(rs->descriptor_digest)) {
-      /* We have the 'best' descriptor for this router. */
-      ++n_uptodate;
-    } else if (!client_would_use_router(rs, now, options)) {
-      /* We wouldn't want this descriptor even if we got it. */
-      ++n_wouldnt_use;
-    } else if (digestmap_get(downloading, rs->descriptor_digest)) {
-      /* We're downloading this one now. */
-      ++n_in_progress;
-    } else if ((ri = router_get_by_digest(rs->identity_digest)) &&
-               ri->cache_info.published_on > rs->published_on) {
-      /* Oddly, we have a descriptor more recent than the 'best' one, but it
-         was once best. So that's okay. */
-      ++n_uptodate;
-    } else if (!download_status_is_ready(&rs->dl_status, now,
-                                         MAX_ROUTERDESC_DOWNLOAD_FAILURES)) {
-      /* We failed too recently to try again. */
-      ++n_not_ready;
-    } else {
-      /* Okay, time to try it. */
-      smartlist_add(downloadable, rs->descriptor_digest);
-      ++n_downloadable;
-    }
-  });
-
-#if 0
-  log_info(LD_DIR,
-       "%d router descriptors are downloadable. "
-       "%d are in progress. %d are up-to-date. "
-       "%d are non-useful. %d failed too recently to retry.",
-       n_downloadable, n_in_progress, n_uptodate,
-       n_wouldnt_use, n_not_ready);
-#endif
-
-  digestmap_free(downloading, NULL);
-  return downloadable;
-}
-
-/** Initiate new router downloads as needed, using the strategy for
- * non-directory-servers.
- *
- * We don't launch any downloads if there are fewer than MAX_DL_TO_DELAY
- * descriptors to get and less than MAX_CLIENT_INTERVAL_WITHOUT_REQUEST
- * seconds have passed.
- *
- * Otherwise, we ask for all descriptors that we think are different from what
- * we have, and that we don't currently have an in-progress download attempt
- * for. */
-static void
-update_router_descriptor_client_downloads(time_t now)
-{
-  /** Max amount of hashes to download per request.
-   * Since squid does not like URLs >= 4096 bytes we limit it to 96.
-   *   4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
-   *   4058/41 (40 for the hash and 1 for the + that separates them) => 98
-   *   So use 96 because it's a nice number.
-   */
 #define MAX_DL_PER_REQUEST 96
-  /** Don't split our requests so finely that we are requesting fewer than
-   * this number per server. */
+/** Don't split our requests so finely that we are requesting fewer than
+ * this number per server. */
 #define MIN_DL_PER_REQUEST 4
-  /** To prevent a single screwy cache from confusing us by selective reply,
-   * try to split our requests into at least this this many requests. */
+/** To prevent a single screwy cache from confusing us by selective reply,
+ * try to split our requests into at least this this many requests. */
 #define MIN_REQUESTS 3
-  /** If we want fewer than this many descriptors, wait until we
-   * want more, or until MAX_CLIENT_INTERVAL_WITHOUT_REQUEST has
-   * passed. */
+/** If we want fewer than this many descriptors, wait until we
+ * want more, or until MAX_CLIENT_INTERVAL_WITHOUT_REQUEST has
+ * passed. */
 #define MAX_DL_TO_DELAY 16
-  /** When directory clients have only a few servers to request, they batch
-   * them until they have more, or until this amount of time has passed. */
+/** When directory clients have only a few servers to request, they batch
+ * them until they have more, or until this amount of time has passed. */
 #define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60)
-  smartlist_t *downloadable = NULL;
-  or_options_t *options = get_options();
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
 
-  if (dirserver_mode(options)) {
-    log_warn(LD_BUG,
-             "Called router_descriptor_client_downloads() on a dir mirror?");
-  }
-
-  if (rep_hist_circbuilding_dormant(now)) {
-//    log_info(LD_CIRC, "Skipping descriptor downloads: we haven't needed "
-//             "any circuits lately.");
-    return;
-  }
-
-  if (networkstatus_list &&
-      smartlist_len(networkstatus_list) <= get_n_v2_authorities()/2) {
-    log_info(LD_DIR,
-             "Not enough networkstatus documents to launch requests.");
-    return;
-  }
-
-  downloadable = router_list_client_downloadable();
-  launch_router_descriptor_downloads(downloadable, now);
-  smartlist_free(downloadable);
-}
-
 /** DOCDOC */
 static void
 launch_router_descriptor_downloads(smartlist_t *downloadable, time_t now)
@@ -3734,18 +3572,18 @@
   int i, j, n;
   int n_download;
   or_options_t *options = get_options();
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
+  const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
 
   if (! dirserver_mode(options)) {
     log_warn(LD_BUG, "Called update_router_descriptor_cache_downloads() "
              "on a non-dir-mirror?");
   }
 
-  if (!networkstatus_list || !smartlist_len(networkstatus_list))
+  if (!networkstatus_v2_list || !smartlist_len(networkstatus_v2_list))
     return;
 
   map = digestmap_new();
-  n = smartlist_len(networkstatus_list);
+  n = smartlist_len(networkstatus_v2_list);
 
   downloadable = tor_malloc_zero(sizeof(smartlist_t*) * n);
   download_from = tor_malloc_zero(sizeof(smartlist_t*) * n);
@@ -3760,7 +3598,7 @@
    * descriptor from the corresponding authority.
    */
   n_download = 0;
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+  SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
     {
       trusted_dir_server_t *ds;
       smartlist_t *dl;
@@ -3837,7 +3675,7 @@
 
   /* Now, we can actually launch our requests. */
   for (i=0; i<n; ++i) {
-    networkstatus_t *ns = smartlist_get(networkstatus_list, i);
+    networkstatus_v2_t *ns = smartlist_get(networkstatus_v2_list, i);
     trusted_dir_server_t *ds =
       router_get_trusteddirserver_by_digest(ns->identity_digest);
     smartlist_t *dl = download_from[i];
@@ -3874,7 +3712,7 @@
   smartlist_t *downloadable = smartlist_create();
   int authdir = authdir_mode(options);
   int dirserver = dirserver_mode(options);
-  networkstatus_vote_t *consensus = networkstatus_get_latest_consensus();
+  networkstatus_vote_t *consensus = networkstatus_get_live_consensus(now);
 
   if (!dirserver) {
     if (rep_hist_circbuilding_dormant(now))
@@ -3887,17 +3725,9 @@
   list_pending_descriptor_downloads(map, 0);
   SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
     {
-      routerstatus_t *lrs;
       if (router_get_by_descriptor_digest(rs->descriptor_digest))
         continue; /* We have it already. */
-
-      /* XXXX020 change this once the real consensus is the canonical place
-       * to go for router information. */
-      lrs = router_get_combined_status_by_digest(rs->identity_digest);
-      if (!lrs ||
-          memcmp(lrs->descriptor_digest, rs->descriptor_digest, DIGEST_LEN))
-        lrs = rs;
-      if (!download_status_is_ready(&lrs->dl_status, now,
+      if (!download_status_is_ready(&rs->dl_status, now,
                                     MAX_ROUTERDESC_DOWNLOAD_FAILURES))
         continue;
 
@@ -3925,10 +3755,8 @@
     return;
   if (dirserver_mode(options)) {
     update_router_descriptor_cache_downloads(now);
-    update_consensus_router_descriptor_downloads(now); /*XXXX020 clients too*/
-  } else {
-    update_router_descriptor_client_downloads(now);
   }
+  update_consensus_router_descriptor_downloads(now);
 }
 
 /** Return true iff <b>sd</b> is the descriptor for a router descriptor that
@@ -3990,19 +3818,6 @@
   smartlist_free(wanted);
 }
 
-/** Return the number of routerstatus_t in <b>entries</b> that we'd actually
- * use. */
-static int
-routerstatus_count_usable_entries(smartlist_t *entries)
-{
-  int count = 0;
-  time_t now = time(NULL);
-  or_options_t *options = get_options();
-  SMARTLIST_FOREACH(entries, routerstatus_t *, rs,
-                    if (client_would_use_router(rs, now, options)) count++);
-  return count;
-}
-
 /** True iff, the last time we checked whether we had enough directory info
  * to build circuits, the answer was "yes". */
 static int have_min_dir_info = 0;
@@ -4041,20 +3856,18 @@
 static void
 update_router_have_minimum_dir_info(void)
 {
-  int tot = 0, num_running = 0;
-  int n_ns, n_authorities, res, avg;
+  /*XXX020 call when dirserver_mode() changes. */
+  int num_present = 0, num_usable=0;
   time_t now = time(NULL);
-  const smartlist_t *routerstatus_list = networkstatus_get_all_statuses();
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
+  int res;
+  or_options_t *options = get_options();
+  const networkstatus_vote_t *consensus =
+    networkstatus_get_live_consensus(now);
 
-  if (!routerlist) {
+  if (!consensus) {
     res = 0;
     goto done;
   }
-  /*XXXX020 remove this call. routerlist_remove_old_routers shows up in some
-   * profiles, and this is the biggest caller of that function. */
-  routerlist_remove_old_routers();
-  networkstatus_list_clean(now);
 
   if (should_delay_dir_fetches(get_options())) {
     log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
@@ -4062,24 +3875,17 @@
     goto done;
   }
 
-  n_authorities = get_n_v2_authorities();
-  n_ns = smartlist_len(networkstatus_list);
-  if (n_ns<=n_authorities/2) {
-    log_info(LD_DIR,
-             "We have %d of %d network statuses, and we want "
-             "more than %d.", n_ns, n_authorities, n_authorities/2);
-    res = 0;
-    goto done;
-  }
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-                    tot += routerstatus_count_usable_entries(ns->entries));
-  avg = tot / n_ns;
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
+  SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
      {
-       if (rs->is_running)
-         num_running++;
+       if (client_would_use_router(rs, now, options)) {
+         ++num_usable;
+         if (router_get_by_digest(rs->identity_digest)) {
+           ++num_present;
+         }
+       }
      });
-  res = smartlist_len(routerlist->routers) >= (avg/4) && num_running > 2;
+  res = num_present >= num_usable/4 && num_usable > 2;
+
  done:
   if (res && !have_min_dir_info) {
     log(LOG_NOTICE, LD_DIR,
@@ -4089,7 +3895,7 @@
   if (!res && have_min_dir_info) {
     log(LOG_NOTICE, LD_DIR,"Our directory information is no longer up-to-date "
         "enough to build circuits.%s",
-        num_running > 2 ? "" : " (Not enough servers seem reachable -- "
+        num_usable > 2 ? "" : " (Not enough servers seem reachable -- "
         "is your network connection down?)");
     control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
   }
@@ -4102,18 +3908,7 @@
 void
 router_reset_descriptor_download_failures(void)
 {
-  const smartlist_t *networkstatus_list = networkstatus_get_v2_list();
-  const smartlist_t *routerstatus_list = networkstatus_get_all_statuses();
-  SMARTLIST_FOREACH(routerstatus_list, routerstatus_t *, rs,
-  {
-    download_status_reset(&rs->dl_status);
-  });
-  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-     SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
-       {
-         if (!router_get_by_descriptor_digest(rs->descriptor_digest))
-           rs->need_to_mirror = 1;
-       }));
+  networkstatus_reset_download_failures();
   last_routerdesc_download_attempted = 0;
   if (!routerlist)
     return;

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2007-10-15 23:15:18 UTC (rev 11956)
+++ tor/trunk/src/or/routerparse.c	2007-10-15 23:15:24 UTC (rev 11957)
@@ -564,36 +564,6 @@
   return ret;
 }
 
-/** Return the combined status of the current version, given that we know of
- * one set of networkstatuses that give us status <b>a</b>, and another that
- * gives us status <b>b</b>.
- *
- * For example, if one authority thinks that we're NEW, and another thinks
- * we're OLD, we're simply UNRECOMMENDED.
- *
- * This function does not handle calculating whether we're RECOMMENDED; that
- * follows a simple majority rule.  This function simply calculates *why*
- * we're not recommended (if we're not).
- */
-version_status_t
-version_status_join(version_status_t a, version_status_t b)
-{
-  if (a == b)
-    return a;
-  else if (a == VS_UNRECOMMENDED || b == VS_UNRECOMMENDED)
-    return VS_UNRECOMMENDED;
-  else if (a == VS_RECOMMENDED)
-    return b;
-  else if (b == VS_RECOMMENDED)
-    return a;
-  /* Okay.  Neither is 'recommended' or 'unrecommended', and they differ. */
-  else if (a == VS_OLD || b == VS_OLD)
-    return VS_UNRECOMMENDED;
-  /* One is VS_NEW, the other is VS_NEW_IN_SERIES */
-  else
-    return VS_NEW_IN_SERIES;
-}
-
 /** Read a signed directory from <b>str</b>.  If it's well-formed, return 0.
  * Otherwise, return -1.  If we're a directory cache, cache it.
  */
@@ -1722,13 +1692,13 @@
  * signature of the network status, but do not (yet) check the signing key for
  * authority.
  */
-networkstatus_t *
-networkstatus_parse_from_string(const char *s)
+networkstatus_v2_t *
+networkstatus_v2_parse_from_string(const char *s)
 {
   const char *eos;
   smartlist_t *tokens = smartlist_create();
   smartlist_t *footer_tokens = smartlist_create();
-  networkstatus_t *ns = NULL;
+  networkstatus_v2_t *ns = NULL;
   char ns_digest[DIGEST_LEN];
   char tmp_digest[DIGEST_LEN];
   struct in_addr in;
@@ -1745,7 +1715,7 @@
     log_warn(LD_DIR, "Error tokenizing network-status header.");
     goto err;
   }
-  ns = tor_malloc_zero(sizeof(networkstatus_t));
+  ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
   memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
 
   tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
@@ -1876,7 +1846,7 @@
   goto done;
  err:
   if (ns)
-    networkstatus_free(ns);
+    networkstatus_v2_free(ns);
   ns = NULL;
  done:
   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));



More information about the tor-commits mailing list