📄 routerlist.c
字号:
* <b>status</b>. Additionally, try to have a non-expired certificate for
* every V3 authority in trusted_dir_servers. Don't fetch certificates we
* already have.
**/
void
authority_certs_fetch_missing(networkstatus_t *status, time_t now)
{
digestmap_t *pending;
smartlist_t *missing_digests;
char *resource = NULL;
cert_list_t *cl;
const int cache = directory_caches_dir_info(get_options());
if (should_delay_dir_fetches(get_options()))
return;
pending = digestmap_new();
missing_digests = smartlist_create();
list_pending_downloads(pending, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
if (status) {
SMARTLIST_FOREACH(status->voters, networkstatus_voter_info_t *, voter,
{
if (tor_digest_is_zero(voter->signing_key_digest))
continue; /* This authority never signed this consensus, so don't
* go looking for a cert with key digest 0000000000. */
if (!cache &&
!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
continue; /* We are not a cache, and we don't know this authority.*/
cl = get_cert_list(voter->identity_digest);
if (authority_cert_get_by_digests(voter->identity_digest,
voter->signing_key_digest)) {
download_status_reset(&cl->dl_status);
continue;
}
if (download_status_is_ready(&cl->dl_status, now,
MAX_CERT_DL_FAILURES)) {
log_notice(LD_DIR, "We're missing a certificate from authority "
"with signing key %s: launching request.",
hex_str(voter->signing_key_digest, DIGEST_LEN));
smartlist_add(missing_digests, voter->identity_digest);
}
});
}
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
int found = 0;
if (!(ds->type & V3_AUTHORITY))
continue;
if (smartlist_digest_isin(missing_digests, ds->v3_identity_digest))
continue;
cl = get_cert_list(ds->v3_identity_digest);
SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
{
if (!ftime_definitely_after(now, cert->expires)) {
/* It's not expired, and we weren't looking for something to
* verify a consensus with. Call it done. */
download_status_reset(&cl->dl_status);
found = 1;
break;
}
});
if (!found && download_status_is_ready(&cl->dl_status, now,
MAX_CERT_DL_FAILURES)) {
log_notice(LD_DIR, "No current certificate known for authority %s; "
"launching request.", ds->nickname);
smartlist_add(missing_digests, ds->v3_identity_digest);
}
});
if (!smartlist_len(missing_digests)) {
goto done;
} else {
smartlist_t *fps = smartlist_create();
smartlist_add(fps, tor_strdup("fp/"));
SMARTLIST_FOREACH(missing_digests, const char *, d, {
char *fp;
if (digestmap_get(pending, d))
continue;
fp = tor_malloc(HEX_DIGEST_LEN+2);
base16_encode(fp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
fp[HEX_DIGEST_LEN] = '+';
fp[HEX_DIGEST_LEN+1] = '\0';
smartlist_add(fps, fp);
});
if (smartlist_len(fps) == 1) {
/* we didn't add any: they were all pending */
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
smartlist_free(fps);
goto done;
}
resource = smartlist_join_strings(fps, "", 0, NULL);
resource[strlen(resource)-1] = '\0';
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
smartlist_free(fps);
}
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
resource, 1);
done:
tor_free(resource);
smartlist_free(missing_digests);
digestmap_free(pending, NULL);
}
/* Router descriptor storage.
*
* Routerdescs are stored in a big file, named "cached-descriptors". As new
* routerdescs arrive, we append them to a journal file named
* "cached-descriptors.new".
*
* From time to time, we replace "cached-descriptors" with a new file
* containing only the live, non-superseded descriptors, and clear
* cached-routers.new.
*
* On startup, we read both files.
*/
/** Helper: return 1 iff the router log is so big we want to rebuild the
* store. */
static int
router_should_rebuild_store(desc_store_t *store)
{
if (store->store_len > (1<<16))
return (store->journal_len > store->store_len / 2 ||
store->bytes_dropped > store->store_len / 2);
else
return store->journal_len > (1<<15);
}
static INLINE desc_store_t *
desc_get_store(routerlist_t *rl, signed_descriptor_t *sd)
{
if (sd->is_extrainfo)
return &rl->extrainfo_store;
else
return &rl->desc_store;
}
/** Add the signed_descriptor_t in <b>desc</b> to the router
* journal; change its saved_location to SAVED_IN_JOURNAL and set its
* offset appropriately. */
static int
signed_desc_append_to_journal(signed_descriptor_t *desc,
desc_store_t *store)
{
char *fname = get_datadir_fname_suffix(store->fname_base, ".new");
const char *body = signed_descriptor_get_body_impl(desc,1);
size_t len = desc->signed_descriptor_len + desc->annotations_len;
tor_assert(len == strlen(body));
if (append_bytes_to_file(fname, body, len, 1)) {
log_warn(LD_FS, "Unable to store router descriptor");
tor_free(fname);
return -1;
}
desc->saved_location = SAVED_IN_JOURNAL;
tor_free(fname);
desc->saved_offset = store->journal_len;
store->journal_len += len;
return 0;
}
/** Sorting helper: return <0, 0, or >0 depending on whether the
* signed_descriptor_t* in *<b>a</b> is older, the same age as, or newer than
* the signed_descriptor_t* in *<b>b</b>. */
static int
_compare_signed_descriptors_by_age(const void **_a, const void **_b)
{
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
return (int)(r1->published_on - r2->published_on);
}
/** If the journal is too long, or if <b>force</b> is true, then atomically
* replace the router store with the routers currently in our routerlist, and
* clear the journal. Return 0 on success, -1 on failure.
*
* If <b>extrainfo</b> is true, rebuild the extrainfo store; else rebuild the
* router descriptor store.
*/
static int
router_rebuild_store(int force, desc_store_t *store)
{
smartlist_t *chunk_list = NULL;
char *fname = NULL, *fname_tmp = NULL;
int r = -1;
off_t offset = 0;
smartlist_t *signed_descriptors = NULL;
int nocache=0;
size_t total_expected_len = 0;
int had_any;
if (!force && !router_should_rebuild_store(store))
return 0;
if (!routerlist)
return 0;
if (store->type == EXTRAINFO_STORE)
had_any = !eimap_isempty(routerlist->extra_info_map);
else
had_any = (smartlist_len(routerlist->routers)+
smartlist_len(routerlist->old_routers))>0;
/* Don't save deadweight. */
routerlist_remove_old_routers();
log_info(LD_DIR, "Rebuilding %s cache", store->description);
fname = get_datadir_fname(store->fname_base);
fname_tmp = get_datadir_fname_suffix(store->fname_base, ".tmp");
chunk_list = smartlist_create();
/* We sort the routers by age to enhance locality on disk. */
signed_descriptors = smartlist_create();
if (store->type == EXTRAINFO_STORE) {
eimap_iter_t *iter;
for (iter = eimap_iter_init(routerlist->extra_info_map);
!eimap_iter_done(iter);
iter = eimap_iter_next(routerlist->extra_info_map, iter)) {
const char *key;
extrainfo_t *ei;
eimap_iter_get(iter, &key, &ei);
smartlist_add(signed_descriptors, &ei->cache_info);
}
} else {
SMARTLIST_FOREACH(routerlist->old_routers, signed_descriptor_t *, sd,
smartlist_add(signed_descriptors, sd));
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
smartlist_add(signed_descriptors, &ri->cache_info));
}
smartlist_sort(signed_descriptors, _compare_signed_descriptors_by_age);
/* Now, add the appropriate members to chunk_list */
SMARTLIST_FOREACH(signed_descriptors, signed_descriptor_t *, sd,
{
sized_chunk_t *c;
const char *body = signed_descriptor_get_body_impl(sd, 1);
if (!body) {
log_warn(LD_BUG, "No descriptor available for router.");
goto done;
}
if (sd->do_not_cache) {
++nocache;
continue;
}
c = tor_malloc(sizeof(sized_chunk_t));
c->bytes = body;
c->len = sd->signed_descriptor_len + sd->annotations_len;
total_expected_len += c->len;
smartlist_add(chunk_list, c);
});
if (write_chunks_to_file(fname_tmp, chunk_list, 1)<0) {
log_warn(LD_FS, "Error writing router store to disk.");
goto done;
}
/* Our mmap is now invalid. */
if (store->mmap) {
tor_munmap_file(store->mmap);
store->mmap = NULL;
}
if (replace_file(fname_tmp, fname)<0) {
log_warn(LD_FS, "Error replacing old router store: %s", strerror(errno));
goto done;
}
errno = 0;
store->mmap = tor_mmap_file(fname);
if (! store->mmap) {
if (errno == ERANGE) {
/* empty store.*/
if (total_expected_len) {
log_warn(LD_FS, "We wrote some bytes to a new descriptor file at '%s',"
" but when we went to mmap it, it was empty!", fname);
} else if (had_any) {
log_info(LD_FS, "We just removed every descriptor in '%s'. This is "
"okay if we're just starting up after a long time. "
"Otherwise, it's a bug.", fname);
}
} else {
log_warn(LD_FS, "Unable to mmap new descriptor file at '%s'.",fname);
}
}
log_info(LD_DIR, "Reconstructing pointers into cache");
offset = 0;
SMARTLIST_FOREACH(signed_descriptors, signed_descriptor_t *, sd,
{
if (sd->do_not_cache)
continue;
sd->saved_location = SAVED_IN_CACHE;
if (store->mmap) {
tor_free(sd->signed_descriptor_body); // sets it to null
sd->saved_offset = offset;
}
offset += sd->signed_descriptor_len + sd->annotations_len;
signed_descriptor_get_body(sd); /* reconstruct and assert */
});
tor_free(fname);
fname = get_datadir_fname_suffix(store->fname_base, ".new");
write_str_to_file(fname, "", 1);
r = 0;
store->store_len = (size_t) offset;
store->journal_len = 0;
store->bytes_dropped = 0;
done:
if (signed_descriptors)
smartlist_free(signed_descriptors);
tor_free(fname);
tor_free(fname_tmp);
SMARTLIST_FOREACH(chunk_list, sized_chunk_t *, c, tor_free(c));
smartlist_free(chunk_list);
return r;
}
/** Helper: Reload a cache file and its associated journal, setting metadata
* appropriately. If <b>extrainfo</b> is true, reload the extrainfo store;
* else reload the router descriptor store. */
static int
router_reload_router_list_impl(desc_store_t *store)
{
char *fname = NULL, *altname = NULL, *contents = NULL;
struct stat st;
int read_from_old_location = 0;
int extrainfo = (store->type == EXTRAINFO_STORE);
time_t now = time(NULL);
store->journal_len = store->store_len = 0;
fname = get_datadir_fname(store->fname_base);
if (store->fname_alt_base)
altname = get_datadir_fname(store->fname_alt_base);
if (store->mmap) /* get rid of it first */
tor_munmap_file(store->mmap);
store->mmap = NULL;
store->mmap = tor_mmap_file(fname);
if (!store->mmap && altname && file_status(altname) == FN_FILE) {
read_from_old_location = 1;
log_notice(LD_DIR, "Couldn't read %s; trying to load routers from old "
"location %s.", fname, altname);
if ((store->mmap = tor_mmap_file(altname)))
read_from_old_location = 1;
}
if (altname && !read_from_old_location) {
remove_file_if_very_old(altname, now);
}
if (store->mmap) {
store->store_len = store->mmap->size;
if (extrainfo)
router_load_extrainfo_from_string(store->mmap->data,
store->mmap->data+store->mmap->size,
SAVED_IN_CACHE, NULL, 0);
else
router_load_routers_from_string(store->mmap->data,
store->mmap->data+store->mmap->size,
SAVED_IN_CACHE, NULL, 0, NULL);
}
tor_free(fname);
fname = get_datadir_fname_suffix(store->fname_base, ".new");
if (file_status(fname) == FN_FILE)
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
if (read_from_old_location) {
tor_free(altname);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -