start sending "bootstrap problem" status events when we're having troubles

reaching relays.


svn:r15116
This commit is contained in:
Roger Dingledine 2008-06-11 01:14:23 +00:00
parent 42f21007a3
commit 8c85eef9b0
7 changed files with 95 additions and 41 deletions

View File

@ -1070,7 +1070,7 @@ $Id$
Reason = "MISC" / "DONE" / "CONNECTREFUSED" / Reason = "MISC" / "DONE" / "CONNECTREFUSED" /
"IDENTITY" / "CONNECTRESET" / "TIMEOUT" / "NOROUTE" / "IDENTITY" / "CONNECTRESET" / "TIMEOUT" / "NOROUTE" /
"IOERROR" "IOERROR" / "RESOURCELIMIT"
NumCircuits counts both established and pending circuits. NumCircuits counts both established and pending circuits.

View File

@ -500,14 +500,18 @@ connection_about_to_close_connection(connection_t *conn)
if (!get_options()->HttpsProxy) if (!get_options()->HttpsProxy)
router_set_status(or_conn->identity_digest, 0); router_set_status(or_conn->identity_digest, 0);
if (conn->state == OR_CONN_STATE_CONNECTING) { if (conn->state == OR_CONN_STATE_CONNECTING) {
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED, 0); control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
errno_to_orconn_end_reason(or_conn->socket_error));
control_event_bootstrap_problem( control_event_bootstrap_problem(
tor_socket_strerror(or_conn->socket_error), 0); tor_socket_strerror(or_conn->socket_error),
errno_to_orconn_end_reason(or_conn->socket_error));
} else { } else {
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error); int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED, control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
reason); reason);
control_event_bootstrap_problem("foo", reason); /* XXX021 come up with a better string for the first arg */
control_event_bootstrap_problem(
orconn_end_reason_to_control_string(reason), reason);
} }
} }
/* Inform any pending (not attached) circs that they should /* Inform any pending (not attached) circs that they should
@ -1097,8 +1101,9 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
} }
/** Take conn, make a nonblocking socket; try to connect to /** Take conn, make a nonblocking socket; try to connect to
* addr:port (they arrive in *host order*). If fail, return -1. Else * addr:port (they arrive in *host order*). If fail, return -1 and if
* assign s to conn-\>s: if connected return 1, if EAGAIN return 0. * applicable put your best guess about errno into *<b>socket_error</b>.
* Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0.
* *
* address is used to make the logs useful. * address is used to make the logs useful.
* *
@ -1106,7 +1111,7 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
*/ */
int int
connection_connect(connection_t *conn, const char *address, connection_connect(connection_t *conn, const char *address,
uint32_t addr, uint16_t port) uint32_t addr, uint16_t port, int *socket_error)
{ {
int s, inprogress = 0; int s, inprogress = 0;
struct sockaddr_in dest_addr; struct sockaddr_in dest_addr;
@ -1123,8 +1128,9 @@ connection_connect(connection_t *conn, const char *address,
s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s < 0) { if (s < 0) {
*socket_error = tor_socket_errno(-1);
log_warn(LD_NET,"Error creating network socket: %s", log_warn(LD_NET,"Error creating network socket: %s",
tor_socket_strerror(tor_socket_errno(-1))); tor_socket_strerror(*socket_error));
return -1; return -1;
} }
@ -1140,8 +1146,9 @@ connection_connect(connection_t *conn, const char *address,
} else { } else {
if (bind(s, (struct sockaddr*)&ext_addr, if (bind(s, (struct sockaddr*)&ext_addr,
(socklen_t)sizeof(ext_addr)) < 0) { (socklen_t)sizeof(ext_addr)) < 0) {
*socket_error = tor_socket_errno(s);
log_warn(LD_NET,"Error binding network socket: %s", log_warn(LD_NET,"Error binding network socket: %s",
tor_socket_strerror(tor_socket_errno(s))); tor_socket_strerror(*socket_error));
tor_close_socket(s); tor_close_socket(s);
return -1; return -1;
} }
@ -1165,6 +1172,7 @@ connection_connect(connection_t *conn, const char *address,
int e = tor_socket_errno(s); int e = tor_socket_errno(s);
if (!ERRNO_IS_CONN_EINPROGRESS(e)) { if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
/* yuck. kill it. */ /* yuck. kill it. */
*socket_error = e;
log_info(LD_NET, log_info(LD_NET,
"connect() to %s:%u failed: %s",escaped_safe_str(address), "connect() to %s:%u failed: %s",escaped_safe_str(address),
port, tor_socket_strerror(e)); port, tor_socket_strerror(e));

View File

@ -236,7 +236,7 @@ connection_edge_end_errno(edge_connection_t *conn)
{ {
uint8_t reason; uint8_t reason;
tor_assert(conn); tor_assert(conn);
reason = (uint8_t)errno_to_stream_end_reason(tor_socket_errno(conn->_base.s)); reason = errno_to_stream_end_reason(tor_socket_errno(conn->_base.s));
return connection_edge_end(conn, reason); return connection_edge_end(conn, reason);
} }
@ -2609,6 +2609,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
uint32_t addr; uint32_t addr;
uint16_t port; uint16_t port;
connection_t *conn = TO_CONN(edge_conn); connection_t *conn = TO_CONN(edge_conn);
int socket_error = 0;
if (!connection_edge_is_rendezvous_stream(edge_conn) && if (!connection_edge_is_rendezvous_stream(edge_conn) &&
router_compare_to_my_exit_policy(edge_conn)) { router_compare_to_my_exit_policy(edge_conn)) {
@ -2644,8 +2645,10 @@ connection_exit_connect(edge_connection_t *edge_conn)
} }
log_debug(LD_EXIT,"about to try connecting"); log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port)) { switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
case -1: case -1:
/* XXX021 use socket_error below rather than trying to piece things
* together from the current errno, which may have been clobbered. */
connection_edge_end_errno(edge_conn); connection_edge_end_errno(edge_conn);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn); connection_free(conn);

View File

@ -513,6 +513,7 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
{ {
or_connection_t *conn; or_connection_t *conn;
or_options_t *options = get_options(); or_options_t *options = get_options();
int socket_error = 0;
tor_assert(id_digest); tor_assert(id_digest);
@ -534,7 +535,8 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
port = options->HttpsProxyPort; port = options->HttpsProxyPort;
} }
switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, port)) { switch (connection_connect(TO_CONN(conn), conn->_base.address,
addr, port, &socket_error)) {
case -1: case -1:
/* If the connection failed immediately, and we're using /* If the connection failed immediately, and we're using
* an https proxy, our https proxy is down. Don't blame the * an https proxy, our https proxy is down. Don't blame the
@ -545,9 +547,9 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
router_set_status(conn->identity_digest, 0); router_set_status(conn->identity_digest, 0);
} }
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
END_OR_CONN_REASON_TCP_REFUSED); errno_to_orconn_end_reason(socket_error));
/* XXX connection_connect() can fail for all sorts of other reasons */ control_event_bootstrap_problem(tor_socket_strerror(socket_error),
control_event_bootstrap_problem("foo", END_OR_CONN_REASON_TCP_REFUSED); errno_to_orconn_end_reason(socket_error));
connection_free(TO_CONN(conn)); connection_free(TO_CONN(conn));
return NULL; return NULL;
case 0: case 0:

View File

@ -659,6 +659,7 @@ directory_initiate_command(const char *address, uint32_t addr,
{ {
dir_connection_t *conn; dir_connection_t *conn;
or_options_t *options = get_options(); or_options_t *options = get_options();
int socket_error = 0;
int use_begindir = supports_begindir && int use_begindir = supports_begindir &&
directory_command_should_use_begindir(options, addr, directory_command_should_use_begindir(options, addr,
or_port, router_purpose, anonymized_connection); or_port, router_purpose, anonymized_connection);
@ -699,7 +700,7 @@ directory_initiate_command(const char *address, uint32_t addr,
} }
switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, switch (connection_connect(TO_CONN(conn), conn->_base.address, addr,
dir_port)) { dir_port, &socket_error)) {
case -1: case -1:
connection_dir_request_failed(conn); /* retry if we want */ connection_dir_request_failed(conn); /* retry if we want */
/* XXX we only pass 'conn' above, not 'resource', 'payload', /* XXX we only pass 'conn' above, not 'resource', 'payload',

View File

@ -501,14 +501,15 @@ typedef enum {
#define RELAY_COMMAND_INTRODUCE_ACK 40 #define RELAY_COMMAND_INTRODUCE_ACK 40
/* Reasons why an OR connection is closed */ /* Reasons why an OR connection is closed */
#define END_OR_CONN_REASON_DONE 1 #define END_OR_CONN_REASON_DONE 1
#define END_OR_CONN_REASON_TCP_REFUSED 2 #define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
#define END_OR_CONN_REASON_OR_IDENTITY 3 #define END_OR_CONN_REASON_OR_IDENTITY 3
#define END_OR_CONN_REASON_TLS_CONNRESET 4 /* tls connection reset by peer */ #define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */
#define END_OR_CONN_REASON_TLS_TIMEOUT 5 #define END_OR_CONN_REASON_TIMEOUT 5
#define END_OR_CONN_REASON_TLS_NO_ROUTE 6 /* no route to host/net */ #define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */
#define END_OR_CONN_REASON_TLS_IO_ERROR 7 /* tls read/write error */ #define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */
#define END_OR_CONN_REASON_TLS_MISC 8 #define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */
#define END_OR_CONN_REASON_MISC 9
/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for /* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for
* documentation of these. */ * documentation of these. */
@ -2742,7 +2743,7 @@ void _connection_mark_for_close(connection_t *conn,int line, const char *file);
void connection_expire_held_open(void); void connection_expire_held_open(void);
int connection_connect(connection_t *conn, const char *address, uint32_t addr, int connection_connect(connection_t *conn, const char *address, uint32_t addr,
uint16_t port); uint16_t port, int *socket_error);
int retry_all_listeners(smartlist_t *replaced_conns, int retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns); smartlist_t *new_conns);
@ -3589,10 +3590,11 @@ void policies_free_all(void);
const char *stream_end_reason_to_control_string(int reason); const char *stream_end_reason_to_control_string(int reason);
const char *stream_end_reason_to_string(int reason); const char *stream_end_reason_to_string(int reason);
socks5_reply_status_t stream_end_reason_to_socks5_response(int reason); socks5_reply_status_t stream_end_reason_to_socks5_response(int reason);
int errno_to_stream_end_reason(int e); uint8_t errno_to_stream_end_reason(int e);
const char *orconn_end_reason_to_control_string(int r); const char *orconn_end_reason_to_control_string(int r);
int tls_error_to_orconn_end_reason(int e); int tls_error_to_orconn_end_reason(int e);
int errno_to_orconn_end_reason(int e);
const char *circuit_end_reason_to_control_string(int reason); const char *circuit_end_reason_to_control_string(int reason);

View File

@ -144,9 +144,8 @@ stream_end_reason_to_socks5_response(int reason)
#endif #endif
/** Given an errno from a failed exit connection, return a reason code /** Given an errno from a failed exit connection, return a reason code
* appropriate for use in a RELAY END cell. * appropriate for use in a RELAY END cell. */
*/ uint8_t
int
errno_to_stream_end_reason(int e) errno_to_stream_end_reason(int e)
{ {
switch (e) { switch (e) {
@ -192,19 +191,21 @@ orconn_end_reason_to_control_string(int r)
switch (r) { switch (r) {
case END_OR_CONN_REASON_DONE: case END_OR_CONN_REASON_DONE:
return "DONE"; return "DONE";
case END_OR_CONN_REASON_TCP_REFUSED: case END_OR_CONN_REASON_REFUSED:
return "CONNECTREFUSED"; return "CONNECTREFUSED";
case END_OR_CONN_REASON_OR_IDENTITY: case END_OR_CONN_REASON_OR_IDENTITY:
return "IDENTITY"; return "IDENTITY";
case END_OR_CONN_REASON_TLS_CONNRESET: case END_OR_CONN_REASON_CONNRESET:
return "CONNECTRESET"; return "CONNECTRESET";
case END_OR_CONN_REASON_TLS_TIMEOUT: case END_OR_CONN_REASON_TIMEOUT:
return "TIMEOUT"; return "TIMEOUT";
case END_OR_CONN_REASON_TLS_NO_ROUTE: case END_OR_CONN_REASON_NO_ROUTE:
return "NOROUTE"; return "NOROUTE";
case END_OR_CONN_REASON_TLS_IO_ERROR: case END_OR_CONN_REASON_IO_ERROR:
return "IOERROR"; return "IOERROR";
case END_OR_CONN_REASON_TLS_MISC: case END_OR_CONN_REASON_RESOURCE_LIMIT:
return "RESOURCELIMIT";
case END_OR_CONN_REASON_MISC:
return "MISC"; return "MISC";
case 0: case 0:
return ""; return "";
@ -220,22 +221,59 @@ tls_error_to_orconn_end_reason(int e)
{ {
switch (e) { switch (e) {
case TOR_TLS_ERROR_IO: case TOR_TLS_ERROR_IO:
return END_OR_CONN_REASON_TLS_IO_ERROR; return END_OR_CONN_REASON_IO_ERROR;
case TOR_TLS_ERROR_CONNREFUSED: case TOR_TLS_ERROR_CONNREFUSED:
return END_OR_CONN_REASON_TCP_REFUSED; return END_OR_CONN_REASON_REFUSED;
case TOR_TLS_ERROR_CONNRESET: case TOR_TLS_ERROR_CONNRESET:
return END_OR_CONN_REASON_TLS_CONNRESET; return END_OR_CONN_REASON_CONNRESET;
case TOR_TLS_ERROR_NO_ROUTE: case TOR_TLS_ERROR_NO_ROUTE:
return END_OR_CONN_REASON_TLS_NO_ROUTE; return END_OR_CONN_REASON_NO_ROUTE;
case TOR_TLS_ERROR_TIMEOUT: case TOR_TLS_ERROR_TIMEOUT:
return END_OR_CONN_REASON_TLS_TIMEOUT; return END_OR_CONN_REASON_TIMEOUT;
case TOR_TLS_WANTREAD: case TOR_TLS_WANTREAD:
case TOR_TLS_WANTWRITE: case TOR_TLS_WANTWRITE:
case TOR_TLS_CLOSE: case TOR_TLS_CLOSE:
case TOR_TLS_DONE: case TOR_TLS_DONE:
return END_OR_CONN_REASON_DONE; return END_OR_CONN_REASON_DONE;
default: default:
return END_OR_CONN_REASON_TLS_MISC; return END_OR_CONN_REASON_MISC;
}
}
/** Given an errno from a failed ORConn connection, return a reason code
* appropriate for use in the controller orconn events. */
/* XXX021 somebody should think about whether the assignments I've made
* are accurate or useful. -RD */
int
errno_to_orconn_end_reason(int e)
{
switch (e) {
case EPIPE:
return END_OR_CONN_REASON_DONE;
S_CASE(ENOTCONN):
S_CASE(ENETUNREACH):
case ENETDOWN: /* << somebody should look into the Windows equiv */
case EHOSTUNREACH:
return END_OR_CONN_REASON_NO_ROUTE;
S_CASE(ECONNREFUSED):
return END_OR_CONN_REASON_REFUSED;
S_CASE(ECONNRESET):
return END_OR_CONN_REASON_CONNRESET;
S_CASE(ETIMEDOUT):
return END_OR_CONN_REASON_TIMEOUT;
S_CASE(ENOBUFS):
case ENOMEM:
case ENFILE:
E_CASE(EMFILE):
E_CASE(EACCES):
E_CASE(EBADF):
E_CASE(EFAULT):
E_CASE(EINVAL):
return END_OR_CONN_REASON_RESOURCE_LIMIT;
default:
log_info(LD_OR, "Didn't recognize errno %d (%s).",
e, tor_socket_strerror(e));
return END_OR_CONN_REASON_MISC;
} }
} }