commit 8cf9fe5ba63c1c2b711d852b61e734c48cf482b5 Author: Andrea Shepard andrea@torproject.org Date: Mon Jun 27 16:38:37 2016 +0000
Expose consensus download statuses on the control port --- src/or/control.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ src/or/networkstatus.c | 46 +++++++++++++ src/or/networkstatus.h | 7 ++ 3 files changed, 229 insertions(+)
diff --git a/src/or/control.c b/src/or/control.c index 6e5dcf6..35a949f 100644 --- a/src/or/control.c +++ b/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,166 @@ getinfo_helper_dir(control_connection_t *control_conn, return 0; }
+/** 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; +} + +/** 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) +{ + const char *flavor; + download_status_t *dl_to_emit = 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/")) { + flavor = question + strlen("downloads/networkstatus/"); + /* + * 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"; + } + } + + if (dl_to_emit) { + *answer = download_status_to_string(dl_to_emit); + + 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 +2652,20 @@ 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"), ITEM("info/names", misc, "List of GETINFO options, types, and documentation."), ITEM("events/names", misc, diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 3471288..45688b1 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1179,6 +1179,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. + */ +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. */ +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. */ +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 * diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index aee6641..752ddf8 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -38,6 +38,13 @@ 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);
+download_status_t * networkstatus_get_dl_status_by_flavor( + consensus_flavor_t flavor); +download_status_t * networkstatus_get_dl_status_by_flavor_bootstrap( + consensus_flavor_t flavor); +download_status_t * networkstatus_get_dl_status_by_flavor_running( + consensus_flavor_t flavor); + MOCK_DECL(download_status_t *,router_get_dl_status_by_descriptor_digest, (const char *d));