mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Merge remote-tracking branch 'andrea/ticket19323_squashed'
This commit is contained in:
commit
cb54390e0f
3
changes/ticket19323
Normal file
3
changes/ticket19323
Normal file
@ -0,0 +1,3 @@
|
||||
o Control port:
|
||||
- Implement new GETINFO queries for all downloads using download_status_t
|
||||
to schedule retries. Closes ticket #19323.
|
449
src/or/control.c
449
src/or/control.c
@ -190,6 +190,8 @@ static void set_cached_network_liveness(int liveness);
|
||||
|
||||
static void flush_queued_events_cb(evutil_socket_t fd, short what, void *arg);
|
||||
|
||||
static char * download_status_to_string(const download_status_t *dl);
|
||||
|
||||
/** Given a control event code for a message event, return the corresponding
|
||||
* log severity. */
|
||||
static inline int
|
||||
@ -2051,6 +2053,410 @@ getinfo_helper_dir(control_connection_t *control_conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Turn a smartlist of digests into a human-readable list of hex strings */
|
||||
|
||||
static char *
|
||||
digest_list_to_string(smartlist_t *sl)
|
||||
{
|
||||
int len;
|
||||
char *result, *s;
|
||||
|
||||
/* Allow for newlines, and a \0 at the end */
|
||||
len = smartlist_len(sl) * (HEX_DIGEST_LEN + 1) + 1;
|
||||
result = tor_malloc_zero(len);
|
||||
|
||||
s = result;
|
||||
SMARTLIST_FOREACH_BEGIN(sl, char *, digest) {
|
||||
base16_encode(s, HEX_DIGEST_LEN + 1, digest, DIGEST_LEN);
|
||||
s[HEX_DIGEST_LEN] = '\n';
|
||||
s += HEX_DIGEST_LEN + 1;
|
||||
} SMARTLIST_FOREACH_END(digest);
|
||||
*s = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Turn a download_status_t into a human-readable description in a newly
|
||||
* allocated string. */
|
||||
|
||||
static char *
|
||||
download_status_to_string(const download_status_t *dl)
|
||||
{
|
||||
char *rv = NULL, *tmp;
|
||||
char tbuf[ISO_TIME_LEN+1];
|
||||
const char *schedule_str, *want_authority_str;
|
||||
const char *increment_on_str, *backoff_str;
|
||||
|
||||
if (dl) {
|
||||
/* Get some substrings of the eventual output ready */
|
||||
format_iso_time(tbuf, dl->next_attempt_at);
|
||||
|
||||
switch (dl->schedule) {
|
||||
case DL_SCHED_GENERIC:
|
||||
schedule_str = "DL_SCHED_GENERIC";
|
||||
break;
|
||||
case DL_SCHED_CONSENSUS:
|
||||
schedule_str = "DL_SCHED_CONSENSUS";
|
||||
break;
|
||||
case DL_SCHED_BRIDGE:
|
||||
schedule_str = "DL_SCHED_BRIDGE";
|
||||
break;
|
||||
default:
|
||||
schedule_str = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dl->want_authority) {
|
||||
case DL_WANT_ANY_DIRSERVER:
|
||||
want_authority_str = "DL_WANT_ANY_DIRSERVER";
|
||||
break;
|
||||
case DL_WANT_AUTHORITY:
|
||||
want_authority_str = "DL_WANT_AUTHORITY";
|
||||
break;
|
||||
default:
|
||||
want_authority_str = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dl->increment_on) {
|
||||
case DL_SCHED_INCREMENT_FAILURE:
|
||||
increment_on_str = "DL_SCHED_INCREMENT_FAILURE";
|
||||
break;
|
||||
case DL_SCHED_INCREMENT_ATTEMPT:
|
||||
increment_on_str = "DL_SCHED_INCREMENT_ATTEMPT";
|
||||
break;
|
||||
default:
|
||||
increment_on_str = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dl->backoff) {
|
||||
case DL_SCHED_DETERMINISTIC:
|
||||
backoff_str = "DL_SCHED_DETERMINISTIC";
|
||||
break;
|
||||
case DL_SCHED_RANDOM_EXPONENTIAL:
|
||||
backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL";
|
||||
break;
|
||||
default:
|
||||
backoff_str = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now assemble them */
|
||||
tor_asprintf(&tmp,
|
||||
"next-attempt-at %s\n"
|
||||
"n-download-failures %u\n"
|
||||
"n-download-attempts %u\n"
|
||||
"schedule %s\n"
|
||||
"want-authority %s\n"
|
||||
"increment-on %s\n"
|
||||
"backoff %s\n",
|
||||
tbuf,
|
||||
dl->n_download_failures,
|
||||
dl->n_download_attempts,
|
||||
schedule_str,
|
||||
want_authority_str,
|
||||
increment_on_str,
|
||||
backoff_str);
|
||||
|
||||
if (dl->backoff == DL_SCHED_RANDOM_EXPONENTIAL) {
|
||||
/* Additional fields become relevant in random-exponential mode */
|
||||
tor_asprintf(&rv,
|
||||
"%s"
|
||||
"last-backoff-position %u\n"
|
||||
"last-delay-used %d\n",
|
||||
tmp,
|
||||
dl->last_backoff_position,
|
||||
dl->last_delay_used);
|
||||
tor_free(tmp);
|
||||
} else {
|
||||
/* That was it */
|
||||
rv = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Handle the consensus download cases for getinfo_helper_downloads() */
|
||||
STATIC void
|
||||
getinfo_helper_downloads_networkstatus(const char *flavor,
|
||||
download_status_t **dl_to_emit,
|
||||
const char **errmsg)
|
||||
{
|
||||
/*
|
||||
* We get the one for the current bootstrapped status by default, or
|
||||
* take an extra /bootstrap or /running suffix
|
||||
*/
|
||||
if (strcmp(flavor, "ns") == 0) {
|
||||
*dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_NS);
|
||||
} else if (strcmp(flavor, "ns/bootstrap") == 0) {
|
||||
*dl_to_emit = networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_NS);
|
||||
} else if (strcmp(flavor, "ns/running") == 0 ) {
|
||||
*dl_to_emit = networkstatus_get_dl_status_by_flavor_running(FLAV_NS);
|
||||
} else if (strcmp(flavor, "microdesc") == 0) {
|
||||
*dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_MICRODESC);
|
||||
} else if (strcmp(flavor, "microdesc/bootstrap") == 0) {
|
||||
*dl_to_emit =
|
||||
networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_MICRODESC);
|
||||
} else if (strcmp(flavor, "microdesc/running") == 0) {
|
||||
*dl_to_emit =
|
||||
networkstatus_get_dl_status_by_flavor_running(FLAV_MICRODESC);
|
||||
} else {
|
||||
*errmsg = "Unknown flavor";
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle the cert download cases for getinfo_helper_downloads() */
|
||||
STATIC void
|
||||
getinfo_helper_downloads_cert(const char *fp_sk_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg)
|
||||
{
|
||||
const char *sk_req;
|
||||
char id_digest[DIGEST_LEN];
|
||||
char sk_digest[DIGEST_LEN];
|
||||
|
||||
/*
|
||||
* We have to handle four cases; fp_sk_req is the request with
|
||||
* a prefix of "downloads/cert/" snipped off.
|
||||
*
|
||||
* Case 1: fp_sk_req = "fps"
|
||||
* - We should emit a digest_list with a list of all the identity
|
||||
* fingerprints that can be queried for certificate download status;
|
||||
* get it by calling list_authority_ids_with_downloads().
|
||||
*
|
||||
* Case 2: fp_sk_req = "fp/<fp>" for some fingerprint fp
|
||||
* - We want the default certificate for this identity fingerprint's
|
||||
* download status; this is the download we get from URLs starting
|
||||
* in /fp/ on the directory server. We can get it with
|
||||
* id_only_download_status_for_authority_id().
|
||||
*
|
||||
* Case 3: fp_sk_req = "fp/<fp>/sks" for some fingerprint fp
|
||||
* - We want a list of all signing key digests for this identity
|
||||
* fingerprint which can be queried for certificate download status.
|
||||
* Get it with list_sk_digests_for_authority_id().
|
||||
*
|
||||
* Case 4: fp_sk_req = "fp/<fp>/<sk>" for some fingerprint fp and
|
||||
* signing key digest sk
|
||||
* - We want the download status for the certificate for this specific
|
||||
* signing key and fingerprint. These correspond to the ones we get
|
||||
* from URLs starting in /fp-sk/ on the directory server. Get it with
|
||||
* list_sk_digests_for_authority_id().
|
||||
*/
|
||||
|
||||
if (strcmp(fp_sk_req, "fps") == 0) {
|
||||
*digest_list = list_authority_ids_with_downloads();
|
||||
if (!(*digest_list)) {
|
||||
*errmsg = "Failed to get list of authority identity digests (!)";
|
||||
}
|
||||
} else if (!strcmpstart(fp_sk_req, "fp/")) {
|
||||
fp_sk_req += strlen("fp/");
|
||||
/* Okay, look for another / to tell the fp from fp-sk cases */
|
||||
sk_req = strchr(fp_sk_req, '/');
|
||||
if (sk_req) {
|
||||
/* okay, split it here and try to parse <fp> */
|
||||
if (base16_decode(id_digest, DIGEST_LEN,
|
||||
fp_sk_req, sk_req - fp_sk_req) == DIGEST_LEN) {
|
||||
/* Skip past the '/' */
|
||||
++sk_req;
|
||||
if (strcmp(sk_req, "sks") == 0) {
|
||||
/* We're asking for the list of signing key fingerprints */
|
||||
*digest_list = list_sk_digests_for_authority_id(id_digest);
|
||||
if (!(*digest_list)) {
|
||||
*errmsg = "Failed to get list of signing key digests for this "
|
||||
"authority identity digest";
|
||||
}
|
||||
} else {
|
||||
/* We've got a signing key digest */
|
||||
if (base16_decode(sk_digest, DIGEST_LEN,
|
||||
sk_req, strlen(sk_req)) == DIGEST_LEN) {
|
||||
*dl_to_emit =
|
||||
download_status_for_authority_id_and_sk(id_digest, sk_digest);
|
||||
if (!(*dl_to_emit)) {
|
||||
*errmsg = "Failed to get download status for this identity/"
|
||||
"signing key digest pair";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like a signing key digest";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like an identity digest";
|
||||
}
|
||||
} else {
|
||||
/* We're either in downloads/certs/fp/<fp>, or we can't parse <fp> */
|
||||
if (strlen(fp_sk_req) == HEX_DIGEST_LEN) {
|
||||
if (base16_decode(id_digest, DIGEST_LEN,
|
||||
fp_sk_req, strlen(fp_sk_req)) == DIGEST_LEN) {
|
||||
*dl_to_emit = id_only_download_status_for_authority_id(id_digest);
|
||||
if (!(*dl_to_emit)) {
|
||||
*errmsg = "Failed to get download status for this authority "
|
||||
"identity digest";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like a digest";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like a digest";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*errmsg = "Unknown certificate download status query";
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle the routerdesc download cases for getinfo_helper_downloads() */
|
||||
STATIC void
|
||||
getinfo_helper_downloads_desc(const char *desc_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg)
|
||||
{
|
||||
char desc_digest[DIGEST_LEN];
|
||||
/*
|
||||
* Two cases to handle here:
|
||||
*
|
||||
* Case 1: desc_req = "descs"
|
||||
* - Emit a list of all router descriptor digests, which we get by
|
||||
* calling router_get_descriptor_digests(); this can return NULL
|
||||
* if we have no current ns-flavor consensus.
|
||||
*
|
||||
* Case 2: desc_req = <fp>
|
||||
* - Check on the specified fingerprint and emit its download_status_t
|
||||
* using router_get_dl_status_by_descriptor_digest().
|
||||
*/
|
||||
|
||||
if (strcmp(desc_req, "descs") == 0) {
|
||||
*digest_list = router_get_descriptor_digests();
|
||||
if (!(*digest_list)) {
|
||||
*errmsg = "We don't seem to have a networkstatus-flavored consensus";
|
||||
}
|
||||
/*
|
||||
* Microdescs don't use the download_status_t mechanism, so we don't
|
||||
* answer queries about their downloads here; see microdesc.c.
|
||||
*/
|
||||
} else if (strlen(desc_req) == HEX_DIGEST_LEN) {
|
||||
if (base16_decode(desc_digest, DIGEST_LEN,
|
||||
desc_req, strlen(desc_req)) == DIGEST_LEN) {
|
||||
/* Okay we got a digest-shaped thing; try asking for it */
|
||||
*dl_to_emit = router_get_dl_status_by_descriptor_digest(desc_digest);
|
||||
if (!(*dl_to_emit)) {
|
||||
*errmsg = "No such descriptor digest found";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like a digest";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "Unknown router descriptor download status query";
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle the bridge download cases for getinfo_helper_downloads() */
|
||||
STATIC void
|
||||
getinfo_helper_downloads_bridge(const char *bridge_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg)
|
||||
{
|
||||
char bridge_digest[DIGEST_LEN];
|
||||
/*
|
||||
* Two cases to handle here:
|
||||
*
|
||||
* Case 1: bridge_req = "bridges"
|
||||
* - Emit a list of all bridge identity digests, which we get by
|
||||
* calling list_bridge_identities(); this can return NULL if we are
|
||||
* not using bridges.
|
||||
*
|
||||
* Case 2: bridge_req = <fp>
|
||||
* - Check on the specified fingerprint and emit its download_status_t
|
||||
* using get_bridge_dl_status_by_id().
|
||||
*/
|
||||
|
||||
if (strcmp(bridge_req, "bridges") == 0) {
|
||||
*digest_list = list_bridge_identities();
|
||||
if (!(*digest_list)) {
|
||||
*errmsg = "We don't seem to be using bridges";
|
||||
}
|
||||
} else if (strlen(bridge_req) == HEX_DIGEST_LEN) {
|
||||
if (base16_decode(bridge_digest, DIGEST_LEN,
|
||||
bridge_req, strlen(bridge_req)) == DIGEST_LEN) {
|
||||
/* Okay we got a digest-shaped thing; try asking for it */
|
||||
*dl_to_emit = get_bridge_dl_status_by_id(bridge_digest);
|
||||
if (!(*dl_to_emit)) {
|
||||
*errmsg = "No such bridge identity digest found";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "That didn't look like a digest";
|
||||
}
|
||||
} else {
|
||||
*errmsg = "Unknown bridge descriptor download status query";
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation helper for GETINFO: knows the answers for questions about
|
||||
* download status information. */
|
||||
STATIC int
|
||||
getinfo_helper_downloads(control_connection_t *control_conn,
|
||||
const char *question, char **answer,
|
||||
const char **errmsg)
|
||||
{
|
||||
download_status_t *dl_to_emit = NULL;
|
||||
smartlist_t *digest_list = NULL;
|
||||
|
||||
/* Assert args are sane */
|
||||
tor_assert(control_conn != NULL);
|
||||
tor_assert(question != NULL);
|
||||
tor_assert(answer != NULL);
|
||||
tor_assert(errmsg != NULL);
|
||||
|
||||
/* We check for this later to see if we should supply a default */
|
||||
*errmsg = NULL;
|
||||
|
||||
/* Are we after networkstatus downloads? */
|
||||
if (!strcmpstart(question, "downloads/networkstatus/")) {
|
||||
getinfo_helper_downloads_networkstatus(
|
||||
question + strlen("downloads/networkstatus/"),
|
||||
&dl_to_emit, errmsg);
|
||||
/* Certificates? */
|
||||
} else if (!strcmpstart(question, "downloads/cert/")) {
|
||||
getinfo_helper_downloads_cert(
|
||||
question + strlen("downloads/cert/"),
|
||||
&dl_to_emit, &digest_list, errmsg);
|
||||
/* Router descriptors? */
|
||||
} else if (!strcmpstart(question, "downloads/desc/")) {
|
||||
getinfo_helper_downloads_desc(
|
||||
question + strlen("downloads/desc/"),
|
||||
&dl_to_emit, &digest_list, errmsg);
|
||||
/* Bridge descriptors? */
|
||||
} else if (!strcmpstart(question, "downloads/bridge/")) {
|
||||
getinfo_helper_downloads_bridge(
|
||||
question + strlen("downloads/bridge/"),
|
||||
&dl_to_emit, &digest_list, errmsg);
|
||||
} else {
|
||||
*errmsg = "Unknown download status query";
|
||||
}
|
||||
|
||||
if (dl_to_emit) {
|
||||
*answer = download_status_to_string(dl_to_emit);
|
||||
|
||||
return 0;
|
||||
} else if (digest_list) {
|
||||
*answer = digest_list_to_string(digest_list);
|
||||
SMARTLIST_FOREACH(digest_list, void *, s, tor_free(s));
|
||||
smartlist_free(digest_list);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (!(*errmsg)) {
|
||||
*errmsg = "Unknown error";
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Allocate and return a description of <b>circ</b>'s current status,
|
||||
* including its path (if any). */
|
||||
static char *
|
||||
@ -2490,6 +2896,49 @@ static const getinfo_item_t getinfo_items[] = {
|
||||
DOC("config/defaults",
|
||||
"List of default values for configuration options. "
|
||||
"See also config/names"),
|
||||
PREFIX("downloads/networkstatus/", downloads,
|
||||
"Download statuses for networkstatus objects"),
|
||||
DOC("downloads/networkstatus/ns",
|
||||
"Download status for current-mode networkstatus download"),
|
||||
DOC("downloads/networkstatus/ns/bootstrap",
|
||||
"Download status for bootstrap-time networkstatus download"),
|
||||
DOC("downloads/networkstatus/ns/running",
|
||||
"Download status for run-time networkstatus download"),
|
||||
DOC("downloads/networkstatus/microdesc",
|
||||
"Download status for current-mode microdesc download"),
|
||||
DOC("downloads/networkstatus/microdesc/bootstrap",
|
||||
"Download status for bootstrap-time microdesc download"),
|
||||
DOC("downloads/networkstatus/microdesc/running",
|
||||
"Download status for run-time microdesc download"),
|
||||
PREFIX("downloads/cert/", downloads,
|
||||
"Download statuses for certificates, by id fingerprint and "
|
||||
"signing key"),
|
||||
DOC("downloads/cert/fps",
|
||||
"List of authority fingerprints for which any download statuses "
|
||||
"exist"),
|
||||
DOC("downloads/cert/fp/<fp>",
|
||||
"Download status for <fp> with the default signing key; corresponds "
|
||||
"to /fp/ URLs on directory server."),
|
||||
DOC("downloads/cert/fp/<fp>/sks",
|
||||
"List of signing keys for which specific download statuses are "
|
||||
"available for this id fingerprint"),
|
||||
DOC("downloads/cert/fp/<fp>/<sk>",
|
||||
"Download status for <fp> with signing key <sk>; corresponds "
|
||||
"to /fp-sk/ URLs on directory server."),
|
||||
PREFIX("downloads/desc/", downloads,
|
||||
"Download statuses for router descriptors, by descriptor digest"),
|
||||
DOC("downloads/desc/descs",
|
||||
"Return a list of known router descriptor digests"),
|
||||
DOC("downloads/desc/<desc>",
|
||||
"Return a download status for a given descriptor digest"),
|
||||
PREFIX("downloads/bridge/", downloads,
|
||||
"Download statuses for bridge descriptors, by bridge identity "
|
||||
"digest"),
|
||||
DOC("downloads/bridge/bridges",
|
||||
"Return a list of configured bridge identity digests with download "
|
||||
"statuses"),
|
||||
DOC("downloads/bridge/<desc>",
|
||||
"Return a download status for a given bridge identity digest"),
|
||||
ITEM("info/names", misc,
|
||||
"List of GETINFO options, types, and documentation."),
|
||||
ITEM("events/names", misc,
|
||||
|
@ -261,6 +261,31 @@ STATIC crypto_pk_t *add_onion_helper_keyarg(const char *arg, int discard_pk,
|
||||
char **err_msg_out);
|
||||
STATIC rend_authorized_client_t *
|
||||
add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out);
|
||||
|
||||
STATIC void getinfo_helper_downloads_networkstatus(
|
||||
const char *flavor,
|
||||
download_status_t **dl_to_emit,
|
||||
const char **errmsg);
|
||||
STATIC void getinfo_helper_downloads_cert(
|
||||
const char *fp_sk_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg);
|
||||
STATIC void getinfo_helper_downloads_desc(
|
||||
const char *desc_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg);
|
||||
STATIC void getinfo_helper_downloads_bridge(
|
||||
const char *bridge_req,
|
||||
download_status_t **dl_to_emit,
|
||||
smartlist_t **digest_list,
|
||||
const char **errmsg);
|
||||
STATIC int getinfo_helper_downloads(
|
||||
control_connection_t *control_conn,
|
||||
const char *question, char **answer,
|
||||
const char **errmsg);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -2424,6 +2424,44 @@ num_bridges_usable(void)
|
||||
return n_options;
|
||||
}
|
||||
|
||||
/** Return a smartlist containing all bridge identity digests */
|
||||
MOCK_IMPL(smartlist_t *,
|
||||
list_bridge_identities, (void))
|
||||
{
|
||||
smartlist_t *result = NULL;
|
||||
char *digest_tmp;
|
||||
|
||||
if (get_options()->UseBridges && bridge_list) {
|
||||
result = smartlist_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
|
||||
digest_tmp = tor_malloc(DIGEST_LEN);
|
||||
memcpy(digest_tmp, b->identity, DIGEST_LEN);
|
||||
smartlist_add(result, digest_tmp);
|
||||
} SMARTLIST_FOREACH_END(b);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Get the download status for a bridge descriptor given its identity */
|
||||
MOCK_IMPL(download_status_t *,
|
||||
get_bridge_dl_status_by_id, (const char *digest))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
|
||||
if (digest && get_options()->UseBridges && bridge_list) {
|
||||
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
|
||||
if (memcmp(digest, b->identity, DIGEST_LEN) == 0) {
|
||||
dl = &(b->fetch_status);
|
||||
break;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(b);
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Return 1 if we have at least one descriptor for an entry guard
|
||||
* (bridge or member of EntryNodes) and all descriptors we know are
|
||||
* down. Else return 0. If <b>act</b> is 1, then mark the down guards
|
||||
|
@ -179,5 +179,9 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
|
||||
int orig_bandwidth,
|
||||
uint32_t guardfraction_percentage);
|
||||
|
||||
MOCK_DECL(smartlist_t *, list_bridge_identities, (void));
|
||||
MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id,
|
||||
(const char *digest));
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -659,6 +659,43 @@ router_get_consensus_status_by_descriptor_digest(networkstatus_t *consensus,
|
||||
consensus, digest);
|
||||
}
|
||||
|
||||
/** Return a smartlist of all router descriptor digests in a consensus */
|
||||
static smartlist_t *
|
||||
router_get_descriptor_digests_in_consensus(networkstatus_t *consensus)
|
||||
{
|
||||
smartlist_t *result = smartlist_new();
|
||||
digestmap_iter_t *i;
|
||||
const char *digest;
|
||||
void *rs;
|
||||
char *digest_tmp;
|
||||
|
||||
for (i = digestmap_iter_init(consensus->desc_digest_map);
|
||||
!(digestmap_iter_done(i));
|
||||
i = digestmap_iter_next(consensus->desc_digest_map, i)) {
|
||||
digestmap_iter_get(i, &digest, &rs);
|
||||
digest_tmp = tor_malloc(DIGEST_LEN);
|
||||
memcpy(digest_tmp, digest, DIGEST_LEN);
|
||||
smartlist_add(result, digest_tmp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Return a smartlist of all router descriptor digests in the current
|
||||
* consensus */
|
||||
MOCK_IMPL(smartlist_t *,
|
||||
router_get_descriptor_digests,(void))
|
||||
{
|
||||
smartlist_t *result = NULL;
|
||||
|
||||
if (current_ns_consensus) {
|
||||
result =
|
||||
router_get_descriptor_digests_in_consensus(current_ns_consensus);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Given the digest of a router descriptor, return its current download
|
||||
* status, or NULL if the digest is unrecognized. */
|
||||
MOCK_IMPL(download_status_t *,
|
||||
@ -1179,6 +1216,52 @@ consensus_is_waiting_for_certs(void)
|
||||
? 1 : 0;
|
||||
}
|
||||
|
||||
/** Look up the currently active (depending on bootstrap status) download
|
||||
* status for this consensus flavor and return a pointer to it.
|
||||
*/
|
||||
MOCK_IMPL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor,(consensus_flavor_t flavor))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
const int we_are_bootstrapping =
|
||||
networkstatus_consensus_is_bootstrapping(time(NULL));
|
||||
|
||||
if (flavor <= N_CONSENSUS_FLAVORS) {
|
||||
dl = &((we_are_bootstrapping ?
|
||||
consensus_bootstrap_dl_status : consensus_dl_status)[flavor]);
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Look up the bootstrap download status for this consensus flavor
|
||||
* and return a pointer to it. */
|
||||
MOCK_IMPL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor_bootstrap,(consensus_flavor_t flavor))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
|
||||
if (flavor <= N_CONSENSUS_FLAVORS) {
|
||||
dl = &(consensus_bootstrap_dl_status[flavor]);
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Look up the running (non-bootstrap) download status for this consensus
|
||||
* flavor and return a pointer to it. */
|
||||
MOCK_IMPL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor_running,(consensus_flavor_t flavor))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
|
||||
if (flavor <= N_CONSENSUS_FLAVORS) {
|
||||
dl = &(consensus_dl_status[flavor]);
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Return the most recent consensus that we have downloaded, or NULL if we
|
||||
* don't have one. */
|
||||
networkstatus_t *
|
||||
|
@ -38,6 +38,17 @@ routerstatus_t *networkstatus_vote_find_mutable_entry(networkstatus_t *ns,
|
||||
int networkstatus_vote_find_entry_idx(networkstatus_t *ns,
|
||||
const char *digest, int *found_out);
|
||||
|
||||
MOCK_DECL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor,
|
||||
(consensus_flavor_t flavor));
|
||||
MOCK_DECL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor_bootstrap,
|
||||
(consensus_flavor_t flavor));
|
||||
MOCK_DECL(download_status_t *,
|
||||
networkstatus_get_dl_status_by_flavor_running,
|
||||
(consensus_flavor_t flavor));
|
||||
|
||||
MOCK_DECL(smartlist_t *, router_get_descriptor_digests, (void));
|
||||
MOCK_DECL(download_status_t *,router_get_dl_status_by_descriptor_digest,
|
||||
(const char *d));
|
||||
|
||||
|
@ -253,6 +253,112 @@ get_cert_list(const char *id_digest)
|
||||
return cl;
|
||||
}
|
||||
|
||||
/** Return a list of authority ID digests with potentially enumerable lists
|
||||
* of download_status_t objects; used by controller GETINFO queries.
|
||||
*/
|
||||
|
||||
MOCK_IMPL(smartlist_t *,
|
||||
list_authority_ids_with_downloads, (void))
|
||||
{
|
||||
smartlist_t *ids = smartlist_new();
|
||||
digestmap_iter_t *i;
|
||||
const char *digest;
|
||||
char *tmp;
|
||||
void *cl;
|
||||
|
||||
if (trusted_dir_certs) {
|
||||
for (i = digestmap_iter_init(trusted_dir_certs);
|
||||
!(digestmap_iter_done(i));
|
||||
i = digestmap_iter_next(trusted_dir_certs, i)) {
|
||||
/*
|
||||
* We always have at least dl_status_by_id to query, so no need to
|
||||
* probe deeper than the existence of a cert_list_t.
|
||||
*/
|
||||
digestmap_iter_get(i, &digest, &cl);
|
||||
tmp = tor_malloc(DIGEST_LEN);
|
||||
memcpy(tmp, digest, DIGEST_LEN);
|
||||
smartlist_add(ids, tmp);
|
||||
}
|
||||
}
|
||||
/* else definitely no downlaods going since nothing even has a cert list */
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/** Given an authority ID digest, return a pointer to the default download
|
||||
* status, or NULL if there is no such entry in trusted_dir_certs */
|
||||
|
||||
MOCK_IMPL(download_status_t *,
|
||||
id_only_download_status_for_authority_id, (const char *digest))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
cert_list_t *cl;
|
||||
|
||||
if (trusted_dir_certs) {
|
||||
cl = digestmap_get(trusted_dir_certs, digest);
|
||||
if (cl) {
|
||||
dl = &(cl->dl_status_by_id);
|
||||
}
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Given an authority ID digest, return a smartlist of signing key digests
|
||||
* for which download_status_t is potentially queryable, or NULL if no such
|
||||
* authority ID digest is known. */
|
||||
|
||||
MOCK_IMPL(smartlist_t *,
|
||||
list_sk_digests_for_authority_id, (const char *digest))
|
||||
{
|
||||
smartlist_t *sks = NULL;
|
||||
cert_list_t *cl;
|
||||
dsmap_iter_t *i;
|
||||
const char *sk_digest;
|
||||
char *tmp;
|
||||
download_status_t *dl;
|
||||
|
||||
if (trusted_dir_certs) {
|
||||
cl = digestmap_get(trusted_dir_certs, digest);
|
||||
if (cl) {
|
||||
sks = smartlist_new();
|
||||
if (cl->dl_status_map) {
|
||||
for (i = dsmap_iter_init(cl->dl_status_map);
|
||||
!(dsmap_iter_done(i));
|
||||
i = dsmap_iter_next(cl->dl_status_map, i)) {
|
||||
/* Pull the digest out and add it to the list */
|
||||
dsmap_iter_get(i, &sk_digest, &dl);
|
||||
tmp = tor_malloc(DIGEST_LEN);
|
||||
memcpy(tmp, sk_digest, DIGEST_LEN);
|
||||
smartlist_add(sks, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sks;
|
||||
}
|
||||
|
||||
/** Given an authority ID digest and a signing key digest, return the
|
||||
* download_status_t or NULL if none exists. */
|
||||
|
||||
MOCK_IMPL(download_status_t *,
|
||||
download_status_for_authority_id_and_sk,
|
||||
(const char *id_digest, const char *sk_digest))
|
||||
{
|
||||
download_status_t *dl = NULL;
|
||||
cert_list_t *cl = NULL;
|
||||
|
||||
if (trusted_dir_certs) {
|
||||
cl = digestmap_get(trusted_dir_certs, id_digest);
|
||||
if (cl && cl->dl_status_map) {
|
||||
dl = dsmap_get(cl->dl_status_map, sk_digest);
|
||||
}
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/** Release all space held by a cert_list_t */
|
||||
static void
|
||||
cert_list_free(cert_list_t *cl)
|
||||
|
@ -104,6 +104,14 @@ void routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int make_old,
|
||||
void routerlist_free_all(void);
|
||||
void routerlist_reset_warnings(void);
|
||||
|
||||
MOCK_DECL(smartlist_t *, list_authority_ids_with_downloads, (void);)
|
||||
MOCK_DECL(download_status_t *, id_only_download_status_for_authority_id,
|
||||
(const char *digest));
|
||||
MOCK_DECL(smartlist_t *, list_sk_digests_for_authority_id,
|
||||
(const char *digest));
|
||||
MOCK_DECL(download_status_t *, download_status_for_authority_id_and_sk,
|
||||
(const char *id_digest, const char *sk_digest));
|
||||
|
||||
static int WRA_WAS_ADDED(was_router_added_t s);
|
||||
static int WRA_WAS_OUTDATED(was_router_added_t s);
|
||||
static int WRA_WAS_REJECTED(was_router_added_t s);
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user