diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/directory.c | 67 | ||||
-rw-r--r-- | src/or/or.h | 25 | ||||
-rw-r--r-- | src/or/routerlist.c | 93 |
3 files changed, 129 insertions, 56 deletions
diff --git a/src/or/directory.c b/src/or/directory.c index 2575d37626..6f3014557c 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -2130,52 +2130,59 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, int was_extrainfo) { char digest[DIGEST_LEN]; - local_routerstatus_t *rs; time_t now = time(NULL); int server = server_mode(get_options()) && get_options()->DirPort; - (void) was_extrainfo; SMARTLIST_FOREACH(failed, const char *, cp, { + download_status_t *dls = NULL; base16_decode(digest, DIGEST_LEN, cp, strlen(cp)); - /* XXXX020 BUG BUG BUG. Fails miserably when requesting by desc digest - * rather than by identity digest. */ - rs = router_get_combined_status_by_digest(digest); - if (!rs || rs->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES) + if (was_extrainfo) { + signed_descriptor_t *sd = + router_get_by_extrainfo_digest(digest); + if (sd) + dls = &sd->ei_dl_status; + } else { + local_routerstatus_t *rs = + router_get_combined_status_by_descriptor_digest(digest); + if (rs) + dls = &rs->dl_status; + } + if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES) continue; if (status_code != 503 || server) - ++rs->n_download_failures; + ++dls->n_download_failures; if (server) { - switch (rs->n_download_failures) { - case 0: rs->next_attempt_at = 0; break; - case 1: rs->next_attempt_at = 0; break; - case 2: rs->next_attempt_at = 0; break; - case 3: rs->next_attempt_at = now+60; break; - case 4: rs->next_attempt_at = now+60; break; - case 5: rs->next_attempt_at = now+60*2; break; - case 6: rs->next_attempt_at = now+60*5; break; - case 7: rs->next_attempt_at = now+60*15; break; - default: rs->next_attempt_at = TIME_MAX; break; + switch (dls->n_download_failures) { + case 0: dls->next_attempt_at = 0; break; + case 1: dls->next_attempt_at = 0; break; + case 2: dls->next_attempt_at = 0; break; + case 3: dls->next_attempt_at = now+60; break; + case 4: dls->next_attempt_at = now+60; break; + case 5: dls->next_attempt_at = now+60*2; break; + case 6: dls->next_attempt_at = now+60*5; break; + case 7: dls->next_attempt_at = now+60*15; break; + default: dls->next_attempt_at = TIME_MAX; break; } } else { - switch (rs->n_download_failures) { - case 0: rs->next_attempt_at = 0; break; - case 1: rs->next_attempt_at = 0; break; - case 2: rs->next_attempt_at = now+60; break; - case 3: rs->next_attempt_at = now+60*5; break; - case 4: rs->next_attempt_at = now+60*10; break; - default: rs->next_attempt_at = TIME_MAX; break; + switch (dls->n_download_failures) { + case 0: dls->next_attempt_at = 0; break; + case 1: dls->next_attempt_at = 0; break; + case 2: dls->next_attempt_at = now+60; break; + case 3: dls->next_attempt_at = now+60*5; break; + case 4: dls->next_attempt_at = now+60*10; break; + default: dls->next_attempt_at = TIME_MAX; break; } } - if (rs->next_attempt_at == 0) + if (dls->next_attempt_at == 0) log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.", - cp, (int)rs->n_download_failures); - else if (rs->next_attempt_at < TIME_MAX) + cp, (int)dls->n_download_failures); + else if (dls->next_attempt_at < TIME_MAX) log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.", - cp, (int)rs->n_download_failures, - (int)(rs->next_attempt_at-now)); + cp, (int)dls->n_download_failures, + (int)(dls->next_attempt_at-now)); else log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.", - cp, (int)rs->n_download_failures); + cp, (int)dls->n_download_failures); }); /* No need to relaunch descriptor downloads here: we already do it diff --git a/src/or/or.h b/src/or/or.h index 82307ac769..33aa81eb41 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1049,6 +1049,14 @@ typedef enum { SAVED_IN_JOURNAL } saved_location_t; +/** DOCDOC */ +typedef struct download_status_t { + time_t next_attempt_at; /**< When should we try downloading this descriptor + * again? */ + uint8_t n_download_failures; /**< Number of failures trying to download the + * most recent descriptor. */ +} download_status_t; + /** Information need to cache an onion router's descriptor. */ typedef struct signed_descriptor_t { /** Pointer to the raw server descriptor. Not necessarily NUL-terminated. @@ -1062,8 +1070,10 @@ typedef struct signed_descriptor_t { char identity_digest[DIGEST_LEN]; /** Declared publication time of the descriptor */ time_t published_on; - /** DOCDOC; routerinfo_t only. */ + /** DOCDOC; routerinfo_t only. */ char extra_info_digest[DIGEST_LEN]; + /** DOCDOC; routerinfo_t only: for the corresponding extrainfo. */ + download_status_t ei_dl_status; /** Where is the descriptor saved? */ saved_location_t saved_location; /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of @@ -1071,8 +1081,6 @@ typedef struct signed_descriptor_t { off_t saved_offset; /* DOCDOC */ unsigned int do_not_cache : 1; - /* DOCDOC; XXXX020 replace with something smarter. */ - unsigned int tried_downloading_extrainfo : 1; } signed_descriptor_t; /** Information about another onion router in the network. */ @@ -1219,12 +1227,9 @@ typedef struct local_routerstatus_t { * descriptor_digest represents the descriptor we would most like to use for * this router. */ routerstatus_t status; - time_t next_attempt_at; /**< When should we try downloading this descriptor - * again? */ time_t last_dir_503_at; /**< When did this router last tell us that it * was too busy to serve directory info? */ - uint8_t n_download_failures; /**< Number of failures trying to download the - * most recent descriptor. */ + download_status_t dl_status; unsigned int name_lookup_warned:1; /**< Have we warned the user for referring * to this (unnamed) router by nickname? */ @@ -1285,6 +1290,8 @@ typedef struct { /** Map from extra-info digest to a signed_descriptor_t. Only for * routers in routers or old_routers. */ digestmap_t *extra_info_map; + /** DOCDOC */ + digestmap_t *desc_by_eid_map; /** List of routerinfo_t for all currently live routers we know. */ smartlist_t *routers; /** List of signed_descriptor_t for older router descriptors we're @@ -3107,6 +3114,7 @@ int hexdigest_to_digest(const char *hexdigest, char *digest); routerinfo_t *router_get_by_hexdigest(const char *hexdigest); routerinfo_t *router_get_by_digest(const char *digest); signed_descriptor_t *router_get_by_descriptor_digest(const char *digest); +signed_descriptor_t *router_get_by_extrainfo_digest(const char *digest); signed_descriptor_t *extrainfo_get_by_descriptor_digest(const char *digest); const char *signed_descriptor_get_body(signed_descriptor_t *desc); int router_digest_version_as_new_as(const char *digest, const char *cutoff); @@ -3159,6 +3167,9 @@ void clear_trusted_dir_servers(void); int any_trusted_dir_is_v1_authority(void); networkstatus_t *networkstatus_get_by_digest(const char *digest); local_routerstatus_t *router_get_combined_status_by_digest(const char *digest); +local_routerstatus_t *router_get_combined_status_by_descriptor_digest( + const char *digest); + routerstatus_t *routerstatus_get_by_hexdigest(const char *hexdigest); void update_networkstatus_downloads(time_t now); void update_router_descriptor_downloads(time_t now); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 3e2475fcac..4de27dca76 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -58,6 +58,8 @@ static smartlist_t *networkstatus_list = NULL; /** Global list of local_routerstatus_t for each router, known or unknown. * Kept sorted by digest. */ static smartlist_t *routerstatus_list = NULL; +/** DOCDOC */ +static digestmap_t *routerstatus_by_desc_digest_map = NULL; /** Map from lowercase nickname to digest of named server, if any. */ static strmap_t *named_server_map = NULL; @@ -1520,6 +1522,18 @@ router_get_by_descriptor_digest(const char *digest) return digestmap_get(routerlist->desc_digest_map, digest); } +/** Return the router in our routerlist whose 20-byte descriptor + * is <b>digest</b>. Return NULL if no such router is known. */ +signed_descriptor_t * +router_get_by_extrainfo_digest(const char *digest) +{ + tor_assert(digest); + + if (!routerlist) return NULL; + + return digestmap_get(routerlist->desc_by_eid_map, digest); +} + /** DOCDOC */ signed_descriptor_t * extrainfo_get_by_descriptor_digest(const char *digest) @@ -1567,6 +1581,7 @@ router_get_routerlist(void) routerlist->old_routers = smartlist_create(); routerlist->identity_map = digestmap_new(); routerlist->desc_digest_map = digestmap_new(); + routerlist->desc_by_eid_map = digestmap_new(); routerlist->extra_info_map = digestmap_new(); } return routerlist; @@ -1641,6 +1656,7 @@ routerlist_free(routerlist_t *rl) tor_assert(rl); digestmap_free(rl->identity_map, NULL); digestmap_free(rl->desc_digest_map, NULL); + digestmap_free(rl->desc_by_eid_map, NULL); digestmap_free(rl->extra_info_map, _extrainfo_free); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, routerinfo_free(r)); @@ -1726,6 +1742,9 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri) tor_assert(!ri_old); digestmap_set(rl->desc_digest_map, ri->cache_info.signed_descriptor_digest, &(ri->cache_info)); + if (!tor_digest_is_zero(ri->cache_info.extra_info_digest)) + digestmap_set(rl->desc_by_eid_map, ri->cache_info.extra_info_digest, + &ri->cache_info); smartlist_add(rl->routers, ri); ri->routerlist_index = smartlist_len(rl->routers) - 1; router_dir_info_changed(); @@ -1793,6 +1812,8 @@ routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri) signed_descriptor_t *sd = signed_descriptor_from_routerinfo(ri); digestmap_set(rl->desc_digest_map, sd->signed_descriptor_digest, sd); smartlist_add(rl->old_routers, sd); + if (!tor_digest_is_zero(sd->extra_info_digest)) + digestmap_set(rl->desc_by_eid_map, sd->extra_info_digest, sd); } else { routerinfo_free(ri); } @@ -1839,7 +1860,6 @@ routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int idx, int make_old) ri->cache_info.signed_descriptor_digest); tor_assert(ri_tmp == ri); router_store_stats.bytes_dropped += ri->cache_info.signed_descriptor_len; - routerinfo_free(ri); ei_tmp = digestmap_remove(rl->extra_info_map, ri->cache_info.extra_info_digest); if (ei_tmp) { @@ -1847,6 +1867,9 @@ routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int idx, int make_old) ei_tmp->cache_info.signed_descriptor_len; extrainfo_free(ei_tmp); } + if (!tor_digest_is_zero(ri->cache_info.extra_info_digest)) + digestmap_remove(rl->desc_by_eid_map, ri->cache_info.extra_info_digest); + routerinfo_free(ri); } // routerlist_assert_ok(rl); routerlist_check_bug_417(); @@ -1867,7 +1890,6 @@ routerlist_remove_old(routerlist_t *rl, signed_descriptor_t *sd, int idx) sd->signed_descriptor_digest); tor_assert(sd_tmp == sd); router_store_stats.bytes_dropped += sd->signed_descriptor_len; - signed_descriptor_free(sd); ei_tmp = digestmap_remove(rl->extra_info_map, sd->extra_info_digest); @@ -1876,7 +1898,10 @@ routerlist_remove_old(routerlist_t *rl, signed_descriptor_t *sd, int idx) ei_tmp->cache_info.signed_descriptor_len; extrainfo_free(ei_tmp); } + if (!tor_digest_is_zero(sd->extra_info_digest)) + digestmap_remove(rl->desc_by_eid_map, sd->extra_info_digest); + signed_descriptor_free(sd); routerlist_check_bug_417(); // routerlist_assert_ok(rl); } @@ -1940,6 +1965,9 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, extrainfo_free(ei_tmp); } } + if (!tor_digest_is_zero(ri_old->cache_info.extra_info_digest)) + digestmap_remove(rl->desc_by_eid_map, + ri_old->cache_info.extra_info_digest); routerinfo_free(ri_old); } // routerlist_assert_ok(rl); @@ -1981,6 +2009,10 @@ routerlist_free_all(void) smartlist_free(routerstatus_list); routerstatus_list = NULL; } + if (routerstatus_by_desc_digest_map) { + digestmap_free(routerstatus_by_desc_digest_map, NULL); + routerstatus_by_desc_digest_map = NULL; + } if (named_server_map) { strmap_free(named_server_map, _tor_free); } @@ -2941,6 +2973,24 @@ router_get_combined_status_by_digest(const char *digest) _compare_digest_to_routerstatus_entry); } +/** DOCDOC */ +local_routerstatus_t * +router_get_combined_status_by_descriptor_digest(const char *digest) +{ + if (!routerstatus_by_desc_digest_map) + return NULL; +#if 0 + /* XXXX020 this could conceivably be critical path when a whole lot + * of descriptors fail. Maybe we should use a digest map instead.*/ + SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, lrs, + if (!memcmp(lrs->status.descriptor_digest, digest)) + return lrs); + return NULL; +#else + return digestmap_get(routerstatus_by_desc_digest_map, digest); +#endif +} + /** Given a nickname (possibly verbose, possibly a hexadecimal digest), return * the corresponding local_routerstatus_t, or NULL if none exists. Warn the * user if <b>warn_if_unnamed</b> is set, and they have specified a router by @@ -3916,8 +3966,8 @@ routerstatus_list_update_from_networkstatus(time_t now) if ((rs_old = router_get_combined_status_by_digest(lowest))) { if (!memcmp(rs_out->status.descriptor_digest, most_recent->descriptor_digest, DIGEST_LEN)) { - rs_out->n_download_failures = rs_old->n_download_failures; - rs_out->next_attempt_at = rs_old->next_attempt_at; + rs_out->dl_status.n_download_failures = rs_old->dl_status.n_download_failures; + rs_out->dl_status.next_attempt_at = rs_old->dl_status.next_attempt_at; } rs_out->name_lookup_warned = rs_old->name_lookup_warned; rs_out->last_dir_503_at = rs_old->last_dir_503_at; @@ -3964,6 +4014,14 @@ routerstatus_list_update_from_networkstatus(time_t now) smartlist_free(routerstatus_list); routerstatus_list = result; + if (routerstatus_by_desc_digest_map) + digestmap_free(routerstatus_by_desc_digest_map, NULL); + routerstatus_by_desc_digest_map = digestmap_new(); + SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs, + digestmap_set(routerstatus_by_desc_digest_map, + rs->status.descriptor_digest, + rs)); + tor_free(networkstatus); tor_free(index); tor_free(size); @@ -4019,8 +4077,8 @@ routers_update_status_from_networkstatus(smartlist_t *routers, ds->n_networkstatus_failures = 0; } if (reset_failures) { - rs->n_download_failures = 0; - rs->next_attempt_at = 0; + rs->dl_status.n_download_failures = 0; + rs->dl_status.next_attempt_at = 0; } }); router_dir_info_changed(); @@ -4165,7 +4223,7 @@ router_list_client_downloadable(void) /* Oddly, we have a descriptor more recent than the 'best' one, but it was once best. So that's okay. */ ++n_uptodate; - } else if (rs->next_attempt_at > now) { + } else if (rs->dl_status.next_attempt_at > now) { /* We failed too recently to try again. */ ++n_not_ready; } else { @@ -4455,13 +4513,12 @@ update_router_descriptor_downloads(time_t now) static INLINE int should_download_extrainfo(signed_descriptor_t *sd, const routerlist_t *rl, - const digestmap_t *pending) + const digestmap_t *pending, + time_t now) { const char *d = sd->extra_info_digest; - /* XXXX020 Check for failures; keep a failure count. Don't just - * do this dumb "try once and give up" thing. */ - return (!sd->tried_downloading_extrainfo && - !tor_digest_is_zero(d) && + return (!tor_digest_is_zero(d) && + sd->ei_dl_status.next_attempt_at <= now && !digestmap_get(rl->extra_info_map, d) && !digestmap_get(pending, d)); } @@ -4475,7 +4532,6 @@ update_extrainfo_downloads(time_t now) smartlist_t *wanted; digestmap_t *pending; int i; - (void) now; if (! options->DownloadExtraInfo) return; @@ -4484,16 +4540,14 @@ update_extrainfo_downloads(time_t now) rl = router_get_routerlist(); wanted = smartlist_create(); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { - if (should_download_extrainfo(&ri->cache_info, rl, pending)) { + if (should_download_extrainfo(&ri->cache_info, rl, pending, now)) { smartlist_add(wanted, ri->cache_info.extra_info_digest); - ri->cache_info.tried_downloading_extrainfo = 1; /*XXXX020 be smarter.*/ } }); if (options->DirPort) { SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd, { - if (should_download_extrainfo(sd, rl, pending)) { + if (should_download_extrainfo(sd, rl, pending, now)) { smartlist_add(wanted, sd->extra_info_digest); - sd->tried_downloading_extrainfo = 1; /*XXXX020 be smarter. */ } }); } @@ -4637,9 +4691,10 @@ router_reset_descriptor_download_failures(void) return; SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs, { - rs->n_download_failures = 0; - rs->next_attempt_at = 0; + rs->dl_status.n_download_failures = 0; + rs->dl_status.next_attempt_at = 0; }); + /* XXXX020 reset extrainfo dl status too. */ tor_assert(networkstatus_list); SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns, SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs, |