summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2006-10-20 14:57:46 +0000
committerNick Mathewson <nickm@torproject.org>2006-10-20 14:57:46 +0000
commit136ed3307140ff82ade78f21765e43c87902d240 (patch)
tree99b1d79e39d022885b82f52f02b5df05ee0c7015 /src
parent77936aa337b05cfea073bced284d764b1a96e852 (diff)
downloadtor-136ed3307140ff82ade78f21765e43c87902d240.tar.gz
tor-136ed3307140ff82ade78f21765e43c87902d240.zip
r9289@31-35-219: nickm | 2006-10-20 09:43:22 -0400
Fix longstanding bug in connection_exit_begin_conn(): Since connection_edge_end() exits when the connection is unattached, we were never sending RELAY_END cells back for failed RELAY_BEGIN attempts. Fix this. This might make clients that were otherwise timing out either fail faster or retry faster, which is good news for us. svn:r8770
Diffstat (limited to 'src')
-rw-r--r--src/or/connection_edge.c65
-rw-r--r--src/or/or.h3
-rw-r--r--src/or/relay.c83
3 files changed, 101 insertions, 50 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 854e75566e..d3232a2475 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1838,36 +1838,51 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
relay_header_t rh;
char *address=NULL;
uint16_t port;
+ char end_payload[1];
assert_circuit_ok(circ);
- /* XXX currently we don't send an end cell back if we drop the
- * begin because it's malformed.
- */
+ relay_header_unpack(&rh, cell->payload);
+
+ /* Note: we have to use relay_send_command_from_edge here, not
+ * connection_edge_end or connection_edge_send_command, since those require
+ * that we have a stream connected to a circuit, and we don't connect to a
+ * circuit unitl we have a pending/sucessful resolve. */
if (!server_mode(get_options()) &&
circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay begin cell at non-server. Dropping.");
+ end_payload[0] = END_STREAM_REASON_EXITPOLICY;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
return 0;
}
- relay_header_unpack(&rh, cell->payload);
if (rh.command == RELAY_COMMAND_BEGIN) {
if (!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay begin cell has no \\0. Dropping.");
+ end_payload[0] = END_STREAM_REASON_TORPROTOCOL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
return 0;
}
if (parse_addr_port(LOG_PROTOCOL_WARN, cell->payload+RELAY_HEADER_SIZE,
&address,NULL,&port)<0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Unable to parse addr:port in relay begin cell. Dropping.");
+ end_payload[0] = END_STREAM_REASON_TORPROTOCOL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
return 0;
}
if (port==0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Missing port in relay begin cell. Dropping.");
+ end_payload[0] = END_STREAM_REASON_TORPROTOCOL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
tor_free(address);
return 0;
}
@@ -1876,6 +1891,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Non-printing characters in address %s in relay "
"begin cell. Dropping.", escaped(address));
+ end_payload[0] = END_STREAM_REASON_TORPROTOCOL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
tor_free(address);
return 0;
}
@@ -1886,15 +1904,27 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
*/
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Attempt to open a stream on first hop of circuit. Dropping.");
+ end_payload[0] = END_STREAM_REASON_TORPROTOCOL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
tor_free(address);
return 0;
}
} else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
or_options_t *options = get_options();
+ port = options->DirPort; /* not actually used to open a connection */
+ if (!port || circ->purpose != CIRCUIT_PURPOSE_OR) {
+ end_payload[0] = END_STREAM_REASON_NOTDIRECTORY;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
+ return 0;
+ }
address = tor_strdup("127.0.0.1");
- port = options->DirPort; /* not actually used. */
} else {
log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command);
+ end_payload[0] = END_STREAM_REASON_INTERNAL;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
return 0;
}
@@ -1908,15 +1938,6 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->package_window = STREAMWINDOW_START;
n_stream->deliver_window = STREAMWINDOW_START;
- if (rh.command == RELAY_COMMAND_BEGIN_DIR &&
- (!get_options()->DirPort || circ->purpose != CIRCUIT_PURPOSE_OR)) {
- connection_edge_end(n_stream, END_STREAM_REASON_NOTDIRECTORY,
- n_stream->cpath_layer);
- connection_free(TO_CONN(n_stream));
- tor_free(address);
- return 0;
- }
-
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
@@ -1929,8 +1950,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
n_stream->_base.port);
- connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
- n_stream->cpath_layer);
+ end_payload[0] = END_STREAM_REASON_EXITPOLICY;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
connection_free(TO_CONN(n_stream));
/* knock the whole thing down, somebody screwed up */
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@@ -1957,8 +1979,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
/* default to failed, change in dns_resolve if it turns out not to fail */
if (we_are_hibernating()) {
- connection_edge_end(n_stream, END_STREAM_REASON_HIBERNATING,
- n_stream->cpath_layer);
+ end_payload[0] = END_STREAM_REASON_HIBERNATING;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
connection_free(TO_CONN(n_stream));
return 0;
}
@@ -1985,7 +2008,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
connection_exit_connect(n_stream);
return 0;
case -1: /* resolve failed */
- /* XXXX send back indication of failure for connect case? -NM*/
+ end_payload[0] = END_STREAM_REASON_RESOLVEFAILED;
+ relay_send_command_from_edge(rh.stream_id, circ, RELAY_COMMAND_END,
+ end_payload, 1, NULL);
/* n_stream got freed. don't touch it. */
break;
case 0: /* resolve added to pending list */
@@ -2157,7 +2182,7 @@ connection_exit_connect_dir(edge_connection_t *exit_conn)
if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) < 0) {
log_warn(LD_NET,
- "Couldn't construct socketpair (%s). Network down? Delaying.",
+ "Couldn't construct socketpair (%s). Out of sockets?",
tor_socket_strerror(-err));
connection_edge_end(exit_conn, END_STREAM_REASON_RESOURCELIMIT,
exit_conn->cpath_layer);
diff --git a/src/or/or.h b/src/or/or.h
index 1ca35c46fb..f44f8a2a90 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2332,6 +2332,9 @@ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
void relay_header_pack(char *dest, const relay_header_t *src);
void relay_header_unpack(relay_header_t *dest, const char *src);
+int relay_send_command_from_edge(uint16_t stream_id, circuit_t *circ,
+ int relay_command, const char *payload,
+ size_t payload_len, crypt_path_t *cpath_layer);
int connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
int relay_command, const char *payload,
size_t payload_len,
diff --git a/src/or/relay.c b/src/or/relay.c
index bfea129270..f70ed23170 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -446,17 +446,17 @@ relay_header_unpack(relay_header_t *dest, const char *src)
dest->length = ntohs(get_uint16(src+9));
}
-/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and
- * send it onto the open circuit <b>circ</b>. <b>fromconn</b> is the stream
- * that's sending the relay cell, or NULL if it's a control cell.
- * <b>cpath_layer</b> is NULL for OR->OP cells, or the destination hop
- * for OP->OR cells.
+/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and send
+ * it onto the open circuit <b>circ</b>. <b>stream_id</b> is the ID on
+ * <b>circ</b> for the stream that's sending the relay cell, or 0 if it's a
+ * control cell. <b>cpath_layer</b> is NULL for OR->OP cells, or the
+ * destination hop for OP->OR cells.
*
- * If you can't send the cell, mark the circuit for close and
- * return -1. Else return 0.
+ * If you can't send the cell, mark the circuit for close and return -1. Else
+ * return 0.
*/
int
-connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
+relay_send_command_from_edge(uint16_t stream_id, circuit_t *circ,
int relay_command, const char *payload,
size_t payload_len, crypt_path_t *cpath_layer)
{
@@ -465,26 +465,7 @@ connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
int cell_direction;
/* XXXX NM Split this function into a separate versions per circuit type? */
- if (fromconn && fromconn->_base.marked_for_close) {
- log_warn(LD_BUG,
- "Bug: called on conn that's already marked for close at %s:%d.",
- fromconn->_base.marked_for_close_file,
- fromconn->_base.marked_for_close);
- return 0;
- }
-
- if (!circ) {
- tor_assert(fromconn);
- if (fromconn->_base.type == CONN_TYPE_AP) {
- log_info(LD_APP,"no circ. Closing conn.");
- connection_mark_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL);
- } else {
- log_info(LD_EXIT,"no circ. Closing conn.");
- fromconn->_base.edge_has_sent_end = 1; /* no circ to send to */
- connection_mark_for_close(TO_CONN(fromconn));
- }
- return -1;
- }
+ tor_assert(circ);
memset(&cell, 0, sizeof(cell_t));
cell.command = CELL_RELAY;
@@ -500,8 +481,7 @@ connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
memset(&rh, 0, sizeof(rh));
rh.command = relay_command;
- if (fromconn)
- rh.stream_id = fromconn->stream_id; /* else it's 0 */
+ rh.stream_id = stream_id;
rh.length = payload_len;
relay_header_pack(cell.payload, &rh);
if (payload_len) {
@@ -521,6 +501,48 @@ connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
return 0;
}
+/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and
+ * send it onto the open circuit <b>circ</b>. <b>fromconn</b> is the stream
+ * that's sending the relay cell, or NULL if it's a control cell.
+ * <b>cpath_layer</b> is NULL for OR->OP cells, or the destination hop
+ * for OP->OR cells.
+ *
+ * If you can't send the cell, mark the circuit for close and
+ * return -1. Else return 0.
+ */
+int
+connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
+ int relay_command, const char *payload,
+ size_t payload_len, crypt_path_t *cpath_layer)
+{
+ /* XXXX NM Split this function into a separate versions per circuit type? */
+
+ if (fromconn && fromconn->_base.marked_for_close) {
+ log_warn(LD_BUG,
+ "Bug: called on conn that's already marked for close at %s:%d.",
+ fromconn->_base.marked_for_close_file,
+ fromconn->_base.marked_for_close);
+ return 0;
+ }
+
+ if (!circ) {
+ tor_assert(fromconn);
+ if (fromconn->_base.type == CONN_TYPE_AP) {
+ log_info(LD_APP,"no circ. Closing conn.");
+ connection_mark_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL);
+ } else {
+ log_info(LD_EXIT,"no circ. Closing conn.");
+ fromconn->_base.edge_has_sent_end = 1; /* no circ to send to */
+ connection_mark_for_close(TO_CONN(fromconn));
+ }
+ return -1;
+ }
+
+ return relay_send_command_from_edge(fromconn ? fromconn->stream_id : 0,
+ circ, relay_command, payload,
+ payload_len, cpath_layer);
+}
+
/** 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.
@@ -545,6 +567,7 @@ connection_edge_end_reason_str(int reason)
case END_STREAM_REASON_RESOURCELIMIT: return "server out of resources";
case END_STREAM_REASON_CONNRESET: return "connection reset";
case END_STREAM_REASON_TORPROTOCOL: return "Tor protocol error";
+ case END_STREAM_REASON_NOTDIRECTORY: return "not a directory";
default:
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Reason for ending (%d) not recognized.",reason);