r15806@catbus: nickm | 2007-10-15 19:14:57 -0400

Implement v3 networkstatus client code.  Remove v2 networkstatus client code, except as needed for caches to fetch and serve v2 networkstatues and the routers they list.


svn:r11957
This commit is contained in:
Nick Mathewson 2007-10-15 23:15:24 +00:00
parent 95f6265a79
commit 3ad6dc0e2e
12 changed files with 517 additions and 1283 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -2380,12 +2380,12 @@ generate_networkstatus_opinion(int v2)
} }
{ {
networkstatus_t *ns; networkstatus_v2_t *ns;
if (!(ns = networkstatus_parse_from_string(status))) { if (!(ns = networkstatus_v2_parse_from_string(status))) {
log_err(LD_BUG,"Generated a networkstatus we couldn't parse."); log_err(LD_BUG,"Generated a networkstatus we couldn't parse.");
goto done; goto done;
} }
networkstatus_free(ns); networkstatus_v2_free(ns);
} }
{ {
@ -2395,7 +2395,7 @@ generate_networkstatus_opinion(int v2)
*ns_ptr = new_cached_dir(status, now); *ns_ptr = new_cached_dir(status, now);
status = NULL; /* So it doesn't get double-freed. */ status = NULL; /* So it doesn't get double-freed. */
the_v2_networkstatus_is_dirty = 0; the_v2_networkstatus_is_dirty = 0;
router_set_networkstatus((*ns_ptr)->dir, now, NS_GENERATED, NULL); router_set_networkstatus_v2((*ns_ptr)->dir, now, NS_GENERATED, NULL);
r = *ns_ptr; r = *ns_ptr;
} }

View File

@ -67,6 +67,8 @@ networkstatus_vote_free(networkstatus_vote_t *ns)
smartlist_free(ns->routerstatus_list); smartlist_free(ns->routerstatus_list);
} }
if (ns->desc_digest_map)
digestmap_free(ns->desc_digest_map, NULL);
memset(ns, 11, sizeof(*ns)); memset(ns, 11, sizeof(*ns));
tor_free(ns); tor_free(ns);

View File

@ -547,7 +547,6 @@ accounting_set_wakeup_time(void)
/* This rounds 0 up to 1000, but that's actually a feature. */ /* This rounds 0 up to 1000, but that's actually a feature. */
#define ROUND_UP(x) (((x) + 0x3ff) & ~0x3ff) #define ROUND_UP(x) (((x) + 0x3ff) & ~0x3ff)
#define BW_ACCOUNTING_VERSION 1
/** Save all our bandwidth tracking information to disk. Return 0 on /** Save all our bandwidth tracking information to disk. Return 0 on
* success, -1 on failure. */ * success, -1 on failure. */
int int

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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