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

[or-cvs] Stop downloading directories and download routers instead. ...



Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv21498/src/or

Modified Files:
	directory.c dirserv.c main.c or.h routerlist.c routerparse.c 
Log Message:
Stop downloading directories and download routers instead.  This still needs some work, but at last clients are finally on the new architecture.  Next comes the tuning and bugfixing.

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/directory.c,v
retrieving revision 1.276
retrieving revision 1.277
diff -u -d -r1.276 -r1.277
--- directory.c	14 Sep 2005 21:09:25 -0000	1.276
+++ directory.c	15 Sep 2005 05:19:38 -0000	1.277
@@ -52,7 +52,9 @@
 static char *http_get_header(const char *headers, const char *which);
 static char *http_get_origin(const char *headers, connection_t *conn);
 static void connection_dir_download_networkstatus_failed(connection_t *conn);
+static void connection_dir_download_routerdesc_failed(connection_t *conn);
 static void dir_networkstatus_download_failed(smartlist_t *failed);
+static void dir_routerdesc_download_failed(smartlist_t *failed);
 
 /********* START VARIABLES **********/
 
@@ -282,6 +284,10 @@
     log_fn(LOG_INFO, "Giving up on directory server at '%s'; retrying",
            conn->address);
     connection_dir_download_networkstatus_failed(conn);
+  } else if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+    log_fn(LOG_INFO, "Giving up on directory server at '%s'; retrying",
+           conn->address);
+    connection_dir_download_routerdesc_failed(conn);
   }
 }
 
@@ -314,6 +320,16 @@
   }
 }
 
+/** Called when an attempt to download one or network status documents
+ * on connection <b>conn</b> failed.
+ */
+static void
+connection_dir_download_routerdesc_failed(connection_t *conn)
+{
+  /* try again. */
+  update_router_descriptor_downloads(time(NULL));
+}
+
 /** Helper for directory_initiate_command_(router|trusted_dir): send the
  * command to a server whose address is <b>address</b>, whose IP is
  * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
@@ -892,14 +908,18 @@
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
+    if (router_parse_directory(body) < 0) {
+      log_fn(LOG_NOTICE,"I failed to parse the directory I fetched from '%s:%d'. Ignoring.", conn->address, conn->port);
+    }
+#if 0
     if (router_load_routerlist_from_directory(body, NULL, !skewed, 0) < 0) {
       log_fn(LOG_NOTICE,"I failed to parse the directory I fetched from '%s:%d'. Ignoring.", conn->address, conn->port);
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
-    log_fn(LOG_INFO,"updated routers.");
     /* do things we've been waiting to do */
     directory_has_arrived(time(NULL), conn->identity_digest);
+#endif
   }
 
   if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
@@ -969,7 +989,8 @@
       else
         break;
     }
-    routers_update_all_from_networkstatus();
+    routers_update_all_from_networkstatus();/*launches router downloads*/
+    directory_info_has_arrived(time(NULL),0);
     if (which) {
       if (smartlist_len(which)) {
         dir_networkstatus_download_failed(which);
@@ -980,8 +1001,36 @@
   }
 
   if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+    smartlist_t *which = NULL;
     /* XXXX NM implement this. */
-    log_fn(LOG_WARN, "Somehow, we requested some individual server descriptors. Skipping.");
+    log_fn(LOG_INFO,"Received server info (size %d) from server '%s:%d'",
+           (int)body_len, conn->address, conn->port);
+    if (status_code != 200) {
+      log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s:%d' while fetching \"/tor/server/%s\". I'll try again soon.",
+             status_code, reason, conn->address, conn->port,
+             conn->requested_resource);
+      tor_free(body); tor_free(headers); tor_free(reason);
+      connection_dir_download_routerdesc_failed(conn);
+      return -1;
+    }
+    if (conn->requested_resource &&
+        !strcmpstart(conn->requested_resource,"fp/")) {
+      int n;
+      which = smartlist_create();
+      smartlist_split_string(which, conn->requested_resource+3, "+", 0, -1);
+      n = smartlist_len(which);
+      if (n && strlen(smartlist_get(which,n-1))==HEX_DIGEST_LEN+2)
+        ((char*)smartlist_get(which,n-1))[HEX_DIGEST_LEN] = '\0';
+    }
+    router_load_routers_from_string(body, 0, which);
+    directory_info_has_arrived(time(NULL),0);
+    if (which) {
+      if (smartlist_len(which)) {
+        dir_routerdesc_download_failed(which);
+      }
+      SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
+      smartlist_free(which);
+    }
   }
 
   if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
@@ -1524,3 +1573,10 @@
   });
 }
 
+/* DOCDOC */
+static void
+dir_routerdesc_download_failed(smartlist_t *failed)
+{
+  /* XXXX writeme!  Give up after a while! */
+}
+

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/dirserv.c,v
retrieving revision 1.230
retrieving revision 1.231
diff -u -d -r1.230 -r1.231
--- dirserv.c	15 Sep 2005 00:51:42 -0000	1.230
+++ dirserv.c	15 Sep 2005 05:19:38 -0000	1.231
@@ -39,6 +39,8 @@
 static int router_is_general_exit(routerinfo_t *ri);
 static router_status_t dirserv_router_get_status(const routerinfo_t *router,
                                                  const char **msg);
+static int dirserv_thinks_router_is_reachable(routerinfo_t *router,
+                                              time_t now);
 
 /************** Fingerprint handling code ************/
 
@@ -283,7 +285,8 @@
 }
 
 /** Check whether we, as a directory server, want to accept <b>ri</b>.  If so,
- * return 0, and set its is_valid and is_named fields.  Otherwise, return -1.
+ * return 0, and set its is_valid,named,running fields.  Otherwise, return -1.
+ *
  * DOCDOC msg
  */
 int
@@ -366,7 +369,7 @@
     *msg = "Rejected: Couldn't parse server descriptor.";
     return -2;
   }
-  if ((r = router_add_to_routerlist(ri, msg))<0) {
+  if ((r = router_add_to_routerlist(ri, msg, 0))<0) {
     return r == -1 ? 0 : -1;
   } else {
     smartlist_t *changed = smartlist_create();
@@ -801,13 +804,6 @@
   cached_dir_t *d;
   d = is_running_routers ? &cached_runningrouters : &cached_directory;
   set_cached_dir(d, tor_strdup(directory), published);
-  if (!is_running_routers) {
-    char filename[512];
-    tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_options()->DataDirectory);
-    if (write_str_to_file(filename,cached_directory.dir,0) < 0) {
-      log_fn(LOG_NOTICE, "Couldn't write cached directory to disk. Ignoring.");
-    }
-  }
 }
 
 /** We've just received a v2 network-status for an authoritative directory
@@ -1077,6 +1073,7 @@
   uint32_t addr;
   crypto_pk_env_t *private_key = get_identity_key();
   smartlist_t *descriptor_list = get_descriptor_list();
+  time_t now = time(NULL);
   const char *contact;
 
   if (!descriptor_list) {
@@ -1147,15 +1144,9 @@
       char digest64[128];
 
       if (options->AuthoritativeDir) {
-        connection_t *conn = connection_get_by_identity_digest(
-                                         ri->identity_digest, CONN_TYPE_OR);
-        f_running = (router_is_me(ri) && !we_are_hibernating()) ||
-          (conn && conn->state == OR_CONN_STATE_OPEN);
-        /* Update router status in routerinfo_t. */
-        ri->is_running = f_running;
-      } else {
-        f_running = ri->is_running;
+        ri->is_running = dirserv_thinks_router_is_reachable(ri, now);
       }
+      f_running = ri->is_running;
 
       format_iso_time(published, ri->published_on);
 

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/main.c,v
retrieving revision 1.551
retrieving revision 1.552
diff -u -d -r1.551 -r1.552
--- main.c	14 Sep 2005 23:42:06 -0000	1.551
+++ main.c	15 Sep 2005 05:19:38 -0000	1.552
@@ -527,43 +527,32 @@
     return 30*60;
 }
 
-/** This function is called whenever we successfully pull down a directory.
- * If <b>identity_digest</b> is defined, it contains the digest of the
- * router that just gave us this directory. */
+/** This function is called whenever we successfully pull down some directory
+ * information. */
 void
-directory_has_arrived(time_t now, char *identity_digest)
+directory_info_has_arrived(time_t now, int from_cache)
 {
   or_options_t *options = get_options();
   /* XXXX011 NM Update this to reflect new directories.  In particular, we
    * can't start building circuits until we have descriptors and networkstatus
    * docs.*/
 
-  log_fn(LOG_INFO, "A directory has arrived.");
-
-  has_fetched_directory=1;
-  /* Don't try to upload or download anything for a while
-   * after the directory we had when we started.
-   */
-  if (!time_to_fetch_directory)
-    time_to_fetch_directory = now + get_dir_fetch_period(options);
-
-  if (!time_to_fetch_running_routers)
-    time_to_fetch_running_routers = now + get_status_fetch_period(options);
-
-  if (identity_digest) /* if it's fresh */
-    helper_nodes_set_status_from_directory();
+  if (!router_have_minimum_dir_info()) {
+    log_fn(LOG_NOTICE, "I know too little.");
+    return;
+  }
 
-  if (server_mode(options) && identity_digest) {
-    /* if this is us, then our dirport is reachable */
-    if (router_digest_is_me(identity_digest))
-      router_dirport_found_reachable();
+  if (!has_fetched_directory) {
+    log_fn(LOG_NOTICE, "We have enough directory information to build circuits.");
   }
 
+  has_fetched_directory=1;
+
   if (server_mode(options) &&
       !we_are_hibernating()) { /* connect to the appropriate routers */
     if (!authdir_mode(options))
       router_retry_connections(0);
-    if (identity_digest) /* we got a fresh directory */
+    if (!from_cache)
       consider_testing_reachability();
   }
 }
@@ -691,7 +680,6 @@
    * new running-routers list, and/or force-uploading our descriptor
    * (if we've passed our internal checks). */
   if (time_to_fetch_directory < now) {
-    time_t next_status_fetch;
     /* purge obsolete entries */
     routerlist_remove_old_routers(ROUTER_MAX_AGE);
 
@@ -701,13 +689,16 @@
       }
     }
 
-    directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
-    time_to_fetch_directory = now + get_dir_fetch_period(options);
-    next_status_fetch = now + get_status_fetch_period(options);
-    if (time_to_fetch_running_routers < next_status_fetch) {
-      time_to_fetch_running_routers = next_status_fetch;
+    /* Only caches actually need to fetch directories now. */
+    if (options->DirPort && !options->V1AuthoritativeDir) {
+      directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
     }
 
+    /* Try to get any routers we don't have. */
+    update_router_descriptor_downloads(now);
+
+    time_to_fetch_directory = now + get_dir_fetch_period(options);
+
     /* Also, take this chance to remove old information from rephist
      * and the rend cache. */
     rep_history_clean(now - options->RephistTrackTime);
@@ -986,10 +977,13 @@
   if (router_reload_router_list()) {
     return -1;
   }
-  /* load the networkstatuses. */
+  /* load the networkstatuses. (This launches a download for new routers as
+   * appropriate.)
+   */
   if (router_reload_networkstatus()) {
     return -1;
   }
+  directory_info_has_arrived(time(NULL),1);
 
   if (authdir_mode(get_options())) {
     /* the directory is already here, run startup things */

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.684
retrieving revision 1.685
diff -u -d -r1.684 -r1.685
--- or.h	15 Sep 2005 00:51:42 -0000	1.684
+++ or.h	15 Sep 2005 05:19:38 -0000	1.685
@@ -1789,7 +1789,7 @@
 void connection_start_writing(connection_t *conn);
 
 void directory_all_unreachable(time_t now);
-void directory_has_arrived(time_t now, char *identity_digest);
+void directory_info_has_arrived(time_t now, int from_cache);
 
 int control_signal_act(int the_signal);
 void handle_signals(int is_parent);
@@ -2089,10 +2089,15 @@
 routerinfo_t *routerinfo_copy(const routerinfo_t *router);
 void router_mark_as_down(const char *digest);
 void routerlist_remove_old_routers(int age);
-int router_add_to_routerlist(routerinfo_t *router, const char **msg);
+int router_add_to_routerlist(routerinfo_t *router, const char **msg,
+                             int from_cache);
 int router_load_single_router(const char *s, const char **msg);
+void router_load_routers_from_string(const char *s, int from_cache,
+                                     smartlist_t *requested_fingerprints);
+#if 0
 int router_load_routerlist_from_directory(const char *s,crypto_pk_env_t *pkey,
                                         int dir_is_recent, int dir_is_cached);
+#endif
 typedef enum { NS_FROM_CACHE, NS_FROM_DIR, NS_GENERATED} networkstatus_source_t;
 int router_set_networkstatus(const char *s, time_t arrived_at,
                              networkstatus_source_t source,
@@ -2120,9 +2125,11 @@
 networkstatus_t *networkstatus_get_by_digest(const char *digest);
 void update_networkstatus_cache_downloads(time_t now);
 void update_networkstatus_client_downloads(time_t now);
+void update_router_descriptor_downloads(time_t now);
 void routers_update_all_from_networkstatus(void);
 void routers_update_status_from_networkstatus(smartlist_t *routers);
 smartlist_t *router_list_superseded(void);
+int router_have_minimum_dir_info(void);
 
 /********************************* routerparse.c ************************/
 
@@ -2153,19 +2160,21 @@
 int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
                                    crypto_pk_env_t *private_key);
 int router_parse_list_from_string(const char **s,
-                                  smartlist_t *dest,
-                                  time_t published);
+                                  smartlist_t *dest);
 int router_parse_routerlist_from_directory(const char *s,
                                            routerlist_t **dest,
                                            crypto_pk_env_t *pkey,
                                            int check_version,
                                            int write_to_cache);
 int router_parse_runningrouters(const char *str);
+int router_parse_directory(const char *str);
 routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
 int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
 addr_policy_t *router_parse_addr_policy_from_string(const char *s,
                                                     int assume_action);
+#if 0
 int check_software_version_against_directory(const char *directory);
+#endif
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_as_new_as(const char *platform, const char *cutoff);
 int tor_version_compare(tor_version_t *a, tor_version_t *b);

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerlist.c,v
retrieving revision 1.291
retrieving revision 1.292
diff -u -d -r1.291 -r1.292
--- routerlist.c	15 Sep 2005 00:51:42 -0000	1.291
+++ routerlist.c	15 Sep 2005 05:19:38 -0000	1.292
@@ -29,7 +29,6 @@
 static void mark_all_trusteddirservers_up(void);
 static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
 static int router_nickname_matches(routerinfo_t *router, const char *nickname);
-static void router_normalize_routerlist(routerlist_t *rl);
 
 /****************************************************************************/
 
@@ -53,38 +52,6 @@
  */
 static int networkstatus_list_has_changed = 0;
 
-/**
- * Reload the most recent cached directory (if present).
- */
-int
-router_reload_router_list(void)
-{
-  char filename[512];
-  int is_recent;
-  struct stat st;
-  char *s;
-  tor_assert(get_options()->DataDirectory);
-
-  tor_snprintf(filename,sizeof(filename),"%s/cached-directory",
-               get_options()->DataDirectory);
-  s = read_file_to_str(filename,0);
-  if (s) {
-    stat(filename, &st); /* if s is true, stat probably worked */
-    log_fn(LOG_INFO, "Loading cached directory from %s", filename);
-    is_recent = st.st_mtime > time(NULL) - 60*15;
-    if (router_load_routerlist_from_directory(s, NULL, is_recent, 1) < 0) {
-      log_fn(LOG_WARN, "Cached directory at '%s' was unparseable; ignoring.", filename);
-    }
-    if (routerlist &&
-        ((routerlist->published_on_xx > time(NULL) - MIN_ONION_KEY_LIFETIME/2)
-         || is_recent)) {
-      directory_has_arrived(st.st_mtime, NULL); /* do things we've been waiting to do */
-    }
-    tor_free(s);
-  }
-  return 0;
-}
-
 /** Repopulate our list of network_status_t objects from the list cached on
  * disk.  Return 0 on success, -1 on failure. */
 int
@@ -129,10 +96,10 @@
  *
  * Routerdescs are stored in a big file, named "cached-routers".  As new
  * routerdescs arrive, we append them to a journal file named
- * "cached-routers.jrn".
+ * "cached-routers.new".
  *
  * From time to time, we replace "cached-routers" with a new file containing
- * only the live, non-superseded descriptors, and clear cached-routers.log.
+ * only the live, non-superseded descriptors, and clear cached-routers.new.
  *
  * On startup, we read both files.
  */
@@ -198,6 +165,9 @@
   if (!routerlist)
     return 0;
 
+  /* Don't save deadweight. */
+  routerlist_remove_old_routers(ROUTER_MAX_AGE);
+
   options = get_options();
   fname_len = strlen(options->DataDirectory)+32;
   fname = tor_malloc(fname_len);
@@ -240,6 +210,50 @@
   return r;
 }
 
+/* DOCDOC */
+int
+router_reload_router_list(void)
+{
+  or_options_t *options = get_options();
+  size_t fname_len = strlen(options->DataDirectory)+32;
+  char *fname = tor_malloc(fname_len);
+  struct stat st;
+  int j;
+
+  if (!routerlist) {
+    routerlist = tor_malloc_zero(sizeof(routerlist_t));
+    routerlist->routers = smartlist_create();
+  }
+
+  router_journal_len = router_store_len = 0;
+
+  for (j = 0; j < 2; ++j) {
+    char *contents;
+    tor_snprintf(fname, fname_len,
+                 (j==0)?"%s/cached-routers":"%s/cached-routers.new",
+                 options->DataDirectory);
+    contents = read_file_to_str(fname, 0);
+    if (contents) {
+      stat(fname, &st);
+      if (j==0)
+        router_store_len = st.st_size;
+      else
+        router_journal_len = st.st_size;
+      router_load_routers_from_string(contents, 1, NULL);
+      tor_free(contents);
+    }
+  }
+
+  /* Don't cache expired routers. */
+  routerlist_remove_old_routers(ROUTER_MAX_AGE);
+
+  if (router_journal_len) {
+    /* Always clear the journal on startup.*/
+    router_rebuild_store(1);
+  }
+  return 0;
+}
+
 /** Set *<b>outp</b> to a smartlist containing a list of
  * trusted_dir_server_t * for all known trusted dirservers.  Callers
  * must not modify the list or its contents.
@@ -1072,10 +1086,15 @@
  * routerinfo was accepted, but we should notify the generator of the
  * descriptor using the message *<b>msg</b>.
  *
- * DOCDOC very changed.  Also, MUST call update_status_from_networkstatus first.
+ * DOCDOC very changed.  Also, MUST call update_status_from_networkstatus
+ * first, and should call router_rebuild_store and
+ * control_event_descriptors_changed after.
+ *
+ * XXXX never replace your own descriptor.
  */
 int
-router_add_to_routerlist(routerinfo_t *router, const char **msg)
+router_add_to_routerlist(routerinfo_t *router, const char **msg,
+                         int from_cache)
 {
   int i;
   char id_digest[DIGEST_LEN];
@@ -1138,6 +1157,9 @@
         }
         routerinfo_free(old_router);
         smartlist_set(routerlist->routers, i, router);
+        if (!from_cache)
+          router_append_to_journal(router->signed_descriptor,
+                                   router->signed_descriptor_len);
         directory_set_dirty();
         *msg = unreachable ? "Dirserver believes your ORPort is unreachable" :
                authdir_verified ? "Verified server updated" :
@@ -1176,6 +1198,9 @@
   /* We haven't seen a router with this name before.  Add it to the end of
    * the list. */
   smartlist_add(routerlist->routers, router);
+  if (!from_cache)
+    router_append_to_journal(router->signed_descriptor,
+                             router->signed_descriptor_len);
   directory_set_dirty();
   return 0;
 }
@@ -1244,7 +1269,7 @@
 #endif
   /* XXXX011 update router status from networkstatus!! */
 
-  if (router_add_to_routerlist(ri, msg)<0) {
+  if (router_add_to_routerlist(ri, msg, 0)<0) {
     log_fn(LOG_WARN, "Couldn't add router to list: %s Dropping.",
            *msg?*msg:"(No message).");
     /* we've already assigned to *msg now, and ri is already freed */
@@ -1260,6 +1285,48 @@
   return 1;
 }
 
+/* DOCDOC */
+void
+router_load_routers_from_string(const char *s, int from_cache,
+                                smartlist_t *requested_fingerprints)
+{
+  smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
+  char fp[HEX_DIGEST_LEN+1];
+  const char *msg;
+
+  router_parse_list_from_string(&s, routers);
+
+  routers_update_status_from_networkstatus(routers);
+
+  SMARTLIST_FOREACH(routers, routerinfo_t *, ri,
+  {
+    base16_encode(fp, sizeof(fp), ri->identity_digest, DIGEST_LEN);
+    if (requested_fingerprints) {
+      if (smartlist_string_isin(requested_fingerprints, fp)) {
+        smartlist_string_remove(requested_fingerprints, fp);
+      } else {
+        char *requested =
+          smartlist_join_strings(requested_fingerprints," ",0,NULL);
+        log_fn(LOG_WARN, "We received a router descriptor with a fingerprint (%s) that we never requested. (We asked for: %s.) Dropping.", fp, requested);
+        tor_free(requested);
+        routerinfo_free(ri);
+        continue;
+      }
+    }
+
+    if (router_add_to_routerlist(ri, &msg, from_cache) >= 0)
+      smartlist_add(changed, ri);
+  });
+
+  control_event_descriptors_changed(changed);
+
+  router_rebuild_store(0);
+
+  smartlist_free(routers);
+  smartlist_free(changed);
+}
+
+#if 0
 /** Add to the current routerlist each router stored in the
  * signed directory <b>s</b>.  If pkey is provided, check the signature
  * against pkey; else check against the pkey of the signing directory
@@ -1291,7 +1358,7 @@
     SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r,
     {
       const char *msg;
-      if (router_add_to_routerlist(r,&msg)>=0)
+      if (router_add_to_routerlist(r,&msg,0)>=0)
         smartlist_add(changed, r);
     });
     smartlist_clear(new_list->routers);
@@ -1306,6 +1373,7 @@
   router_normalize_routerlist(routerlist);
   return 0;
 }
+#endif
 
 /** Helper: return a newly allocated string containing the name of the filename
  * where we plan to cache <b>ns</b>. */
@@ -1319,7 +1387,6 @@
   base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
   tor_snprintf(fn, len, "%s/cached-status/%s",datadir,fp);
   return fn;
-
 }
 
 /** Helper for smartlist_sort: Compare two networkstatus objects by
@@ -1696,28 +1763,6 @@
   tor_free(resource);
 }
 
-/** Ensure that our own routerinfo is at the front, and remove duplicates
- * of our routerinfo.
- */
-static void
-router_normalize_routerlist(routerlist_t *rl)
-{
-  int i=0;
-  routerinfo_t *r;
-  if ((r = router_get_my_routerinfo())) {
-    smartlist_insert(rl->routers, 0, routerinfo_copy(r));
-    ++i;
-  }
-
-  for ( ; i < smartlist_len(rl->routers); ++i) {
-    r = smartlist_get(rl->routers,i);
-    if (router_is_me(r)) {
-      routerinfo_free(r);
-      smartlist_del_keeporder(rl->routers, i--);
-    }
-  }
-}
-
 /** Decide whether a given addr:port is definitely accepted,
  * definitely rejected, probably accepted, or probably rejected by a
  * given policy.  If <b>addr</b> is 0, we don't know the IP of the
@@ -2192,6 +2237,8 @@
 
   helper_nodes_set_status_from_directory();
 
+  update_router_descriptor_downloads(time(NULL));
+
   networkstatus_list_has_changed = 0;
 }
 
@@ -2287,20 +2334,21 @@
   });
 }
 
-/** Return new list of ID digests for superseded routers.  A router is
+/** Return new list of ID fingerprints for superseded routers.  A router is
  * superseded if any network-status has a router with a different digest
  * published more recently, or it it is listed in the network-status but not
  * in the router list.
  */
 smartlist_t *
-router_list_superseded(void)
+router_list_downloadable(void)
 {
   smartlist_t *superseded = smartlist_create();
   strmap_t *most_recent = NULL;
   char fp[HEX_DIGEST_LEN+1];
   routerstatus_t *rs_old;
+  strmap_iter_t *iter;
 
-  if (!routerlist || !networkstatus_list)
+  if (!networkstatus_list)
     return superseded;
 
   /* Build a map from fingerprint to most recent routerstatus_t. If this
@@ -2313,29 +2361,93 @@
     {
       base16_encode(fp, sizeof(fp), rs->identity_digest, DIGEST_LEN);
       rs_old = strmap_get(most_recent, fp);
-      if (!rs_old || rs_old->published_on < rs->published_on)
+      if (!rs_old || rs_old->published_on < rs->published_on) {
         strmap_set(most_recent, fp, rs);
+      }
     });
   });
 
   /* Compare each router to the most recent routerstatus. */
-  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
-  {
-    routerstatus_t *rs;
-    base16_encode(fp, sizeof(fp), ri->identity_digest, DIGEST_LEN);
-    rs = strmap_get(most_recent, fp);
-    if (!rs)
-      continue;
-    if (memcmp(ri->signed_descriptor_digest,rs->descriptor_digest,DIGEST_LEN)
-        && rs->published_on > ri->published_on) {
-      char *d = tor_malloc(DIGEST_LEN);
-      memcpy(d, ri->identity_digest, DIGEST_LEN);
-      smartlist_add(superseded, d);
-      break;
-    }
-  });
+  if (routerlist) {
+    SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
+    {
+      routerstatus_t *rs;
+      base16_encode(fp, sizeof(fp), ri->identity_digest, DIGEST_LEN);
+      rs = strmap_get(most_recent, fp);
+      if (!rs)
+        continue;
+      if (memcmp(ri->signed_descriptor_digest,rs->descriptor_digest,DIGEST_LEN)
+          && rs->published_on > ri->published_on) {
+        char *d = tor_malloc(HEX_DIGEST_LEN+1);
+        base16_encode(d, HEX_DIGEST_LEN+1, ri->identity_digest, DIGEST_LEN);
+        smartlist_add(superseded, d);
+        break;
+      }
+      strmap_remove(most_recent, fp);
+    });
+  }
+
+  /* Anything left over, we don't even know about yet. */
+  for (iter = strmap_iter_init(most_recent); !strmap_iter_done(iter);
+       iter = strmap_iter_next(most_recent, iter)) {
+    const char *key;
+    void *val;
+    strmap_iter_get(iter, &key, &val);
+    smartlist_add(superseded, tor_strdup(key));
+  }
+
   strmap_free(most_recent, NULL);
 
   return superseded;
 }
 
+/* DOCDOC */
+void
+update_router_descriptor_downloads(time_t now)
+{
+  char *resource = NULL;
+
+  if (connection_get_by_type_purpose(CONN_TYPE_DIR,
+                                     DIR_PURPOSE_FETCH_SERVERDESC))
+    return;
+
+  if (!networkstatus_list || smartlist_len(networkstatus_list)<2) {
+    resource = tor_strdup("all.z");
+  } else {
+    smartlist_t *downloadable = router_list_downloadable();
+    if (smartlist_len(downloadable)) {
+      char *dl = smartlist_join_strings(downloadable,"+",0,NULL);
+      size_t r_len = smartlist_len(downloadable)*(DIGEST_LEN+1)+16;
+      /* Damn, that's an ugly way to do this. XXXX011 NM */
+      resource = tor_malloc(r_len);
+      tor_snprintf(resource, r_len, "fp/%s.z", dl);
+      tor_free(dl);
+    }
+    SMARTLIST_FOREACH(downloadable, char *, c, tor_free(c));
+    smartlist_free(downloadable);
+  }
+
+  if (!resource) {
+    log_fn(LOG_NOTICE, "No routers to download.");
+    return;
+  }
+
+  log_fn(LOG_NOTICE, "Launching request for routers: %s", resource);
+  directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,resource,1);
+  tor_free(resource);
+}
+
+/* DOCDOC */
+int
+router_have_minimum_dir_info(void)
+{
+  int tot = 0, avg;
+  if (!networkstatus_list || smartlist_len(networkstatus_list)<2 ||
+      !routerlist)
+    return 0;
+  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+                    tot += smartlist_len(ns->entries));
+  avg = tot / smartlist_len(networkstatus_list);
+  return smartlist_len(routerlist->routers) > (avg/4);
+}
+

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerparse.c,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -d -r1.140 -r1.141
--- routerparse.c	14 Sep 2005 23:42:06 -0000	1.140
+++ routerparse.c	15 Sep 2005 05:19:38 -0000	1.141
@@ -247,6 +247,7 @@
   return -1;
 }
 
+#if 0
 /**
  * Find the first instance of "recommended-software ...\n" at the start of
  * a line; return a newly allocated string containing the "..." portion.
@@ -273,6 +274,7 @@
   return tor_strndup(cp, eol-cp);
 #undef REC
 }
+#endif
 
 /** Return 1 if <b>myversion</b> is not in <b>versionlist</b>, and if at least
  * one version of Tor on <b>versionlist</b> is newer than <b>myversion</b>.
@@ -373,6 +375,7 @@
   return ret;
 }
 
+#if 0
 /* Return 0 if myversion is supported; else warn and return -1. */
 int
 check_software_version_against_directory(const char *directory)
@@ -394,38 +397,24 @@
   tor_free(v);
   return -1;
 }
+#endif
 
-/** Parse a directory from <b>str</b> and, when done, store the
- * resulting routerlist in *<b>dest</b>, freeing the old value if
- * necessary.
- *
- * If <b>pkey</b> is provided, we check the directory signature with pkey.
- *
- * If <b>check_version</b> is non-zero, then examine the
- * Recommended-versions * line in the directory, and warn or quit
- * as needed.
- *
- * If <b>write_to_cache</b> is non-zero, then store this directory in
- * memory and/or disk as well.
+/** Read a signed directory from <b>str</b>.  If it's well-formed, return 0.
+ * Otherwise, return -1.  If we're a directory cache, cache it.
  */
-int /* Should be static; exposed for unit tests */
-router_parse_routerlist_from_directory(const char *str,
-                                       routerlist_t **dest,
-                                       crypto_pk_env_t *pkey,
-                                       int check_version,
-                                       int write_to_cache)
+int
+router_parse_directory(const char *str)
 {
   directory_token_t *tok;
   char digest[DIGEST_LEN];
-  routerlist_t *new_dir = NULL;
-  char *versions = NULL;
   time_t published_on;
   int r;
   const char *end, *cp;
   smartlist_t *tokens = NULL;
-  char dirnickname[MAX_NICKNAME_LEN+1];
   crypto_pk_env_t *declared_key = NULL;
 
+  /* XXXX011 This could be simplified a lot! NM */
+
   if (router_get_dir_hash(str, digest)) {
     log_fn(LOG_WARN, "Unable to compute digest of directory");
     goto err;
@@ -452,24 +441,13 @@
     log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
   }
   declared_key = find_dir_signing_key(str);
-  if (check_directory_signature(digest, tok, pkey, declared_key, 1)<0)
-    goto err;
-
-  /* now we know tok->n_args == 1, so it's safe to access tok->args[0] */
-  if (!is_legal_nickname(tok->args[0])) {
-    log_fn(LOG_WARN, "Directory nickname '%s' is misformed", tok->args[0]);
+  if (check_directory_signature(digest, tok, NULL, declared_key, 1)<0)
     goto err;
-  }
-  strlcpy(dirnickname, tok->args[0], sizeof(dirnickname));
 
   SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
   smartlist_free(tokens);
   tokens = NULL;
 
-  /* Now that we know the signature is okay, check the version. */
-  if (check_version)
-    check_software_version_against_directory(str);
-
   /* Now try to parse the first part of the directory. */
   if ((end = strstr(str,"\nrouter "))) {
     ++end;
@@ -483,20 +461,6 @@
   if (tokenize_string(str,end,tokens,DIR)) {
     log_fn(LOG_WARN, "Error tokenizing directory"); goto err;
   }
-  if (smartlist_len(tokens) < 1) {
-    log_fn(LOG_WARN, "Impossibly short directory header"); goto err;
-  }
-  if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
-    log_fn(LOG_WARN, "Unrecognized keyword \"%s\" in directory header; can't parse directory.",
-           tok->args[0]);
-    goto err;
-  }
-
-  tok = smartlist_get(tokens,0);
-  if (tok->tp != K_SIGNED_DIRECTORY) {
-    log_fn(LOG_WARN, "Directory doesn't start with signed-directory.");
-    goto err;
-  }
 
   if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
     log_fn(LOG_WARN, "Missing published time on directory.");
@@ -510,54 +474,13 @@
 
   /* Now that we know the signature is okay, and we have a
    * publication time, cache the directory. */
-  if (!get_options()->AuthoritativeDir && write_to_cache)
+  if (get_options()->DirPort && !get_options()->V1AuthoritativeDir)
     dirserv_set_cached_directory(str, published_on, 0);
 
-  if (!(tok = find_first_by_keyword(tokens, K_RECOMMENDED_SOFTWARE))) {
-    log_fn(LOG_WARN, "Missing recommended-software line from directory.");
-    goto err;
-  }
-  if (tok->n_args > 1) {
-    log_fn(LOG_WARN, "Invalid recommended-software line");
-    goto err;
-  }
-  versions = tok->n_args ? tor_strdup(tok->args[0]) : tor_strdup("");
-
-  /* Prefer router-status, then running-routers. */
-  if (!(tok = find_first_by_keyword(tokens, K_ROUTER_STATUS))) {
-    log_fn(LOG_WARN,
-           "Missing router-status line from directory.");
-    goto err;
-  }
-
-  /* Read the router list from s, advancing s up past the end of the last
-   * router. */
-  str = end;
-  new_dir = tor_malloc_zero(sizeof(routerlist_t));
-  new_dir->routers = smartlist_create();
-  if (router_parse_list_from_string(&str, new_dir->routers,
-                                    published_on)) {
-    log_fn(LOG_WARN, "Error reading routers from directory");
-    goto err;
-  }
-
-  new_dir->published_on_xx = published_on;
-
-  SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
-  smartlist_free(tokens);
-  tokens = NULL;
-
-  if (*dest)
-    routerlist_free(*dest);
-  *dest = new_dir;
-
   r = 0;
   goto done;
  err:
   r = -1;
-  if (new_dir)
-    routerlist_free(new_dir);
-  tor_free(versions);
  done:
   if (declared_key) crypto_free_pk_env(declared_key);
   if (tokens) {
@@ -567,8 +490,9 @@
   return r;
 }
 
-/** Read a signed router status statement from <b>str</b>.  If it's well-formed,
- * return 0.  Otherwise, return -1.  If we're a directory cache, cache it.*/
+/** Read a signed router status statement from <b>str</b>.  If it's
+ * well-formed, return 0.  Otherwise, return -1.  If we're a directory cache,
+ * cache it.*/
 int
 router_parse_runningrouters(const char *str)
 {
@@ -761,8 +685,7 @@
  * following the last router entry.  Returns 0 on success and -1 on failure.
  */
 int
-router_parse_list_from_string(const char **s, smartlist_t *dest,
-                              time_t published_on)
+router_parse_list_from_string(const char **s, smartlist_t *dest)
 {
   routerinfo_t *router;
   smartlist_t *routers;