diff options
-rw-r--r-- | src/or/circuitlist.c | 18 | ||||
-rw-r--r-- | src/or/circuituse.c | 13 | ||||
-rw-r--r-- | src/or/connection_edge.c | 35 | ||||
-rw-r--r-- | src/or/connection_edge.h | 1 | ||||
-rw-r--r-- | src/or/or.h | 24 |
5 files changed, 82 insertions, 9 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 9f688801f3..6f17697b21 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -210,9 +210,23 @@ circuit_set_state(circuit_t *circ, uint8_t state) /* add to waiting-circuit list. */ smartlist_add(circuits_pending_or_conns, circ); } - if (state == CIRCUIT_STATE_OPEN) - tor_assert(!circ->n_conn_onionskin); + circ->state = state; + + if (state == CIRCUIT_STATE_OPEN) { + tor_assert(!circ->n_conn_onionskin); + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (origin_circ->isolation_values_set && + !origin_circ->isolation_any_streams_attached) { + /* If we have any isolation information set on this circuit, + * but we never attached any streams to it, then all of the + * isolation information was hypothetical. Clear it. + */ + circuit_clear_isolation(origin_circ); + } + } + } } /** Add <b>circ</b> to the global list of circuits. This is called only from diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 19a62344f3..93098e527d 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1457,12 +1457,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, rend_client_rendcirc_has_opened(circ); } } - } - if (!circ) + } /* endif (!circ) */ + if (circ) { + /* Mark the circuit with the isolation fields for this connection. + * When the circuit arrives, we'll clear these flags: this is + * just some internal bookkeeping to make sure that we have + * launched enough circuits. + */ + connection_edge_update_circuit_isolation(conn, circ, 0); + } else { log_info(LD_APP, "No safe circuit (purpose %d) ready for edge " "connection; delaying.", desired_circuit_purpose); + } *circp = circ; return 0; } @@ -1509,6 +1517,7 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, apconn->cpath_layer = circ->cpath->prev; } + circ->isolation_any_streams_attached = 1; connection_edge_update_circuit_isolation(apconn, circ, 0); } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index ce555ed5e2..20f01b15f6 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -3414,3 +3414,38 @@ connection_edge_update_circuit_isolation(const edge_connection_t *conn, } } +/** + * Clear the isolation settings on <b>circ</b>. + * + * This only works on an open circuit that has never had a stream attached to + * it, and whose isolation settings are hypothetical. (We set hypothetical + * isolation settings on circuits as we're launching them, so that we + * know whether they can handle more streams or whether we need to launch + * even more circuits. We clear the flags once the circuits are open, + * in case the streams that made us launch the circuits have closed + * since we began launching the circuits.) + */ +void +circuit_clear_isolation(origin_circuit_t *circ) +{ + if (circ->isolation_any_streams_attached) { + log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit"); + return; + } + if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) { + log_warn(LD_BUG, "Tried to clear the isolation status of a non-open " + "circuit"); + return; + } + + circ->isolation_values_set = 0; + circ->isolation_flags_mixed = 0; + circ->client_proto_type = 0; + circ->client_proto_socksver = 0; + circ->dest_port = 0; + tor_addr_make_unspec(&circ->client_addr); + tor_free(circ->dest_address); + circ->session_group = -1; + circ->nym_epoch = 0; +} + diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index ddcf8cc6aa..8bd308d5ba 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -110,6 +110,7 @@ int connection_edge_compatible_with_circuit(const edge_connection_t *conn, int connection_edge_update_circuit_isolation(const edge_connection_t *conn, origin_circuit_t *circ, int dry_run); +void circuit_clear_isolation(origin_circuit_t *circ); #endif diff --git a/src/or/or.h b/src/or/or.h index 9cf508c2de..97418f574a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2461,9 +2461,19 @@ typedef struct origin_circuit_t { /* XXXX NM This can get re-used after 2**32 circuits. */ uint32_t global_identifier; - /** True if we have attached at least one stream to this circuit, thereby - * setting the isolation paramaters for this circuit. */ + /** True if we have associated one stream to this circuit, thereby setting + * the isolation paramaters for this circuit. Note that this doesn't + * necessarily mean that we've <em>attached</em> any streams to the circuit: + * we may only have marked up this circuit during the launch process. + */ unsigned int isolation_values_set : 1; + /** True iff any stream has <em>ever</em> been attached to this circuit. + * + * In a better world we could use timestamp_dirty for this, but + * timestamp_dirty is far too overloaded at the moment. + */ + unsigned int isolation_any_streams_attached : 1; + /** A bitfield of ISO_* flags for every isolation field such that this * circuit has had streams with more than one value for that field * attached to it. */ @@ -2471,11 +2481,15 @@ typedef struct origin_circuit_t { /** @name Isolation parameters * - * If any streams have been attached to this circuit (isolation_values_set - * == 1), and all streams attached to the circuit have had the same value - * for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these + * If any streams have been associated with this circ (isolation_values_set + * == 1), and all streams associated with the circuit have had the same + * value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these * elements hold the value for that field. * + * Note again that "associated" is not the same as "attached": we + * preliminarily associate streams with a circuit while the circuit is being + * launched, so that we can tell whether we need to launch more circuits. + * * @{ */ uint8_t client_proto_type; |