📄 routerlist.c
字号:
altname = get_datadir_fname_suffix(store->fname_alt_base, ".new");
if (!contents)
contents = read_file_to_str(altname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
else
remove_file_if_very_old(altname, now);
}
if (contents) {
if (extrainfo)
router_load_extrainfo_from_string(contents, NULL,SAVED_IN_JOURNAL,
NULL, 0);
else
router_load_routers_from_string(contents, NULL, SAVED_IN_JOURNAL,
NULL, 0, NULL);
store->journal_len = (size_t) st.st_size;
tor_free(contents);
}
tor_free(fname);
tor_free(altname);
if (store->journal_len || read_from_old_location) {
/* Always clear the journal on startup.*/
router_rebuild_store(1, store);
} else if (!extrainfo) {
/* Don't cache expired routers. (This is in an else because
* router_rebuild_store() also calls remove_old_routers().) */
routerlist_remove_old_routers();
}
return 0;
}
/** Load all cached router descriptors and extra-info documents from the
* store. Return 0 on success and -1 on failure.
*/
int
router_reload_router_list(void)
{
routerlist_t *rl = router_get_routerlist();
if (router_reload_router_list_impl(&rl->desc_store))
return -1;
if (router_reload_router_list_impl(&rl->extrainfo_store))
return -1;
return 0;
}
/** Return a smartlist containing a list of trusted_dir_server_t * for all
* known trusted dirservers. Callers must not modify the list or its
* contents.
*/
smartlist_t *
router_get_trusted_dir_servers(void)
{
if (!trusted_dir_servers)
trusted_dir_servers = smartlist_create();
return trusted_dir_servers;
}
/** Try to find a running dirserver that supports operations of <b>type</b>.
*
* If there are no running dirservers in our routerlist and the
* <b>PDS_RETRY_IF_NO_SERVERS</b> flag is set, set all the authoritative ones
* as running again, and pick one.
*
* If the <b>PDS_IGNORE_FASCISTFIREWALL</b> flag is set, then include
* dirservers that we can't reach.
*
* If the <b>PDS_ALLOW_SELF</b> flag is not set, then don't include ourself
* (if we're a dirserver).
*
* Don't pick an authority if any non-authority is viable; try to avoid using
* servers that have returned 503 recently.
*/
routerstatus_t *
router_pick_directory_server(authority_type_t type, int flags)
{
routerstatus_t *choice;
if (get_options()->PreferTunneledDirConns)
flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
if (!routerlist)
return NULL;
choice = router_pick_directory_server_impl(type, flags);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
log_info(LD_DIR,
"No reachable router entries for dirservers. "
"Trying them all again.");
/* mark all authdirservers as up again */
mark_all_trusteddirservers_up();
/* try again */
choice = router_pick_directory_server_impl(type, flags);
if (choice)
return choice;
/* XXXX021 arma: what's the point of *reloading* and trying again?? -NM */
/* XXXX021 <arma> once upon a time, reloading set the is_running back
to 1. i think. i bet it has no purpose now. */
/* XXXX021 Let's stop reloading in 0.2.1.x, then, and see if anything
* breaks -NM */
log_info(LD_DIR,"Still no %s router entries. Reloading and trying again.",
(flags & PDS_IGNORE_FASCISTFIREWALL) ? "known" : "reachable");
if (router_reload_router_list()) {
return NULL;
}
/* give it one last try */
choice = router_pick_directory_server_impl(type, flags);
return choice;
}
/** Return the trusted_dir_server_t for the directory authority whose identity
* key hashes to <b>digest</b>, or NULL if no such authority is known.
*/
trusted_dir_server_t *
router_get_trusteddirserver_by_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
if (!memcmp(ds->digest, digest, DIGEST_LEN))
return ds;
});
return NULL;
}
/** Return the trusted_dir_server_t for the directory authority whose identity
* key hashes to <b>digest</b>, or NULL if no such authority is known.
*/
trusted_dir_server_t *
trusteddirserver_get_by_v3_auth_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
if (!memcmp(ds->v3_identity_digest, digest, DIGEST_LEN) &&
(ds->type & V3_AUTHORITY))
return ds;
});
return NULL;
}
/** Try to find a running trusted dirserver. Flags are as for
* router_pick_directory_server.
*/
routerstatus_t *
router_pick_trusteddirserver(authority_type_t type, int flags)
{
routerstatus_t *choice;
if (get_options()->PreferTunneledDirConns)
flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
choice = router_pick_trusteddirserver_impl(type, flags);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
log_info(LD_DIR,
"No trusted dirservers are reachable. Trying them all again.");
mark_all_trusteddirservers_up();
return router_pick_trusteddirserver_impl(type, flags);
}
/** How long do we avoid using a directory server after it's given us a 503? */
#define DIR_503_TIMEOUT (60*60)
/** Pick a random running valid directory server/mirror from our
* routerlist. Arguments are as for router_pick_directory_server(), except
* that RETRY_IF_NO_SERVERS is ignored, and:
*
* If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers
* that we can use with BEGINDIR.
*/
static routerstatus_t *
router_pick_directory_server_impl(authority_type_t type, int flags)
{
routerstatus_t *result;
smartlist_t *direct, *tunnel;
smartlist_t *trusted_direct, *trusted_tunnel;
smartlist_t *overloaded_direct, *overloaded_tunnel;
time_t now = time(NULL);
const networkstatus_t *consensus = networkstatus_get_latest_consensus();
int requireother = ! (flags & PDS_ALLOW_SELF);
int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
if (!consensus)
return NULL;
direct = smartlist_create();
tunnel = smartlist_create();
trusted_direct = smartlist_create();
trusted_tunnel = smartlist_create();
overloaded_direct = smartlist_create();
overloaded_tunnel = smartlist_create();
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, status,
{
int is_trusted;
int is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
if (!status->is_running || !status->dir_port || !status->is_valid)
continue;
if (status->is_bad_directory)
continue;
if (requireother && router_digest_is_me(status->identity_digest))
continue;
if (type & V3_AUTHORITY) {
if (!(status->version_supports_v3_dir ||
router_digest_is_trusted_dir_type(status->identity_digest,
V3_AUTHORITY)))
continue;
}
is_trusted = router_digest_is_trusted_dir(status->identity_digest);
if ((type & V2_AUTHORITY) && !(status->is_v2_dir || is_trusted))
continue;
if ((type & EXTRAINFO_CACHE) &&
!router_supports_extrainfo(status->identity_digest, 0))
continue;
if (prefer_tunnel &&
status->version_supports_begindir &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(status->addr, status->or_port)))
smartlist_add(is_trusted ? trusted_tunnel :
is_overloaded ? overloaded_tunnel : tunnel, status);
else if (!fascistfirewall ||
fascist_firewall_allows_address_dir(status->addr,
status->dir_port))
smartlist_add(is_trusted ? trusted_direct :
is_overloaded ? overloaded_direct : direct, status);
});
if (smartlist_len(tunnel)) {
result = routerstatus_sl_choose_by_bandwidth(tunnel);
} else if (smartlist_len(overloaded_tunnel)) {
result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel);
} else if (smartlist_len(trusted_tunnel)) {
/* FFFF We don't distinguish between trusteds and overloaded trusteds
* yet. Maybe one day we should. */
/* FFFF We also don't load balance over authorities yet. I think this
* is a feature, but it could easily be a bug. -RD */
result = smartlist_choose(trusted_tunnel);
} else if (smartlist_len(direct)) {
result = routerstatus_sl_choose_by_bandwidth(direct);
} else if (smartlist_len(overloaded_direct)) {
result = routerstatus_sl_choose_by_bandwidth(overloaded_direct);
} else {
result = smartlist_choose(trusted_direct);
}
smartlist_free(direct);
smartlist_free(tunnel);
smartlist_free(trusted_direct);
smartlist_free(trusted_tunnel);
smartlist_free(overloaded_direct);
smartlist_free(overloaded_tunnel);
return result;
}
/** Choose randomly from among the trusted dirservers that are up. Flags
* are as for router_pick_directory_server_impl().
*/
static routerstatus_t *
router_pick_trusteddirserver_impl(authority_type_t type, int flags)
{
smartlist_t *direct, *tunnel;
smartlist_t *overloaded_direct, *overloaded_tunnel;
routerinfo_t *me = router_get_my_routerinfo();
routerstatus_t *result;
time_t now = time(NULL);
int requireother = ! (flags & PDS_ALLOW_SELF);
int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
if (!trusted_dir_servers)
return NULL;
direct = smartlist_create();
tunnel = smartlist_create();
overloaded_direct = smartlist_create();
overloaded_tunnel = smartlist_create();
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
{
int is_overloaded =
d->fake_status.last_dir_503_at + DIR_503_TIMEOUT > now;
if (!d->is_running) continue;
if ((type & d->type) == 0)
continue;
if ((type & EXTRAINFO_CACHE) &&
!router_supports_extrainfo(d->digest, 1))
continue;
if (requireother && me && router_digest_is_me(d->digest))
continue;
if (prefer_tunnel &&
d->or_port &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(d->addr, d->or_port)))
smartlist_add(is_overloaded ? overloaded_tunnel : tunnel,
&d->fake_status);
else if (!fascistfirewall ||
fascist_firewall_allows_address_dir(d->addr, d->dir_port))
smartlist_add(is_overloaded ? overloaded_direct : direct,
&d->fake_status);
});
if (smartlist_len(tunnel)) {
result = smartlist_choose(tunnel);
} else if (smartlist_len(overloaded_tunnel)) {
result = smartlist_choose(overloaded_tunnel);
} else if (smartlist_len(direct)) {
result = smartlist_choose(direct);
} else {
result = smartlist_choose(overloaded_direct);
}
smartlist_free(direct);
smartlist_free(tunnel);
smartlist_free(overloaded_direct);
smartlist_free(overloaded_tunnel);
return result;
}
/** Go through and mark the authoritative dirservers as up. */
static void
mark_all_trusteddirservers_up(void)
{
if (routerlist) {
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
if (router_digest_is_trusted_dir(router->cache_info.identity_digest) &&
router->dir_port > 0) {
router->is_running = 1;
});
}
if (trusted_dir_servers) {
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
{
routerstatus_t *rs;
dir->is_running = 1;
download_status_reset(&dir->v2_ns_dl_status);
rs = router_get_consensus_status_by_id(dir->digest);
if (rs && !rs->is_running) {
rs->is_running = 1;
rs->last_dir_503_at = 0;
control_event_networkstatus_changed_single(rs);
}
});
}
router_dir_info_changed();
}
/** Reset all internal variables used to count failed downloads of network
* status objects. */
void
router_reset_status_download_failures(void)
{
mark_all_trusteddirservers_up();
}
/** Return true iff router1 and router2 have the same /16 network. */
static INLINE int
routers_in_same_network_family(routerinfo_t *r1, routerinfo_t *r2)
{
return (r1->addr & 0xffff0000) == (r2->addr & 0xffff0000);
}
/** Look through the routerlist and identify routers that
* advertise the same /16 network address as <b>router</b>.
* Add each of them to <b>sl</b>.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -