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

[or-cvs] [tor/master] Merge remote branch 'origin/maint-0.2.2' for bug2203_rebased



commit 69f7c0385b16acdfa4a38cb36c86aaceebf61301
Merge: a6c8113 e9803aa
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date:   Fri Feb 4 12:26:59 2011 -0500

    Merge remote branch 'origin/maint-0.2.2' for bug2203_rebased
    
    There was a merge conflict in routerlist.c due to the new node_t logic.
    
    Conflicts:
    	src/or/routerlist.c

 changes/bug2203       |    6 ++++++
 doc/spec/dir-spec.txt |    5 +++++
 src/or/dirvote.c      |   11 +++++++++--
 src/or/routerlist.c   |    2 +-
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --combined doc/spec/dir-spec.txt
index df1b798,c843a7c..49b64e8
--- a/doc/spec/dir-spec.txt
+++ b/doc/spec/dir-spec.txt
@@@ -530,8 -530,16 +530,8 @@@
          dns logic.  Versions of Tor with this field set to false SHOULD NOT
          be used for reverse hostname lookups.
  
 -        [All versions of Tor before 0.1.2.2-alpha should be assumed to have
 -         this option set to 0 if it is not present.  All Tor versions at
 -         0.1.2.2-alpha or later should be assumed to have this option set to
 -         1 if it is not present.  Until 0.1.2.1-alpha-dev, this option was
 -         not generated, even when the new DNS code was in use.  Versions of Tor
 -         before 0.1.2.1-alpha-dev did not parse this option, so it should be
 -         marked "opt".  The dnsworker logic has been removed, so this option
 -         should not be used by new server code.  However, it can still be
 -         used, and should still be recognized by new code until Tor 0.1.2.x
 -         is obsolete.]
 +        [This option is obsolete.  All Tor current servers should be presumed
 +         to have the evdns backend.]
  
     "caches-extra-info" NL
  
@@@ -622,12 -630,6 +622,12 @@@
  
          As documented in 2.1 above.  See migration notes in section 2.2.1.
  
 +    "geoip-db-digest" Digest NL
 +        [At most once.]
 +
 +        SHA1 digest of the GeoIP database file that is used to resolve IP
 +        addresses to country codes.
 +
      ("geoip-start" YYYY-MM-DD HH:MM:SS NL)
      ("geoip-client-origins" CC=N,CC=N,... NL)
  
@@@ -848,20 -850,6 +848,20 @@@
          Mean number of circuits that are included in any of the deciles,
          rounded up to the next integer.
  
 +    "conn-bi-direct" YYYY-MM-DD HH:MM:SS (NSEC s) BELOW,READ,WRITE,BOTH NL
 +        [At most once]
 +
 +        Number of connections, split into 10-second intervals, that are
 +        used uni-directionally or bi-directionally as observed in the NSEC
 +        seconds (usually 86400 seconds) before YYYY-MM-DD HH:MM:SS.  Every
 +        10 seconds, we determine for every connection whether we read and
 +        wrote less than a threshold of 20 KiB (BELOW), read at least 10
 +        times more than we wrote (READ), wrote at least 10 times more than
 +        we read (WRITE), or read and wrote more than the threshold, but
 +        not 10 times more in either direction (BOTH).  After classifying a
 +        connection, read and write counters are reset for the next
 +        10-second interval.
 +
      "exit-stats-end" YYYY-MM-DD HH:MM:SS (NSEC s) NL
          [At most once.]
  
@@@ -1199,11 -1187,9 +1199,11 @@@
          proxies. See trac entry 1751 for details.
          Min: 0, Max: 1
  
 -        See also "2.4.5. Consensus parameters governing behavior"
 -        in path-spec.txt for a series of circuit build time related
 -        consensus params.
 +        "cbtdisabled", "cbtnummodes", "cbtrecentcount", "cbtmaxtimeouts",
 +        "cbtmincircs", "cbtquantile", "cbtclosequantile", "cbttestfreq",
 +        "cbtmintimeout", and "cbtinitialtimeout" -- see "2.4.5. Consensus
 +        parameters governing behavior" in path-spec.txt for a series of
 +        circuit build time related consensus params.
  
     The authority section of a vote contains the following items, followed
     in turn by the authority's current key certificate:
@@@ -1632,6 -1618,11 +1632,11 @@@
          * If consensus-method 7 or later is in use, the params line is
            included in the output.
  
+         * If the consensus method is under 11, bad exits are considered as
+           possible exits when computing bandwidth weights.  Otherwise, if
+           method 11 or later is in use, any router that is determined to get
+           the BadExit flag doesn't count when we're calculating weights.
+ 
       The signatures at the end of a consensus document are sorted in
       ascending order by identity digest.
  
diff --combined src/or/dirvote.c
index 8ef5b14,529b45c..1052da9
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@@ -50,7 -50,7 +50,7 @@@ static int dirvote_publish_consensus(vo
  static char *make_consensus_method_list(int low, int high, const char *sep);
  
  /** The highest consensus method that we currently support. */
- #define MAX_SUPPORTED_CONSENSUS_METHOD 10
+ #define MAX_SUPPORTED_CONSENSUS_METHOD 11
  
  /** Lowest consensus method that contains a 'directory-footer' marker */
  #define MIN_METHOD_FOR_FOOTER 9
@@@ -83,7 -83,9 +83,7 @@@ format_networkstatus_vote(crypto_pk_env
    const char *client_versions = NULL, *server_versions = NULL;
    char *outp, *endp;
    char fingerprint[FINGERPRINT_LEN+1];
 -  char ipaddr[INET_NTOA_BUF_LEN];
    char digest[DIGEST_LEN];
 -  struct in_addr in;
    uint32_t addr;
    routerlist_t *rl = router_get_routerlist();
    char *version_lines = NULL;
@@@ -96,6 -98,8 +96,6 @@@
    voter = smartlist_get(v3_ns->voters, 0);
  
    addr = voter->addr;
 -  in.s_addr = htonl(addr);
 -  tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
  
    base16_encode(fingerprint, sizeof(fingerprint),
                  v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
@@@ -182,8 -186,7 +182,8 @@@
                   flags,
                   params,
                   voter->nickname, fingerprint, voter->address,
 -                 ipaddr, voter->dir_port, voter->or_port, voter->contact);
 +                 fmt_addr32(addr), voter->dir_port, voter->or_port,
 +                 voter->contact);
  
      if (r < 0) {
        log_err(LD_BUG, "Insufficient memory for network status line");
@@@ -1526,6 -1529,8 +1526,6 @@@ networkstatus_compute_consensus(smartli
      smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id);
  
      SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) {
 -      struct in_addr in;
 -      char ip[INET_NTOA_BUF_LEN];
        char fingerprint[HEX_DIGEST_LEN+1];
        char votedigest[HEX_DIGEST_LEN+1];
        networkstatus_t *v = e->v;
@@@ -1535,6 -1540,8 +1535,6 @@@
        if (e->is_legacy)
          tor_assert(consensus_method >= 2);
  
 -      in.s_addr = htonl(voter->addr);
 -      tor_inet_ntoa(&in, ip, sizeof(ip));
        base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN);
        base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
                      DIGEST_LEN);
@@@ -1542,7 -1549,7 +1542,7 @@@
        tor_asprintf(&buf,
                     "dir-source %s%s %s %s %s %d %d\n",
                     voter->nickname, e->is_legacy ? "-legacy" : "",
 -                   fingerprint, voter->address, ip,
 +                   fingerprint, voter->address, fmt_addr32(voter->addr),
                     voter->dir_port,
                     voter->or_port);
        smartlist_add(chunks, buf);
@@@ -1686,7 -1693,7 +1686,7 @@@
        const char *chosen_name = NULL;
        int exitsummary_disagreement = 0;
        int is_named = 0, is_unnamed = 0, is_running = 0;
-       int is_guard = 0, is_exit = 0;
+       int is_guard = 0, is_exit = 0, is_bad_exit = 0;
        int naming_conflict = 0;
        int n_listing = 0;
        int i;
@@@ -1812,6 -1819,8 +1812,8 @@@
                is_guard = 1;
              else if (!strcmp(fl, "Running"))
                is_running = 1;
+             else if (!strcmp(fl, "BadExit"))
+               is_bad_exit = 1;
            }
          }
        });
@@@ -1838,6 -1847,11 +1840,11 @@@
          rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
        }
  
+       /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
+       if (consensus_method >= 11) {
+         is_exit = is_exit && !is_bad_exit;
+       }
+ 
        if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
          if (rs_out.has_bandwidth) {
            T += rs_out.bandwidth;
diff --combined src/or/routerlist.c
index 380e34b,6d63862..66066f6
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@@ -22,9 -22,7 +22,9 @@@
  #include "geoip.h"
  #include "hibernate.h"
  #include "main.h"
 +#include "microdesc.h"
  #include "networkstatus.h"
 +#include "nodelist.h"
  #include "policies.h"
  #include "reasons.h"
  #include "rendcommon.h"
@@@ -39,21 -37,20 +39,21 @@@
  /****************************************************************************/
  
  /* static function prototypes */
 -static routerstatus_t *router_pick_directory_server_impl(
 +static const routerstatus_t *router_pick_directory_server_impl(
                                             authority_type_t auth, int flags);
 -static routerstatus_t *router_pick_trusteddirserver_impl(
 +static const routerstatus_t *router_pick_trusteddirserver_impl(
                            authority_type_t auth, int flags, int *n_busy_out);
  static void mark_all_trusteddirservers_up(void);
 -static int router_nickname_matches(routerinfo_t *router, const char *nickname);
 +static int router_nickname_matches(const routerinfo_t *router,
 +                                   const char *nickname);
 +static int node_nickname_matches(const node_t *router,
 +                                 const char *nickname);
  static void trusted_dir_server_free(trusted_dir_server_t *ds);
 -static void launch_router_descriptor_downloads(smartlist_t *downloadable,
 -                                               routerstatus_t *source,
 -                                               time_t now);
  static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
  static void update_router_have_minimum_dir_info(void);
 -static const char *signed_descriptor_get_body_impl(signed_descriptor_t *desc,
 -                                                   int with_annotations);
 +static const char *signed_descriptor_get_body_impl(
 +                                              const signed_descriptor_t *desc,
 +                                              int with_annotations);
  static void list_pending_downloads(digestmap_t *result,
                                     int purpose, const char *prefix);
  
@@@ -315,7 -312,6 +315,7 @@@ trusted_dirs_remove_old_certs(void
    time_t now = time(NULL);
  #define DEAD_CERT_LIFETIME (2*24*60*60)
  #define OLD_CERT_LIFETIME (7*24*60*60)
 +#define CERT_EXPIRY_SKEW (60*60)
    if (!trusted_dir_certs)
      return;
  
@@@ -332,7 -328,7 +332,7 @@@
          time_t cert_published;
          if (newest == cert)
            continue;
 -        expired = ftime_definitely_after(now, cert->expires);
 +        expired = time_definitely_after(now, cert->expires, CERT_EXPIRY_SKEW);
          cert_published = cert->cache_info.published_on;
          /* Store expired certs for 48 hours after a newer arrives;
           */
@@@ -524,7 -520,7 +524,7 @@@ authority_certs_fetch_missing(networkst
        continue;
      cl = get_cert_list(ds->v3_identity_digest);
      SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, {
 -      if (!ftime_definitely_after(now, cert->expires)) {
 +      if (! time_definitely_after(now, cert->expires, CERT_EXPIRY_SKEW)) {
          /* It's not expired, and we weren't looking for something to
           * verify a consensus with.  Call it done. */
          download_status_reset(&cl->dl_status);
@@@ -604,7 -600,7 +604,7 @@@ router_should_rebuild_store(desc_store_
  /** Return the desc_store_t in <b>rl</b> that should be used to store
   * <b>sd</b>. */
  static INLINE desc_store_t *
 -desc_get_store(routerlist_t *rl, signed_descriptor_t *sd)
 +desc_get_store(routerlist_t *rl, const signed_descriptor_t *sd)
  {
    if (sd->is_extrainfo)
      return &rl->extrainfo_store;
@@@ -930,10 -926,10 +930,10 @@@ router_get_trusted_dir_servers(void
   * Don't pick an authority if any non-authority is viable; try to avoid using
   * servers that have returned 503 recently.
   */
 -routerstatus_t *
 +const routerstatus_t *
  router_pick_directory_server(authority_type_t type, int flags)
  {
 -  routerstatus_t *choice;
 +  const routerstatus_t *choice;
    if (get_options()->PreferTunneledDirConns)
      flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
  
@@@ -962,8 -958,8 +962,8 @@@ in
  router_get_my_share_of_directory_requests(double *v2_share_out,
                                            double *v3_share_out)
  {
 -  routerinfo_t *me = router_get_my_routerinfo();
 -  routerstatus_t *rs;
 +  const routerinfo_t *me = router_get_my_routerinfo();
 +  const routerstatus_t *rs;
    const int pds_flags = PDS_ALLOW_SELF|PDS_IGNORE_FASCISTFIREWALL;
    *v2_share_out = *v3_share_out = 0.0;
    if (!me)
@@@ -1036,10 -1032,10 +1036,10 @@@ trusteddirserver_get_by_v3_auth_digest(
  /** Try to find a running trusted dirserver.  Flags are as for
   * router_pick_directory_server.
   */
 -routerstatus_t *
 +const routerstatus_t *
  router_pick_trusteddirserver(authority_type_t type, int flags)
  {
 -  routerstatus_t *choice;
 +  const routerstatus_t *choice;
    int busy = 0;
    if (get_options()->PreferTunneledDirConns)
      flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
@@@ -1051,8 -1047,7 +1051,8 @@@
      /* If the reason that we got no server is that servers are "busy",
       * we must be excluding good servers because we already have serverdesc
       * fetches with them.  Do not mark down servers up because of this. */
 -    tor_assert((flags & PDS_NO_EXISTING_SERVERDESC_FETCH));
 +    tor_assert((flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
 +                         PDS_NO_EXISTING_MICRODESC_FETCH)));
      return NULL;
    }
  
@@@ -1072,10 -1067,10 +1072,10 @@@
   * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers
   * that we can use with BEGINDIR.
   */
 -static routerstatus_t *
 +static const routerstatus_t *
  router_pick_directory_server_impl(authority_type_t type, int flags)
  {
 -  routerstatus_t *result;
 +  const node_t *result;
    smartlist_t *direct, *tunnel;
    smartlist_t *trusted_direct, *trusted_tunnel;
    smartlist_t *overloaded_direct, *overloaded_tunnel;
@@@ -1096,54 -1091,49 +1096,54 @@@
    overloaded_tunnel = smartlist_create();
  
    /* Find all the running dirservers we know about. */
 -  SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *,
 -                          status) {
 +  SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
      int is_trusted;
 -    int is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
 +    int is_overloaded;
      tor_addr_t addr;
 -    if (!status->is_running || !status->dir_port || !status->is_valid)
 +    const routerstatus_t *status = node->rs;
 +    if (!status)
        continue;
 -    if (status->is_bad_directory)
 +
 +    if (!node->is_running || !status->dir_port || !node->is_valid)
 +      continue;
 +    if (node->is_bad_directory)
        continue;
 -    if (requireother && router_digest_is_me(status->identity_digest))
 +    if (requireother && router_digest_is_me(node->identity))
        continue;
      if (type & V3_AUTHORITY) {
        if (!(status->version_supports_v3_dir ||
 -            router_digest_is_trusted_dir_type(status->identity_digest,
 +            router_digest_is_trusted_dir_type(node->identity,
                                                V3_AUTHORITY)))
          continue;
      }
 -    is_trusted = router_digest_is_trusted_dir(status->identity_digest);
 -    if ((type & V2_AUTHORITY) && !(status->is_v2_dir || is_trusted))
 +    is_trusted = router_digest_is_trusted_dir(node->identity);
 +    if ((type & V2_AUTHORITY) && !(node->rs->is_v2_dir || is_trusted))
        continue;
      if ((type & EXTRAINFO_CACHE) &&
 -        !router_supports_extrainfo(status->identity_digest, 0))
 +        !router_supports_extrainfo(node->identity, 0))
        continue;
  
      /* XXXX IP6 proposal 118 */
 -    tor_addr_from_ipv4h(&addr, status->addr);
 +    tor_addr_from_ipv4h(&addr, node->rs->addr);
 +
 +    is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
  
      if (prefer_tunnel &&
          status->version_supports_begindir &&
          (!fascistfirewall ||
           fascist_firewall_allows_address_or(&addr, status->or_port)))
        smartlist_add(is_trusted ? trusted_tunnel :
 -                      is_overloaded ? overloaded_tunnel : tunnel, status);
 +                    is_overloaded ? overloaded_tunnel : tunnel, (void*)node);
      else if (!fascistfirewall ||
               fascist_firewall_allows_address_dir(&addr, status->dir_port))
        smartlist_add(is_trusted ? trusted_direct :
 -                      is_overloaded ? overloaded_direct : direct, status);
 -  } SMARTLIST_FOREACH_END(status);
 +                    is_overloaded ? overloaded_direct : direct, (void*)node);
 +  } SMARTLIST_FOREACH_END(node);
  
    if (smartlist_len(tunnel)) {
 -    result = routerstatus_sl_choose_by_bandwidth(tunnel, WEIGHT_FOR_DIR);
 +    result = node_sl_choose_by_bandwidth(tunnel, WEIGHT_FOR_DIR);
    } else if (smartlist_len(overloaded_tunnel)) {
 -    result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel,
 +    result = node_sl_choose_by_bandwidth(overloaded_tunnel,
                                                   WEIGHT_FOR_DIR);
    } else if (smartlist_len(trusted_tunnel)) {
      /* FFFF We don't distinguish between trusteds and overloaded trusteds
@@@ -1152,10 -1142,10 +1152,10 @@@
       * is a feature, but it could easily be a bug. -RD */
      result = smartlist_choose(trusted_tunnel);
    } else if (smartlist_len(direct)) {
 -    result = routerstatus_sl_choose_by_bandwidth(direct, WEIGHT_FOR_DIR);
 +    result = node_sl_choose_by_bandwidth(direct, WEIGHT_FOR_DIR);
    } else if (smartlist_len(overloaded_direct)) {
 -    result = routerstatus_sl_choose_by_bandwidth(overloaded_direct,
 -                                                 WEIGHT_FOR_DIR);
 +    result = node_sl_choose_by_bandwidth(overloaded_direct,
 +                                         WEIGHT_FOR_DIR);
    } else {
      result = smartlist_choose(trusted_direct);
    }
@@@ -1165,26 -1155,25 +1165,26 @@@
    smartlist_free(trusted_tunnel);
    smartlist_free(overloaded_direct);
    smartlist_free(overloaded_tunnel);
 -  return result;
 +  return result ? result->rs : NULL;
  }
  
  /** Choose randomly from among the trusted dirservers that are up.  Flags
   * are as for router_pick_directory_server_impl().
   */
 -static routerstatus_t *
 +static const routerstatus_t *
  router_pick_trusteddirserver_impl(authority_type_t type, int flags,
                                    int *n_busy_out)
  {
    smartlist_t *direct, *tunnel;
    smartlist_t *overloaded_direct, *overloaded_tunnel;
 -  routerinfo_t *me = router_get_my_routerinfo();
 -  routerstatus_t *result;
 +  const routerinfo_t *me = router_get_my_routerinfo();
 +  const routerstatus_t *result;
    time_t now = time(NULL);
    const int requireother = ! (flags & PDS_ALLOW_SELF);
    const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
    const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
    const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
 +  const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH);
    int n_busy = 0;
  
    if (!trusted_dir_servers)
@@@ -1223,13 -1212,6 +1223,13 @@@
            continue;
          }
        }
 +      if (no_microdesc_fetching) {
 +        if (connection_get_by_type_addr_port_purpose(
 +             CONN_TYPE_DIR, &addr, d->dir_port, DIR_PURPOSE_FETCH_MICRODESC)) {
 +          ++n_busy;
 +          continue;
 +        }
 +      }
  
        if (prefer_tunnel &&
            d->or_port &&
@@@ -1268,18 -1250,22 +1268,18 @@@
  static void
  mark_all_trusteddirservers_up(void)
  {
 -  if (routerlist) {
 -    SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -       if (router_digest_is_trusted_dir(router->cache_info.identity_digest) &&
 -         router->dir_port > 0) {
 -         router->is_running = 1;
 -       });
 -  }
 +  SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, {
 +       if (router_digest_is_trusted_dir(node->identity))
 +         node->is_running = 1;
 +    });
    if (trusted_dir_servers) {
      SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
      {
        routerstatus_t *rs;
        dir->is_running = 1;
        download_status_reset(&dir->v2_ns_dl_status);
 -      rs = router_get_consensus_status_by_id(dir->digest);
 -      if (rs && !rs->is_running) {
 -        rs->is_running = 1;
 +      rs = router_get_mutable_consensus_status_by_id(dir->digest);
 +      if (rs) {
          rs->last_dir_503_at = 0;
          control_event_networkstatus_changed_single(rs);
        }
@@@ -1303,14 -1289,25 +1303,14 @@@ router_reset_status_download_failures(v
    mark_all_trusteddirservers_up();
  }
  
 -/** Return true iff router1 and router2 have the same /16 network. */
 +/** Return true iff router1 and router2 have similar enough network addresses
 + * that we should treat them as being in the same family */
  static INLINE int
 -routers_in_same_network_family(routerinfo_t *r1, routerinfo_t *r2)
 -{
 -  return (r1->addr & 0xffff0000) == (r2->addr & 0xffff0000);
 -}
 -
 -/** Look through the routerlist and identify routers that
 - * advertise the same /16 network address as <b>router</b>.
 - * Add each of them to <b>sl</b>.
 - */
 -static void
 -routerlist_add_network_family(smartlist_t *sl, routerinfo_t *router)
 +addrs_in_same_network_family(const tor_addr_t *a1,
 +                             const tor_addr_t *a2)
  {
 -  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
 -  {
 -    if (router != r && routers_in_same_network_family(router, r))
 -      smartlist_add(sl, r);
 -  });
 +  /* XXXX MOVE ? */
 +  return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
  }
  
  /** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
@@@ -1318,132 -1315,122 +1318,132 @@@
   * or pick more than one relay from a family for our entry guard list.
   */
  void
 -routerlist_add_family(smartlist_t *sl, routerinfo_t *router)
 +nodelist_add_node_family(smartlist_t *sl, const node_t *node)
  {
 -  routerinfo_t *r;
 -  config_line_t *cl;
 +  /* XXXX MOVE */
 +  const smartlist_t *all_nodes = nodelist_get_list();
 +  const smartlist_t *declared_family;
    or_options_t *options = get_options();
  
 -  /* First, add any routers with similar network addresses. */
 -  if (options->EnforceDistinctSubnets)
 -    routerlist_add_network_family(sl, router);
 +  tor_assert(node);
  
 -  if (router->declared_family) {
 -    /* Add every r such that router declares familyness with r, and r
 +  declared_family = node_get_declared_family(node);
 +
 +  /* First, add any nodes with similar network addresses. */
 +  if (options->EnforceDistinctSubnets) {
 +    tor_addr_t node_addr;
 +    node_get_addr(node, &node_addr);
 +
 +    SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
 +      tor_addr_t a;
 +      node_get_addr(node2, &a);
 +      if (addrs_in_same_network_family(&a, &node_addr))
 +        smartlist_add(sl, (void*)node2);
 +    } SMARTLIST_FOREACH_END(node2);
 +  }
 +
 +  /* Now, add all nodes in the declared_family of this node, if they
 +   * also declare this node to be in their family. */
 +  if (declared_family) {
 +    /* Add every r such that router declares familyness with node, and node
       * declares familyhood with router. */
 -    SMARTLIST_FOREACH(router->declared_family, const char *, n,
 -      {
 -        if (!(r = router_get_by_nickname(n, 0)))
 -          continue;
 -        if (!r->declared_family)
 -          continue;
 -        SMARTLIST_FOREACH(r->declared_family, const char *, n2,
 -          {
 -            if (router_nickname_matches(router, n2))
 -              smartlist_add(sl, r);
 -          });
 -      });
 +    SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
 +      const node_t *node2;
 +      const smartlist_t *family2;
 +      if (!(node2 = node_get_by_nickname(name, 0)))
 +        continue;
 +      if (!(family2 = node_get_declared_family(node2)))
 +        continue;
 +      SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
 +          if (node_nickname_matches(node, name2)) {
 +            smartlist_add(sl, (void*)node2);
 +            break;
 +          }
 +      } SMARTLIST_FOREACH_END(name2);
 +    } SMARTLIST_FOREACH_END(name);
    }
  
    /* If the user declared any families locally, honor those too. */
 -  for (cl = options->NodeFamilies; cl; cl = cl->next) {
 -    if (router_nickname_is_in_list(router, cl->value)) {
 -      add_nickname_list_to_smartlist(sl, cl->value, 0);
 -    }
 +  if (options->NodeFamilySets) {
 +    SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
 +      if (routerset_contains_node(rs, node)) {
 +        routerset_get_all_nodes(sl, rs, 0);
 +      }
 +    });
 +  }
 +}
 +
 +/** Given a <b>router</b>, add every node_t in its family to <b>sl</b>.
 + *
 + * Note the type mismatch: This function takes a routerinfo, but adds nodes
 + * to the smartlist!
 + */
 +static void
 +routerlist_add_nodes_in_family(smartlist_t *sl, const routerinfo_t *router)
 +{
 +  /* XXXX MOVE ? */
 +  node_t fake_node;
 +  const node_t *node = node_get_by_id(router->cache_info.identity_digest);;
 +  if (node == NULL) {
 +    memset(&fake_node, 0, sizeof(fake_node));
 +    fake_node.ri = (routerinfo_t *)router;
 +    memcpy(fake_node.identity, router->cache_info.identity_digest, DIGEST_LEN);
 +    node = &fake_node;
    }
 +  nodelist_add_node_family(sl, node);
  }
  
 -/** Return true iff r is named by some nickname in <b>lst</b>. */
 +/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
  static INLINE int
 -router_in_nickname_smartlist(smartlist_t *lst, routerinfo_t *r)
 +node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
  {
 +  /* XXXX MOVE */
    if (!lst) return 0;
 -  SMARTLIST_FOREACH(lst, const char *, name,
 -    if (router_nickname_matches(r, name))
 -      return 1;);
 +  SMARTLIST_FOREACH(lst, const char *, name, {
 +    if (node_nickname_matches(node, name))
 +      return 1;
 +  });
    return 0;
  }
  
  /** Return true iff r1 and r2 are in the same family, but not the same
   * router. */
  int
 -routers_in_same_family(routerinfo_t *r1, routerinfo_t *r2)
 +nodes_in_same_family(const node_t *node1, const node_t *node2)
  {
 +  /* XXXX MOVE */
    or_options_t *options = get_options();
 -  config_line_t *cl;
 -
 -  if (options->EnforceDistinctSubnets && routers_in_same_network_family(r1,r2))
 -    return 1;
  
 -  if (router_in_nickname_smartlist(r1->declared_family, r2) &&
 -      router_in_nickname_smartlist(r2->declared_family, r1))
 -    return 1;
 -
 -  for (cl = options->NodeFamilies; cl; cl = cl->next) {
 -    if (router_nickname_is_in_list(r1, cl->value) &&
 -        router_nickname_is_in_list(r2, cl->value))
 +  /* Are they in the same family because of their addresses? */
 +  if (options->EnforceDistinctSubnets) {
 +    tor_addr_t a1, a2;
 +    node_get_addr(node1, &a1);
 +    node_get_addr(node2, &a2);
 +    if (addrs_in_same_network_family(&a1, &a2))
        return 1;
    }
 -  return 0;
 -}
  
 -/** Given a (possibly NULL) comma-and-whitespace separated list of nicknames,
 - * see which nicknames in <b>list</b> name routers in our routerlist, and add
 - * the routerinfos for those routers to <b>sl</b>.  If <b>must_be_running</b>,
 - * only include routers that we think are running.
 - * Warn if any non-Named routers are specified by nickname.
 - */
 -void
 -add_nickname_list_to_smartlist(smartlist_t *sl, const char *list,
 -                               int must_be_running)
 -{
 -  routerinfo_t *router;
 -  smartlist_t *nickname_list;
 -  int have_dir_info = router_have_minimum_dir_info();
 -
 -  if (!list)
 -    return; /* nothing to do */
 -  tor_assert(sl);
 -
 -  nickname_list = smartlist_create();
 -  if (!warned_nicknames)
 -    warned_nicknames = smartlist_create();
 +  /* Are they in the same family because the agree they are? */
 +  {
 +    const smartlist_t *f1, *f2;
 +    f1 = node_get_declared_family(node1);
 +    f2 = node_get_declared_family(node2);
 +    if (f1 && f2 &&
 +        node_in_nickname_smartlist(f1, node2) &&
 +        node_in_nickname_smartlist(f2, node1))
 +      return 1;
 +  }
  
 -  smartlist_split_string(nickname_list, list, ",",
 -                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
 +  /* Are they in the same option because the user says they are? */
 +  if (options->NodeFamilySets) {
 +    SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
 +        if (routerset_contains_node(rs, node1) &&
 +            routerset_contains_node(rs, node2))
 +          return 1;
 +      });
 +  }
  
 -  SMARTLIST_FOREACH(nickname_list, const char *, nick, {
 -    int warned;
 -    if (!is_legal_nickname_or_hexdigest(nick)) {
 -      log_warn(LD_CONFIG, "Nickname '%s' is misformed; skipping", nick);
 -      continue;
 -    }
 -    router = router_get_by_nickname(nick, 1);
 -    warned = smartlist_string_isin(warned_nicknames, nick);
 -    if (router) {
 -      if (!must_be_running || router->is_running) {
 -        smartlist_add(sl,router);
 -      }
 -    } 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);
 -        smartlist_add(warned_nicknames, tor_strdup(nick));
 -      }
 -    }
 -  });
 -  SMARTLIST_FOREACH(nickname_list, char *, nick, tor_free(nick));
 -  smartlist_free(nickname_list);
 +  return 0;
  }
  
  /** Return 1 iff any member of the (possibly NULL) comma-separated list
@@@ -1451,7 -1438,7 +1451,7 @@@
   * return 0.
   */
  int
 -router_nickname_is_in_list(routerinfo_t *router, const char *list)
 +router_nickname_is_in_list(const routerinfo_t *router, const char *list)
  {
    smartlist_t *nickname_list;
    int v = 0;
@@@ -1470,32 -1457,34 +1470,32 @@@
    return v;
  }
  
 -/** Add every suitable router from our routerlist to <b>sl</b>, so that
 +/** Add every suitable node from our nodelist to <b>sl</b>, so that
   * we can pick a node for a circuit.
   */
  static void
 -router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_invalid,
 -                                        int need_uptime, int need_capacity,
 -                                        int need_guard)
 -{
 -  if (!routerlist)
 -    return;
 +router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
 +                                      int need_uptime, int need_capacity,
 +                                      int need_guard, int need_desc)
 +{ /* XXXX MOVE */
 +  SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
 +    if (!node->is_running ||
 +        (!node->is_valid && !allow_invalid))
 +      continue;
 +    if (need_desc && !(node->ri || (node->rs && node->md)))
 +      continue;
 +    if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
 +      continue;
 +    if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
 +      continue;
  
 -  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -  {
 -    if (router->is_running &&
 -        router->purpose == ROUTER_PURPOSE_GENERAL &&
 -        (router->is_valid || allow_invalid) &&
 -        !router_is_unreliable(router, need_uptime,
 -                              need_capacity, need_guard)) {
 -      /* If it's running, and it's suitable according to the
 -       * other flags we had in mind */
 -      smartlist_add(sl, router);
 -    }
 -  });
 +    smartlist_add(sl, (void *)node);
 +  } SMARTLIST_FOREACH_END(node);
  }
  
  /** Look through the routerlist until we find a router that has my key.
   Return it. */
 -routerinfo_t *
 +const routerinfo_t *
  routerlist_find_my_routerinfo(void)
  {
    if (!routerlist)
@@@ -1513,9 -1502,9 +1513,9 @@@
   * that allows exit to this address:port, or return NULL if there
   * isn't a good one.
   */
 -routerinfo_t *
 +const node_t *
  router_find_exact_exit_enclave(const char *address, uint16_t port)
 -{
 +{/*XXXX MOVE*/
    uint32_t addr;
    struct in_addr in;
    tor_addr_t a;
@@@ -1526,12 -1515,13 +1526,12 @@@
  
    tor_addr_from_ipv4h(&a, addr);
  
 -  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -  {
 -    if (router->addr == addr &&
 -        router->is_running &&
 -        compare_tor_addr_to_addr_policy(&a, port, router->exit_policy) ==
 +  SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
 +    if (node_get_addr_ipv4h(node) == addr &&
 +        node->is_running &&
 +        compare_tor_addr_to_node_policy(&a, port, node) ==
            ADDR_POLICY_ACCEPTED)
 -      return router;
 +      return node;
    });
    return NULL;
  }
@@@ -1543,14 -1533,14 +1543,14 @@@
   * If <b>need_guard</b>, we require that the router is a possible entry guard.
   */
  int
 -router_is_unreliable(routerinfo_t *router, int need_uptime,
 -                     int need_capacity, int need_guard)
 +node_is_unreliable(const node_t *node, int need_uptime,
 +                   int need_capacity, int need_guard)
  {
 -  if (need_uptime && !router->is_stable)
 +  if (need_uptime && !node->is_stable)
      return 1;
 -  if (need_capacity && !router->is_fast)
 +  if (need_capacity && !node->is_fast)
      return 1;
 -  if (need_guard && !router->is_possible_guard)
 +  if (need_guard && !node->is_possible_guard)
      return 1;
    return 0;
  }
@@@ -1558,7 -1548,7 +1558,7 @@@
  /** Return the smaller of the router's configured BandwidthRate
   * and its advertised capacity. */
  uint32_t
 -router_get_advertised_bandwidth(routerinfo_t *router)
 +router_get_advertised_bandwidth(const routerinfo_t *router)
  {
    if (router->bandwidthcapacity < router->bandwidthrate)
      return router->bandwidthcapacity;
@@@ -1572,7 -1562,7 +1572,7 @@@
  /** Return the smaller of the router's configured BandwidthRate
   * and its advertised capacity, capped by max-believe-bw. */
  uint32_t
 -router_get_advertised_bandwidth_capped(routerinfo_t *router)
 +router_get_advertised_bandwidth_capped(const routerinfo_t *router)
  {
    uint32_t result = router->bandwidthcapacity;
    if (result > router->bandwidthrate)
@@@ -1614,10 -1604,13 +1614,10 @@@ kb_to_bytes(uint32_t bw
  }
  
  /** Helper function:
 - * choose a random element of smartlist <b>sl</b>, weighted by
 + * choose a random element of smartlist <b>sl</b> of nodes, weighted by
   * the advertised bandwidth of each element using the consensus
   * bandwidth weights.
   *
 - * If <b>statuses</b> is zero, then <b>sl</b> is a list of
 - * routerinfo_t's. Otherwise it's a list of routerstatus_t's.
 - *
   * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
   * nodes' bandwidth equally regardless of their Exit status, since there may
   * be some in the list because they exit to obscure ports. If
@@@ -1627,9 -1620,10 +1627,9 @@@
   * guard node: consider all guard's bandwidth equally. Otherwise, weight
   * guards proportionally less.
   */
 -static void *
 -smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
 -                                      bandwidth_weight_rule_t rule,
 -                                      int statuses)
 +static const node_t *
 +smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
 +                                           bandwidth_weight_rule_t rule)
  {
    int64_t weight_scale;
    int64_t rand_bw;
@@@ -1723,14 -1717,15 +1723,14 @@@
    bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
  
    // Cycle through smartlist and total the bandwidth.
 -  for (i = 0; i < (unsigned)smartlist_len(sl); ++i) {
 +  SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
      int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0, is_me = 0;
      double weight = 1;
-     is_exit = node->is_exit;
 -    if (statuses) {
 -      routerstatus_t *status = smartlist_get(sl, i);
 -      is_exit = status->is_exit && !status->is_bad_exit;
 -      is_guard = status->is_possible_guard;
 -      is_dir = (status->dir_port != 0);
 -      if (!status->has_bandwidth) {
++    is_exit = node->is_exit && ! node->is_bad_exit;
 +    is_guard = node->is_possible_guard;
 +    is_dir = node_is_dir(node);
 +    if (node->rs) {
 +      if (!node->rs->has_bandwidth) {
          tor_free(bandwidths);
          /* This should never happen, unless all the authorites downgrade
           * to 0.2.0 or rogue routerstatuses get inserted into our consensus. */
@@@ -1739,17 -1734,26 +1739,17 @@@
                   "old router selection algorithm.");
          return NULL;
        }
 -      this_bw = kb_to_bytes(status->bandwidth);
 -      if (router_digest_is_me(status->identity_digest))
 -        is_me = 1;
 +      this_bw = kb_to_bytes(node->rs->bandwidth);
 +    } else if (node->ri) {
 +      /* bridge or other descriptor not in our consensus */
 +      this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
 +      have_unknown = 1;
      } else {
 -      routerstatus_t *rs;
 -      routerinfo_t *router = smartlist_get(sl, i);
 -      rs = router_get_consensus_status_by_id(
 -             router->cache_info.identity_digest);
 -      is_exit = router->is_exit && !router->is_bad_exit;
 -      is_guard = router->is_possible_guard;
 -      is_dir = (router->dir_port != 0);
 -      if (rs && rs->has_bandwidth) {
 -        this_bw = kb_to_bytes(rs->bandwidth);
 -      } else { /* bridge or other descriptor not in our consensus */
 -        this_bw = bridge_get_advertised_bandwidth_bounded(router);
 -        have_unknown = 1;
 -      }
 -      if (router_digest_is_me(router->cache_info.identity_digest))
 -        is_me = 1;
 +      /* We can't use this one. */
 +      continue;
      }
 +    is_me = router_digest_is_me(node->identity);
 +
      if (is_guard && is_exit) {
        weight = (is_dir ? Wdb*Wd : Wd);
      } else if (is_guard) {
@@@ -1760,11 -1764,11 +1760,11 @@@
        weight = (is_dir ? Wmb*Wm : Wm);
      }
  
 -    bandwidths[i] = weight*this_bw;
 +    bandwidths[node_sl_idx] = weight*this_bw;
      weighted_bw += weight*this_bw;
      if (is_me)
        sl_last_weighted_bw_of_me = weight*this_bw;
 -  }
 +  } SMARTLIST_FOREACH_END(node);
  
    /* XXXX022 this is a kludge to expose these values. */
    sl_last_total_weighted_bw = weighted_bw;
@@@ -1812,9 -1816,12 +1812,9 @@@
  }
  
  /** Helper function:
 - * choose a random element of smartlist <b>sl</b>, weighted by
 + * choose a random node_t element of smartlist <b>sl</b>, weighted by
   * the advertised bandwidth of each element.
   *
 - * If <b>statuses</b> is zero, then <b>sl</b> is a list of
 - * routerinfo_t's. Otherwise it's a list of routerstatus_t's.
 - *
   * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
   * nodes' bandwidth equally regardless of their Exit status, since there may
   * be some in the list because they exit to obscure ports. If
@@@ -1824,11 -1831,13 +1824,11 @@@
   * guard node: consider all guard's bandwidth equally. Otherwise, weight
   * guards proportionally less.
   */
 -static void *
 -smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule,
 -                              int statuses)
 +static const node_t *
 +smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 +                                   bandwidth_weight_rule_t rule)
  {
 -  unsigned int i;
 -  routerinfo_t *router;
 -  routerstatus_t *status=NULL;
 +  unsigned i;
    int32_t *bandwidths;
    int is_exit;
    int is_guard;
@@@ -1869,34 -1878,49 +1869,34 @@@
    guard_bits = bitarray_init_zero(smartlist_len(sl));
  
    /* Iterate over all the routerinfo_t or routerstatus_t, and */
 -  for (i = 0; i < (unsigned)smartlist_len(sl); ++i) {
 +  SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
      /* first, learn what bandwidth we think i has */
      int is_known = 1;
      int32_t flags = 0;
      uint32_t this_bw = 0;
 -    if (statuses) {
 -      status = smartlist_get(sl, i);
 -      if (router_digest_is_me(status->identity_digest))
 -        me_idx = i;
 -      router = router_get_by_digest(status->identity_digest);
 -      is_exit = status->is_exit;
 -      is_guard = status->is_possible_guard;
 -      if (status->has_bandwidth) {
 -        this_bw = kb_to_bytes(status->bandwidth);
 +    i = node_sl_idx;
 +
 +    if (router_digest_is_me(node->identity))
 +      me_idx = node_sl_idx;
 +
 +    is_exit = node->is_exit;
 +    is_guard = node->is_possible_guard;
 +    if (node->rs) {
 +      if (node->rs->has_bandwidth) {
 +        this_bw = kb_to_bytes(node->rs->bandwidth);
        } else { /* guess */
          /* XXX022 once consensuses always list bandwidths, we can take
           * this guessing business out. -RD */
          is_known = 0;
 -        flags = status->is_fast ? 1 : 0;
 +        flags = node->rs->is_fast ? 1 : 0;
          flags |= is_exit ? 2 : 0;
          flags |= is_guard ? 4 : 0;
        }
 -    } else {
 -      routerstatus_t *rs;
 -      router = smartlist_get(sl, i);
 -      rs = router_get_consensus_status_by_id(
 -             router->cache_info.identity_digest);
 -      if (router_digest_is_me(router->cache_info.identity_digest))
 -        me_idx = i;
 -      is_exit = router->is_exit;
 -      is_guard = router->is_possible_guard;
 -      if (rs && rs->has_bandwidth) {
 -        this_bw = kb_to_bytes(rs->bandwidth);
 -      } else if (rs) { /* guess; don't trust the descriptor */
 -        /* XXX022 once consensuses always list bandwidths, we can take
 -         * this guessing business out. -RD */
 -        is_known = 0;
 -        flags = router->is_fast ? 1 : 0;
 -        flags |= is_exit ? 2 : 0;
 -        flags |= is_guard ? 4 : 0;
 -      } else /* bridge or other descriptor not in our consensus */
 -        this_bw = bridge_get_advertised_bandwidth_bounded(router);
 +    } else if (node->ri) {
 +      /* Must be a bridge if we're willing to use it */
 +      this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
      }
 +
      if (is_exit)
        bitarray_set(exit_bits, i);
      if (is_guard)
@@@ -1916,9 -1940,9 +1916,9 @@@
          total_nonexit_bw += this_bw;
      } else {
        ++n_unknown;
 -      bandwidths[i] = -flags;
 +      bandwidths[node_sl_idx] = -flags;
      }
 -  }
 +  } SMARTLIST_FOREACH_END(node);
  
    /* Now, fill in the unknown values. */
    if (n_unknown) {
@@@ -2060,23 -2084,40 +2060,23 @@@
    return smartlist_get(sl, i);
  }
  
 -/** Choose a random element of router list <b>sl</b>, weighted by
 - * the advertised bandwidth of each router.
 - */
 -routerinfo_t *
 -routerlist_sl_choose_by_bandwidth(smartlist_t *sl,
 -                                  bandwidth_weight_rule_t rule)
 -{
 -  routerinfo_t *ret;
 -  if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 0))) {
 -    return ret;
 -  } else {
 -    return smartlist_choose_by_bandwidth(sl, rule, 0);
 -  }
 -}
 -
  /** Choose a random element of status list <b>sl</b>, weighted by
 - * the advertised bandwidth of each status.
 - */
 -routerstatus_t *
 -routerstatus_sl_choose_by_bandwidth(smartlist_t *sl,
 -                                    bandwidth_weight_rule_t rule)
 -{
 -  /* We are choosing neither exit nor guard here. Weight accordingly. */
 -  routerstatus_t *ret;
 -  if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 1))) {
 + * the advertised bandwidth of each node */
 +const node_t *
 +node_sl_choose_by_bandwidth(smartlist_t *sl,
 +                            bandwidth_weight_rule_t rule)
 +{ /*XXXX MOVE */
 +  const node_t *ret;
 +  if ((ret = smartlist_choose_node_by_bandwidth_weights(sl, rule))) {
      return ret;
    } else {
 -    return smartlist_choose_by_bandwidth(sl, rule, 1);
 +    return smartlist_choose_node_by_bandwidth(sl, rule);
    }
  }
  
 -/** Return a random running router from the routerlist. Never
 - * pick a node whose routerinfo is in
 - * <b>excludedsmartlist</b>, or whose routerinfo matches <b>excludedset</b>,
 +/** Return a random running node from the nodelist. Never
 + * pick a node that is in
 + * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>,
   * even if they are the only nodes available.
   * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than
   * a minimum uptime, return one of those.
@@@ -2088,26 -2129,21 +2088,26 @@@
   * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if
   * picking an exit node, otherwise we weight bandwidths for picking a relay
   * node (that is, possibly discounting exit nodes).
 + * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that
 + * have a routerinfo or microdescriptor -- that is, enough info to be
 + * used to build a circuit.
   */
 -routerinfo_t *
 +const node_t *
  router_choose_random_node(smartlist_t *excludedsmartlist,
                            routerset_t *excludedset,
                            router_crn_flags_t flags)
 -{
 +{ /* XXXX MOVE */
    const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
    const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
    const int need_guard = (flags & CRN_NEED_GUARD) != 0;
    const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0;
    const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0;
 +  const int need_desc = (flags & CRN_NEED_DESC) != 0;
  
    smartlist_t *sl=smartlist_create(),
 -              *excludednodes=smartlist_create();
 -  routerinfo_t *choice = NULL, *r;
 +    *excludednodes=smartlist_create();
 +  const node_t *choice = NULL;
 +  const routerinfo_t *r;
    bandwidth_weight_rule_t rule;
  
    tor_assert(!(weight_for_exit && need_guard));
@@@ -2117,30 -2153,29 +2117,30 @@@
    /* Exclude relays that allow single hop exit circuits, if the user
     * wants to (such relays might be risky) */
    if (get_options()->ExcludeSingleHopRelays) {
 -    routerlist_t *rl = router_get_routerlist();
 -    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
 -      if (r->allow_single_hop_exits) {
 -        smartlist_add(excludednodes, r);
 +    SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node,
 +      if (node_allows_single_hop_exits(node)) {
 +        smartlist_add(excludednodes, node);
        });
    }
  
    if ((r = routerlist_find_my_routerinfo())) {
 -    smartlist_add(excludednodes, r);
 -    routerlist_add_family(excludednodes, r);
 +    const node_t *me = node_get_by_id(r->cache_info.identity_digest);
 +    if (me)
 +      smartlist_add(excludednodes, (void *)me);
 +    routerlist_add_nodes_in_family(excludednodes, r);
    }
  
 -  router_add_running_routers_to_smartlist(sl, allow_invalid,
 -                                          need_uptime, need_capacity,
 -                                          need_guard);
 +  router_add_running_nodes_to_smartlist(sl, allow_invalid,
 +                                        need_uptime, need_capacity,
 +                                        need_guard, need_desc);
    smartlist_subtract(sl,excludednodes);
    if (excludedsmartlist)
      smartlist_subtract(sl,excludedsmartlist);
    if (excludedset)
 -    routerset_subtract_routers(sl,excludedset);
 +    routerset_subtract_nodes(sl,excludedset);
  
    // Always weight by bandwidth
 -  choice = routerlist_sl_choose_by_bandwidth(sl, rule);
 +  choice = node_sl_choose_by_bandwidth(sl, rule);
  
    smartlist_free(sl);
    if (!choice && (need_uptime || need_capacity || need_guard)) {
@@@ -2163,88 -2198,35 +2163,88 @@@
    return choice;
  }
  
 -/** Helper: Return true iff the <b>identity_digest</b> and <b>nickname</b>
 - * combination of a router, encoded in hexadecimal, matches <b>hexdigest</b>
 - * (which is optionally prefixed with a single dollar sign).  Return false if
 - * <b>hexdigest</b> is malformed, or it doesn't match.  */
 -static INLINE int
 -hex_digest_matches(const char *hexdigest, const char *identity_digest,
 -                   const char *nickname, int is_named)
 +/** Helper: given an extended nickname in <b>hexdigest</b> try to decode it.
 + * Return 0 on success, -1 on failure.  Store the result into the
 + * DIGEST_LEN-byte buffer at <b>digest_out</b>, the single character at
 + * <b>nickname_qualifier_char_out</b>, and the MAXNICKNAME_LEN+1-byte buffer
 + * at <b>nickname_out</b>.
 + *
 + * The recognized format is:
 + *   HexName = Dollar? HexDigest NamePart?
 + *   Dollar = '?'
 + *   HexDigest = HexChar*20
 + *   HexChar = 'a'..'f' | 'A'..'F' | '0'..'9'
 + *   NamePart = QualChar Name
 + *   QualChar = '=' | '~'
 + *   Name = NameChar*(1..MAX_NICKNAME_LEN)
 + *   NameChar = Any ASCII alphanumeric character
 + */
 +int
 +hex_digest_nickname_decode(const char *hexdigest,
 +                           char *digest_out,
 +                           char *nickname_qualifier_char_out,
 +                           char *nickname_out)
  {
 -  char digest[DIGEST_LEN];
    size_t len;
 +
    tor_assert(hexdigest);
    if (hexdigest[0] == '$')
      ++hexdigest;
  
    len = strlen(hexdigest);
 -  if (len < HEX_DIGEST_LEN)
 +  if (len < HEX_DIGEST_LEN) {
 +    return -1;
 +  } else if (len > HEX_DIGEST_LEN && (hexdigest[HEX_DIGEST_LEN] == '=' ||
 +                                    hexdigest[HEX_DIGEST_LEN] == '~') &&
 +           len <= HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) {
 +    *nickname_qualifier_char_out = hexdigest[HEX_DIGEST_LEN];
 +    strlcpy(nickname_out, hexdigest+HEX_DIGEST_LEN+1 , MAX_NICKNAME_LEN+1);
 +  } else if (len == HEX_DIGEST_LEN) {
 +    ;
 +  } else {
 +    return -1;
 +  }
 +
 +  if (base16_decode(digest_out, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
 +    return -1;
 +  return 0;
 +}
 +
 +/** Helper: Return true iff the <b>identity_digest</b> and <b>nickname</b>
 + * combination of a router, encoded in hexadecimal, matches <b>hexdigest</b>
 + * (which is optionally prefixed with a single dollar sign).  Return false if
 + * <b>hexdigest</b> is malformed, or it doesn't match.  */
 +static int
 +hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest,
 +                            const char *nickname, int is_named)
 +{
 +  char digest[DIGEST_LEN];
 +  char nn_char='\0';
 +  char nn_buf[MAX_NICKNAME_LEN+1];
 +
 +  if (hex_digest_nickname_decode(hexdigest, digest, &nn_char, nn_buf) == -1)
      return 0;
 -  else if (len > HEX_DIGEST_LEN &&
 -           (hexdigest[HEX_DIGEST_LEN] == '=' ||
 -            hexdigest[HEX_DIGEST_LEN] == '~')) {
 -    if (strcasecmp(hexdigest+HEX_DIGEST_LEN+1, nickname))
 +
 +  if (nn_char == '=' || nn_char == '~') {
 +    if (strcasecmp(nn_buf, nickname))
        return 0;
 -    if (hexdigest[HEX_DIGEST_LEN] == '=' && !is_named)
 +    if (nn_char == '=' && !is_named)
        return 0;
    }
  
 -  if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
 -    return 0;
 -  return (!memcmp(digest, identity_digest, DIGEST_LEN));
 +  return !memcmp(digest, identity_digest, DIGEST_LEN);
 +}
 +
 +/* Return true iff <b>router</b> is listed as named in the current
 + * consensus. */
 +static int
 +router_is_named(const routerinfo_t *router)
 +{
 +  const char *digest =
 +    networkstatus_get_router_digest_by_nickname(router->nickname);
 +
 +  return (digest &&
 +          !memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN));
  }
  
  /** Return true iff the digest of <b>router</b>'s identity key,
@@@ -2252,12 -2234,10 +2252,12 @@@
   * optionally prefixed with a single dollar sign).  Return false if
   * <b>hexdigest</b> is malformed, or it doesn't match.  */
  static INLINE int
 -router_hex_digest_matches(routerinfo_t *router, const char *hexdigest)
 +router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest)
  {
 -  return hex_digest_matches(hexdigest, router->cache_info.identity_digest,
 -                            router->nickname, router->is_named);
 +  return hex_digest_nickname_matches(hexdigest,
 +                                     router->cache_info.identity_digest,
 +                                     router->nickname,
 +                                     router_is_named(router));
  }
  
  /** Return true if <b>router</b>'s nickname matches <b>nickname</b>
@@@ -2265,43 -2245,20 +2265,43 @@@
   * matches a hexadecimal value stored in <b>nickname</b>.  Return
   * false otherwise. */
  static int
 -router_nickname_matches(routerinfo_t *router, const char *nickname)
 +router_nickname_matches(const routerinfo_t *router, const char *nickname)
  {
    if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname))
      return 1;
    return router_hex_digest_matches(router, nickname);
  }
  
 +/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
 + * (case-insensitive), or if <b>node's</b> identity key digest
 + * matches a hexadecimal value stored in <b>nickname</b>.  Return
 + * false otherwise. */
 +static int
 +node_nickname_matches(const node_t *node, const char *nickname)
 +{
 +  const char *n = node_get_nickname(node);
 +  if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
 +    return 1;
 +  return hex_digest_nickname_matches(nickname,
 +                                     node->identity,
 +                                     n,
 +                                     node_is_named(node));
 +}
 +
  /** Return the router in our routerlist whose (case-insensitive)
   * nickname or (case-sensitive) hexadecimal key digest is
   * <b>nickname</b>.  Return NULL if no such router is known.
   */
 -routerinfo_t *
 +const routerinfo_t *
  router_get_by_nickname(const char *nickname, int warn_if_unnamed)
  {
 +#if 1
 +  const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed);
 +  if (node)
 +    return node->ri;
 +  else
 +    return NULL;
 +#else
    int maybedigest;
    char digest[DIGEST_LEN];
    routerinfo_t *best_match=NULL;
@@@ -2347,14 -2304,15 +2347,14 @@@
      if (warn_if_unnamed && n_matches > 1) {
        smartlist_t *fps = smartlist_create();
        int any_unwarned = 0;
 -      SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -        {
 +      SMARTLIST_FOREACH_BEGIN(routerlist->routers, routerinfo_t *, router) {
            routerstatus_t *rs;
            char *desc;
            size_t dlen;
            char fp[HEX_DIGEST_LEN+1];
            if (strcasecmp(router->nickname, nickname))
              continue;
 -          rs = router_get_consensus_status_by_id(
 +          rs = router_get_mutable_consensus_status_by_id(
                                            router->cache_info.identity_digest);
            if (rs && !rs->name_lookup_warned) {
              rs->name_lookup_warned = 1;
@@@ -2367,7 -2325,7 +2367,7 @@@
            tor_snprintf(desc, dlen, "\"$%s\" for the one at %s:%d",
                         fp, router->address, router->or_port);
            smartlist_add(fps, desc);
 -        });
 +      } SMARTLIST_FOREACH_END(router);
        if (any_unwarned) {
          char *alternatives = smartlist_join_strings(fps, "; ",0,NULL);
          log_warn(LD_CONFIG,
@@@ -2380,7 -2338,7 +2380,7 @@@
        SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
        smartlist_free(fps);
      } else if (warn_if_unnamed) {
 -      routerstatus_t *rs = router_get_consensus_status_by_id(
 +      routerstatus_t *rs = router_get_mutable_consensus_status_by_id(
            best_match->cache_info.identity_digest);
        if (rs && !rs->name_lookup_warned) {
          char fp[HEX_DIGEST_LEN+1];
@@@ -2396,8 -2354,8 +2396,8 @@@
      }
      return best_match;
    }
 -
    return NULL;
 +#endif
  }
  
  /** Try to find a routerinfo for <b>digest</b>. If we don't have one,
@@@ -2406,7 -2364,7 +2406,7 @@@
  int
  router_digest_version_as_new_as(const char *digest, const char *cutoff)
  {
 -  routerinfo_t *router = router_get_by_digest(digest);
 +  const routerinfo_t *router = router_get_by_id_digest(digest);
    if (!router)
      return 1;
    return tor_version_as_new_as(router->platform, cutoff);
@@@ -2460,20 -2418,44 +2460,20 @@@ hexdigest_to_digest(const char *hexdige
  
  /** Return the router in our routerlist whose hexadecimal key digest
   * is <b>hexdigest</b>.  Return NULL if no such router is known. */
 -routerinfo_t *
 +const routerinfo_t *
  router_get_by_hexdigest(const char *hexdigest)
  {
 -  char digest[DIGEST_LEN];
 -  size_t len;
 -  routerinfo_t *ri;
 -
 -  tor_assert(hexdigest);
 -  if (!routerlist)
 -    return NULL;
 -  if (hexdigest[0]=='$')
 -    ++hexdigest;
 -  len = strlen(hexdigest);
 -  if (hexdigest_to_digest(hexdigest, digest) < 0)
 +  if (is_legal_nickname(hexdigest))
      return NULL;
  
 -  ri = router_get_by_digest(digest);
 -
 -  if (ri && len > HEX_DIGEST_LEN) {
 -    if (hexdigest[HEX_DIGEST_LEN] == '=') {
 -      if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1) ||
 -          !ri->is_named)
 -        return NULL;
 -    } else if (hexdigest[HEX_DIGEST_LEN] == '~') {
 -      if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1))
 -        return NULL;
 -    } else {
 -      return NULL;
 -    }
 -  }
 -
 -  return ri;
 +  /* It's not a legal nickname, so it must be a hexdigest or nothing. */
 +  return router_get_by_nickname(hexdigest, 1);
  }
  
 -/** Return the router in our routerlist whose 20-byte key digest
 - * is <b>digest</b>.  Return NULL if no such router is known. */
 +/** As router_get_by_id_digest,but return a pointer that you're allowed to
 + * modify */
  routerinfo_t *
 -router_get_by_digest(const char *digest)
 +router_get_mutable_by_digest(const char *digest)
  {
    tor_assert(digest);
  
@@@ -2484,14 -2466,6 +2484,14 @@@
    return rimap_get(routerlist->identity_map, digest);
  }
  
 +/** Return the router in our routerlist whose 20-byte key digest
 + * is <b>digest</b>.  Return NULL if no such router is known. */
 +const routerinfo_t *
 +router_get_by_id_digest(const char *digest)
 +{
 +  return router_get_mutable_by_digest(digest);
 +}
 +
  /** Return the router in our routerlist whose 20-byte descriptor
   * is <b>digest</b>.  Return NULL if no such router is known. */
  signed_descriptor_t *
@@@ -2542,7 -2516,7 +2542,7 @@@ extrainfo_get_by_descriptor_digest(cons
   * The caller must not free the string returned.
   */
  static const char *
 -signed_descriptor_get_body_impl(signed_descriptor_t *desc,
 +signed_descriptor_get_body_impl(const signed_descriptor_t *desc,
                                  int with_annotations)
  {
    const char *r = NULL;
@@@ -2591,7 -2565,7 +2591,7 @@@
   * The caller must not free the string returned.
   */
  const char *
 -signed_descriptor_get_body(signed_descriptor_t *desc)
 +signed_descriptor_get_body(const signed_descriptor_t *desc)
  {
    return signed_descriptor_get_body_impl(desc, 0);
  }
@@@ -2599,7 -2573,7 +2599,7 @@@
  /** As signed_descriptor_get_body(), but points to the beginning of the
   * annotations section rather than the beginning of the descriptor. */
  const char *
 -signed_descriptor_get_annotations(signed_descriptor_t *desc)
 +signed_descriptor_get_annotations(const signed_descriptor_t *desc)
  {
    return signed_descriptor_get_body_impl(desc, 1);
  }
@@@ -2652,6 -2626,7 +2652,6 @@@ routerinfo_free(routerinfo_t *router
    }
    addr_policy_list_free(router->exit_policy);
  
 -  /* XXXX Remove if this turns out to affect performance. */
    memset(router, 77, sizeof(routerinfo_t));
  
    tor_free(router);
@@@ -2666,6 -2641,7 +2666,6 @@@ extrainfo_free(extrainfo_t *extrainfo
    tor_free(extrainfo->cache_info.signed_descriptor_body);
    tor_free(extrainfo->pending_sig);
  
 -  /* XXXX remove this if it turns out to slow us down. */
    memset(extrainfo, 88, sizeof(extrainfo_t)); /* debug bad memory usage */
    tor_free(extrainfo);
  }
@@@ -2679,6 -2655,7 +2679,6 @@@ signed_descriptor_free(signed_descripto
  
    tor_free(sd->signed_descriptor_body);
  
 -  /* XXXX remove this once more bugs go away. */
    memset(sd, 99, sizeof(signed_descriptor_t)); /* Debug bad mem usage */
    tor_free(sd);
  }
@@@ -2784,7 -2761,8 +2784,7 @@@ routerlist_insert(routerlist_t *rl, rou
    routerinfo_t *ri_old;
    signed_descriptor_t *sd_old;
    {
 -    /* XXXX Remove if this slows us down. */
 -    routerinfo_t *ri_generated = router_get_my_routerinfo();
 +    const routerinfo_t *ri_generated = router_get_my_routerinfo();
      tor_assert(ri_generated != ri);
    }
    tor_assert(ri->cache_info.routerlist_index == -1);
@@@ -2806,7 -2784,6 +2806,7 @@@
                &ri->cache_info);
    smartlist_add(rl->routers, ri);
    ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1;
 +  nodelist_add_routerinfo(ri);
    router_dir_info_changed();
  #ifdef DEBUG_ROUTERLIST
    routerlist_assert_ok(rl);
@@@ -2827,6 -2804,7 +2827,6 @@@ extrainfo_insert(routerlist_t *rl, extr
    extrainfo_t *ei_tmp;
  
    {
 -    /* XXXX remove this code if it slows us down. */
      extrainfo_t *ei_generated = router_get_my_extrainfo();
      tor_assert(ei_generated != ei);
    }
@@@ -2872,7 -2850,8 +2872,7 @@@ static voi
  routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri)
  {
    {
 -    /* XXXX remove this code if it slows us down. */
 -    routerinfo_t *ri_generated = router_get_my_routerinfo();
 +    const routerinfo_t *ri_generated = router_get_my_routerinfo();
      tor_assert(ri_generated != ri);
    }
    tor_assert(ri->cache_info.routerlist_index == -1);
@@@ -2912,8 -2891,6 +2912,8 @@@ routerlist_remove(routerlist_t *rl, rou
    tor_assert(0 <= idx && idx < smartlist_len(rl->routers));
    tor_assert(smartlist_get(rl->routers, idx) == ri);
  
 +  nodelist_remove_routerinfo(ri);
 +
    /* make sure the rephist module knows that it's not running */
    rep_hist_note_router_unreachable(ri->cache_info.identity_digest, now);
  
@@@ -3025,7 -3002,8 +3025,7 @@@ routerlist_replace(routerlist_t *rl, ro
    routerinfo_t *ri_tmp;
    extrainfo_t *ei_tmp;
    {
 -    /* XXXX Remove this if it turns out to slow us down. */
 -    routerinfo_t *ri_generated = router_get_my_routerinfo();
 +    const routerinfo_t *ri_generated = router_get_my_routerinfo();
      tor_assert(ri_generated != ri_new);
    }
    tor_assert(ri_old != ri_new);
@@@ -3035,9 -3013,6 +3035,9 @@@
    tor_assert(0 <= idx && idx < smartlist_len(rl->routers));
    tor_assert(smartlist_get(rl->routers, idx) == ri_old);
  
 +  nodelist_remove_routerinfo(ri_old);
 +  nodelist_add_routerinfo(ri_new);
 +
    router_dir_info_changed();
    if (idx >= 0) {
      smartlist_set(rl->routers, idx, ri_new);
@@@ -3184,27 -3159,28 +3184,27 @@@ routerlist_reset_warnings(void
  void
  router_set_status(const char *digest, int up)
  {
 -  routerinfo_t *router;
 -  routerstatus_t *status;
 +  node_t *node;
    tor_assert(digest);
  
    SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
                      if (!memcmp(d->digest, digest, DIGEST_LEN))
                        d->is_running = up);
  
 -  router = router_get_by_digest(digest);
 -  if (router) {
 -    log_debug(LD_DIR,"Marking router '%s/%s' as %s.",
 -              router->nickname, router->address, up ? "up" : "down");
 -    if (!up && router_is_me(router) && !we_are_hibernating())
 +  node = node_get_mutable_by_id(digest);
 +  if (node) {
 +#if 0
 +    char buf[MAX_VERBOSE_NICKNAME_LEN+1];
 +    node_get_verbose_nickname(node,buf);
 +    log_debug(LD_DIR,"Marking router %s as %s.",
 +              buf, up ? "up" : "down");
 +#endif
 +    if (!up && node_is_me(node) && !we_are_hibernating())
        log_warn(LD_NET, "We just marked ourself as down. Are your external "
                 "addresses reachable?");
 -    router->is_running = up;
 -  }
 -  status = router_get_consensus_status_by_id(digest);
 -  if (status && status->is_running != up) {
 -    status->is_running = up;
 -    control_event_networkstatus_changed_single(status);
 +    node->is_running = up;
    }
 +
    router_dir_info_changed();
  }
  
@@@ -3247,7 -3223,7 +3247,7 @@@ router_add_to_routerlist(routerinfo_t *
  
    id_digest = router->cache_info.identity_digest;
  
 -  old_router = router_get_by_digest(id_digest);
 +  old_router = router_get_mutable_by_digest(id_digest);
  
    /* Make sure that we haven't already got this exact descriptor. */
    if (sdmap_get(routerlist->desc_digest_map,
@@@ -3278,12 -3254,12 +3278,12 @@@
  
    if (authdir) {
      if (authdir_wants_to_reject_router(router, msg,
 -                                       !from_cache && !from_fetch)) {
 +                                       !from_cache && !from_fetch,
 +                                       &authdir_believes_valid)) {
        tor_assert(*msg);
        routerinfo_free(router);
        return ROUTER_AUTHDIR_REJECTS;
      }
 -    authdir_believes_valid = router->is_valid;
    } else if (from_fetch) {
      /* Only check the descriptor digest against the network statuses when
       * we are receiving in response to a fetch. */
@@@ -3310,15 -3286,14 +3310,15 @@@
    SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
    {
      routerstatus_t *rs =
 -      networkstatus_v2_find_entry(ns, id_digest);
 +      networkstatus_v2_find_mutable_entry(ns, id_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, id_digest);
 +    routerstatus_t *rs = networkstatus_vote_find_mutable_entry(
 +                                                     consensus, id_digest);
      if (rs && !memcmp(rs->descriptor_digest,
                        router->cache_info.signed_descriptor_digest,
                        DIGEST_LEN)) {
@@@ -3918,7 -3893,7 +3918,7 @@@ router_load_extrainfo_from_string(cons
  static int
  signed_desc_digest_is_recognized(signed_descriptor_t *desc)
  {
 -  routerstatus_t *rs;
 +  const routerstatus_t *rs;
    networkstatus_t *consensus = networkstatus_get_latest_consensus();
    int caches = directory_caches_dir_info(get_options());
    const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list();
@@@ -3951,34 -3926,33 +3951,34 @@@ routerlist_retry_directory_downloads(ti
    router_reset_descriptor_download_failures();
    update_networkstatus_downloads(now);
    update_router_descriptor_downloads(now);
 +  update_microdesc_downloads(now);
  }
  
 -/** Return 1 if all running sufficiently-stable routers will reject
 +/** Return 1 if all running sufficiently-stable routers we can use will reject
   * addr:port, return 0 if any might accept it. */
  int
 -router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port,
 -                                          int need_uptime)
 -{
 +router_exit_policy_all_nodes_reject(uint32_t addr, uint16_t port,
 +                                    int need_uptime)
 +{ /* XXXX MOVE */
    addr_policy_result_t r;
 -  if (!routerlist) return 1;
  
 -  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -  {
 -    if (router->is_running &&
 -        !router_is_unreliable(router, need_uptime, 0, 0)) {
 -      r = compare_addr_to_addr_policy(addr, port, router->exit_policy);
 +  SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
 +    if (node->is_running &&
 +        !node_is_unreliable(node, need_uptime, 0, 0)) {
 +
 +      r = compare_addr_to_node_policy(addr, port, node);
 +
        if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
          return 0; /* this one could be ok. good enough. */
      }
 -  });
 +  } SMARTLIST_FOREACH_END(node);
    return 1; /* all will reject. */
  }
  
  /** Return true iff <b>router</b> does not permit exit streams.
   */
  int
 -router_exit_policy_rejects_all(routerinfo_t *router)
 +router_exit_policy_rejects_all(const routerinfo_t *router)
  {
    return router->policy_is_reject_star;
  }
@@@ -4113,9 -4087,7 +4113,9 @@@ any_trusted_dir_is_v1_authority(void
  /** For every current directory connection whose purpose is <b>purpose</b>,
   * and where the resource being downloaded begins with <b>prefix</b>, split
   * rest of the resource into base16 fingerprints, decode them, and set the
 - * corresponding elements of <b>result</b> to a nonzero value. */
 + * corresponding elements of <b>result</b> to a nonzero value.
 + * DOCDOC purpose==microdesc
 + */
  static void
  list_pending_downloads(digestmap_t *result,
                         int purpose, const char *prefix)
@@@ -4123,23 -4095,20 +4123,23 @@@
    const size_t p_len = strlen(prefix);
    smartlist_t *tmp = smartlist_create();
    smartlist_t *conns = get_connection_array();
 +  int flags = DSR_HEX;
 +  if (purpose == DIR_PURPOSE_FETCH_MICRODESC)
 +    flags = DSR_DIGEST256|DSR_BASE64;
  
    tor_assert(result);
  
 -  SMARTLIST_FOREACH(conns, connection_t *, conn,
 -  {
 +  SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
      if (conn->type == CONN_TYPE_DIR &&
          conn->purpose == purpose &&
          !conn->marked_for_close) {
        const char *resource = TO_DIR_CONN(conn)->requested_resource;
        if (!strcmpstart(resource, prefix))
          dir_split_resource_into_fingerprints(resource + p_len,
 -                                             tmp, NULL, DSR_HEX);
 +                                             tmp, NULL, flags);
      }
 -  });
 +  } SMARTLIST_FOREACH_END(conn);
 +
    SMARTLIST_FOREACH(tmp, char *, d,
                      {
                        digestmap_set(result, d, (void*)1);
@@@ -4159,21 -4128,13 +4159,21 @@@ list_pending_descriptor_downloads(diges
    list_pending_downloads(result, purpose, "d/");
  }
  
 -/** Launch downloads for all the descriptors whose digests are listed
 - * as digests[i] for lo <= i < hi.  (Lo and hi may be out of range.)
 - * If <b>source</b> is given, download from <b>source</b>; otherwise,
 - * download from an appropriate random directory server.
 +/** DOCDOC */
 +/*XXXX NM should use digest256, if one comes into being. */
 +void
 +list_pending_microdesc_downloads(digestmap_t *result)
 +{
 +  list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
 +}
 +
 +/** Launch downloads for all the descriptors whose digests or digests256
 + * are listed as digests[i] for lo <= i < hi.  (Lo and hi may be out of
 + * range.)  If <b>source</b> is given, download from <b>source</b>;
 + * otherwise, download from an appropriate random directory server.
   */
  static void
 -initiate_descriptor_downloads(routerstatus_t *source,
 +initiate_descriptor_downloads(const routerstatus_t *source,
                                int purpose,
                                smartlist_t *digests,
                                int lo, int hi, int pds_flags)
@@@ -4181,20 -4142,6 +4181,20 @@@
    int i, n = hi-lo;
    char *resource, *cp;
    size_t r_len;
 +
 +  int digest_len = DIGEST_LEN, enc_digest_len = HEX_DIGEST_LEN;
 +  char sep = '+';
 +  int b64_256 = 0;
 +
 +  if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
 +    /* Microdescriptors are downloaded by "-"-separated base64-encoded
 +     * 256-bit digests. */
 +    digest_len = DIGEST256_LEN;
 +    enc_digest_len = BASE64_DIGEST256_LEN;
 +    sep = '-';
 +    b64_256 = 1;
 +  }
 +
    if (n <= 0)
      return;
    if (lo < 0)
@@@ -4202,19 -4149,15 +4202,19 @@@
    if (hi > smartlist_len(digests))
      hi = smartlist_len(digests);
  
 -  r_len = 8 + (HEX_DIGEST_LEN+1)*n;
 +  r_len = 8 + (enc_digest_len+1)*n;
    cp = resource = tor_malloc(r_len);
    memcpy(cp, "d/", 2);
    cp += 2;
    for (i = lo; i < hi; ++i) {
 -    base16_encode(cp, r_len-(cp-resource),
 -                  smartlist_get(digests,i), DIGEST_LEN);
 -    cp += HEX_DIGEST_LEN;
 -    *cp++ = '+';
 +    if (b64_256) {
 +      digest256_to_base64(cp, smartlist_get(digests, i));
 +    } else {
 +      base16_encode(cp, r_len-(cp-resource),
 +                    smartlist_get(digests,i), digest_len);
 +    }
 +    cp += enc_digest_len;
 +    *cp++ = sep;
    }
    memcpy(cp-1, ".z", 3);
  
@@@ -4237,7 -4180,7 +4237,7 @@@
  static INLINE int
  client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options)
  {
 -  if (!rs->is_running && !options->FetchUselessDescriptors) {
 +  if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
      /* If we had this router descriptor, we wouldn't even bother using it.
       * But, if we want to have a complete list, fetch it anyway. */
      return 0;
@@@ -4261,7 -4204,6 +4261,7 @@@
   *   So use 96 because it's a nice number.
   */
  #define MAX_DL_PER_REQUEST 96
 +#define MAX_MICRODESC_DL_PER_REQUEST 92
  /** Don't split our requests so finely that we are requesting fewer than
   * this number per server. */
  #define MIN_DL_PER_REQUEST 4
@@@ -4276,33 -4218,21 +4276,33 @@@
   * them until they have more, or until this amount of time has passed. */
  #define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60)
  
 -/** Given a list of router descriptor digests in <b>downloadable</b>, decide
 - * whether to delay fetching until we have more.  If we don't want to delay,
 - * launch one or more requests to the appropriate directory authorities. */
 -static void
 -launch_router_descriptor_downloads(smartlist_t *downloadable,
 -                                   routerstatus_t *source, time_t now)
 +/** Given a <b>purpose</b> (FETCH_MICRODESC or FETCH_SERVERDESC) and a list of
 + * router descriptor digests or microdescriptor digest256s in
 + * <b>downloadable</b>, decide whether to delay fetching until we have more.
 + * If we don't want to delay, launch one or more requests to the appropriate
 + * directory authorities.
 + */
 +void
 +launch_descriptor_downloads(int purpose,
 +                            smartlist_t *downloadable,
 +                            const routerstatus_t *source, time_t now)
  {
    int should_delay = 0, n_downloadable;
    or_options_t *options = get_options();
 +  const char *descname;
 +
 +  tor_assert(purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
 +             purpose == DIR_PURPOSE_FETCH_MICRODESC);
 +
 +  descname = (purpose == DIR_PURPOSE_FETCH_SERVERDESC) ?
 +    "routerdesc" : "microdesc";
  
    n_downloadable = smartlist_len(downloadable);
    if (!directory_fetches_dir_info_early(options)) {
      if (n_downloadable >= MAX_DL_TO_DELAY) {
        log_debug(LD_DIR,
 -             "There are enough downloadable routerdescs to launch requests.");
 +                "There are enough downloadable %ss to launch requests.",
 +                descname);
        should_delay = 0;
      } else {
        should_delay = (last_routerdesc_download_attempted +
@@@ -4310,15 -4240,13 +4310,15 @@@
        if (!should_delay && n_downloadable) {
          if (last_routerdesc_download_attempted) {
            log_info(LD_DIR,
 -                   "There are not many downloadable routerdescs, but we've "
 +                   "There are not many downloadable %ss, but we've "
                     "been waiting long enough (%d seconds). Downloading.",
 +                   descname,
                     (int)(now-last_routerdesc_download_attempted));
          } else {
            log_info(LD_DIR,
 -                 "There are not many downloadable routerdescs, but we haven't "
 -                 "tried downloading descriptors recently. Downloading.");
 +                   "There are not many downloadable %ss, but we haven't "
 +                   "tried downloading descriptors recently. Downloading.",
 +                   descname);
          }
        }
      }
@@@ -4345,19 -4273,12 +4345,19 @@@
         * update_router_descriptor_downloads() later on, once the connections
         * have succeeded or failed.
         */
 -      pds_flags |= PDS_NO_EXISTING_SERVERDESC_FETCH;
 +      pds_flags |= (purpose == DIR_PURPOSE_FETCH_MICRODESC) ?
 +        PDS_NO_EXISTING_MICRODESC_FETCH :
 +        PDS_NO_EXISTING_SERVERDESC_FETCH;
      }
  
      n_per_request = CEIL_DIV(n_downloadable, MIN_REQUESTS);
 -    if (n_per_request > MAX_DL_PER_REQUEST)
 -      n_per_request = MAX_DL_PER_REQUEST;
 +    if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
 +      if (n_per_request > MAX_MICRODESC_DL_PER_REQUEST)
 +        n_per_request = MAX_MICRODESC_DL_PER_REQUEST;
 +    } else {
 +      if (n_per_request > MAX_DL_PER_REQUEST)
 +        n_per_request = MAX_DL_PER_REQUEST;
 +    }
      if (n_per_request < MIN_DL_PER_REQUEST)
        n_per_request = MIN_DL_PER_REQUEST;
  
@@@ -4372,7 -4293,7 +4372,7 @@@
               req_plural, n_downloadable, rtr_plural, n_per_request);
      smartlist_sort_digests(downloadable);
      for (i=0; i < n_downloadable; i += n_per_request) {
 -      initiate_descriptor_downloads(source, DIR_PURPOSE_FETCH_SERVERDESC,
 +      initiate_descriptor_downloads(source, purpose,
                                      downloadable, i, i+n_per_request,
                                      pds_flags);
      }
@@@ -4562,14 -4483,15 +4562,14 @@@ update_consensus_router_descriptor_down
  
    map = digestmap_new();
    list_pending_descriptor_downloads(map, 0);
 -  SMARTLIST_FOREACH(consensus->routerstatus_list, void *, rsp,
 -    {
 +  SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) {
        routerstatus_t *rs =
          is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp;
        signed_descriptor_t *sd;
        if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) {
 -        routerinfo_t *ri;
 +        const routerinfo_t *ri;
          ++n_have;
 -        if (!(ri = router_get_by_digest(rs->identity_digest)) ||
 +        if (!(ri = router_get_by_id_digest(rs->identity_digest)) ||
              memcmp(ri->cache_info.signed_descriptor_digest,
                     sd->signed_descriptor_digest, DIGEST_LEN)) {
            /* We have a descriptor with this digest, but either there is no
@@@ -4602,8 -4524,7 +4602,8 @@@
        if (is_vote && source) {
          char time_bufnew[ISO_TIME_LEN+1];
          char time_bufold[ISO_TIME_LEN+1];
 -        routerinfo_t *oldrouter = router_get_by_digest(rs->identity_digest);
 +        const routerinfo_t *oldrouter;
 +        oldrouter = router_get_by_id_digest(rs->identity_digest);
          format_iso_time(time_bufnew, rs->published_on);
          if (oldrouter)
            format_iso_time(time_bufold, oldrouter->cache_info.published_on);
@@@ -4613,7 -4534,7 +4613,7 @@@
                   source->nickname, oldrouter ? "known" : "unknown");
        }
        smartlist_add(downloadable, rs->descriptor_digest);
 -    });
 +  } SMARTLIST_FOREACH_END(rsp);
  
    if (!authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL)
        && smartlist_len(no_longer_old)) {
@@@ -4645,8 -4566,7 +4645,8 @@@
             smartlist_len(downloadable), n_delayed, n_have, n_in_oldrouters,
             n_would_reject, n_wouldnt_use, n_inprogress);
  
 -  launch_router_descriptor_downloads(downloadable, source, now);
 +  launch_descriptor_downloads(DIR_PURPOSE_FETCH_SERVERDESC,
 +                              downloadable, source, now);
  
    digestmap_free(map, NULL);
   done:
@@@ -4671,13 -4591,10 +4671,13 @@@ update_router_descriptor_downloads(time
    if (directory_fetches_dir_info_early(options)) {
      update_router_descriptor_cache_downloads_v2(now);
    }
 +
    update_consensus_router_descriptor_downloads(now, 0,
 -    networkstatus_get_reasonably_live_consensus(now));
 +                  networkstatus_get_reasonably_live_consensus(now, FLAV_NS));
  
    /* XXXX021 we could be smarter here; see notes on bug 652. */
 +  /* XXXX NM Microdescs: if we're not fetching microdescriptors, we need
 +   * to make something else invoke this. */
    /* If we're a server that doesn't have a configured address, we rely on
     * directory fetches to learn when our address changes.  So if we haven't
     * tried to get any routerdescs in a long time, try a dummy fetch now. */
@@@ -4724,7 -4641,7 +4724,7 @@@ update_extrainfo_downloads(time_t now
          sd = &((routerinfo_t*)smartlist_get(lst, i))->cache_info;
        if (sd->is_extrainfo)
          continue; /* This should never happen. */
 -      if (old_routers && !router_get_by_digest(sd->identity_digest))
 +      if (old_routers && !router_get_by_id_digest(sd->identity_digest))
          continue; /* Couldn't check the signature if we got it. */
        if (sd->extrainfo_is_bogus)
          continue;
@@@ -4825,7 -4742,7 +4825,7 @@@ count_usable_descriptors(int *num_prese
  
    SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
       {
 -       if (in_set && ! routerset_contains_routerstatus(in_set, rs))
 +       if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
           continue;
         if (client_would_use_router(rs, now, options)) {
           ++*num_usable; /* the consensus says we want it. */
@@@ -4848,7 -4765,7 +4848,7 @@@ count_loading_descriptors_progress(void
    int num_present = 0, num_usable=0;
    time_t now = time(NULL);
    const networkstatus_t *consensus =
 -    networkstatus_get_reasonably_live_consensus(now);
 +    networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
    double fraction;
  
    if (!consensus)
@@@ -4878,7 -4795,7 +4878,7 @@@ update_router_have_minimum_dir_info(voi
    int res;
    or_options_t *options = get_options();
    const networkstatus_t *consensus =
 -    networkstatus_get_reasonably_live_consensus(now);
 +    networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
  
    if (!consensus) {
      if (!networkstatus_get_latest_consensus())
@@@ -4988,7 -4905,7 +4988,7 @@@ router_reset_descriptor_download_failur
   * would not cause a recent (post 0.1.1.6) dirserver to republish.
   */
  int
 -router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2)
 +router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
  {
    time_t r1pub, r2pub;
    long time_difference;
@@@ -4996,7 -4913,7 +4996,7 @@@
  
    /* r1 should be the one that was published first. */
    if (r1->cache_info.published_on > r2->cache_info.published_on) {
 -    routerinfo_t *ri_tmp = r2;
 +    const routerinfo_t *ri_tmp = r2;
      r2 = r1;
      r1 = ri_tmp;
    }
@@@ -5015,6 -4932,7 +5015,6 @@@
        (r1->contact_info && r2->contact_info &&
         strcasecmp(r1->contact_info, r2->contact_info)) ||
        r1->is_hibernating != r2->is_hibernating ||
 -      r1->has_old_dnsworkers != r2->has_old_dnsworkers ||
        cmp_addr_policies(r1->exit_policy, r2->exit_policy))
      return 0;
    if ((r1->declared_family == NULL) != (r2->declared_family == NULL))
@@@ -5069,8 -4987,7 +5069,8 @@@
   * incompatibility (if any).
   **/
  int
 -routerinfo_incompatible_with_extrainfo(routerinfo_t *ri, extrainfo_t *ei,
 +routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
 +                                       extrainfo_t *ei,
                                         signed_descriptor_t *sd,
                                         const char **msg)
  {
@@@ -5078,7 -4995,7 +5078,7 @@@
    tor_assert(ri);
    tor_assert(ei);
    if (!sd)
 -    sd = &ri->cache_info;
 +    sd = (signed_descriptor_t*)&ri->cache_info;
  
    if (ei->bad_sig) {
      if (msg) *msg = "Extrainfo signature was bad, or signed with wrong key.";
@@@ -5142,7 -5059,7 +5142,7 @@@
  /** Assert that the internal representation of <b>rl</b> is
   * self-consistent. */
  void
 -routerlist_assert_ok(routerlist_t *rl)
 +routerlist_assert_ok(const routerlist_t *rl)
  {
    routerinfo_t *r2;
    signed_descriptor_t *sd2;
@@@ -5232,7 -5149,7 +5232,7 @@@
   * If <b>router</b> is NULL, it just frees its internal memory and returns.
   */
  const char *
 -esc_router_info(routerinfo_t *router)
 +esc_router_info(const routerinfo_t *router)
  {
    static char *info=NULL;
    char *esc_contact, *esc_platform;
@@@ -5334,6 -5251,38 +5334,6 @@@ routerset_get_countryname(const char *c
    return country;
  }
  
 -#if 0
 -/** Add the GeoIP database's integer index (+1) of a valid two-character
 - * country code to the routerset's <b>countries</b> bitarray. Return the
 - * integer index if the country code is valid, -1 otherwise.*/
 -static int
 -routerset_add_country(const char *c)
 -{
 -  char country[3];
 -  country_t cc;
 -
 -  /* XXXX: Country codes must be of the form \{[a-z\?]{2}\} but this accepts
 -     \{[.]{2}\}. Do we need to be strict? -RH */
 -  /* Nope; if the country code is bad, we'll get 0 when we look it up. */
 -
 -  if (!geoip_is_loaded()) {
 -    log(LOG_WARN, LD_CONFIG, "GeoIP database not loaded: Cannot add country"
 -                             "entry %s, ignoring.", c);
 -    return -1;
 -  }
 -
 -  memcpy(country, c+1, 2);
 -  country[2] = '\0';
 -  tor_strlower(country);
 -
 -  if ((cc=geoip_get_country(country))==-1) {
 -    log(LOG_WARN, LD_CONFIG, "Country code '%s' is not valid, ignoring.",
 -        country);
 -  }
 -  return cc;
 -}
 -#endif
 -
  /** Update the routerset's <b>countries</b> bitarray_t. Called whenever
   * the GeoIP database is reloaded.
   */
@@@ -5435,7 -5384,7 +5435,7 @@@ refresh_all_country_info(void
    if (options->_ExcludeExitNodesUnion)
      routerset_refresh_countries(options->_ExcludeExitNodesUnion);
  
 -  routerlist_refresh_countries();
 +  nodelist_refresh_countries();
  }
  
  /** Add all members of the set <b>source</b> to <b>target</b>. */
@@@ -5485,10 -5434,11 +5485,10 @@@ routerset_is_empty(const routerset_t *s
  static int
  routerset_contains(const routerset_t *set, const tor_addr_t *addr,
                     uint16_t orport,
 -                   const char *nickname, const char *id_digest, int is_named,
 +                   const char *nickname, const char *id_digest,
                     country_t country)
  {
    if (!set || !set->list) return 0;
 -  (void) is_named; /* not supported */
    if (nickname && strmap_get_lc(set->names, nickname))
      return 4;
    if (id_digest && digestmap_get(set->digests, id_digest))
@@@ -5516,14 -5466,13 +5516,14 @@@ routerset_contains_extendinfo(const rou
                              ei->port,
                              ei->nickname,
                              ei->identity_digest,
                              -1 /*country*/);
  }
  
 -/** Return true iff <b>ri</b> is in <b>set</b>. */
 +/** Return true iff <b>ri</b> is in <b>set</b>.  If country is <b>-1</b>, we
 + * look up the country. */
  int
 -routerset_contains_router(const routerset_t *set, routerinfo_t *ri)
 +routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
 +                          country_t country)
  {
    tor_addr_t addr;
    tor_addr_from_ipv4h(&addr, ri->addr);
@@@ -5532,15 -5481,13 +5532,15 @@@
                              ri->or_port,
                              ri->nickname,
                              ri->cache_info.identity_digest,
 -                            ri->is_named,
 -                            ri->country);
 +                            country);
  }
  
 -/** Return true iff <b>rs</b> is in <b>set</b>. */
 +/** Return true iff <b>rs</b> is in <b>set</b>.  If country is <b>-1</b>, we
 + * look up the country. */
  int
 -routerset_contains_routerstatus(const routerset_t *set, routerstatus_t *rs)
 +routerset_contains_routerstatus(const routerset_t *set,
 +                                const routerstatus_t *rs,
 +                                country_t country)
  {
    tor_addr_t addr;
    tor_addr_from_ipv4h(&addr, rs->addr);
@@@ -5549,55 -5496,46 +5549,55 @@@
                              rs->or_port,
                              rs->nickname,
                              rs->identity_digest,
 -                            rs->is_named,
 -                            -1);
 +                            country);
 +}
 +
 +/** Return true iff <b>node</b> is in <b>set</b>. */
 +int
 +routerset_contains_node(const routerset_t *set, const node_t *node)
 +{
 +  if (node->rs)
 +    return routerset_contains_routerstatus(set, node->rs, node->country);
 +  else if (node->ri)
 +    return routerset_contains_router(set, node->ri, node->country);
 +  else
 +    return 0;
  }
  
 -/** Add every known routerinfo_t that is a member of <b>routerset</b> to
 +/** Add every known node_t that is a member of <b>routerset</b> to
   * <b>out</b>.  If <b>running_only</b>, only add the running ones. */
  void
 -routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
 -                          int running_only)
 -{
 +routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
 +                        int running_only)
 +{ /* XXXX MOVE */
    tor_assert(out);
    if (!routerset || !routerset->list)
      return;
 -  if (!warned_nicknames)
 -    warned_nicknames = smartlist_create();
 -  if (routerset_is_list(routerset)) {
  
 +  if (routerset_is_list(routerset)) {
      /* No routers are specified by type; all are given by name or digest.
       * we can do a lookup in O(len(list)). */
      SMARTLIST_FOREACH(routerset->list, const char *, name, {
 -        routerinfo_t *router = router_get_by_nickname(name, 1);
 -        if (router) {
 -          if (!running_only || router->is_running)
 -            smartlist_add(out, router);
 +        const node_t *node = node_get_by_nickname(name, 1);
 +        if (node) {
 +          if (!running_only || node->is_running)
 +            smartlist_add(out, (void*)node);
          }
      });
    } else {
      /* We need to iterate over the routerlist to get all the ones of the
       * right kind. */
 -    routerlist_t *rl = router_get_routerlist();
 -    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, {
 -        if (running_only && !router->is_running)
 +    smartlist_t *nodes = nodelist_get_list();
 +    SMARTLIST_FOREACH(nodes, const node_t *, node, {
 +        if (running_only && !node->is_running)
            continue;
 -        if (routerset_contains_router(routerset, router))
 -          smartlist_add(out, router);
 +        if (routerset_contains_node(routerset, node))
 +          smartlist_add(out, (void*)node);
      });
    }
  }
  
 -/** Add to <b>target</b> every routerinfo_t from <b>source</b> except:
 +/** Add to <b>target</b> every node_t from <b>source</b> except:
   *
   * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
   * <b>include</b>; and
@@@ -5606,39 -5544,39 +5606,39 @@@
   * 3) If <b>running_only</b>, don't add non-running routers.
   */
  void
 -routersets_get_disjunction(smartlist_t *target,
 +routersets_get_node_disjunction(smartlist_t *target,
                             const smartlist_t *source,
                             const routerset_t *include,
                             const routerset_t *exclude, int running_only)
  {
 -  SMARTLIST_FOREACH(source, routerinfo_t *, router, {
 +  SMARTLIST_FOREACH(source, const node_t *, node, {
      int include_result;
 -    if (running_only && !router->is_running)
 +    if (running_only && !node->is_running)
        continue;
      if (!routerset_is_empty(include))
 -      include_result = routerset_contains_router(include, router);
 +      include_result = routerset_contains_node(include, node);
      else
        include_result = 1;
  
      if (include_result) {
 -      int exclude_result = routerset_contains_router(exclude, router);
 +      int exclude_result = routerset_contains_node(exclude, node);
        if (include_result >= exclude_result)
 -        smartlist_add(target, router);
 +        smartlist_add(target, (void*)node);
      }
    });
  }
  
 -/** Remove every routerinfo_t from <b>lst</b> that is in <b>routerset</b>. */
 +/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
  void
 -routerset_subtract_routers(smartlist_t *lst, const routerset_t *routerset)
 -{
 +routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
 +{ /*XXXX MOVE ? */
    tor_assert(lst);
    if (!routerset)
      return;
 -  SMARTLIST_FOREACH(lst, routerinfo_t *, r, {
 -      if (routerset_contains_router(routerset, r)) {
 +  SMARTLIST_FOREACH(lst, const node_t *, node, {
 +      if (routerset_contains_node(routerset, node)) {
          //log_debug(LD_DIR, "Subtracting %s",r->nickname);
 -        SMARTLIST_DEL_CURRENT(lst, r);
 +        SMARTLIST_DEL_CURRENT(lst, node);
        }
      });
  }
@@@ -5699,23 -5637,18 +5699,23 @@@ routerset_free(routerset_t *routerset
  /** Refresh the country code of <b>ri</b>.  This function MUST be called on
   * each router when the GeoIP database is reloaded, and on all new routers. */
  void
 -routerinfo_set_country(routerinfo_t *ri)
 +node_set_country(node_t *node)
  {
 -  ri->country = geoip_get_country_by_ip(ri->addr);
 +  if (node->rs)
 +    node->country = geoip_get_country_by_ip(node->rs->addr);
 +  else if (node->ri)
 +    node->country = geoip_get_country_by_ip(node->ri->addr);
 +  else
 +    node->country = -1;
  }
  
  /** Set the country code of all routers in the routerlist. */
  void
 -routerlist_refresh_countries(void)
 +nodelist_refresh_countries(void) /* MOVE */
  {
 -  routerlist_t *rl = router_get_routerlist();
 -  SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri,
 -                    routerinfo_set_country(ri));
 +  smartlist_t *nodes = nodelist_get_list();
 +  SMARTLIST_FOREACH(nodes, node_t *, node,
 +                    node_set_country(node));
  }
  
  /** Determine the routers that are responsible for <b>id</b> (binary) and
@@@ -5764,9 -5697,9 +5764,9 @@@ hid_serv_get_responsible_directories(sm
  int
  hid_serv_acting_as_directory(void)
  {
 -  routerinfo_t *me = router_get_my_routerinfo();
 +  const routerinfo_t *me = router_get_my_routerinfo();
    networkstatus_t *c;
 -  routerstatus_t *rs;
 +  const routerstatus_t *rs;
    if (!me)
      return 0;
    if (!get_options()->HidServDirectoryV2) {
@@@ -5798,7 -5731,7 +5798,7 @@@
  int
  hid_serv_responsible_for_desc_id(const char *query)
  {
 -  routerinfo_t *me;
 +  const routerinfo_t *me;
    routerstatus_t *last_rs;
    const char *my_id, *last_id;
    int result;