mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
Choose directory servers from routerstatus list, not from routerinfo list. This way, as soon was we have a networkstatus, we can ask a cache to give us routers, rather than needing to ask the directories.
svn:r5586
This commit is contained in:
parent
7e6a41af93
commit
9482b1b9d5
4
doc/TODO
4
doc/TODO
@ -194,8 +194,8 @@ N - Clients use Stable and Fast instead of uptime and bandwidth to
|
||||
servers?
|
||||
- Is this still necessary?
|
||||
o All versions of Tor should get cosmetic changes rate-limited.
|
||||
- Pick directories from networkstatus objects, not from routerlist.
|
||||
- But! We can't do this easily, since we want to know about platform,
|
||||
o Pick directories from networkstatus objects, not from routerlist.
|
||||
o But! We can't do this easily, since we want to know about platform,
|
||||
and networkstatus doesn't tell us Tor version. Can we solve this?
|
||||
Should we do it by adding flags to networkstatus or what?
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
#define HT_INITIALIZER() \
|
||||
{ 0, NULL, 0, 0, -1 }
|
||||
{ NULL, 0, 0, 0, -1 }
|
||||
|
||||
#define HT_INIT(root) do { \
|
||||
(root)->hth_table_length = 0; \
|
||||
|
@ -31,11 +31,6 @@ const char directory_c_id[] =
|
||||
* connection_finished_connecting() in connection.c
|
||||
*/
|
||||
static void
|
||||
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
|
||||
uint8_t purpose, int private_connection,
|
||||
const char *resource,
|
||||
const char *payload, size_t payload_len);
|
||||
static void
|
||||
directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
|
||||
const char *platform,
|
||||
const char *digest, uint8_t purpose,
|
||||
@ -143,10 +138,11 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
|
||||
*/
|
||||
SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
|
||||
{
|
||||
routerstatus_t *rs = &(ds->fake_status);
|
||||
post_via_tor = purpose_is_private(purpose) ||
|
||||
!fascist_firewall_allows_address(ds->addr,ds->dir_port);
|
||||
directory_initiate_command_trusted_dir(ds, purpose, post_via_tor,
|
||||
NULL, payload, payload_len);
|
||||
directory_initiate_command_routerstatus(rs, purpose, post_via_tor,
|
||||
NULL, payload, payload_len);
|
||||
});
|
||||
}
|
||||
|
||||
@ -159,8 +155,7 @@ void
|
||||
directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
int retry_if_no_servers)
|
||||
{
|
||||
routerinfo_t *r = NULL;
|
||||
trusted_dir_server_t *ds = NULL;
|
||||
routerstatus_t *rs = NULL;
|
||||
or_options_t *options = get_options();
|
||||
int fetch_fresh_first = server_mode(options) && options->DirPort != 0;
|
||||
int directconn = !purpose_is_private(purpose);
|
||||
@ -175,19 +170,21 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
!strcmpstart(resource,"fp/") && strlen(resource) == HEX_DIGEST_LEN+3) {
|
||||
/* Try to ask the actual dirserver its opinion. */
|
||||
char digest[DIGEST_LEN];
|
||||
trusted_dir_server_t *ds;
|
||||
base16_decode(digest, DIGEST_LEN, resource+3, HEX_DIGEST_LEN);
|
||||
ds = router_get_trusteddirserver_by_digest(digest);
|
||||
rs = &(ds->fake_status);
|
||||
}
|
||||
if (!ds && fetch_fresh_first) {
|
||||
if (!rs && fetch_fresh_first) {
|
||||
/* only ask authdirservers, and don't ask myself */
|
||||
ds = router_pick_trusteddirserver(need_v1_support, 1, 1,
|
||||
rs = router_pick_trusteddirserver(need_v1_support, 1, 1,
|
||||
retry_if_no_servers);
|
||||
}
|
||||
if (!ds) {
|
||||
if (!rs) {
|
||||
/* anybody with a non-zero dirport will do */
|
||||
r = router_pick_directory_server(1, 1, need_v2_support,
|
||||
retry_if_no_servers);
|
||||
if (!r) {
|
||||
rs = router_pick_directory_server(1, 1, need_v2_support,
|
||||
retry_if_no_servers);
|
||||
if (!rs) {
|
||||
const char *which;
|
||||
if (purpose == DIR_PURPOSE_FETCH_DIR)
|
||||
which = "directory";
|
||||
@ -199,9 +196,9 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
which = "server descriptors";
|
||||
info(LD_DIR,
|
||||
"No router found for %s; falling back to dirserver list", which);
|
||||
ds = router_pick_trusteddirserver(1, 1, 1,
|
||||
rs = router_pick_trusteddirserver(1, 1, 1,
|
||||
retry_if_no_servers);
|
||||
if (!ds)
|
||||
if (!rs)
|
||||
directconn = 0; /* last resort: try routing it via Tor */
|
||||
}
|
||||
}
|
||||
@ -210,20 +207,18 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
/* Never use fascistfirewall; we're going via Tor. */
|
||||
if (purpose == DIR_PURPOSE_FETCH_RENDDESC) {
|
||||
/* only ask authdirservers, any of them will do */
|
||||
ds = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
|
||||
rs = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
|
||||
} else {
|
||||
/* anybody with a non-zero dirport will do. Disregard firewalls. */
|
||||
r = router_pick_directory_server(1, 0, need_v2_support,
|
||||
retry_if_no_servers);
|
||||
rs = router_pick_directory_server(1, 0, need_v2_support,
|
||||
retry_if_no_servers);
|
||||
/* XXXX If no rs, fall back to trusted dir servers? -NM */
|
||||
}
|
||||
}
|
||||
|
||||
if (r)
|
||||
directory_initiate_command_router(r, purpose, !directconn,
|
||||
resource, NULL, 0);
|
||||
else if (ds)
|
||||
directory_initiate_command_trusted_dir(ds, purpose, !directconn,
|
||||
resource, NULL, 0);
|
||||
if (rs)
|
||||
directory_initiate_command_routerstatus(rs, purpose, !directconn,
|
||||
resource, NULL, 0);
|
||||
else {
|
||||
notice(LD_DIR,
|
||||
"No running dirservers known. Will try again later. (purpose %d)",
|
||||
@ -247,28 +242,56 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
* want to fetch.
|
||||
*/
|
||||
void
|
||||
directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
|
||||
int private_connection, const char *resource,
|
||||
const char *payload, size_t payload_len)
|
||||
directory_initiate_command_router(routerinfo_t *router,
|
||||
uint8_t purpose,
|
||||
int private_connection,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len)
|
||||
{
|
||||
directory_initiate_command(router->address, router->addr, router->dir_port,
|
||||
router->platform, router->cache_info.identity_digest,
|
||||
purpose, private_connection, resource,
|
||||
payload, payload_len);
|
||||
router->platform,
|
||||
router->cache_info.identity_digest,
|
||||
purpose, private_connection, resource,
|
||||
payload, payload_len);
|
||||
}
|
||||
|
||||
/** As directory_initiate_command_router, but send the command to a trusted
|
||||
* directory server <b>dirserv</b>. **/
|
||||
static void
|
||||
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
|
||||
uint8_t purpose, int private_connection,
|
||||
const char *resource,
|
||||
const char *payload, size_t payload_len)
|
||||
/** Launch a new connection to the directory server <b>status</b> to upload or
|
||||
* download a service or rendezvous descriptor. <b>purpose</b> determines what
|
||||
* kind of directory connection we're launching, and must be one of
|
||||
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
|
||||
*
|
||||
* When uploading, <b>payload</b> and <b>payload_len</b> determine the content
|
||||
* of the HTTP post. Otherwise, <b>payload</b> should be NULL.
|
||||
*
|
||||
* When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
|
||||
* want to fetch.
|
||||
*/
|
||||
void
|
||||
directory_initiate_command_routerstatus(routerstatus_t *status,
|
||||
uint8_t purpose,
|
||||
int private_connection,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len)
|
||||
{
|
||||
directory_initiate_command(dirserv->address, dirserv->addr,
|
||||
dirserv->dir_port, NULL, dirserv->digest, purpose,
|
||||
private_connection, resource,
|
||||
payload, payload_len);
|
||||
const char *platform = NULL;
|
||||
routerinfo_t *router;
|
||||
char address_buf[INET_NTOA_BUF_LEN];
|
||||
struct in_addr in;
|
||||
const char *address;
|
||||
if ((router = router_get_by_digest(status->identity_digest))) {
|
||||
platform = router->platform;
|
||||
address = router->address;
|
||||
} else {
|
||||
in.s_addr = htonl(status->addr);
|
||||
tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
|
||||
address = address_buf;
|
||||
}
|
||||
directory_initiate_command(address, status->addr, status->dir_port,
|
||||
platform, status->identity_digest,
|
||||
purpose, private_connection, resource,
|
||||
payload, payload_len);
|
||||
}
|
||||
|
||||
/** Called when we are unable to complete the client's request to a
|
||||
|
30
src/or/or.h
30
src/or/or.h
@ -1822,6 +1822,12 @@ void directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len);
|
||||
void directory_initiate_command_routerstatus(routerstatus_t *status,
|
||||
uint8_t purpose,
|
||||
int private_connection,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len);
|
||||
|
||||
int parse_http_response(const char *headers, int *code, time_t *date,
|
||||
int *compression, char **response);
|
||||
@ -2183,24 +2189,26 @@ typedef struct trusted_dir_server_t {
|
||||
uint16_t dir_port; /**< Directory port */
|
||||
char digest[DIGEST_LEN]; /**< Digest of identity key */
|
||||
unsigned int is_running:1; /**< True iff we think this server is running. */
|
||||
unsigned int supports_v1_protocol:1; /**< True iff this server is an
|
||||
* authority for the older ("v1")
|
||||
* directory protocol.*/
|
||||
unsigned int is_v1_authority:1; /**< True iff this server is an
|
||||
* authority for the older ("v1")
|
||||
* directory protocol.*/
|
||||
int n_networkstatus_failures; /**< How many times have we asked for this
|
||||
* server's network-status unsuccessfully? */
|
||||
routerstatus_t fake_status; /**< Used when we need to pass this trusted
|
||||
* dir_server_t as a routerstatus_t. */
|
||||
} trusted_dir_server_t;
|
||||
|
||||
int router_reload_router_list(void);
|
||||
int router_reload_networkstatus(void);
|
||||
void router_get_trusted_dir_servers(smartlist_t **outp);
|
||||
routerinfo_t *router_pick_directory_server(int requireother,
|
||||
int fascistfirewall,
|
||||
int for_v2_directory,
|
||||
int retry_if_no_servers);
|
||||
trusted_dir_server_t *router_pick_trusteddirserver(int need_v1_support,
|
||||
int requireother,
|
||||
int fascistfirewall,
|
||||
int retry_if_no_servers);
|
||||
routerstatus_t *router_pick_directory_server(int requireother,
|
||||
int fascistfirewall,
|
||||
int for_v2_directory,
|
||||
int retry_if_no_servers);
|
||||
routerstatus_t *router_pick_trusteddirserver(int need_v1_authority,
|
||||
int requireother,
|
||||
int fascistfirewall,
|
||||
int retry_if_no_servers);
|
||||
trusted_dir_server_t *router_get_trusteddirserver_by_digest(
|
||||
const char *digest);
|
||||
int all_trusted_directory_servers_down(void);
|
||||
|
@ -3,7 +3,8 @@
|
||||
* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
const char relay_c_id[] = "$Id$";
|
||||
const char relay_c_id[] =
|
||||
"$Id$";
|
||||
|
||||
/**
|
||||
* \file relay.c
|
||||
|
@ -18,11 +18,11 @@ const char routerlist_c_id[] =
|
||||
/****************************************************************************/
|
||||
|
||||
/* static function prototypes */
|
||||
static routerinfo_t *router_pick_directory_server_impl(int requireother,
|
||||
int fascistfirewall,
|
||||
int for_v2_directory);
|
||||
static trusted_dir_server_t *router_pick_trusteddirserver_impl(
|
||||
int need_v1_support, int requireother, int fascistfirewall);
|
||||
static routerstatus_t *router_pick_directory_server_impl(int requireother,
|
||||
int fascistfirewall,
|
||||
int for_v2_directory);
|
||||
static routerstatus_t *router_pick_trusteddirserver_impl(
|
||||
int need_v1_authority, int requireother, int fascistfirewall);
|
||||
static void mark_all_trusteddirservers_up(void);
|
||||
static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
|
||||
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
|
||||
@ -321,13 +321,13 @@ router_get_trusted_dir_servers(smartlist_t **outp)
|
||||
* (that is, a trusted dirserver, or one running 0.0.9rc5-cvs or later).
|
||||
* Other args are as in router_pick_directory_server_impl().
|
||||
*/
|
||||
routerinfo_t *
|
||||
routerstatus_t *
|
||||
router_pick_directory_server(int requireother,
|
||||
int fascistfirewall,
|
||||
int for_v2_directory,
|
||||
int retry_if_no_servers)
|
||||
{
|
||||
routerinfo_t *choice;
|
||||
routerstatus_t *choice;
|
||||
|
||||
if (!routerlist)
|
||||
return NULL;
|
||||
@ -358,6 +358,9 @@ router_pick_directory_server(int requireother,
|
||||
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)
|
||||
{
|
||||
@ -376,24 +379,26 @@ router_get_trusteddirserver_by_digest(const char *digest)
|
||||
/** Try to find a running trusted dirserver. If there are no running
|
||||
* trusted dirservers and <b>retry_if_no_servers</b> is non-zero,
|
||||
* set them all as running again, and try again.
|
||||
* If <b>need_v1_authority</b> is set, return only trusted servers
|
||||
* that are authorities for the V1 directory protocol.
|
||||
* Other args are as in router_pick_trusteddirserver_impl().
|
||||
*/
|
||||
trusted_dir_server_t *
|
||||
router_pick_trusteddirserver(int need_v1_support,
|
||||
routerstatus_t *
|
||||
router_pick_trusteddirserver(int need_v1_authority,
|
||||
int requireother,
|
||||
int fascistfirewall,
|
||||
int retry_if_no_servers)
|
||||
{
|
||||
trusted_dir_server_t *choice;
|
||||
routerstatus_t *choice;
|
||||
|
||||
choice = router_pick_trusteddirserver_impl(need_v1_support,
|
||||
choice = router_pick_trusteddirserver_impl(need_v1_authority,
|
||||
requireother, fascistfirewall);
|
||||
if (choice || !retry_if_no_servers)
|
||||
return choice;
|
||||
|
||||
info(LD_DIR,"No trusted dirservers are reachable. Trying them all again.");
|
||||
mark_all_trusteddirservers_up();
|
||||
return router_pick_trusteddirserver_impl(need_v1_support,
|
||||
return router_pick_trusteddirserver_impl(need_v1_authority,
|
||||
requireother, fascistfirewall);
|
||||
}
|
||||
|
||||
@ -405,37 +410,34 @@ router_pick_trusteddirserver(int need_v1_support,
|
||||
* choose a directory server new enough to support the v2 directory
|
||||
* functionality.
|
||||
*/
|
||||
static routerinfo_t *
|
||||
static routerstatus_t *
|
||||
router_pick_directory_server_impl(int requireother, int fascistfirewall,
|
||||
int for_v2_directory)
|
||||
{
|
||||
routerinfo_t *result;
|
||||
routerstatus_t *result;
|
||||
smartlist_t *sl;
|
||||
|
||||
if (!routerlist)
|
||||
if (!routerstatus_list)
|
||||
return NULL;
|
||||
|
||||
/* Find all the running dirservers we know about. */
|
||||
sl = smartlist_create();
|
||||
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
||||
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, _local_status,
|
||||
{
|
||||
if (!router->is_running || !router->dir_port || !router->is_verified)
|
||||
routerstatus_t *status = &(_local_status->status);
|
||||
if (!status->is_running || !status->dir_port || !status->is_valid)
|
||||
continue;
|
||||
if (requireother && router_is_me(router))
|
||||
if (requireother && router_digest_is_me(status->identity_digest))
|
||||
continue;
|
||||
if (fascistfirewall) {
|
||||
if (!fascist_firewall_allows_address(router->addr, router->dir_port))
|
||||
if (!fascist_firewall_allows_address(status->addr, status->dir_port))
|
||||
continue;
|
||||
}
|
||||
/* Before 0.1.1.6-alpha, only trusted dirservers served status info.
|
||||
* Before 0.1.1.7-alpha, retrieving nonexistent server IDs could bork
|
||||
* the directory server.
|
||||
*/
|
||||
if (for_v2_directory &&
|
||||
!(tor_version_as_new_as(router->platform,"0.1.1.7-alpha") ||
|
||||
router_digest_is_trusted_dir(router->cache_info.identity_digest)))
|
||||
!(status->is_v2_dir ||
|
||||
router_digest_is_trusted_dir(status->identity_digest)))
|
||||
continue;
|
||||
smartlist_add(sl, router);
|
||||
smartlist_add(sl, status);
|
||||
});
|
||||
|
||||
result = smartlist_choose(sl);
|
||||
@ -443,19 +445,19 @@ router_pick_directory_server_impl(int requireother, int fascistfirewall,
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Choose randomly from among the trusted dirservers that are up.
|
||||
* If <b>fascistfirewall</b>,
|
||||
* make sure the port we pick is allowed by our firewall options.
|
||||
* If <b>requireother</b>, it cannot be us. If <b>need_v1_support</b>, choose
|
||||
* a trusted authority for the v1 directory system.
|
||||
/** Choose randomly from among the trusted dirservers that are up. If
|
||||
* <b>fascistfirewall</b>, make sure the port we pick is allowed by our
|
||||
* firewall options. If <b>requireother</b>, it cannot be us. If
|
||||
* <b>need_v1_authority</b>, choose a trusted authority for the v1 directory
|
||||
* system.
|
||||
*/
|
||||
static trusted_dir_server_t *
|
||||
router_pick_trusteddirserver_impl(int need_v1_support,
|
||||
static routerstatus_t *
|
||||
router_pick_trusteddirserver_impl(int need_v1_authority,
|
||||
int requireother, int fascistfirewall)
|
||||
{
|
||||
smartlist_t *sl;
|
||||
routerinfo_t *me;
|
||||
trusted_dir_server_t *ds;
|
||||
routerstatus_t *rs;
|
||||
sl = smartlist_create();
|
||||
me = router_get_my_routerinfo();
|
||||
|
||||
@ -465,7 +467,7 @@ router_pick_trusteddirserver_impl(int need_v1_support,
|
||||
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
|
||||
{
|
||||
if (!d->is_running) continue;
|
||||
if (need_v1_support && !d->supports_v1_protocol)
|
||||
if (need_v1_authority && !d->is_v1_authority)
|
||||
continue;
|
||||
if (requireother && me && router_digest_is_me(d->digest))
|
||||
continue;
|
||||
@ -473,12 +475,12 @@ router_pick_trusteddirserver_impl(int need_v1_support,
|
||||
if (!fascist_firewall_allows_address(d->addr, d->dir_port))
|
||||
continue;
|
||||
}
|
||||
smartlist_add(sl, d);
|
||||
smartlist_add(sl, &d->fake_status);
|
||||
});
|
||||
|
||||
ds = smartlist_choose(sl);
|
||||
rs = smartlist_choose(sl);
|
||||
smartlist_free(sl);
|
||||
return ds;
|
||||
return rs;
|
||||
}
|
||||
|
||||
/** Go through and mark the authoritative dirservers as up. */
|
||||
@ -2526,7 +2528,7 @@ add_trusted_dir_server(const char *nickname, const char *address,
|
||||
ent->addr = a;
|
||||
ent->dir_port = port;
|
||||
ent->is_running = 1;
|
||||
ent->supports_v1_protocol = supports_v1;
|
||||
ent->is_v1_authority = supports_v1;
|
||||
memcpy(ent->digest, digest, DIGEST_LEN);
|
||||
|
||||
dlen = 64 + strlen(hostname) + (nickname?strlen(nickname):0);
|
||||
@ -2538,6 +2540,16 @@ add_trusted_dir_server(const char *nickname, const char *address,
|
||||
tor_snprintf(ent->description, dlen, "directory server at %s:%d",
|
||||
hostname, (int)port);
|
||||
|
||||
ent->fake_status.addr = ent->addr;
|
||||
memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
|
||||
strlcpy(ent->fake_status.nickname, nickname,
|
||||
sizeof(ent->fake_status.nickname));
|
||||
ent->fake_status.dir_port = ent->dir_port;
|
||||
ent->fake_status.is_running = 1;
|
||||
ent->fake_status.is_named = 1;
|
||||
ent->fake_status.is_valid = 1;
|
||||
ent->fake_status.is_v2_dir = 1;
|
||||
|
||||
smartlist_add(trusted_dir_servers, ent);
|
||||
}
|
||||
|
||||
@ -2848,6 +2860,7 @@ routerstatus_list_update_from_networkstatus(time_t now)
|
||||
*/
|
||||
while (1) {
|
||||
int n_running=0, n_named=0, n_valid=0, n_listing=0;
|
||||
int n_v2_dir=0, n_fast=0, n_stable=0, n_exit=0;
|
||||
const char *the_name = NULL;
|
||||
local_routerstatus_t *rs_out, *rs_old;
|
||||
routerstatus_t *rs, *most_recent;
|
||||
@ -2902,6 +2915,14 @@ routerstatus_list_update_from_networkstatus(time_t now)
|
||||
++n_valid;
|
||||
if (rs->is_running && ns->is_recent)
|
||||
++n_running;
|
||||
if (rs->is_exit)
|
||||
++n_exit;
|
||||
if (rs->is_fast)
|
||||
++n_fast;
|
||||
if (rs->is_stable)
|
||||
++n_stable;
|
||||
if (rs->is_v2_dir)
|
||||
++n_v2_dir;
|
||||
}
|
||||
rs_out = tor_malloc_zero(sizeof(local_routerstatus_t));
|
||||
memcpy(&rs_out->status, most_recent, sizeof(routerstatus_t));
|
||||
@ -2930,6 +2951,10 @@ routerstatus_list_update_from_networkstatus(time_t now)
|
||||
sizeof(rs_out->status.nickname));
|
||||
rs_out->status.is_valid = n_valid > n_statuses/2;
|
||||
rs_out->status.is_running = n_running > n_recent/2;
|
||||
rs_out->status.is_exit = n_exit > n_statuses/2;
|
||||
rs_out->status.is_fast = n_fast > n_statuses/2;
|
||||
rs_out->status.is_stable = n_stable > n_statuses/2;
|
||||
rs_out->status.is_v2_dir = n_v2_dir > n_statuses/2;
|
||||
}
|
||||
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
|
||||
local_routerstatus_free(rs));
|
||||
|
Loading…
Reference in New Issue
Block a user