From 5227395aba9928a5505117f632e1ea7271944d8a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 27 Jul 2006 05:03:57 +0000 Subject: [PATCH] r6922@Kushana: nickm | 2006-07-26 16:32:24 -0400 Rename some fields, compress a bitfield, and document some structs and fields svn:r6919 --- src/or/circuitlist.c | 18 +++---- src/or/circuituse.c | 10 ++-- src/or/connection.c | 6 +-- src/or/connection_edge.c | 2 +- src/or/main.c | 60 +++++++++++----------- src/or/or.h | 104 ++++++++++++++++++++++++--------------- src/or/relay.c | 17 ++++--- 7 files changed, 122 insertions(+), 95 deletions(-) diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 90929d0051..a74ed97a4b 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -420,12 +420,12 @@ circuit_free_cpath_node(crypt_path_t *victim) * of information about circuit circ. */ static void -circuit_dump_details(int severity, circuit_t *circ, int poll_index, +circuit_dump_details(int severity, circuit_t *circ, int conn_array_index, const char *type, int this_circid, int other_circid) { log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " "state %d (%s), born %d:", - poll_index, type, this_circid, other_circid, circ->state, + conn_array_index, type, this_circid, other_circid, circ->state, circuit_state_to_string(circ->state), (int)circ->timestamp_created); if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); @@ -451,26 +451,26 @@ circuit_dump_by_conn(connection_t *conn, int severity) if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn && TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn) - circuit_dump_details(severity, circ, conn->poll_index, "App-ward", + circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward", p_circ_id, n_circ_id); if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { - circuit_dump_details(severity, circ, conn->poll_index, "App-ward", - p_circ_id, n_circ_id); + circuit_dump_details(severity, circ, conn->conn_array_index, + "App-ward", p_circ_id, n_circ_id); } } } if (circ->n_conn && TO_CONN(circ->n_conn) == conn) - circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", + circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward", n_circ_id, p_circ_id); if (! CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { - circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", - n_circ_id, p_circ_id); + circuit_dump_details(severity, circ, conn->conn_array_index, + "Exit-ward", n_circ_id, p_circ_id); } } } @@ -480,7 +480,7 @@ circuit_dump_by_conn(connection_t *conn, int severity) conn->type == CONN_TYPE_OR && !memcmp(TO_OR_CONN(conn)->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) { - circuit_dump_details(severity, circ, conn->poll_index, + circuit_dump_details(severity, circ, conn->conn_array_index, (circ->state == CIRCUIT_STATE_OPEN && !CIRCUIT_IS_ORIGIN(circ)) ? "Endpoint" : "Pending", diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 2d5188c874..ba819de4d3 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -982,13 +982,13 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (conn->chosen_exit_name) { routerinfo_t *r; - int opt = conn->chosen_exit_optional; + int opt = conn->_base.chosen_exit_optional; if (!(r = router_get_by_nickname(conn->chosen_exit_name, 1))) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is not known. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { - conn->chosen_exit_optional = 0; + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); return 0; } @@ -1173,13 +1173,13 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn) if (conn->chosen_exit_name) { routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1); - int opt = conn->chosen_exit_optional; + int opt = conn->_base.chosen_exit_optional; if (!router) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is not known. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { - conn->chosen_exit_optional = 0; + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); return 0; } @@ -1190,7 +1190,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn) "Requested exit point '%s' would refuse request. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { - conn->chosen_exit_optional = 0; + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); return 0; } diff --git a/src/or/connection.c b/src/or/connection.c index 48ceb2623d..ecf838830e 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -145,7 +145,7 @@ conn_state_to_string(int type, int state) /** Allocate space for a new connection_t. This function just initializes * conn; you must call connection_add() to link it into the main array. * - * Set conn-\>type to type. Set conn-\>s and conn-\>poll_index to + * Set conn-\>type to type. Set conn-\>s and conn-\>conn_array_index to * -1 to signify they are not yet assigned. * * If conn is not a listener type, allocate buffers for it. If it's @@ -191,7 +191,7 @@ connection_new(int type) conn = tor_malloc_zero(length); conn->magic = magic; conn->s = -1; /* give it a default of 'not used' */ - conn->poll_index = -1; /* also default to 'not used' */ + conn->conn_array_index = -1; /* also default to 'not used' */ conn->global_identifier = n_connections_allocated++; conn->type = type; @@ -2182,7 +2182,7 @@ assert_connection_ok(connection_t *conn, time_t now) if (conn->hold_open_until_flushed) tor_assert(conn->marked_for_close); - /* XXX check: wants_to_read, wants_to_write, s, poll_index, + /* XXX check: wants_to_read, wants_to_write, s, conn_array_index, * marked_for_close. */ /* buffers */ diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 127783dbeb..7839a91de2 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1139,7 +1139,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, routers with this nickname */ conn->chosen_exit_name = tor_strdup(hex_str(r->cache_info.identity_digest, DIGEST_LEN)); - conn->chosen_exit_optional = 1; + conn->_base.chosen_exit_optional = 1; } } diff --git a/src/or/main.c b/src/or/main.c index 6d0ab93c7c..4ef3260e8b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -50,13 +50,12 @@ static time_t time_to_fetch_directory = 0; /** When do we next download a running-routers summary? */ static time_t time_to_fetch_running_routers = 0; -/** Array of all open connections; each element corresponds to the element of - * poll_array in the same position. The first nfds elements are valid. */ +/** Array of all open connections. The first n_conns elements are valid. */ static connection_t *connection_array[MAXCONNECTIONS+1] = { NULL }; static smartlist_t *closeable_connection_lst = NULL; -static int nfds=0; /**< Number of connections currently active. */ +static int n_conns=0; /**< Number of connections currently active. */ /** We set this to 1 when we've opened a circuit, so we can print a log * entry to inform the user that Tor is working. */ @@ -121,8 +120,7 @@ static char* nt_strerror(uint32_t errnum); /**************************************************************************** * * This section contains accessors and other methods on the connection_array -* and poll_array variables (which are global within this file and unavailable -* outside it). +* variables (which are global within this file and unavailable outside it). * ****************************************************************************/ @@ -136,15 +134,15 @@ connection_add(connection_t *conn) tor_assert(conn); tor_assert(conn->s >= 0); - if (nfds >= get_options()->_ConnLimit-1) { + if (n_conns >= get_options()->_ConnLimit-1) { log_warn(LD_NET,"Failing because we have %d connections already. Please " - "raise your ulimit -n.", nfds); + "raise your ulimit -n.", n_conns); return -1; } - tor_assert(conn->poll_index == -1); /* can only connection_add once */ - conn->poll_index = nfds; - connection_array[nfds] = conn; + tor_assert(conn->conn_array_index == -1); /* can only connection_add once */ + conn->conn_array_index = n_conns; + connection_array[n_conns] = conn; conn->read_event = tor_malloc_zero(sizeof(struct event)); conn->write_event = tor_malloc_zero(sizeof(struct event)); @@ -153,10 +151,10 @@ connection_add(connection_t *conn) event_set(conn->write_event, conn->s, EV_WRITE|EV_PERSIST, conn_write_callback, conn); - nfds++; + n_conns++; - log_debug(LD_NET,"new conn type %s, socket %d, nfds %d.", - conn_type_to_string(conn->type), conn->s, nfds); + log_debug(LD_NET,"new conn type %s, socket %d, n_conns %d.", + conn_type_to_string(conn->type), conn->s, n_conns); return 0; } @@ -171,24 +169,24 @@ connection_remove(connection_t *conn) int current_index; tor_assert(conn); - tor_assert(nfds>0); + tor_assert(n_conns>0); - log_debug(LD_NET,"removing socket %d (type %s), nfds now %d", - conn->s, conn_type_to_string(conn->type), nfds-1); + log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d", + conn->s, conn_type_to_string(conn->type), n_conns-1); - tor_assert(conn->poll_index >= 0); - current_index = conn->poll_index; - if (current_index == nfds-1) { /* this is the end */ - nfds--; + tor_assert(conn->conn_array_index >= 0); + current_index = conn->conn_array_index; + if (current_index == n_conns-1) { /* this is the end */ + n_conns--; return 0; } connection_unregister(conn); /* replace this one with the one at the end */ - nfds--; - connection_array[current_index] = connection_array[nfds]; - connection_array[current_index]->poll_index = current_index; + n_conns--; + connection_array[current_index] = connection_array[n_conns]; + connection_array[current_index]->conn_array_index = current_index; return 0; } @@ -243,7 +241,7 @@ int connection_in_array(connection_t *conn) { int i; - for (i=0; iconn to events. (The event @@ -382,10 +380,10 @@ close_closeable_connections(void) int i; for (i = 0; i < smartlist_len(closeable_connection_lst); ) { connection_t *conn = smartlist_get(closeable_connection_lst, i); - if (conn->poll_index < 0) { + if (conn->conn_array_index < 0) { connection_unlink(conn, 0); /* blow it away right now */ } else { - if (!conn_close_if_marked(conn->poll_index)) + if (!conn_close_if_marked(conn->conn_array_index)) ++i; } } @@ -893,11 +891,11 @@ run_scheduled_events(time_t now) circuit_build_needed_circs(now); /** 5. We do housekeeping for each connection... */ - for (i=0;ioutbuf) buf_shrink(conn->outbuf); @@ -1306,7 +1304,7 @@ dumpmemusage(int severity) log(severity, LD_GENERAL, "In buffers: "U64_FORMAT" used/"U64_FORMAT" allocated (%d conns).", U64_PRINTF_ARG(buf_total_used), U64_PRINTF_ARG(buf_total_alloc), - nfds); + n_conns); log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num); dump_routerlist_mem_usage(severity); @@ -1324,7 +1322,7 @@ dumpstats(int severity) log(severity, LD_GENERAL, "Dumping stats:"); - for (i=0;ioutbuf. Connections differ primarily in the functions called * to fill and drain these buffers. */ -struct connection_t { - uint32_t magic; /**< For memory debugging: must equal CONNECTION_MAGIC. */ +typedef struct connection_t { + uint32_t magic; /**< For memory debugging: must equal one of + * *_CONNECTION_MAGIC. */ uint8_t type; /**< What kind of connection is this? */ uint8_t state; /**< Current state of this connection. */ @@ -622,9 +623,12 @@ struct connection_t { unsigned int control_events_are_extended:1; /** Used for OR conns that shouldn't get any new circs attached to them. */ unsigned int or_is_obsolete:1; + /** For AP connections only. If 1, and we fail to reach the chosen exit, + * stop requiring it. */ + unsigned int chosen_exit_optional:1; int s; /**< Our socket; -1 if this connection is closed. */ - int poll_index; /* XXXX rename. */ + int conn_array_index; /**< Index into the global connection array. */ struct event *read_event; /**< Libevent event structure. */ struct event *write_event; /**< Libevent event structure. */ buf_t *inbuf; /**< Buffer holding data read over this connection. */ @@ -657,12 +661,10 @@ struct connection_t { /** Quasi-global identifier for this connection; used for control.c */ /* XXXX NM This can get re-used after 2**32 circuits. */ uint32_t global_identifier; +} connection_t; -}; - -typedef struct connection_t connection_t; - -/** DOCDOC */ +/** Subtype of connection_t for an "OR connection" -- that is, one that speaks + * cells over TLS. */ typedef struct or_connection_t { connection_t _base; @@ -670,7 +672,7 @@ typedef struct or_connection_t { * the other side's signing key. */ char *nickname; /**< Nickname of OR on other side (if any). */ - tor_tls_t *tls; /**< TLS connection state (OR only.) */ + tor_tls_t *tls; /**< TLS connection state */ /* bandwidth* and receiver_bucket only used by ORs in OPEN state: */ int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */ @@ -687,21 +689,21 @@ typedef struct or_connection_t { * identity digest as this one. */ uint16_t next_circ_id; /**< Which circ_id do we try to use next on * this connection? This is always in the - * range 0..1<<15-1. (OR only.)*/ + * range 0..1<<15-1. */ } or_connection_t; +/** Subtype of connection_t for an "edge connection" -- that is, a socks (ap) + * connection, or an exit. */ typedef struct edge_connection_t { connection_t _base; - uint16_t stream_id; struct edge_connection_t *next_stream; /**< Points to the next stream at this - * edge, if any (Edge only). */ + * edge, if any */ struct crypt_path_t *cpath_layer; /**< A pointer to which node in the circ - * this conn exits at. (Edge only.) */ - int package_window; /**< How many more relay cells can i send into the - * circuit? (Edge only.) */ - int deliver_window; /**< How many more relay cells can end at me? (Edge - * only.) */ + * this conn exits at. */ + int package_window; /**< How many more relay cells can I send into the + * circuit? */ + int deliver_window; /**< How many more relay cells can end at me? */ /** Number of times we've reassigned this application connection to * a new circuit. We keep track because the timeout is longer if we've @@ -710,32 +712,34 @@ typedef struct edge_connection_t { /** Nickname of planned exit node -- used with .exit support. */ char *chosen_exit_name; - /** If 1, and we fail to reach the chosen exit, stop requiring it. */ - unsigned int chosen_exit_optional:1; -/* Used only by AP connections */ socks_request_t *socks_request; /**< SOCKS structure describing request (AP * only.) */ - struct circuit_t *on_circuit; /**< The circuit (if any) that this edge * connection is using. */ uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit * connection. Exit connections only. */ -/* Used only by DIR and AP connections: */ + uint16_t stream_id; /**< The stream ID used for this edge connection on its + * circuit */ + char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we - * querying for? (DIR/AP only) */ + * querying for? (AP only) */ } edge_connection_t; +/** Subtype of connection_t for an "directory connection" -- that is, an HTTP + * connection to retrieve or serve directory material. */ typedef struct dir_connection_t { connection_t _base; -/* Used only by Dir connections */ char *requested_resource; /**< Which 'resource' did we ask the directory * for? */ unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ -/* Used only for server sides of some dir connections. */ + + /* Used only for server sides of some dir connections, to implement + * "spooling" of directory material to the outbuf. Otherwise, we'd have + * to append everything to the outbuf in one enormous chunk. */ enum { DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP, DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS @@ -745,19 +749,19 @@ typedef struct dir_connection_t { off_t cached_dir_offset; tor_zlib_state_t *zlib_state; -/* Used only by DIR and AP connections: */ char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we - * querying for? (DIR/AP only) */ + * querying for? */ char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for * the directory server's signing key. */ } dir_connection_t; +/** Subtype of connection_t for an connection to a controller. */ typedef struct control_connection_t { connection_t _base; - /* Used only by control connections */ - uint32_t event_mask; + uint32_t event_mask; /**< Bitfield: which events does this controller + * care about? */ uint32_t incoming_cmd_len; uint32_t incoming_cmd_cur_len; char *incoming_cmd; @@ -765,13 +769,23 @@ typedef struct control_connection_t { uint16_t incoming_cmd_type; } control_connection_t; +/** Cast a connection_t subtype pointer to a connection_t **/ #define TO_CONN(c) &(((c)->_base)) +/** Helper macro: Given a pointer to to._base, of type from*, return &to. */ #define DOWNCAST(from, to, ptr) \ (to*) (((from*)(ptr)) - STRUCT_OFFSET(to, _base)) +/** Convert a connection_t* to an or_connection_t*; assert if the cast is + * invalid. */ or_connection_t *TO_OR_CONN(connection_t *); +/** Convert a connection_t* to a dir_connection_t*; assert if the cast is + * invalid. */ dir_connection_t *TO_DIR_CONN(connection_t *); +/** Convert a connection_t* to an edge_connection_t*; assert if the cast is + * invalid. */ edge_connection_t *TO_EDGE_CONN(connection_t *); +/** Convert a connection_t* to an control_connection_t*; assert if the cast is + * invalid. */ control_connection_t *TO_CONTROL_CONN(connection_t *); extern INLINE or_connection_t *TO_OR_CONN(connection_t *c) @@ -1115,13 +1129,14 @@ typedef uint16_t circid_t; * OR connections multiplex many circuits at once, and stay standing even * when there are no circuits running over them. * - * A circuit_t structure fills two roles. First, a circuit_t links two - * connections together: either an edge connection and an OR connection, - * or two OR connections. (When joined to an OR connection, a circuit_t - * affects only cells sent to a particular circID on that connection. When - * joined to an edge connection, a circuit_t affects all data.) + * A circuit_t structure cann fill one of two roles. First, a or_circuit_t + * links two connections together: either an edge connection and an OR + * connection, or two OR connections. (When joined to an OR connection, a + * circuit_t affects only cells sent to a particular circID on that + * connection. When joined to an edge connection, a circuit_t affects all + * data.) - * Second, a circuit_t holds the cipher keys and state for sending data + * Second, an origin_circuit_t holds the cipher keys and state for sending data * along a given circuit. At the OP, it has a sequence of ciphers, each * of which is shared with a single OR along the circuit. Separate * ciphers are used for data going "forward" (away from the OP) and @@ -1178,6 +1193,8 @@ typedef struct circuit_t { struct circuit_t *next; /**< Next circuit in linked list. */ } circuit_t; +/** An origin_circuit_t holds data necessary to build and use a circuit. + */ typedef struct origin_circuit_t { circuit_t _base; @@ -1219,6 +1236,8 @@ typedef struct origin_circuit_t { } origin_circuit_t; +/** An or_circuit_t holds information needed to implement a circuit at an + * OR. */ typedef struct or_circuit_t { circuit_t _base; @@ -1258,23 +1277,30 @@ typedef struct or_circuit_t { #endif /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a - * rendezvous cookie if purpose is REND_POINT_WAITING or - * C_ESTABLISH_REND. Filled with zeroes otherwise. + * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes + * otherwise. */ char rend_token[REND_TOKEN_LEN]; char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */ } or_circuit_t; +/** Convert a circuit subtype to a circuit_t.*/ #define TO_CIRCUIT(x) (&((x)->_base)) -or_circuit_t *TO_OR_CIRCUIT(circuit_t *x); + +/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Asserts + * if the cast is impossible. */ +or_circuit_t *TO_OR_CIRCUIT(circuit_t *); +/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. + * Asserts if the cast is impossible. */ +origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); + extern INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x) { tor_assert(x->magic == OR_CIRCUIT_MAGIC); //return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base)); return DOWNCAST(circuit_t, or_circuit_t, x); } -origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x); extern INLINE origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x) { tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); diff --git a/src/or/relay.c b/src/or/relay.c index 094697361f..f7eee2917b 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -717,8 +717,9 @@ connection_edge_process_end_not_open( /* rewrite it to an IP if we learned one. */ addressmap_rewrite(conn->socks_request->address, sizeof(conn->socks_request->address)); - if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ - conn->chosen_exit_optional = 0; + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); } if (connection_ap_detach_retriable(conn, circ) >= 0) @@ -726,7 +727,7 @@ connection_edge_process_end_not_open( /* else, conn will get closed below */ break; case END_STREAM_REASON_CONNECTREFUSED: - if (!conn->chosen_exit_optional) + if (!conn->_base.chosen_exit_optional) break; /* break means it'll close, below */ /* Else fall through: expire this circuit, clear the * chosen_exit_name field, and try again. */ @@ -740,8 +741,9 @@ connection_edge_process_end_not_open( tor_assert(circ->_base.timestamp_dirty); circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; - if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ - conn->chosen_exit_optional = 0; + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); } if (connection_ap_detach_retriable(conn, circ) >= 0) @@ -764,8 +766,9 @@ connection_edge_process_end_not_open( exitrouter->exit_policy = router_parse_addr_policy_from_string("reject *:*", -1); } - if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ - conn->chosen_exit_optional = 0; + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); } if (connection_ap_detach_retriable(conn, circ) >= 0)