The big bootstrap phase redefinition

Redefine the set of bootstrap phases to allow display of finer-grained
progress in the early connection stages of connecting to a relay.

This includes adding intermediate phases for proxy and PT connections.

Also add a separate new phase to indicate obtaining enough directory
info to build circuits so we can report that independently of actually
initiating an ORCONN to build the first application circuit.
Previously, we would claim to be connecting to a relay when we had
merely finished obtaining directory info.

Part of ticket 27167.
This commit is contained in:
Taylor Yu 2018-12-17 09:31:16 -06:00 committed by Nick Mathewson
parent 936c93e562
commit 85542ee5a0
5 changed files with 159 additions and 40 deletions

View File

@ -4,6 +4,11 @@
/**
* \file btrack_orconn_cevent.c
* \brief Emit bootstrap status events for OR connections
*
* We do some decoding of the raw OR_CONN_STATE_* values. For
* example, OR_CONN_STATE_CONNECTING means the first TCP connect()
* completing, regardless of whether it's directly to a relay instead
* of a proxy or a PT.
**/
#include <stdbool.h>
@ -25,33 +30,68 @@
**/
static bool bto_first_orconn = false;
/** Is the ORCONN using a pluggable transport? */
static bool
using_pt(const bt_orconn_t *bto)
{
return bto->proxy_type == PROXY_PLUGGABLE;
}
/** Is the ORCONN using a non-PT proxy? */
static bool
using_proxy(const bt_orconn_t *bto)
{
switch (bto->proxy_type) {
case PROXY_CONNECT:
case PROXY_SOCKS4:
case PROXY_SOCKS5:
return true;
default:
return false;
}
}
/**
* Emit control events when we have updated our idea of the best state
* that any OR connection has reached.
*
* Do some decoding of the ORCONN states depending on whether a PT or
* a proxy is in use.
**/
void
bto_cevent_anyconn(const bt_orconn_t *bto)
{
switch (bto->state) {
case OR_CONN_STATE_CONNECTING:
/* Exactly what kind of thing we're connecting to isn't
* information we directly get from the states in connection_or.c,
* so decode it here. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PROXY, 0);
else
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
break;
case OR_CONN_STATE_PROXY_HANDSHAKING:
/* XXX This isn't quite right, because this isn't necessarily a
directory server we're talking to, but we'll improve the
bootstrap tags and messages later */
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
/* Similarly, starting a proxy handshake means the TCP connect()
* succeeded to the proxy. Let's be specific about what kind of
* proxy. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PROXY, 0);
break;
case OR_CONN_STATE_TLS_HANDSHAKING:
/* Here we should report a connection completed (TCP or proxied),
if we had the states */
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE, 0);
break;
case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
/* XXX Again, this isn't quite right, because it's not necessarily
a directory server we're talking to. */
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DIR, 0);
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
break;
case OR_CONN_STATE_OPEN:
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DONE, 0);
/* Unblock directory progress display */
control_event_boot_first_orconn();
/* Unblock apconn progress display */
@ -65,6 +105,9 @@ bto_cevent_anyconn(const bt_orconn_t *bto)
/**
* Emit control events when we have updated our idea of the best state
* that any application circuit OR connection has reached.
*
* Do some decoding of the ORCONN states depending on whether a PT or
* a proxy is in use.
**/
void
bto_cevent_apconn(const bt_orconn_t *bto)
@ -74,21 +117,35 @@ bto_cevent_apconn(const bt_orconn_t *bto)
switch (bto->state) {
case OR_CONN_STATE_CONNECTING:
/* Exactly what kind of thing we're connecting to isn't
* information we directly get from the states in connection_or.c,
* so decode it here. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PROXY, 0);
else
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN, 0);
break;
case OR_CONN_STATE_PROXY_HANDSHAKING:
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
/* Similarly, starting a proxy handshake means the TCP connect()
* succeeded to the proxy. Let's be specific about what kind of
* proxy. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, 0);
break;
case OR_CONN_STATE_TLS_HANDSHAKING:
/* Here we should report a connection completed (TCP or proxied) */
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE, 0);
break;
case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_OR, 0);
control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE, 0);
break;
case OR_CONN_STATE_OPEN:
/* XXX Not quite right, because it implictly reports the next
state, but we'll improve it later. */
control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0);
control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, 0);
default:
break;
}

View File

@ -51,17 +51,42 @@ typedef enum buildtimeout_set_event_t {
typedef enum {
BOOTSTRAP_STATUS_UNDEF=-1,
BOOTSTRAP_STATUS_STARTING=0,
BOOTSTRAP_STATUS_CONN_DIR=5,
BOOTSTRAP_STATUS_HANDSHAKE_DIR=10,
BOOTSTRAP_STATUS_ONEHOP_CREATE=15,
BOOTSTRAP_STATUS_REQUESTING_STATUS=20,
BOOTSTRAP_STATUS_LOADING_STATUS=25,
/* Initial connection to any relay */
BOOTSTRAP_STATUS_CONN_PT=1,
BOOTSTRAP_STATUS_CONN_DONE_PT=2,
BOOTSTRAP_STATUS_CONN_PROXY=3,
BOOTSTRAP_STATUS_CONN_DONE_PROXY=4,
BOOTSTRAP_STATUS_CONN=5,
BOOTSTRAP_STATUS_CONN_DONE=10,
BOOTSTRAP_STATUS_HANDSHAKE=14,
BOOTSTRAP_STATUS_HANDSHAKE_DONE=15,
/* Loading directory info */
BOOTSTRAP_STATUS_ONEHOP_CREATE=20,
BOOTSTRAP_STATUS_REQUESTING_STATUS=25,
BOOTSTRAP_STATUS_LOADING_STATUS=30,
BOOTSTRAP_STATUS_LOADING_KEYS=40,
BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45,
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50,
BOOTSTRAP_STATUS_CONN_OR=80,
BOOTSTRAP_STATUS_HANDSHAKE_OR=85,
BOOTSTRAP_STATUS_CIRCUIT_CREATE=90,
BOOTSTRAP_STATUS_ENOUGH_DIRINFO=75,
/* Connecting to a relay for AP circuits */
BOOTSTRAP_STATUS_AP_CONN_PT=76,
BOOTSTRAP_STATUS_AP_CONN_DONE_PT=77,
BOOTSTRAP_STATUS_AP_CONN_PROXY=78,
BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY=79,
BOOTSTRAP_STATUS_AP_CONN=80,
BOOTSTRAP_STATUS_AP_CONN_DONE=85,
BOOTSTRAP_STATUS_AP_HANDSHAKE=89,
BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE=90,
/* Creating AP circuits */
BOOTSTRAP_STATUS_CIRCUIT_CREATE=95,
BOOTSTRAP_STATUS_DONE=100
} bootstrap_status_t;

View File

@ -33,9 +33,24 @@ static const struct {
} boot_to_str_tab[] = {
{ BOOTSTRAP_STATUS_UNDEF, "undef", "Undefined" },
{ BOOTSTRAP_STATUS_STARTING, "starting", "Starting" },
{ BOOTSTRAP_STATUS_CONN_DIR, "conn_dir", "Connecting to directory server" },
{ BOOTSTRAP_STATUS_HANDSHAKE_DIR, "handshake_dir",
"Finishing handshake with directory server" },
/* Initial connection to any relay */
{ BOOTSTRAP_STATUS_CONN_PT, "conn_pt", "Connecting to pluggable transport" },
{ BOOTSTRAP_STATUS_CONN_DONE_PT, "conn_done_pt",
"Connected to pluggable transport" },
{ BOOTSTRAP_STATUS_CONN_PROXY, "conn_proxy", "Connecting to proxy" },
{ BOOTSTRAP_STATUS_CONN_DONE_PROXY, "conn_done_proxy",
"Connected to proxy" },
{ BOOTSTRAP_STATUS_CONN, "conn", "Connecting to a relay" },
{ BOOTSTRAP_STATUS_CONN_DONE, "conn_done", "Connected to a relay" },
{ BOOTSTRAP_STATUS_HANDSHAKE, "handshake",
"Handshaking with a relay" },
{ BOOTSTRAP_STATUS_HANDSHAKE_DONE, "handshake_done",
"Handshake with a relay done" },
/* Loading directory info */
{ BOOTSTRAP_STATUS_ONEHOP_CREATE, "onehop_create",
"Establishing an encrypted directory connection" },
{ BOOTSTRAP_STATUS_REQUESTING_STATUS, "requesting_status",
@ -48,9 +63,30 @@ static const struct {
"Asking for relay descriptors" },
{ BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, "loading_descriptors",
"Loading relay descriptors" },
{ BOOTSTRAP_STATUS_CONN_OR, "conn_or", "Connecting to the Tor network" },
{ BOOTSTRAP_STATUS_HANDSHAKE_OR, "handshake_or",
"Finishing handshake with first hop" },
{ BOOTSTRAP_STATUS_ENOUGH_DIRINFO, "enough_dirinfo",
"Loaded enough directory info to build circuits" },
/* Connecting to a relay for AP circuits */
{ BOOTSTRAP_STATUS_AP_CONN_PT, "ap_conn_pt",
"Connecting to pluggable transport to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_DONE_PT, "ap_conn_done_pt",
"Connected to pluggable transport to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_PROXY, "ap_conn_proxy",
"Connecting to proxy " },
{ BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, "ap_conn_done_proxy",
"Connected to proxy to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN, "ap_conn",
"Connecting to a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_DONE, "ap_conn_done",
"Connected to a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_HANDSHAKE, "ap_handshake",
"Finishing handshake with a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, "ap_handshake_done",
"Handshake fininshed with a relay to build circuits" },
/* Creating AP circuits */
{ BOOTSTRAP_STATUS_CIRCUIT_CREATE, "circuit_create",
"Establishing a Tor circuit" },
{ BOOTSTRAP_STATUS_DONE, "done", "Done" },

View File

@ -2546,7 +2546,7 @@ count_loading_descriptors_progress(void)
if (fraction > 1.0)
return 0; /* it's not the number of descriptors holding us back */
return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
(fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
(fraction*(BOOTSTRAP_STATUS_ENOUGH_DIRINFO-1 -
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
}
@ -2633,6 +2633,7 @@ update_router_have_minimum_dir_info(void)
/* If paths have just become available in this update. */
if (res && !have_min_dir_info) {
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
log_info(LD_DIR,
"We now have enough directory information to build circuits.");
}

View File

@ -351,10 +351,10 @@ test_cntev_dirboot_defer_desc(void *arg)
/* This event should get deferred */
control_event_boot_dir(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
assert_bootmsg("0 TAG=starting");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
assert_bootmsg("5 TAG=conn_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DIR, 0);
assert_bootmsg("10 TAG=handshake_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
assert_bootmsg("45 TAG=requesting_descriptors");
@ -374,15 +374,15 @@ test_cntev_dirboot_defer_orconn(void *arg)
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
assert_bootmsg("0 TAG=starting");
/* This event should get deferred */
control_event_boot_dir(BOOTSTRAP_STATUS_CONN_OR, 0);
control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
assert_bootmsg("0 TAG=starting");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
assert_bootmsg("5 TAG=conn_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DIR, 0);
assert_bootmsg("10 TAG=handshake_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
assert_bootmsg("80 TAG=conn_or");
assert_bootmsg("75 TAG=enough_dirinfo");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);