commit 1e441df2d0d06aa66eaf2c0e00a42d7fe9c39c87 Author: Nick Mathewson nickm@torproject.org Date: Mon Jul 18 13:56:22 2011 -0400
Only use optimistic data with exits that support it
This adds a little code complexity: we need to remember for each node whether it supports the right feature, and then check for each connection whether it's exiting at such a node. We store this in a flag in the edge_connection_t, and set that flag at link time. --- src/or/circuituse.c | 21 +++++++++++++++++ src/or/connection_edge.c | 56 ++++++++++++++++++++++++++++++++------------- src/or/or.h | 8 ++++++ src/or/routerparse.c | 3 ++ 4 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 460c41f..3c8cacb 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -677,6 +677,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) tor_assert(conn);
conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */ + conn->exit_allows_optimistic_data = 0; conn->on_circuit = NULL;
if (CIRCUIT_IS_ORIGIN(circ)) { @@ -1449,6 +1450,8 @@ static void link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, crypt_path_t *cpath) { + const node_t *exitnode; + /* add it into the linked list of streams on this circuit */ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.", circ->_base.n_circ_id); @@ -1468,6 +1471,24 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); apconn->cpath_layer = circ->cpath->prev; } + + /* See if we can use optimistic data on this circuit */ + if (apconn->cpath_layer->extend_info && + (exitnode = node_get_by_id( + apconn->cpath_layer->extend_info->identity_digest)) && + exitnode->rs) { + /* Okay; we know what exit node this is. */ + if (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL && + exitnode->rs->version_supports_optimistic_data) + apconn->exit_allows_optimistic_data = 1; + else + apconn->exit_allows_optimistic_data = 0; + log_info(LD_APP, "Looks like completed circuit to %s %s allow " + "optimistic data for connection to %s", + safe_str_client(node_describe(exitnode)), + apconn->exit_allows_optimistic_data ? "does" : "doesn't", + safe_str_client(apconn->socks_request->address)); + } }
/** Return true iff <b>address</b> is matched by one of the entries in diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 6f91d1a..20f8bc9 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -57,6 +57,7 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn); static int address_is_in_virtual_range(const char *addr); static int consider_plaintext_ports(edge_connection_t *conn, uint16_t port); static void clear_trackexithost_mappings(const char *exitname); +static int connection_ap_supports_optimistic_data(const edge_connection_t *);
/** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set @@ -154,6 +155,22 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) return -1; } return 0; + case AP_CONN_STATE_CONNECT_WAIT: + if (connection_ap_supports_optimistic_data(conn)) { + log_info(LD_EDGE, + "data from edge while in '%s' state. Sending it anyway. " + "package_partial=%d, buflen=%ld", + conn_state_to_string(conn->_base.type, conn->_base.state), + package_partial, connection_get_inbuf_len(TO_CONN(conn))); + if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) { + /* (We already sent an end cell if possible) */ + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + return 0; + } + /* Fall through if the connection is on a circuit without optimistic + * data support. */ case EXIT_CONN_STATE_CONNECTING: case AP_CONN_STATE_RENDDESC_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: @@ -163,18 +180,6 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) "data from edge while in '%s' state. Leaving it on buffer.", conn_state_to_string(conn->_base.type, conn->_base.state)); return 0; - case AP_CONN_STATE_CONNECT_WAIT: - log_info(LD_EDGE, - "data from edge while in '%s' state. Sending it anyway. " - "package_partial=%d, buflen=%ld", - conn_state_to_string(conn->_base.type, conn->_base.state), - package_partial, connection_get_inbuf_len(TO_CONN(conn))); - if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) { - /* (We already sent an end cell if possible) */ - connection_mark_for_close(TO_CONN(conn)); - return -1; - } - return 0; } log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->_base.state); tor_fragile_assert(); @@ -2345,6 +2350,22 @@ get_unique_stream_id_by_circ(origin_circuit_t *circ) return test_stream_id; }
+/** Return true iff <b>conn</b> is linked to a circuit and configured to use + * an exit that supports optimistic data. */ +static int +connection_ap_supports_optimistic_data(const edge_connection_t *conn) +{ + tor_assert(conn->_base.type == CONN_TYPE_AP); + /* We can only send optimistic data if we're connected to an open + general circuit. */ + if (conn->on_circuit == NULL || + conn->on_circuit->state != CIRCUIT_STATE_OPEN || + conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) + return 0; + + return conn->exit_allows_optimistic_data; +} + /** Write a relay begin cell, using destaddr and destport from ap_conn's * socks_request field, and send it down circ. * @@ -2408,10 +2429,13 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn) control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
/* If there's queued-up data, send it now */ - log_info(LD_APP, "Possibly sending queued-up data: %ld", - connection_get_inbuf_len(TO_CONN(ap_conn))); - if (connection_edge_package_raw_inbuf(ap_conn, 1, NULL) < 0) { - connection_mark_for_close(TO_CONN(ap_conn)); + if (connection_get_inbuf_len(TO_CONN(ap_conn)) && + connection_ap_supports_optimistic_data(ap_conn)) { + log_info(LD_APP, "Sending up to %ld bytes of queued-up data", + connection_get_inbuf_len(TO_CONN(ap_conn))); + if (connection_edge_package_raw_inbuf(ap_conn, 1, NULL) < 0) { + connection_mark_for_close(TO_CONN(ap_conn)); + } }
return 0; diff --git a/src/or/or.h b/src/or/or.h index 7a2bde5..f805215 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1232,6 +1232,11 @@ typedef struct edge_connection_t { * NATd connection */ unsigned int is_transparent_ap:1;
+ /** Set if this connection's target exit node allows optimistic data. + * (That is, data sent on this stream before the exit has sent a + * CONNECTED cell.)*/ + unsigned int exit_allows_optimistic_data : 1; + /** If this is a DNSPort connection, this field holds the pending DNS * request that we're going to try to answer. */ struct evdns_server_request *dns_server_request; @@ -1667,6 +1672,9 @@ typedef struct routerstatus_t { /** True iff this router is a version that, if it caches directory info, * we can get microdescriptors from. */ unsigned int version_supports_microdesc_cache:1; + /** True iff this router is a version that allows DATA cells to arrive on + * a stream before it has sent a CONNECTED cell. */ + unsigned int version_supports_optimistic_data:1;
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index d1b2cd0..5f160d0 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2092,6 +2092,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->version_supports_extrainfo_upload = 1; rs->version_supports_conditional_consensus = 1; rs->version_supports_microdesc_cache = 1; + rs->version_supports_optimistic_data = 1; } else { rs->version_supports_begindir = tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha"); @@ -2109,6 +2110,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, */ rs->version_supports_microdesc_cache = tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha"); + rs->version_supports_optimistic_data = + tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]);
tor-commits@lists.torproject.org