Refactor control_event_bootstrap_problem

Change the contract of control_event_bootstrap_problem() to be more
general and to take a connection_t.  New function
control_event_bootstrap_prob_or() has the specific or_connection_t
funcionality previously used.
This commit is contained in:
Taylor Yu 2017-09-13 14:47:18 -05:00
parent 00bf4ed592
commit 818332e7f1
4 changed files with 82 additions and 48 deletions

View File

@ -727,7 +727,7 @@ connection_or_about_to_close(or_connection_t *or_conn)
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
reason);
if (!authdir_mode_tests_reachability(options))
control_event_bootstrap_problem(
control_event_bootstrap_prob_or(
orconn_end_reason_to_control_string(reason),
reason, or_conn);
}
@ -1113,7 +1113,7 @@ connection_or_connect_failed(or_connection_t *conn,
{
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason);
if (!authdir_mode_tests_reachability(get_options()))
control_event_bootstrap_problem(msg, reason, conn);
control_event_bootstrap_prob_or(msg, reason, conn);
}
/** <b>conn</b> got an error in connection_handle_read_impl() or
@ -1236,7 +1236,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port),
transport_name, transport_name);
control_event_bootstrap_problem(
control_event_bootstrap_prob_or(
"Can't connect to bridge",
END_OR_CONN_REASON_PT_MISSING,
conn);
@ -1714,7 +1714,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
END_OR_CONN_REASON_OR_IDENTITY);
if (!authdir_mode_tests_reachability(options))
control_event_bootstrap_problem(
control_event_bootstrap_prob_or(
"Unexpected identity in router certificate",
END_OR_CONN_REASON_OR_IDENTITY,
conn);

View File

@ -6754,80 +6754,112 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
}
/** Called when Tor has failed to make bootstrapping progress in a way
* that indicates a problem. <b>warn</b> gives a hint as to why, and
* <b>reason</b> provides an "or_conn_end_reason" tag. <b>or_conn</b>
* is the connection that caused this problem.
* that indicates a problem. <b>warn</b> gives a human-readable hint
* as to why, and <b>reason</b> provides a controller-facing short
* tag. <b>conn</b> is the connection that caused this problem and
* can be NULL if a connection cannot be easily identified.
*/
MOCK_IMPL(void,
control_event_bootstrap_problem, (const char *warn, int reason,
or_connection_t *or_conn))
void
control_event_bootstrap_problem(const char *warn, const char *reason,
const connection_t *conn, int dowarn)
{
int status = bootstrap_percent;
const char *tag = "", *summary = "";
char buf[BOOTSTRAP_MSG_LEN];
const char *recommendation = "ignore";
int severity;
char *or_id = NULL, *hostaddr = NULL;
or_connection_t *or_conn = NULL;
/* bootstrap_percent must not be in "undefined" state here. */
tor_assert(status >= 0);
if (or_conn->have_noted_bootstrap_problem)
return;
or_conn->have_noted_bootstrap_problem = 1;
if (bootstrap_percent == 100)
return; /* already bootstrapped; nothing to be done here. */
bootstrap_problems++;
if (bootstrap_problems >= BOOTSTRAP_PROBLEM_THRESHOLD)
recommendation = "warn";
if (reason == END_OR_CONN_REASON_NO_ROUTE)
recommendation = "warn";
/* If we are using bridges and all our OR connections are now
closed, it means that we totally failed to connect to our
bridges. Throw a warning. */
if (get_options()->UseBridges && !any_other_active_or_conns(or_conn))
recommendation = "warn";
dowarn = 1;
if (we_are_hibernating())
recommendation = "ignore";
dowarn = 0;
while (status>=0 && bootstrap_status_to_string(status, &tag, &summary) < 0)
status--; /* find a recognized status string based on current progress */
status = bootstrap_percent; /* set status back to the actual number */
severity = !strcmp(recommendation, "warn") ? LOG_WARN : LOG_INFO;
severity = dowarn ? LOG_WARN : LOG_INFO;
if (dowarn)
recommendation = "warn";
if (conn && conn->type == CONN_TYPE_OR) {
/* XXX TO_OR_CONN can't deal with const */
or_conn = TO_OR_CONN((connection_t *)conn);
or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN));
} else {
or_id = tor_strdup("?");
}
if (conn)
tor_asprintf(&hostaddr, "%s:%d", conn->address, (int)conn->port);
else
hostaddr = tor_strdup("?");
log_fn(severity,
LD_CONTROL, "Problem bootstrapping. Stuck at %d%%: %s. (%s; %s; "
"count %d; recommendation %s; host %s at %s:%d)",
status, summary, warn,
orconn_end_reason_to_control_string(reason),
"count %d; recommendation %s; host %s at %s)",
status, summary, warn, reason,
bootstrap_problems, recommendation,
hex_str(or_conn->identity_digest, DIGEST_LEN),
or_conn->base_.address,
or_conn->base_.port);
or_id, hostaddr);
connection_or_report_broken_states(severity, LD_HANDSHAKE);
tor_snprintf(buf, sizeof(buf),
"BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s "
"COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s:%d\"",
bootstrap_percent, tag, summary, warn,
orconn_end_reason_to_control_string(reason), bootstrap_problems,
"COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s\"",
bootstrap_percent, tag, summary, warn, reason, bootstrap_problems,
recommendation,
hex_str(or_conn->identity_digest, DIGEST_LEN),
or_conn->base_.address,
(int)or_conn->base_.port);
or_id, hostaddr);
tor_snprintf(last_sent_bootstrap_message,
sizeof(last_sent_bootstrap_message),
"WARN %s", buf);
control_event_client_status(LOG_WARN, "%s", buf);
tor_free(hostaddr);
tor_free(or_id);
}
/** Called when Tor has failed to make bootstrapping progress in a way
* that indicates a problem. <b>warn</b> gives a hint as to why, and
* <b>reason</b> provides an "or_conn_end_reason" tag. <b>or_conn</b>
* is the connection that caused this problem.
*/
MOCK_IMPL(void,
control_event_bootstrap_prob_or, (const char *warn, int reason,
or_connection_t *or_conn))
{
int dowarn = 0;
if (or_conn->have_noted_bootstrap_problem)
return;
or_conn->have_noted_bootstrap_problem = 1;
if (reason == END_OR_CONN_REASON_NO_ROUTE)
dowarn = 1;
/* If we are using bridges and all our OR connections are now
closed, it means that we totally failed to connect to our
bridges. Throw a warning. */
if (get_options()->UseBridges && !any_other_active_or_conns(or_conn))
dowarn = 1;
control_event_bootstrap_problem(warn,
orconn_end_reason_to_control_string(reason),
TO_CONN(or_conn), dowarn);
}
/** We just generated a new summary of which countries we've seen clients

View File

@ -99,9 +99,11 @@ void enable_control_logging(void);
void monitor_owning_controller_process(const char *process_spec);
int control_event_bootstrap(bootstrap_status_t status, int progress);
MOCK_DECL(void, control_event_bootstrap_problem,(const char *warn,
MOCK_DECL(void, control_event_bootstrap_prob_or,(const char *warn,
int reason,
or_connection_t *or_conn));
void control_event_bootstrap_problem(const char *warn, const char *reason,
const connection_t *conn, int dowarn);
void control_event_clients_seen(const char *controller_str);
void control_event_transport_launched(const char *mode,

View File

@ -497,14 +497,14 @@ test_ext_or_handshake(void *arg)
"te road There is always another ", 64);
/* Send the wrong response. */
WRITE("not with a bang but a whimper...", 32);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x00", 1);
tt_assert(TO_CONN(conn)->marked_for_close);
/* XXXX Hold-open-until-flushed. */
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_problem);
UNMOCK(control_event_bootstrap_prob_or);
MOCK(connection_start_reading, note_read_started);
MOCK(connection_stop_reading, note_read_stopped);
@ -552,26 +552,26 @@ test_ext_or_handshake(void *arg)
do_ext_or_handshake(conn);
/* USERADDR command with an extra NUL byte */
WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_problem);
UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* TRANSPORT command with an extra NUL byte */
WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_problem);
UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
@ -579,13 +579,13 @@ test_ext_or_handshake(void *arg)
/* TRANSPORT command with transport name with symbols (not a
C-identifier) */
WRITE("\x00\x02\x00\x07""rf*1149", 11);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_problem);
UNMOCK(control_event_bootstrap_prob_or);
done:
UNMOCK(connection_write_to_buf_impl_);