summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2008-06-11 01:14:23 +0000
committerRoger Dingledine <arma@torproject.org>2008-06-11 01:14:23 +0000
commit8c85eef9b065573da2be12c631e906dc149b1a4f (patch)
tree7d2fbc51f23e83911e03ba5e83932c68ec095851
parent42f21007a34ed5f0474e7eccd0991f1d8c5423f0 (diff)
downloadtor-8c85eef9b065573da2be12c631e906dc149b1a4f.tar.gz
tor-8c85eef9b065573da2be12c631e906dc149b1a4f.zip
start sending "bootstrap problem" status events when we're having troubles
reaching relays. svn:r15116
-rw-r--r--doc/spec/control-spec.txt2
-rw-r--r--src/or/connection.c24
-rw-r--r--src/or/connection_edge.c7
-rw-r--r--src/or/connection_or.c10
-rw-r--r--src/or/directory.c3
-rw-r--r--src/or/or.h22
-rw-r--r--src/or/reasons.c68
7 files changed, 95 insertions, 41 deletions
diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt
index da149c602c..4693407de6 100644
--- a/doc/spec/control-spec.txt
+++ b/doc/spec/control-spec.txt
@@ -1070,7 +1070,7 @@ $Id$
Reason = "MISC" / "DONE" / "CONNECTREFUSED" /
"IDENTITY" / "CONNECTRESET" / "TIMEOUT" / "NOROUTE" /
- "IOERROR"
+ "IOERROR" / "RESOURCELIMIT"
NumCircuits counts both established and pending circuits.
diff --git a/src/or/connection.c b/src/or/connection.c
index 8cbead64e3..8cfea46ea4 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -500,14 +500,18 @@ connection_about_to_close_connection(connection_t *conn)
if (!get_options()->HttpsProxy)
router_set_status(or_conn->identity_digest, 0);
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(
- 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 {
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
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
@@ -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
- * addr:port (they arrive in *host order*). If fail, return -1. Else
- * assign s to conn-\>s: if connected return 1, if EAGAIN return 0.
+ * addr:port (they arrive in *host order*). If fail, return -1 and if
+ * 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.
*
@@ -1106,7 +1111,7 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
*/
int
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;
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);
if (s < 0) {
+ *socket_error = tor_socket_errno(-1);
log_warn(LD_NET,"Error creating network socket: %s",
- tor_socket_strerror(tor_socket_errno(-1)));
+ tor_socket_strerror(*socket_error));
return -1;
}
@@ -1140,8 +1146,9 @@ connection_connect(connection_t *conn, const char *address,
} else {
if (bind(s, (struct sockaddr*)&ext_addr,
(socklen_t)sizeof(ext_addr)) < 0) {
+ *socket_error = tor_socket_errno(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);
return -1;
}
@@ -1165,6 +1172,7 @@ connection_connect(connection_t *conn, const char *address,
int e = tor_socket_errno(s);
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
/* yuck. kill it. */
+ *socket_error = e;
log_info(LD_NET,
"connect() to %s:%u failed: %s",escaped_safe_str(address),
port, tor_socket_strerror(e));
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 84f80eb18d..964824c15e 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -236,7 +236,7 @@ connection_edge_end_errno(edge_connection_t *conn)
{
uint8_t reason;
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);
}
@@ -2609,6 +2609,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
uint32_t addr;
uint16_t port;
connection_t *conn = TO_CONN(edge_conn);
+ int socket_error = 0;
if (!connection_edge_is_rendezvous_stream(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");
- switch (connection_connect(conn, conn->address, addr, port)) {
+ switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
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);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 5a15bddbca..1081a46437 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -513,6 +513,7 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
{
or_connection_t *conn;
or_options_t *options = get_options();
+ int socket_error = 0;
tor_assert(id_digest);
@@ -534,7 +535,8 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
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:
/* If the connection failed immediately, and we're using
* 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);
}
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
- END_OR_CONN_REASON_TCP_REFUSED);
- /* XXX connection_connect() can fail for all sorts of other reasons */
- control_event_bootstrap_problem("foo", END_OR_CONN_REASON_TCP_REFUSED);
+ errno_to_orconn_end_reason(socket_error));
+ control_event_bootstrap_problem(tor_socket_strerror(socket_error),
+ errno_to_orconn_end_reason(socket_error));
connection_free(TO_CONN(conn));
return NULL;
case 0:
diff --git a/src/or/directory.c b/src/or/directory.c
index ee1940e9b8..1cf6f2b38d 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -659,6 +659,7 @@ directory_initiate_command(const char *address, uint32_t addr,
{
dir_connection_t *conn;
or_options_t *options = get_options();
+ int socket_error = 0;
int use_begindir = supports_begindir &&
directory_command_should_use_begindir(options, addr,
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,
- dir_port)) {
+ dir_port, &socket_error)) {
case -1:
connection_dir_request_failed(conn); /* retry if we want */
/* XXX we only pass 'conn' above, not 'resource', 'payload',
diff --git a/src/or/or.h b/src/or/or.h
index d561fe4ea9..1851808397 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -501,14 +501,15 @@ typedef enum {
#define RELAY_COMMAND_INTRODUCE_ACK 40
/* Reasons why an OR connection is closed */
-#define END_OR_CONN_REASON_DONE 1
-#define END_OR_CONN_REASON_TCP_REFUSED 2
-#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_TLS_TIMEOUT 5
-#define END_OR_CONN_REASON_TLS_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_TLS_MISC 8
+#define END_OR_CONN_REASON_DONE 1
+#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
+#define END_OR_CONN_REASON_OR_IDENTITY 3
+#define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */
+#define END_OR_CONN_REASON_TIMEOUT 5
+#define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */
+#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */
+#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
* 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);
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,
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_string(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);
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);
diff --git a/src/or/reasons.c b/src/or/reasons.c
index 3052176e50..7ce73bafd2 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -144,9 +144,8 @@ stream_end_reason_to_socks5_response(int reason)
#endif
/** Given an errno from a failed exit connection, return a reason code
- * appropriate for use in a RELAY END cell.
- */
-int
+ * appropriate for use in a RELAY END cell. */
+uint8_t
errno_to_stream_end_reason(int e)
{
switch (e) {
@@ -192,19 +191,21 @@ orconn_end_reason_to_control_string(int r)
switch (r) {
case END_OR_CONN_REASON_DONE:
return "DONE";
- case END_OR_CONN_REASON_TCP_REFUSED:
+ case END_OR_CONN_REASON_REFUSED:
return "CONNECTREFUSED";
case END_OR_CONN_REASON_OR_IDENTITY:
return "IDENTITY";
- case END_OR_CONN_REASON_TLS_CONNRESET:
+ case END_OR_CONN_REASON_CONNRESET:
return "CONNECTRESET";
- case END_OR_CONN_REASON_TLS_TIMEOUT:
+ case END_OR_CONN_REASON_TIMEOUT:
return "TIMEOUT";
- case END_OR_CONN_REASON_TLS_NO_ROUTE:
+ case END_OR_CONN_REASON_NO_ROUTE:
return "NOROUTE";
- case END_OR_CONN_REASON_TLS_IO_ERROR:
+ case END_OR_CONN_REASON_IO_ERROR:
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";
case 0:
return "";
@@ -220,22 +221,59 @@ tls_error_to_orconn_end_reason(int e)
{
switch (e) {
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:
- return END_OR_CONN_REASON_TCP_REFUSED;
+ return END_OR_CONN_REASON_REFUSED;
case TOR_TLS_ERROR_CONNRESET:
- return END_OR_CONN_REASON_TLS_CONNRESET;
+ return END_OR_CONN_REASON_CONNRESET;
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:
- return END_OR_CONN_REASON_TLS_TIMEOUT;
+ return END_OR_CONN_REASON_TIMEOUT;
case TOR_TLS_WANTREAD:
case TOR_TLS_WANTWRITE:
case TOR_TLS_CLOSE:
case TOR_TLS_DONE:
return END_OR_CONN_REASON_DONE;
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;
}
}