summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2005-04-04 03:30:49 +0000
committerRoger Dingledine <arma@torproject.org>2005-04-04 03:30:49 +0000
commitf1edeebf7d15ba9e0947985e0539f98288bda697 (patch)
tree80ca601dbf918d451287ae7c69a6966d7b036e28
parentf89ef9793e5d57a4dfdeb4f6c10e78b7621550f2 (diff)
downloadtor-f1edeebf7d15ba9e0947985e0539f98288bda697.tar.gz
tor-f1edeebf7d15ba9e0947985e0539f98288bda697.zip
client now retries when streams end early for 'hibernating' or
'resource limit' reasons; refactor. svn:r4004
-rw-r--r--src/or/relay.c226
1 files changed, 117 insertions, 109 deletions
diff --git a/src/or/relay.c b/src/or/relay.c
index 39cab5311b..ee4389dcf4 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -457,17 +457,16 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
return 0;
}
-/** Translate the <b>payload</b> of length <b>length</b>, which
- * came from a relay 'end' cell, into a static const string describing
- * why the stream is closing.
+/** Translate <b>reason</b>, which came from a relay 'end' cell,
+ * into a static const string describing why the stream is closing.
+ * <b>reason</b> is -1 if no reason was provided.
*/
static const char *
-connection_edge_end_reason_str(char *payload, uint16_t length) {
- if (length < 1) {
- log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
- return "MALFORMED";
- }
- switch (*payload) {
+connection_edge_end_reason_str(int reason) {
+ switch (reason) {
+ case -1:
+ log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
+ return "MALFORMED";
case END_STREAM_REASON_MISC: return "misc error";
case END_STREAM_REASON_RESOLVEFAILED: return "resolve failed";
case END_STREAM_REASON_CONNECTREFUSED: return "connection refused";
@@ -481,7 +480,7 @@ connection_edge_end_reason_str(char *payload, uint16_t length) {
case END_STREAM_REASON_CONNRESET: return "connection reset";
case END_STREAM_REASON_TORPROTOCOL: return "Tor protocol error";
default:
- log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
+ log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",reason);
return "unknown";
}
}
@@ -583,100 +582,121 @@ errno_to_end_reason(int e)
*/
#define MAX_RESOLVE_FAILURES 3
-/** An incoming relay cell has arrived from circuit <b>circ</b> to
- * stream <b>conn</b>.
- *
- * The arguments here are the same as in
- * connection_edge_process_relay_cell() below; this function is called
- * from there when <b>conn</b> is defined and not in an open state.
- */
+/** Return 1 if reason is something that you should retry if you
+ * get the end cell before you've connected; else return 0. */
static int
-connection_edge_process_relay_cell_not_open(
+edge_reason_is_retriable(int reason) {
+ return reason == END_STREAM_REASON_HIBERNATING ||
+ reason == END_STREAM_REASON_RESOURCELIMIT ||
+ reason == END_STREAM_REASON_EXITPOLICY ||
+ reason == END_STREAM_REASON_RESOLVEFAILED;
+}
+
+static int
+connection_edge_process_end_not_open(
relay_header_t *rh, cell_t *cell, circuit_t *circ,
connection_t *conn, crypt_path_t *layer_hint) {
struct in_addr in;
- uint32_t addr;
- int reason;
routerinfo_t *exitrouter;
+ int reason = *(cell->payload+RELAY_HEADER_SIZE);
- if (rh->command == RELAY_COMMAND_END) {
- reason = *(cell->payload+RELAY_HEADER_SIZE);
- /* We have to check this here, since we aren't connected yet. */
- if (rh->length >= 5 && reason == END_STREAM_REASON_EXITPOLICY) {
- if (conn->type != CONN_TYPE_AP) {
- log_fn(LOG_WARN,"Got an end because of exitpolicy, but we're not an AP. Closing.");
- return -1;
- }
- addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
- if (addr) {
- log_fn(LOG_INFO,"Address '%s' refused due to exit policy. Retrying.",
- conn->socks_request->address);
- } else {
- log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
- conn->socks_request->address);
- connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
- return 0;
- }
- client_dns_set_addressmap(conn->socks_request->address, addr,
- conn->chosen_exit_name);
+ if (rh->length > 0 && edge_reason_is_retriable(reason)) {
+ if (conn->type != CONN_TYPE_AP) {
+ log_fn(LOG_WARN,"Got an end because of %s, but we're not an AP. Closing.",
+ connection_edge_end_reason_str(reason));
+ return -1;
+ }
+ log_fn(LOG_INFO,"Address '%s' refused due to '%s'. Considering retrying.",
+ conn->socks_request->address,
+ connection_edge_end_reason_str(reason));
+ exitrouter = router_get_by_digest(circ->build_state->chosen_exit_digest);
+ if (!exitrouter) {
+ log_fn(LOG_INFO,"Skipping broken circ (exit router vanished)");
+ return 0; /* this circuit is screwed and doesn't know it yet */
+ }
+ switch (reason) {
+ case END_STREAM_REASON_EXITPOLICY:
+ if (rh->length >= 5) {
+ uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+ if (!addr) {
+ log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
+ conn->socks_request->address);
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
+ client_dns_set_addressmap(conn->socks_request->address, addr,
+ conn->chosen_exit_name);
+ }
+ /* check if he *ought* to have allowed it */
+ if (rh->length < 5 ||
+ (!tor_inet_aton(conn->socks_request->address, &in) &&
+ !conn->chosen_exit_name)) {
+ log_fn(LOG_NOTICE,"Exitrouter '%s' seems to be more restrictive than its exit policy. Not using this router as exit for now.", exitrouter->nickname);
+ addr_policy_free(exitrouter->exit_policy);
+ exitrouter->exit_policy =
+ router_parse_addr_policy_from_string("reject *:*");
+ }
- /* check if he *ought* to have allowed it */
- exitrouter = router_get_by_digest(circ->build_state->chosen_exit_digest);
- if (!exitrouter) {
- log_fn(LOG_INFO,"Skipping broken circ (exit router vanished)");
- return 0; /* this circuit is screwed and doesn't know it yet */
- }
- if (!tor_inet_aton(conn->socks_request->address, &in) &&
- !conn->chosen_exit_name) {
- log_fn(LOG_NOTICE,"Exitrouter '%s' seems to be more restrictive than its exit policy. Not using this router as exit for now.", exitrouter->nickname);
+ if (connection_ap_detach_retriable(conn, circ) >= 0)
+ return 0;
+ /* else, conn will get closed below */
+ break;
+ case END_STREAM_REASON_RESOLVEFAILED:
+ if (client_dns_incr_failures(conn->socks_request->address)
+ < MAX_RESOLVE_FAILURES) {
+ /* We haven't retried too many times; reattach the connection. */
+ circuit_log_path(LOG_INFO,circ);
+ tor_assert(circ->timestamp_dirty);
+ circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+
+ if (connection_ap_detach_retriable(conn, circ) >= 0)
+ return 0;
+ /* else, conn will get closed below */
+ } else {
+ log_fn(LOG_NOTICE,"Have tried resolving address '%s' at %d different places. Giving up.",
+ conn->socks_request->address, MAX_RESOLVE_FAILURES);
+ }
+ break;
+ case END_STREAM_REASON_HIBERNATING:
+ case END_STREAM_REASON_RESOURCELIMIT:
addr_policy_free(exitrouter->exit_policy);
exitrouter->exit_policy =
router_parse_addr_policy_from_string("reject *:*");
- }
-
- if (connection_ap_detach_retriable(conn, circ) >= 0)
- return 0;
-
- log_fn(LOG_INFO,"Giving up on retrying (from exitpolicy); conn can't be handled.");
- /* else, conn will get closed below */
- } else if (rh->length && reason == END_STREAM_REASON_RESOLVEFAILED) {
- if (conn->type != CONN_TYPE_AP) {
- log_fn(LOG_WARN,"Got an end because of resolvefailed, but we're not an AP. Closing.");
- return -1;
- }
- if (client_dns_incr_failures(conn->socks_request->address)
- < MAX_RESOLVE_FAILURES) {
- /* We haven't retried too many times; reattach the connection. */
- log_fn(LOG_INFO,"Resolve of '%s' failed, trying again.",
- conn->socks_request->address);
- circuit_log_path(LOG_INFO,circ);
- tor_assert(circ->timestamp_dirty);
- circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
if (connection_ap_detach_retriable(conn, circ) >= 0)
return 0;
+ /* else, will close below */
+ break;
+ } /* end switch */
+ log_fn(LOG_INFO,"Giving up on retrying; conn can't be handled.");
+ }
- /* else, conn will get closed below */
- log_fn(LOG_INFO,"Giving up on retrying (from resolvefailed); conn can't be handled.");
- } else {
- log_fn(LOG_NOTICE,"Have tried resolving address '%s' at %d different places. Giving up.",
- conn->socks_request->address, MAX_RESOLVE_FAILURES);
- }
- }
- log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
- connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
- rh->length));
- if (CIRCUIT_IS_ORIGIN(circ))
- circuit_log_path(LOG_INFO,circ);
- if (conn->type == CONN_TYPE_AP) {
- connection_mark_unattached_ap(conn,
- *(char *)(cell->payload+RELAY_HEADER_SIZE));
- } else {
- conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
- connection_mark_for_close(conn);
- }
- return 0;
+ log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
+ connection_edge_end_reason_str(rh->length > 0 ? reason : -1));
+ if (conn->type == CONN_TYPE_AP) {
+ circuit_log_path(LOG_INFO,circ);
+ connection_mark_unattached_ap(conn, reason);
+ } else {
+ conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
+ connection_mark_for_close(conn);
}
+ return 0;
+}
+
+/** An incoming relay cell has arrived from circuit <b>circ</b> to
+ * stream <b>conn</b>.
+ *
+ * The arguments here are the same as in
+ * connection_edge_process_relay_cell() below; this function is called
+ * from there when <b>conn</b> is defined and not in an open state.
+ */
+static int
+connection_edge_process_relay_cell_not_open(
+ relay_header_t *rh, cell_t *cell, circuit_t *circ,
+ connection_t *conn, crypt_path_t *layer_hint) {
+
+ if (rh->command == RELAY_COMMAND_END)
+ return connection_edge_process_end_not_open(rh, cell, circ, conn, layer_hint);
if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
@@ -688,7 +708,7 @@ connection_edge_process_relay_cell_not_open(
log_fn(LOG_INFO,"'connected' received after %d seconds.",
(int)(time(NULL) - conn->timestamp_lastread));
if (rh->length >= 4) {
- addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
+ uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
if (!addr) {
log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing.");
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer);
@@ -762,12 +782,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* either conn is NULL, in which case we've got a control cell, or else
* conn points to the recognized stream. */
- if (conn &&
- conn->state != AP_CONN_STATE_OPEN &&
- conn->state != EXIT_CONN_STATE_OPEN) {
+ if (conn && !connection_state_is_open(conn))
return connection_edge_process_relay_cell_not_open(
&rh, cell, circ, conn, layer_hint);
- }
switch (rh.command) {
case RELAY_COMMAND_DROP:
@@ -821,27 +838,18 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_END:
if (!conn) {
log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream.",
- connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
- rh.length));
+ connection_edge_end_reason_str(rh.length > 0 ?
+ *(char *)(cell->payload+RELAY_HEADER_SIZE) : -1));
return 0;
}
/* XXX add to this log_fn the exit node's nickname? */
log_fn(LOG_INFO,"%d: end cell (%s) for stream %d. Removing stream. Size %d.",
conn->s,
- connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
- rh.length),
+ connection_edge_end_reason_str(rh.length > 0 ?
+ *(char *)(cell->payload+RELAY_HEADER_SIZE) : -1),
conn->stream_id, (int)conn->stream_size);
- if (conn->socks_request && !conn->socks_request->has_finished) {
- socks5_reply_status_t status;
- if (rh.length < 1) {
- log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
- status = SOCKS5_GENERAL_ERROR;
- } else {
- status = connection_edge_end_reason_socks5_response(
- *(uint8_t*)cell->payload+RELAY_HEADER_SIZE);
- }
- connection_ap_handshake_socks_reply(conn, NULL, 0, status);
- }
+ if (conn->socks_request && !conn->socks_request->has_finished)
+ log_fn(LOG_WARN,"Bug: open stream hasn't sent socks answer yet? Closing.");
#ifdef HALF_OPEN
conn->done_sending = 1;
shutdown(conn->s, 1); /* XXX check return; refactor NM */