From 519c971f6a3b89f1e81cda3c0290d4d943ec0d78 Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Thu, 23 Aug 2012 19:30:49 -0700 Subject: Use channel_t in cmd.c --- src/or/command.c | 1046 ++++++------------------------------------------------ 1 file changed, 101 insertions(+), 945 deletions(-) (limited to 'src/or/command.c') diff --git a/src/or/command.c b/src/or/command.c index a5ae2399f0..c7a1b1ac07 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -12,10 +12,13 @@ /* In-points to command.c: * * - command_process_cell(), called from - * connection_or_process_cells_from_inbuf() in connection_or.c + * incoming cell handlers of channel_t instances; + * callbacks registered in command_setup_channel(), + * called when channels are created in circuitbuild.c */ #include "or.h" +#include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" #include "command.h" @@ -31,8 +34,6 @@ #include "router.h" #include "routerlist.h" -/** How many CELL_PADDING cells have we received, ever? */ -uint64_t stats_n_padding_cells_processed = 0; /** How many CELL_CREATE cells have we received, ever? */ uint64_t stats_n_create_cells_processed = 0; /** How many CELL_CREATED cells have we received, ever? */ @@ -41,38 +42,16 @@ uint64_t stats_n_created_cells_processed = 0; uint64_t stats_n_relay_cells_processed = 0; /** How many CELL_DESTROY cells have we received, ever? */ uint64_t stats_n_destroy_cells_processed = 0; -/** How many CELL_VERSIONS cells have we received, ever? */ -uint64_t stats_n_versions_cells_processed = 0; -/** How many CELL_NETINFO cells have we received, ever? */ -uint64_t stats_n_netinfo_cells_processed = 0; -/** How many CELL_VPADDING cells have we received, ever? */ -uint64_t stats_n_vpadding_cells_processed = 0; -/** How many CELL_CERTS cells have we received, ever? */ -uint64_t stats_n_certs_cells_processed = 0; -/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */ -uint64_t stats_n_auth_challenge_cells_processed = 0; -/** How many CELL_AUTHENTICATE cells have we received, ever? */ -uint64_t stats_n_authenticate_cells_processed = 0; -/** How many CELL_AUTHORIZE cells have we received, ever? */ -uint64_t stats_n_authorize_cells_processed = 0; +/* Handle an incoming channel */ +static void command_handle_incoming_channel(channel_t *listener, + channel_t *chan); /* These are the main functions for processing cells */ -static void command_process_create_cell(cell_t *cell, or_connection_t *conn); -static void command_process_created_cell(cell_t *cell, or_connection_t *conn); -static void command_process_relay_cell(cell_t *cell, or_connection_t *conn); -static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn); -static void command_process_versions_cell(var_cell_t *cell, - or_connection_t *conn); -static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn); -static void command_process_certs_cell(var_cell_t *cell, - or_connection_t *conn); -static void command_process_auth_challenge_cell(var_cell_t *cell, - or_connection_t *conn); -static void command_process_authenticate_cell(var_cell_t *cell, - or_connection_t *conn); -static int enter_v3_handshake_with_cell(var_cell_t *cell, - or_connection_t *conn); +static void command_process_create_cell(cell_t *cell, channel_t *chan); +static void command_process_created_cell(cell_t *cell, channel_t *chan); +static void command_process_relay_cell(cell_t *cell, channel_t *chan); +static void command_process_destroy_cell(cell_t *cell, channel_t *chan); #ifdef KEEP_TIMING_STATS /** This is a wrapper function around the actual function that processes the @@ -80,15 +59,15 @@ static int enter_v3_handshake_with_cell(var_cell_t *cell, * by the number of microseconds used by the call to *func(cell, conn). */ static void -command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time, - void (*func)(cell_t *, or_connection_t *)) +command_time_process_cell(cell_t *cell, channel_t *chan, int *time, + void (*func)(cell_t *, channel_t *)) { struct timeval start, end; long time_passed; tor_gettimeofday(&start); - (*func)(cell, conn); + (*func)(cell, chan); tor_gettimeofday(&end); time_passed = tv_udiff(&start, &end) ; @@ -104,15 +83,14 @@ command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time, } #endif -/** Process a cell that was just received on conn. Keep internal +/** Process a cell that was just received on chan. Keep internal * statistics about how many of each cell we've processed so far * this second, and the total number of microseconds it took to * process each type of cell. */ void -command_process_cell(cell_t *cell, or_connection_t *conn) +command_process_cell(channel_t *chan, cell_t *cell) { - int handshaking = (conn->_base.state != OR_CONN_STATE_OPEN); #ifdef KEEP_TIMING_STATS /* how many of each cell have we seen so far this second? needs better * name. */ @@ -152,255 +130,114 @@ command_process_cell(cell_t *cell, or_connection_t *conn) #define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn) #endif - if (conn->_base.marked_for_close) - return; - - /* Reject all but VERSIONS and NETINFO when handshaking. */ - /* (VERSIONS should actually be impossible; it's variable-length.) */ - if (handshaking && cell->command != CELL_VERSIONS && - cell->command != CELL_NETINFO) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received unexpected cell command %d in state %s; closing the " - "connection.", - (int)cell->command, - conn_state_to_string(CONN_TYPE_OR,conn->_base.state)); - connection_mark_for_close(TO_CONN(conn)); - return; - } - - if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) - or_handshake_state_record_cell(conn->handshake_state, cell, 1); - switch (cell->command) { - case CELL_PADDING: - ++stats_n_padding_cells_processed; - /* do nothing */ - break; case CELL_CREATE: case CELL_CREATE_FAST: ++stats_n_create_cells_processed; - PROCESS_CELL(create, cell, conn); + PROCESS_CELL(create, cell, chan); break; case CELL_CREATED: case CELL_CREATED_FAST: ++stats_n_created_cells_processed; - PROCESS_CELL(created, cell, conn); + PROCESS_CELL(created, cell, chan); break; case CELL_RELAY: case CELL_RELAY_EARLY: ++stats_n_relay_cells_processed; - PROCESS_CELL(relay, cell, conn); + PROCESS_CELL(relay, cell, chan); break; case CELL_DESTROY: ++stats_n_destroy_cells_processed; - PROCESS_CELL(destroy, cell, conn); - break; - case CELL_VERSIONS: - tor_fragile_assert(); - break; - case CELL_NETINFO: - ++stats_n_netinfo_cells_processed; - PROCESS_CELL(netinfo, cell, conn); + PROCESS_CELL(destroy, cell, chan); break; default: log_fn(LOG_INFO, LD_PROTOCOL, - "Cell of unknown type (%d) received. Dropping.", cell->command); + "Cell of unknown or unexpected type (%d) received. " + "Dropping.", + cell->command); break; } } -/** Return true if command is a cell command that's allowed to start a - * V3 handshake. */ -static int -command_allowed_before_handshake(uint8_t command) -{ - switch (command) { - case CELL_VERSIONS: - case CELL_VPADDING: - case CELL_AUTHORIZE: - return 1; - default: - return 0; - } -} - -/** Process a cell that was just received on conn. Keep internal - * statistics about how many of each cell we've processed so far - * this second, and the total number of microseconds it took to - * process each type of cell. +/** Process an incoming var_cell from a channel; in the current protocol all + * the var_cells are handshake-related and handles below the channel layer, + * so this just logs a warning and drops the cell. */ + void -command_process_var_cell(var_cell_t *cell, or_connection_t *conn) +command_process_var_cell(channel_t *chan, var_cell_t *var_cell) { -#ifdef KEEP_TIMING_STATS - /* how many of each cell have we seen so far this second? needs better - * name. */ - static int num_versions=0, num_certs=0; - - time_t now = time(NULL); - - if (now > current_second) { /* the second has rolled over */ - /* print stats */ - log_info(LD_OR, - "At end of second: %d versions (%d ms), %d certs (%d ms)", - num_versions, versions_time/1000, - num_certs, certs_time/1000); - - num_versions = num_certs = 0; - versions_time = certs_time = 0; + tor_assert(chan); + tor_assert(var_cell); - /* remember which second it is, for next time */ - current_second = now; - } -#endif - - if (conn->_base.marked_for_close) - return; - - switch (conn->_base.state) - { - case OR_CONN_STATE_OR_HANDSHAKING_V2: - if (cell->command != CELL_VERSIONS) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received a cell with command %d in state %s; " - "closing the connection.", - (int)cell->command, - conn_state_to_string(CONN_TYPE_OR,conn->_base.state)); - connection_mark_for_close(TO_CONN(conn)); - return; - } - break; - case OR_CONN_STATE_TLS_HANDSHAKING: - /* If we're using bufferevents, it's entirely possible for us to - * notice "hey, data arrived!" before we notice "hey, the handshake - * finished!" And we need to be accepting both at once to handle both - * the v2 and v3 handshakes. */ - - /* fall through */ - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: - if (! command_allowed_before_handshake(cell->command)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received a cell with command %d in state %s; " - "closing the connection.", - (int)cell->command, - conn_state_to_string(CONN_TYPE_OR,conn->_base.state)); - connection_mark_for_close(TO_CONN(conn)); - return; - } else { - if (enter_v3_handshake_with_cell(cell, conn)<0) - return; - } - break; - case OR_CONN_STATE_OR_HANDSHAKING_V3: - if (cell->command != CELL_AUTHENTICATE) - or_handshake_state_record_var_cell(conn->handshake_state, cell, 1); - break; /* Everything is allowed */ - case OR_CONN_STATE_OPEN: - if (conn->link_proto < 3) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received a variable-length cell with command %d in state %s " - "with link protocol %d; ignoring it.", - (int)cell->command, - conn_state_to_string(CONN_TYPE_OR,conn->_base.state), - (int)conn->link_proto); - return; - } - break; - default: - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received var-length cell with command %d in unexpected state " - "%s [%d]; ignoring it.", - (int)cell->command, - conn_state_to_string(CONN_TYPE_OR,conn->_base.state), - (int)conn->_base.state); - return; - } - - switch (cell->command) { - case CELL_VERSIONS: - ++stats_n_versions_cells_processed; - PROCESS_CELL(versions, cell, conn); - break; - case CELL_VPADDING: - ++stats_n_vpadding_cells_processed; - /* Do nothing */ - break; - case CELL_CERTS: - ++stats_n_certs_cells_processed; - PROCESS_CELL(certs, cell, conn); - break; - case CELL_AUTH_CHALLENGE: - ++stats_n_auth_challenge_cells_processed; - PROCESS_CELL(auth_challenge, cell, conn); - break; - case CELL_AUTHENTICATE: - ++stats_n_authenticate_cells_processed; - PROCESS_CELL(authenticate, cell, conn); - break; - case CELL_AUTHORIZE: - ++stats_n_authorize_cells_processed; - /* Ignored so far. */ - break; - default: - log_fn(LOG_INFO, LD_PROTOCOL, - "Variable-length cell of unknown type (%d) received.", - cell->command); - break; - } + log_info(LD_PROTOCOL, + "Received unexpected var_cell above the channel layer of type %d" + "; dropping it.", + var_cell->command); } -/** Process a 'create' cell that just arrived from conn. Make a +/** Process a 'create' cell that just arrived from chan. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void -command_process_create_cell(cell_t *cell, or_connection_t *conn) +command_process_create_cell(cell_t *cell, channel_t *chan) { or_circuit_t *circ; const or_options_t *options = get_options(); int id_is_high; + tor_assert(cell); + tor_assert(chan); + tor_assert(!(chan->is_listener)); + + log_debug(LD_OR, + "Got a CREATE cell for circ_id %d on channel %lu (%p)", + cell->circ_id, chan->global_identifier, chan); + if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); - connection_or_send_destroy(cell->circ_id, conn, + channel_send_destroy(cell->circ_id, chan, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(options) || - (!public_server_mode(options) && conn->is_outgoing)) { + (!public_server_mode(options) && channel_is_outgoing(chan))) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received create cell (type %d) from %s:%d, but we're connected " + "Received create cell (type %d) from %s, but we're connected " "to it as a client. " "Sending back a destroy.", - (int)cell->command, conn->_base.address, conn->_base.port); - connection_or_send_destroy(cell->circ_id, conn, - END_CIRC_REASON_TORPROTOCOL); + (int)cell->command, channel_get_canonical_remote_descr(chan)); + channel_send_destroy(cell->circ_id, chan, + END_CIRC_REASON_TORPROTOCOL); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ id_is_high = cell->circ_id & (1<<15); - if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) || - (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) { + if ((id_is_high && + chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_HIGHER) || + (!id_is_high && + chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); - connection_or_send_destroy(cell->circ_id, conn, - END_CIRC_REASON_TORPROTOCOL); + channel_send_destroy(cell->circ_id, chan, + END_CIRC_REASON_TORPROTOCOL); return; } - if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) { - const node_t *node = node_get_by_id(conn->identity_digest); + if (circuit_id_in_use_on_channel(cell->circ_id, chan)) { + const node_t *node = node_get_by_id(chan->u.cell_chan.identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", - cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created)); + cell->circ_id, (int)(time(NULL) - channel_when_created(chan))); if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, @@ -411,7 +248,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) return; } - circ = or_circuit_new(cell->circ_id, conn); + circ = or_circuit_new(cell->circ_id, chan); circ->_base.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { @@ -442,7 +279,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) /* Make sure we never try to use the OR connection on which we * received this cell to satisfy an EXTEND request, */ - conn->is_connection_with_client = 1; + channel_mark_client(chan); if (fast_server_handshake(cell->payload, (uint8_t*)reply, (uint8_t*)keys, sizeof(keys))<0) { @@ -458,7 +295,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) } } -/** Process a 'created' cell that just arrived from conn. +/** Process a 'created' cell that just arrived from chan. * Find the circuit * that it's intended for. If we're not the origin of the circuit, package * the 'created' cell in an 'extended' relay cell and pass it back. If we @@ -467,11 +304,11 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) * extend to the next hop in the circuit if necessary. */ static void -command_process_created_cell(cell_t *cell, or_connection_t *conn) +command_process_created_cell(cell_t *cell, channel_t *chan) { circuit_t *circ; - circ = circuit_get_by_circid_orconn(cell->circ_id, conn); + circ = circuit_get_by_circid_channel(cell->circ_id, chan); if (!circ) { log_info(LD_OR, @@ -518,17 +355,17 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn) * circuit_receive_relay_cell() for actual processing. */ static void -command_process_relay_cell(cell_t *cell, or_connection_t *conn) +command_process_relay_cell(cell_t *cell, channel_t *chan) { circuit_t *circ; int reason, direction; - circ = circuit_get_by_circid_orconn(cell->circ_id, conn); + circ = circuit_get_by_circid_channel(cell->circ_id, chan); if (!circ) { log_debug(LD_OR, - "unknown circuit %d on connection from %s:%d. Dropping.", - cell->circ_id, conn->_base.address, conn->_base.port); + "unknown circuit %d on connection from %s. Dropping.", + cell->circ_id, channel_get_canonical_remote_descr(chan)); return; } @@ -541,7 +378,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn) if (CIRCUIT_IS_ORIGIN(circ)) { /* if we're a relay and treating connections with recent local * traffic better, then this is one of them. */ - conn->client_used = time(NULL); + channel_timestamp_client(chan); } if (!CIRCUIT_IS_ORIGIN(circ) && @@ -562,10 +399,10 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn) or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->remaining_relay_early_cells == 0) { log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received too many RELAY_EARLY cells on circ %d from %s:%d." + "Received too many RELAY_EARLY cells on circ %d from %s." " Closing circuit.", - cell->circ_id, safe_str(conn->_base.address), - conn->_base.port); + cell->circ_id, + safe_str(channel_get_canonical_remote_descr(chan))); circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); return; } @@ -582,7 +419,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn) } /** Process a 'destroy' cell that just arrived from - * conn. Find the circ that it refers to (if any). + * chan. Find the circ that it refers to (if any). * * If the circ is in state * onionskin_pending, then call onion_pending_remove() to remove it @@ -595,15 +432,15 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn) * and passes the destroy cell onward if necessary). */ static void -command_process_destroy_cell(cell_t *cell, or_connection_t *conn) +command_process_destroy_cell(cell_t *cell, channel_t *chan) { circuit_t *circ; int reason; - circ = circuit_get_by_circid_orconn(cell->circ_id, conn); + circ = circuit_get_by_circid_channel(cell->circ_id, chan); if (!circ) { - log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.", - cell->circ_id, conn->_base.address, conn->_base.port); + log_info(LD_OR,"unknown circuit %d on connection from %s. Dropping.", + cell->circ_id, channel_get_canonical_remote_descr(chan)); return; } log_debug(LD_OR,"Received for circID %d.",cell->circ_id); @@ -613,10 +450,10 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn) if (!CIRCUIT_IS_ORIGIN(circ) && cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) { /* the destroy came from behind */ - circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL); + circuit_set_p_circid_chan(TO_OR_CIRCUIT(circ), 0, NULL); circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); } else { /* the destroy came from ahead */ - circuit_set_n_circid_orconn(circ, 0, NULL); + circuit_set_n_circid_chan(circ, 0, NULL); if (CIRCUIT_IS_ORIGIN(circ)) { circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); } else { @@ -629,724 +466,43 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn) } } -/** Called when we as a server receive an appropriate cell while waiting - * either for a cell or a TLS handshake. Set the connection's state to - * "handshaking_v3', initializes the or_handshake_state field as needed, - * and add the cell to the hash of incoming cells.) - * - * Return 0 on success; return -1 and mark the connection on failure. +/** Callback to handle a new channel; call command_setup_channel() to give + * it the right cell handlers. */ -static int -enter_v3_handshake_with_cell(var_cell_t *cell, or_connection_t *conn) -{ - const int started_here = connection_or_nonopen_was_started_here(conn); - tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING || - conn->_base.state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); - - if (started_here) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received a cell while TLS-handshaking, not in " - "OR_HANDSHAKING_V3, on a connection we originated."); - } - conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3; - if (connection_init_or_handshake_state(conn, started_here) < 0) { - connection_mark_for_close(TO_CONN(conn)); - return -1; - } - or_handshake_state_record_var_cell(conn->handshake_state, cell, 1); - return 0; -} - -/** Process a 'versions' cell. The current link protocol version must be 0 - * to indicate that no version has yet been negotiated. We compare the - * versions in the cell to the list of versions we support, pick the - * highest version we have in common, and continue the negotiation from - * there. - */ static void -command_process_versions_cell(var_cell_t *cell, or_connection_t *conn) +command_handle_incoming_channel(channel_t *listener, channel_t *chan) { - int highest_supported_version = 0; - const uint8_t *cp, *end; - const int started_here = connection_or_nonopen_was_started_here(conn); - if (conn->link_proto != 0 || - (conn->handshake_state && conn->handshake_state->received_versions)) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received a VERSIONS cell on a connection with its version " - "already set to %d; dropping", (int) conn->link_proto); - return; - } - switch (conn->_base.state) - { - case OR_CONN_STATE_OR_HANDSHAKING_V2: - case OR_CONN_STATE_OR_HANDSHAKING_V3: - break; - case OR_CONN_STATE_TLS_HANDSHAKING: - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: - default: - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "VERSIONS cell while in unexpected state"); - return; - } - - tor_assert(conn->handshake_state); - end = cell->payload + cell->payload_len; - for (cp = cell->payload; cp+1 < end; ++cp) { - uint16_t v = ntohs(get_uint16(cp)); - if (is_or_protocol_version_known(v) && v > highest_supported_version) - highest_supported_version = v; - } - if (!highest_supported_version) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Couldn't find a version in common between my version list and the " - "list in the VERSIONS cell; closing connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } else if (highest_supported_version == 1) { - /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS - * cells. */ - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Used version negotiation protocol to negotiate a v1 connection. " - "That's crazily non-compliant. Closing connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } else if (highest_supported_version < 3 && - conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Negotiated link protocol 2 or lower after doing a v3 TLS " - "handshake. Closing connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } - - conn->link_proto = highest_supported_version; - conn->handshake_state->received_versions = 1; - - if (conn->link_proto == 2) { - log_info(LD_OR, "Negotiated version %d with %s:%d; sending NETINFO.", - highest_supported_version, - safe_str_client(conn->_base.address), - conn->_base.port); - - if (connection_or_send_netinfo(conn) < 0) { - connection_mark_for_close(TO_CONN(conn)); - return; - } - } else { - const int send_versions = !started_here; - /* If we want to authenticate, send a CERTS cell */ - const int send_certs = !started_here || public_server_mode(get_options()); - /* If we're a relay that got a connection, ask for authentication. */ - const int send_chall = !started_here && public_server_mode(get_options()); - /* If our certs cell will authenticate us, we can send a netinfo cell - * right now. */ - const int send_netinfo = !started_here; - const int send_any = - send_versions || send_certs || send_chall || send_netinfo; - tor_assert(conn->link_proto >= 3); - - log_info(LD_OR, "Negotiated version %d with %s:%d; %s%s%s%s%s", - highest_supported_version, - safe_str_client(conn->_base.address), - conn->_base.port, - send_any ? "Sending cells:" : "Waiting for CERTS cell", - send_versions ? " VERSIONS" : "", - send_certs ? " CERTS" : "", - send_chall ? " AUTH_CHALLENGE" : "", - send_netinfo ? " NETINFO" : ""); - -#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE - if (1) { - connection_mark_for_close(TO_CONN(conn)); - return; - } -#endif - - if (send_versions) { - if (connection_or_send_versions(conn, 1) < 0) { - log_warn(LD_OR, "Couldn't send versions cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } - if (send_certs) { - if (connection_or_send_certs_cell(conn) < 0) { - log_warn(LD_OR, "Couldn't send certs cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } - if (send_chall) { - if (connection_or_send_auth_challenge_cell(conn) < 0) { - log_warn(LD_OR, "Couldn't send auth_challenge cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } - if (send_netinfo) { - if (connection_or_send_netinfo(conn) < 0) { - log_warn(LD_OR, "Couldn't send netinfo cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } - } -} - -/** Process a 'netinfo' cell: read and act on its contents, and set the - * connection state to "open". */ -static void -command_process_netinfo_cell(cell_t *cell, or_connection_t *conn) -{ - time_t timestamp; - uint8_t my_addr_type; - uint8_t my_addr_len; - const uint8_t *my_addr_ptr; - const uint8_t *cp, *end; - uint8_t n_other_addrs; - time_t now = time(NULL); - - long apparent_skew = 0; - tor_addr_t my_apparent_addr = TOR_ADDR_NULL; + tor_assert(listener); + tor_assert(chan); - if (conn->link_proto < 2) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received a NETINFO cell on %s connection; dropping.", - conn->link_proto == 0 ? "non-versioned" : "a v1"); - return; - } - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && - conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Received a NETINFO cell on non-handshaking connection; dropping."); - return; - } - tor_assert(conn->handshake_state && - conn->handshake_state->received_versions); - - if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { - tor_assert(conn->link_proto >= 3); - if (conn->handshake_state->started_here) { - if (!conn->handshake_state->authenticated) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got a NETINFO cell from server, " - "but no authentication. Closing the connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } else { - /* we're the server. If the client never authenticated, we have - some housekeeping to do.*/ - if (!conn->handshake_state->authenticated) { - tor_assert(tor_digest_is_zero( - (const char*)conn->handshake_state->authenticated_peer_id)); - connection_or_set_circid_type(conn, NULL); - - connection_or_init_conn_from_address(conn, - &conn->_base.addr, - conn->_base.port, - (const char*)conn->handshake_state->authenticated_peer_id, - 0); - } - } - } - - /* Decode the cell. */ - timestamp = ntohl(get_uint32(cell->payload)); - if (labs(now - conn->handshake_state->sent_versions_at) < 180) { - apparent_skew = now - timestamp; - } - - my_addr_type = (uint8_t) cell->payload[4]; - my_addr_len = (uint8_t) cell->payload[5]; - my_addr_ptr = (uint8_t*) cell->payload + 6; - end = cell->payload + CELL_PAYLOAD_SIZE; - cp = cell->payload + 6 + my_addr_len; - if (cp >= end) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Addresses too long in netinfo cell; closing connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) { - tor_addr_from_ipv4n(&my_apparent_addr, get_uint32(my_addr_ptr)); - } else if (my_addr_type == RESOLVED_TYPE_IPV6 && my_addr_len == 16) { - tor_addr_from_ipv6_bytes(&my_apparent_addr, (const char *) my_addr_ptr); - } - - n_other_addrs = (uint8_t) *cp++; - while (n_other_addrs && cp < end-2) { - /* Consider all the other addresses; if any matches, this connection is - * "canonical." */ - tor_addr_t addr; - const uint8_t *next = - decode_address_from_payload(&addr, cp, (int)(end-cp)); - if (next == NULL) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Bad address in netinfo cell; closing connection."); - connection_mark_for_close(TO_CONN(conn)); - return; - } - if (tor_addr_eq(&addr, &conn->real_addr)) { - conn->is_canonical = 1; - break; - } - cp = next; - --n_other_addrs; - } - - /* Act on apparent skew. */ - /** Warn when we get a netinfo skew with at least this value. */ -#define NETINFO_NOTICE_SKEW 3600 - if (labs(apparent_skew) > NETINFO_NOTICE_SKEW && - router_get_by_id_digest(conn->identity_digest)) { - char dbuf[64]; - int severity; - /*XXXX be smarter about when everybody says we are skewed. */ - if (router_digest_is_trusted_dir(conn->identity_digest)) - severity = LOG_WARN; - else - severity = LOG_INFO; - format_time_interval(dbuf, sizeof(dbuf), apparent_skew); - log_fn(severity, LD_GENERAL, "Received NETINFO cell with skewed time from " - "server at %s:%d. It seems that our clock is %s by %s, or " - "that theirs is %s. Tor requires an accurate clock to work: " - "please check your time and date settings.", - conn->_base.address, (int)conn->_base.port, - apparent_skew>0 ? "ahead" : "behind", dbuf, - apparent_skew>0 ? "behind" : "ahead"); - if (severity == LOG_WARN) /* only tell the controller if an authority */ - control_event_general_status(LOG_WARN, - "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d", - apparent_skew, - conn->_base.address, conn->_base.port); - } - - /* XXX maybe act on my_apparent_addr, if the source is sufficiently - * trustworthy. */ - - if (connection_or_set_state_open(conn)<0) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but " - "was unable to make the OR connection become open.", - safe_str_client(conn->_base.address), - conn->_base.port); - connection_mark_for_close(TO_CONN(conn)); - } else { - log_info(LD_OR, "Got good NETINFO cell from %s:%d; OR connection is now " - "open, using protocol version %d. Its ID digest is %s. " - "Our address is apparently %s.", - safe_str_client(conn->_base.address), - conn->_base.port, (int)conn->link_proto, - hex_str(conn->identity_digest, DIGEST_LEN), - tor_addr_is_null(&my_apparent_addr) ? - "" : fmt_and_decorate_addr(&my_apparent_addr)); - } - assert_connection_ok(TO_CONN(conn),time(NULL)); + command_setup_channel(chan); } -/** Process a CERTS cell from an OR connection. - * - * If the other side should not have sent us a CERTS cell, or the cell is - * malformed, or it is supposed to authenticate the TLS key but it doesn't, - * then mark the connection. - * - * If the cell has a good cert chain and we're doing a v3 handshake, then - * store the certificates in or_handshake_state. If this is the client side - * of the connection, we then authenticate the server or mark the connection. - * If it's the server side, wait for an AUTHENTICATE cell. +/** Given a channel, install the right handlers to process incoming + * cells on it. */ -static void -command_process_certs_cell(var_cell_t *cell, or_connection_t *conn) -{ -#define ERR(s) \ - do { \ - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad CERTS cell from %s:%d: %s", \ - safe_str(conn->_base.address), conn->_base.port, (s)); \ - connection_mark_for_close(TO_CONN(conn)); \ - goto err; \ - } while (0) - - tor_cert_t *link_cert = NULL; - tor_cert_t *id_cert = NULL; - tor_cert_t *auth_cert = NULL; - - uint8_t *ptr; - int n_certs, i; - int send_netinfo = 0; - - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) - ERR("We're not doing a v3 handshake!"); - if (conn->link_proto < 3) - ERR("We're not using link protocol >= 3"); - if (conn->handshake_state->received_certs_cell) - ERR("We already got one"); - if (conn->handshake_state->authenticated) { - /* Should be unreachable, but let's make sure. */ - ERR("We're already authenticated!"); - } - if (cell->payload_len < 1) - ERR("It had no body"); - if (cell->circ_id) - ERR("It had a nonzero circuit ID"); - - n_certs = cell->payload[0]; - ptr = cell->payload + 1; - for (i = 0; i < n_certs; ++i) { - uint8_t cert_type; - uint16_t cert_len; - if (ptr + 3 > cell->payload + cell->payload_len) { - goto truncated; - } - cert_type = *ptr; - cert_len = ntohs(get_uint16(ptr+1)); - if (ptr + 3 + cert_len > cell->payload + cell->payload_len) { - goto truncated; - } - if (cert_type == OR_CERT_TYPE_TLS_LINK || - cert_type == OR_CERT_TYPE_ID_1024 || - cert_type == OR_CERT_TYPE_AUTH_1024) { - tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len); - if (!cert) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received undecodable certificate in CERTS cell from %s:%d", - safe_str(conn->_base.address), conn->_base.port); - } else { - if (cert_type == OR_CERT_TYPE_TLS_LINK) { - if (link_cert) { - tor_cert_free(cert); - ERR("Too many TLS_LINK certificates"); - } - link_cert = cert; - } else if (cert_type == OR_CERT_TYPE_ID_1024) { - if (id_cert) { - tor_cert_free(cert); - ERR("Too many ID_1024 certificates"); - } - id_cert = cert; - } else if (cert_type == OR_CERT_TYPE_AUTH_1024) { - if (auth_cert) { - tor_cert_free(cert); - ERR("Too many AUTH_1024 certificates"); - } - auth_cert = cert; - } else { - tor_cert_free(cert); - } - } - } - ptr += 3 + cert_len; - continue; - - truncated: - ERR("It ends in the middle of a certificate"); - } - - if (conn->handshake_state->started_here) { - int severity; - if (! (id_cert && link_cert)) - ERR("The certs we wanted were missing"); - /* Okay. We should be able to check the certificates now. */ - if (! tor_tls_cert_matches_key(conn->tls, link_cert)) { - ERR("The link certificate didn't match the TLS public key"); - } - /* Note that this warns more loudly about time and validity if we were - * _trying_ to connect to an authority, not necessarily if we _did_ connect - * to one. */ - if (router_digest_is_trusted_dir(conn->identity_digest)) - severity = LOG_WARN; - else - severity = LOG_PROTOCOL_WARN; - - if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0)) - ERR("The link certificate was not valid"); - if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1)) - ERR("The ID certificate was not valid"); - - conn->handshake_state->authenticated = 1; - { - const digests_t *id_digests = tor_cert_get_id_digests(id_cert); - crypto_pk_t *identity_rcvd; - if (!id_digests) - ERR("Couldn't compute digests for key in ID cert"); - - identity_rcvd = tor_tls_cert_get_key(id_cert); - if (!identity_rcvd) - ERR("Internal error: Couldn't get RSA key from ID cert."); - memcpy(conn->handshake_state->authenticated_peer_id, - id_digests->d[DIGEST_SHA1], DIGEST_LEN); - connection_or_set_circid_type(conn, identity_rcvd); - crypto_pk_free(identity_rcvd); - } - - if (connection_or_client_learned_peer_id(conn, - conn->handshake_state->authenticated_peer_id) < 0) - ERR("Problem setting or checking peer id"); - - log_info(LD_OR, "Got some good certificates from %s:%d: Authenticated it.", - safe_str(conn->_base.address), conn->_base.port); - - conn->handshake_state->id_cert = id_cert; - id_cert = NULL; - - if (!public_server_mode(get_options())) { - /* If we initiated the connection and we are not a public server, we - * aren't planning to authenticate at all. At this point we know who we - * are talking to, so we can just send a netinfo now. */ - send_netinfo = 1; - } - } else { - if (! (id_cert && auth_cert)) - ERR("The certs we wanted were missing"); - - /* Remember these certificates so we can check an AUTHENTICATE cell */ - if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1)) - ERR("The authentication certificate was not valid"); - if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1)) - ERR("The ID certificate was not valid"); - - log_info(LD_OR, "Got some good certificates from %s:%d: " - "Waiting for AUTHENTICATE.", - safe_str(conn->_base.address), conn->_base.port); - /* XXXX check more stuff? */ - conn->handshake_state->id_cert = id_cert; - conn->handshake_state->auth_cert = auth_cert; - id_cert = auth_cert = NULL; - } - - conn->handshake_state->received_certs_cell = 1; - - if (send_netinfo) { - if (connection_or_send_netinfo(conn) < 0) { - log_warn(LD_OR, "Couldn't send netinfo cell"); - connection_mark_for_close(TO_CONN(conn)); - goto err; - } - } - - err: - tor_cert_free(id_cert); - tor_cert_free(link_cert); - tor_cert_free(auth_cert); -#undef ERR -} - -/** Process an AUTH_CHALLENGE cell from an OR connection. - * - * If we weren't supposed to get one (for example, because we're not the - * originator of the connection), or it's ill-formed, or we aren't doing a v3 - * handshake, mark the connection. If the cell is well-formed but we don't - * want to authenticate, just drop it. If the cell is well-formed *and* we - * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell. */ -static void -command_process_auth_challenge_cell(var_cell_t *cell, or_connection_t *conn) +void +command_setup_channel(channel_t *chan) { - int n_types, i, use_type = -1; - uint8_t *cp; - -#define ERR(s) \ - do { \ - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \ - safe_str(conn->_base.address), conn->_base.port, (s)); \ - connection_mark_for_close(TO_CONN(conn)); \ - return; \ - } while (0) - - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) - ERR("We're not currently doing a v3 handshake"); - if (conn->link_proto < 3) - ERR("We're not using link protocol >= 3"); - if (! conn->handshake_state->started_here) - ERR("We didn't originate this connection"); - if (conn->handshake_state->received_auth_challenge) - ERR("We already received one"); - if (! conn->handshake_state->received_certs_cell) - ERR("We haven't gotten a CERTS cell yet"); - if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2) - ERR("It was too short"); - if (cell->circ_id) - ERR("It had a nonzero circuit ID"); - - n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN)); - if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types) - ERR("It looks truncated"); - - /* Now see if there is an authentication type we can use */ - cp=cell->payload+OR_AUTH_CHALLENGE_LEN+2; - for (i=0; i < n_types; ++i, cp += 2) { - uint16_t authtype = ntohs(get_uint16(cp)); - if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET) - use_type = authtype; - } - - conn->handshake_state->received_auth_challenge = 1; - - if (! public_server_mode(get_options())) { - /* If we're not a public server then we don't want to authenticate on a - connection we originated, and we already sent a NETINFO cell when we - got the CERTS cell. We have nothing more to do. */ - return; - } - - if (use_type >= 0) { - log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d: Sending " - "authentication", - safe_str(conn->_base.address), conn->_base.port); - - if (connection_or_send_authenticate_cell(conn, use_type) < 0) { - log_warn(LD_OR, "Couldn't send authenticate cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } - } else { - log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d, but we don't " - "know any of its authentication types. Not authenticating.", - safe_str(conn->_base.address), conn->_base.port); - } - - if (connection_or_send_netinfo(conn) < 0) { - log_warn(LD_OR, "Couldn't send netinfo cell"); - connection_mark_for_close(TO_CONN(conn)); - return; - } + tor_assert(chan); -#undef ERR + channel_set_cell_handlers(chan, + command_process_cell, + command_process_var_cell); } -/** Process an AUTHENTICATE cell from an OR connection. - * - * If it's ill-formed or we weren't supposed to get one or we're not doing a - * v3 handshake, then mark the connection. If it does not authenticate the - * other side of the connection successfully (because it isn't signed right, - * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept - * the identity of the router on the other side of the connection. +/** Given a listener, install the right handler to process incoming + * channels on it. */ -static void -command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn) -{ - uint8_t expected[V3_AUTH_FIXED_PART_LEN]; - const uint8_t *auth; - int authlen; - -#define ERR(s) \ - do { \ - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad AUTHENTICATE cell from %s:%d: %s", \ - safe_str(conn->_base.address), conn->_base.port, (s)); \ - connection_mark_for_close(TO_CONN(conn)); \ - return; \ - } while (0) - - if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) - ERR("We're not doing a v3 handshake"); - if (conn->link_proto < 3) - ERR("We're not using link protocol >= 3"); - if (conn->handshake_state->started_here) - ERR("We originated this connection"); - if (conn->handshake_state->received_authenticate) - ERR("We already got one!"); - if (conn->handshake_state->authenticated) { - /* Should be impossible given other checks */ - ERR("The peer is already authenticated"); - } - if (! conn->handshake_state->received_certs_cell) - ERR("We never got a certs cell"); - if (conn->handshake_state->auth_cert == NULL) - ERR("We never got an authentication certificate"); - if (conn->handshake_state->id_cert == NULL) - ERR("We never got an identity certificate"); - if (cell->payload_len < 4) - ERR("Cell was way too short"); - - auth = cell->payload; - { - uint16_t type = ntohs(get_uint16(auth)); - uint16_t len = ntohs(get_uint16(auth+2)); - if (4 + len > cell->payload_len) - ERR("Authenticator was truncated"); - - if (type != AUTHTYPE_RSA_SHA256_TLSSECRET) - ERR("Authenticator type was not recognized"); - - auth += 4; - authlen = len; - } - - if (authlen < V3_AUTH_BODY_LEN + 1) - ERR("Authenticator was too short"); - - if (connection_or_compute_authenticate_cell_body( - conn, expected, sizeof(expected), NULL, 1) < 0) - ERR("Couldn't compute expected AUTHENTICATE cell body"); - - if (tor_memneq(expected, auth, sizeof(expected))) - ERR("Some field in the AUTHENTICATE cell body was not as expected"); - - { - crypto_pk_t *pk = tor_tls_cert_get_key( - conn->handshake_state->auth_cert); - char d[DIGEST256_LEN]; - char *signed_data; - size_t keysize; - int signed_len; - if (!pk) - ERR("Internal error: couldn't get RSA key from AUTH cert."); - crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256); - - keysize = crypto_pk_keysize(pk); - signed_data = tor_malloc(keysize); - signed_len = crypto_pk_public_checksig(pk, signed_data, keysize, - (char*)auth + V3_AUTH_BODY_LEN, - authlen - V3_AUTH_BODY_LEN); - crypto_pk_free(pk); - if (signed_len < 0) { - tor_free(signed_data); - ERR("Signature wasn't valid"); - } - if (signed_len < DIGEST256_LEN) { - tor_free(signed_data); - ERR("Not enough data was signed"); - } - /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here, - * in case they're later used to hold a SHA3 digest or something. */ - if (tor_memneq(signed_data, d, DIGEST256_LEN)) { - tor_free(signed_data); - ERR("Signature did not match data to be signed."); - } - tor_free(signed_data); - } - - /* Okay, we are authenticated. */ - conn->handshake_state->received_authenticate = 1; - conn->handshake_state->authenticated = 1; - conn->handshake_state->digest_received_data = 0; - { - crypto_pk_t *identity_rcvd = - tor_tls_cert_get_key(conn->handshake_state->id_cert); - const digests_t *id_digests = - tor_cert_get_id_digests(conn->handshake_state->id_cert); - - /* This must exist; we checked key type when reading the cert. */ - tor_assert(id_digests); - - memcpy(conn->handshake_state->authenticated_peer_id, - id_digests->d[DIGEST_SHA1], DIGEST_LEN); - - connection_or_set_circid_type(conn, identity_rcvd); - crypto_pk_free(identity_rcvd); - - connection_or_init_conn_from_address(conn, - &conn->_base.addr, - conn->_base.port, - (const char*)conn->handshake_state->authenticated_peer_id, - 0); - - log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.", - safe_str(conn->_base.address), conn->_base.port); - } +void +command_setup_listener(channel_t *listener) +{ + tor_assert(listener); + tor_assert(listener->state == CHANNEL_STATE_LISTENING); -#undef ERR + channel_set_listener(listener, command_handle_incoming_channel); } -- cgit v1.2.3-54-g00ecf From e709fe320a872d8ddbeb62c029cec0246eeabc39 Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Mon, 8 Oct 2012 19:48:06 -0700 Subject: Use U64_FORMAT/U64_PRINTF_ARG rather than %lu for channel_t --- src/or/channel.c | 286 +++++++++++++++++++++++++++------------------------ src/or/channeltls.c | 18 ++-- src/or/circuitlist.c | 10 +- src/or/command.c | 6 +- src/or/cpuworker.c | 5 +- 5 files changed, 177 insertions(+), 148 deletions(-) (limited to 'src/or/command.c') diff --git a/src/or/channel.c b/src/or/channel.c index cf08e3b435..2fe4466e53 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -241,14 +241,15 @@ channel_register(channel_t *chan) if (chan->is_listener) { log_debug(LD_CHANNEL, - "Registering listener channel %p (ID %lu) in state %s (%d)", - chan, chan->global_identifier, + "Registering listener channel %p (ID " U64_FORMAT ") " + "in state %s (%d)", + chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state); } else { log_debug(LD_CHANNEL, - "Registering cell channel %p (ID %lu) in state %s (%d) " - "with digest %s", - chan, chan->global_identifier, + "Registering cell channel %p (ID " U64_FORMAT ") " + "in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); } @@ -282,9 +283,9 @@ channel_register(channel_t *chan) channel_add_to_digest_map(chan); } else { log_info(LD_CHANNEL, - "Channel %p (global ID %lu) in state %s (%d) registered " - "with no identity digest", - chan, chan->global_identifier, + "Channel %p (global ID " U64_FORMAT ") " + "in state %s (%d) registered with no identity digest", + chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state); } } @@ -398,9 +399,9 @@ channel_add_to_digest_map(channel_t *chan) } log_debug(LD_CHANNEL, - "Added channel %p (%lu) to identity map in state %s (%d) " - "with digest %s", - chan, chan->global_identifier, + "Added channel %p (global ID " U64_FORMAT ") " + "to identity map in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); } @@ -432,9 +433,10 @@ channel_remove_from_digest_map(channel_t *chan) * case is similar to digestmap_get() failing below. */ log_warn(LD_BUG, - "Trying to remove channel %p (%lu) with digest %s from " - "identity map, but didn't have any identity map", - chan, chan->global_identifier, + "Trying to remove channel %p (global ID " U64_FORMAT ") " + "with digest %s from identity map, but didn't have any identity " + "map", + chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); /* Clear out its next/prev pointers */ if (chan->u.cell_chan.next_with_same_id) { @@ -496,18 +498,18 @@ channel_remove_from_digest_map(channel_t *chan) chan->u.cell_chan.prev_with_same_id = NULL; log_debug(LD_CHANNEL, - "Removed channel %p (%lu) from identity map in state %s (%d) " - "with digest %s", - chan, chan->global_identifier, + "Removed channel %p (global ID " U64_FORMAT ") from " + "identity map in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); } else { /* This is not good */ log_warn(LD_BUG, - "Trying to remove channel %p (%lu) with digest %s from " - "identity map, but couldn't find it in the list for that " - "digest", - chan, chan->global_identifier, + "Trying to remove channel %p (global ID " U64_FORMAT ") " + "with digest %s from identity map, but couldn't find it in " + "the list for that digest", + chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); /* Unlink it and hope for the best */ if (chan->u.cell_chan.next_with_same_id) { @@ -526,9 +528,10 @@ channel_remove_from_digest_map(channel_t *chan) } else { /* Shouldn't happen */ log_warn(LD_BUG, - "Trying to remove channel %p (%lu) with digest %s from " - "identity map, but couldn't find any with that digest", - chan, chan->global_identifier, + "Trying to remove channel %p (global ID " U64_FORMAT ") with " + "digest %s from identity map, but couldn't find any with " + "that digest", + chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); /* Clear out its next/prev pointers */ if (chan->u.cell_chan.next_with_same_id) { @@ -1256,8 +1259,8 @@ channel_clear_identity_digest(channel_t *chan) log_debug(LD_CHANNEL, "Clearing remote endpoint digest on channel %p with " - "global ID %lu", - chan, chan->global_identifier); + "global ID " U64_FORMAT, + chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = (chan->state == CHANNEL_STATE_LISTENING || @@ -1295,8 +1298,8 @@ channel_set_identity_digest(channel_t *chan, log_debug(LD_CHANNEL, "Setting remote endpoint digest on channel %p with " - "global ID %lu to digest %s", - chan, chan->global_identifier, + "global ID " U64_FORMAT " to digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), identity_digest ? hex_str(identity_digest, DIGEST_LEN) : "(null)"); @@ -1354,8 +1357,8 @@ channel_clear_remote_end(channel_t *chan) log_debug(LD_CHANNEL, "Clearing remote endpoint identity on channel %p with " - "global ID %lu", - chan, chan->global_identifier); + "global ID " U64_FORMAT, + chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = (chan->state == CHANNEL_STATE_LISTENING || @@ -1396,8 +1399,8 @@ channel_set_remote_end(channel_t *chan, log_debug(LD_CHANNEL, "Setting remote endpoint identity on channel %p with " - "global ID %lu to nickname %s, digest %s", - chan, chan->global_identifier, + "global ID " U64_FORMAT " to nickname %s, digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), nickname ? nickname : "(null)", identity_digest ? hex_str(identity_digest, DIGEST_LEN) : "(null)"); @@ -1469,8 +1472,9 @@ channel_write_cell(channel_t *chan, cell_t *cell) chan->state == CHANNEL_STATE_MAINT); log_debug(LD_CHANNEL, - "Writing cell_t %p to channel %p with global ID %lu", - cell, chan, chan->global_identifier); + "Writing cell_t %p to channel %p with global ID " + U64_FORMAT, + cell, chan, U64_PRINTF_ARG(chan->global_identifier)); /* Increment the timestamp unless it's padding */ if (!(cell->command == CELL_PADDING || @@ -1532,8 +1536,10 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell) chan->state == CHANNEL_STATE_MAINT); log_debug(LD_CHANNEL, - "Writing packed_cell_t %p to channel %p with global ID %lu", - packed_cell, chan, chan->global_identifier); + "Writing packed_cell_t %p to channel %p with global ID " + U64_FORMAT, + packed_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); /* Increment the timestamp */ chan->u.cell_chan.timestamp_last_added_nonpadding = approx_time(); @@ -1594,8 +1600,10 @@ channel_write_var_cell(channel_t *chan, var_cell_t *var_cell) chan->state == CHANNEL_STATE_MAINT); log_debug(LD_CHANNEL, - "Writing var_cell_t %p to channel %p with global ID %lu", - var_cell, chan, chan->global_identifier); + "Writing var_cell_t %p to channel %p with global ID " + U64_FORMAT, + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); /* Increment the timestamp unless it's padding */ if (!(var_cell->command == CELL_PADDING || @@ -2064,8 +2072,8 @@ channel_process_incoming(channel_t *listener) log_debug(LD_CHANNEL, "Processing queue of incoming connections for listening " - "channel %p (global ID %lu)", - listener, listener->global_identifier); + "channel %p (global ID " U64_FORMAT ")", + listener, U64_PRINTF_ARG(listener->global_identifier)); if (!(listener->u.listener.incoming_list)) return; @@ -2075,9 +2083,12 @@ channel_process_incoming(channel_t *listener) tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, - "Handling incoming connection %p (%lu) for listener %p (%lu)", - chan, chan->global_identifier, - listener, listener->global_identifier); + "Handling incoming connection %p (" U64_FORMAT ") " + "for listener %p (" U64_FORMAT ")", + chan, + U64_PRINTF_ARG(chan->global_identifier), + listener, + U64_PRINTF_ARG(listener->global_identifier)); /* Make sure this is set correctly */ channel_mark_incoming(chan); listener->u.listener.listener(listener, chan); @@ -2524,8 +2535,9 @@ channel_free_all(void) /* Deregister and free it */ tor_assert(tmp); log_debug(LD_CHANNEL, - "Cleaning up finished channel %p (ID %lu) in state %s (%d)", - tmp, tmp->global_identifier, + "Cleaning up finished channel %p (ID " U64_FORMAT ") " + "in state %s (%d)", + tmp, U64_PRINTF_ARG(tmp->global_identifier), channel_state_to_string(tmp->state), tmp->state); channel_unregister(tmp); channel_free(tmp); @@ -2545,8 +2557,9 @@ channel_free_all(void) /* Close, deregister and free it */ tor_assert(tmp); log_debug(LD_CHANNEL, - "Cleaning up listening channel %p (ID %lu) in state %s (%d)", - tmp, tmp->global_identifier, + "Cleaning up listening channel %p (ID " U64_FORMAT ") " + "in state %s (%d)", + tmp, U64_PRINTF_ARG(tmp->global_identifier), channel_state_to_string(tmp->state), tmp->state); /* * We have to unregister first so we don't put it in finished_channels @@ -2570,8 +2583,9 @@ channel_free_all(void) /* Close, deregister and free it */ tor_assert(tmp); log_debug(LD_CHANNEL, - "Cleaning up active channel %p (ID %lu) in state %s (%d)", - tmp, tmp->global_identifier, + "Cleaning up active channel %p (ID " U64_FORMAT ") " + "in state %s (%d)", + tmp, U64_PRINTF_ARG(tmp->global_identifier), channel_state_to_string(tmp->state), tmp->state); /* * We have to unregister first so we don't put it in finished_channels @@ -2595,8 +2609,9 @@ channel_free_all(void) /* Close, deregister and free it */ tor_assert(tmp); log_debug(LD_CHANNEL, - "Cleaning up leftover channel %p (ID %lu) in state %s (%d)", - tmp, tmp->global_identifier, + "Cleaning up leftover channel %p (ID " U64_FORMAT ") " + "in state %s (%d)", + tmp, U64_PRINTF_ARG(tmp->global_identifier), channel_state_to_string(tmp->state), tmp->state); channel_unregister(tmp); if (!(tmp->state == CHANNEL_STATE_CLOSING || @@ -2875,27 +2890,32 @@ channel_dump_statistics(channel_t *chan, int severity) age = (double)(now - chan->timestamp_created); log(severity, LD_GENERAL, - "Channel %lu (at %p) with transport %s is in state %s (%d) and %s", - chan->global_identifier, chan, + "Channel " U64_FORMAT " (at %p) with transport %s is in state " + "%s (%d) and %s", + U64_PRINTF_ARG(chan->global_identifier), chan, channel_describe_transport(chan), channel_state_to_string(chan->state), chan->state, chan->is_listener ? "listens for incoming connections" : "transports cells"); log(severity, LD_GENERAL, - " * Channel %lu was created at %lu (%lu seconds ago) and last active " - "at %lu (%lu seconds ago)", - chan->global_identifier, - chan->timestamp_created, now - chan->timestamp_created, - chan->timestamp_active, now - chan->timestamp_active); + " * Channel " U64_FORMAT " was created at " U64_FORMAT + " (" U64_FORMAT " seconds ago) " + "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_created), + U64_PRINTF_ARG(now - chan->timestamp_created), + U64_PRINTF_ARG(chan->timestamp_active), + U64_PRINTF_ARG(now - chan->timestamp_active)); if (chan->is_listener) { log(severity, LD_GENERAL, - " * Listener channel %lu last accepted an incoming channel at %lu " - "(%lu seconds ago) and has accepted %lu channels in total", - chan->global_identifier, - chan->u.listener.timestamp_accepted, - now - chan->u.listener.timestamp_accepted, - chan->u.listener.n_accepted); + " * Listener channel " U64_FORMAT " last accepted an incoming " + "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " + "and has accepted " U64_FORMAT " channels in total", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.listener.timestamp_accepted), + U64_PRINTF_ARG(now - chan->u.listener.timestamp_accepted), + U64_PRINTF_ARG(chan->u.listener.n_accepted)); /* * If it's sensible to do so, get the rate of incoming channels on this @@ -2907,15 +2927,15 @@ channel_dump_statistics(channel_t *chan, int severity) avg = (double)(chan->u.listener.n_accepted) / age; if (avg >= 1.0) { log(severity, LD_GENERAL, - " * Listener channel %lu has averaged %f incoming channels per " - "second", - chan->global_identifier, avg); + " * Listener channel " U64_FORMAT " has averaged %f incoming " + "channels per second", + U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; log(severity, LD_GENERAL, - " * Listener channel %lu has averaged %f seconds between " - "incoming channels", - chan->global_identifier, interval); + " * Listener channel " U64_FORMAT " has averaged %f seconds " + "between incoming channels", + U64_PRINTF_ARG(chan->global_identifier), interval); } } } else { @@ -2923,30 +2943,30 @@ channel_dump_statistics(channel_t *chan, int severity) if (!tor_digest_is_zero(chan->u.cell_chan.identity_digest)) { if (chan->u.cell_chan.nickname) { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu says it is connected to an OR " - "with digest %s and nickname %s", - chan->global_identifier, + " * Cell-bearing channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and nickname %s", + U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN), chan->u.cell_chan.nickname); } else { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu says it is connected to an OR " - "with digest %s and no known nickname", - chan->global_identifier, + " * Cell-bearing channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and no known nickname", + U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); } } else { if (chan->u.cell_chan.nickname) { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu does not know the digest of the " - "OR it is connected to, but reports its nickname is %s", - chan->global_identifier, + " * Cell-bearing channel " U64_FORMAT " does not know the digest" + " of the OR it is connected to, but reports its nickname is %s", + U64_PRINTF_ARG(chan->global_identifier), chan->u.cell_chan.nickname); } else { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu does not know the digest or the " - "nickname of the OR it is connected to", - chan->global_identifier); + " * Cell-bearing channel " U64_FORMAT " does not know the digest" + " or the nickname of the OR it is connected to", + U64_PRINTF_ARG(chan->global_identifier)); } } @@ -2955,29 +2975,29 @@ channel_dump_statistics(channel_t *chan, int severity) if (have_remote_addr) { remote_addr_str = tor_dup_addr(&remote_addr); log(severity, LD_GENERAL, - " * Cell-bearing channel %lu says its remote address is %s, " - "and gives a canonical description of \"%s\" and an " + " * Cell-bearing channel " U64_FORMAT " says its remote address" + " is %s, and gives a canonical description of \"%s\" and an " "actual description of \"%s\"", - chan->global_identifier, + U64_PRINTF_ARG(chan->global_identifier), remote_addr_str, channel_get_canonical_remote_descr(chan), channel_get_actual_remote_descr(chan)); tor_free(remote_addr_str); } else { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu does not know its remote address, " - "but gives a canonical description of \"%s\" and an " + " * Cell-bearing channel " U64_FORMAT " does not know its remote " + "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", - chan->global_identifier, + U64_PRINTF_ARG(chan->global_identifier), channel_get_canonical_remote_descr(chan), channel_get_actual_remote_descr(chan)); } /* Handle marks */ log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has these marks: %s %s %s " + " * Cell-bearing channel " U64_FORMAT " has these marks: %s %s %s " "%s %s %s", - chan->global_identifier, + U64_PRINTF_ARG(chan->global_identifier), channel_is_bad_for_new_circs(chan) ? "bad_for_new_circs" : "!bad_for_new_circs", channel_is_canonical(chan) ? @@ -2994,9 +3014,9 @@ channel_dump_statistics(channel_t *chan, int severity) /* Describe queues */ log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has %d queued incoming cells " - "and %d queued outgoing cells", - chan->global_identifier, + " * Cell-bearing channel " U64_FORMAT " has %d queued incoming cells" + " and %d queued outgoing cells", + U64_PRINTF_ARG(chan->global_identifier), (chan->u.cell_chan.cell_queue != NULL) ? smartlist_len(chan->u.cell_chan.cell_queue) : 0, (chan->u.cell_chan.outgoing_queue != NULL) ? @@ -3004,9 +3024,9 @@ channel_dump_statistics(channel_t *chan, int severity) /* Describe circuits */ log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has %d active circuits out of %d" - " in total", - chan->global_identifier, + " * Cell-bearing channel " U64_FORMAT " has %d active circuits out of" + " %d in total", + U64_PRINTF_ARG(chan->global_identifier), (chan->u.cell_chan.active_circuit_pqueue != NULL) ? smartlist_len(chan->u.cell_chan.active_circuit_pqueue) : 0, chan->u.cell_chan.n_circuits); @@ -3014,67 +3034,67 @@ channel_dump_statistics(channel_t *chan, int severity) /* Describe timestamps */ log(severity, LD_GENERAL, - " * Cell-bearing channel %lu was last used by a client at %lu " - "(%lu seconds ago)", - chan->global_identifier, - chan->u.cell_chan.timestamp_client, - now - chan->u.cell_chan.timestamp_client); + " * Cell-bearing channel " U64_FORMAT " was last used by a " + "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.cell_chan.timestamp_client), + U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_client)); log(severity, LD_GENERAL, - " * Cell-bearing channel %lu was last drained at %lu " - "(%lu seconds ago)", - chan->global_identifier, - chan->u.cell_chan.timestamp_drained, - now - chan->u.cell_chan.timestamp_drained); + " * Cell-bearing channel " U64_FORMAT " was last drained at " + U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.cell_chan.timestamp_drained), + U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_drained)); log(severity, LD_GENERAL, - " * Cell-bearing channel %lu last received a cell at %lu " - "(%lu seconds ago)", - chan->global_identifier, - chan->u.cell_chan.timestamp_recv, - now - chan->u.cell_chan.timestamp_recv); + " * Cell-bearing channel " U64_FORMAT " last received a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.cell_chan.timestamp_recv), + U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_recv)); log(severity, LD_GENERAL, - " * Cell-bearing channel %lu last trasmitted a cell at %lu " - "(%lu seconds ago)", - chan->global_identifier, - chan->u.cell_chan.timestamp_xmit, - now - chan->u.cell_chan.timestamp_xmit); + " * Cell-bearing channel " U64_FORMAT " last trasmitted a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.cell_chan.timestamp_xmit), + U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_xmit)); /* Describe counters and rates */ log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has received %lu cells and " - " transmitted %lu", - chan->global_identifier, - chan->u.cell_chan.n_cells_recved, - chan->u.cell_chan.n_cells_xmitted); + " * Cell-bearing channel " U64_FORMAT " has received " + U64_FORMAT " cells and transmitted " U64_FORMAT, + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->u.cell_chan.n_cells_recved), + U64_PRINTF_ARG(chan->u.cell_chan.n_cells_xmitted)); if (now > chan->timestamp_created && chan->timestamp_created > 0) { if (chan->u.cell_chan.n_cells_recved > 0) { avg = (double)(chan->u.cell_chan.n_cells_recved) / age; if (avg >= 1.0) { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has averaged %f cells received " - "per second", - chan->global_identifier, avg); + " * Cell-bearing channel " U64_FORMAT " has averaged %f " + "cells received per second", + U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has averaged %f seconds between " - "received cells", - chan->global_identifier, interval); + " * Cell-bearing channel " U64_FORMAT " has averaged %f " + "seconds between received cells", + U64_PRINTF_ARG(chan->global_identifier), interval); } } if (chan->u.cell_chan.n_cells_xmitted > 0) { avg = (double)(chan->u.cell_chan.n_cells_xmitted) / age; if (avg >= 1.0) { log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has averaged %f cells transmitted " - "per second", - chan->global_identifier, avg); + " * Cell-bearing channel " U64_FORMAT " has averaged %f " + "cells transmitted per second", + U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; log(severity, LD_GENERAL, - " * Cell-bearing channel %lu has averaged %f seconds between " - "transmitted cells", - chan->global_identifier, interval); + " * Cell-bearing channel " U64_FORMAT " has averaged %f " + "seconds between transmitted cells", + U64_PRINTF_ARG(chan->global_identifier), interval); } } } diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 03792dd796..9fd7e6c339 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -118,8 +118,10 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, chan->u.cell_chan.write_var_cell = channel_tls_write_var_cell_method; log_debug(LD_CHANNEL, - "In channel_tls_connect() for channel %p (global id %lu)", - tlschan, chan->global_identifier); + "In channel_tls_connect() for channel %p " + "(global id " U64_FORMAT ")", + tlschan, + U64_PRINTF_ARG(chan->global_identifier)); if (is_local_addr(addr)) channel_mark_local(chan); channel_mark_outgoing(chan); @@ -137,8 +139,8 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, } log_debug(LD_CHANNEL, - "Got orconn %p for channel with global id %lu", - tlschan->conn, chan->global_identifier); + "Got orconn %p for channel with global id " U64_FORMAT, + tlschan->conn, U64_PRINTF_ARG(chan->global_identifier)); goto done; @@ -195,8 +197,8 @@ channel_tls_start_listener(void) channel_tls_listener = listener; log_debug(LD_CHANNEL, - "Starting TLS listener channel %p with global id %lu", - lchan, lchan->global_identifier); + "Starting TLS listener channel %p with global id " U64_FORMAT, + lchan, U64_PRINTF_ARG(lchan->global_identifier)); channel_register(lchan); } else lchan = TLS_CHAN_TO_BASE(channel_tls_listener); @@ -366,7 +368,9 @@ channel_tls_describe_transport_method(channel_t *chan) id = TO_CONN(tlschan->conn)->global_identifier; if (buf) tor_free(buf); - tor_asprintf(&buf, "TLS channel (connection %lu)", id); + tor_asprintf(&buf, + "TLS channel (connection " U64_FORMAT ")", + U64_PRINTF_ARG(id)); rv = buf; } else { diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 4746f912de..68cd19e152 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -918,15 +918,17 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan) if (found && found->circuit) { log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() returning circuit %p for" - " circ_id %d, channel ID %lu (%p)", - found->circuit, circ_id, chan->global_identifier, chan); + " circ_id %d, channel ID " U64_FORMAT " (%p)", + found->circuit, circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); return found->circuit; } log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() found nothing for" - " circ_id %d, channel ID %lu (%p)", - circ_id, chan->global_identifier, chan); + " circ_id %d, channel ID " U64_FORMAT " (%p)", + circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); return NULL; /* The rest of this checks for bugs. Disabled by default. */ diff --git a/src/or/command.c b/src/or/command.c index c7a1b1ac07..351ab08549 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -193,8 +193,10 @@ command_process_create_cell(cell_t *cell, channel_t *chan) tor_assert(!(chan->is_listener)); log_debug(LD_OR, - "Got a CREATE cell for circ_id %d on channel %lu (%p)", - cell->circ_id, chan->global_identifier, chan); + "Got a CREATE cell for circ_id %d on channel " U64_FORMAT + " (%p)", + cell->circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); if (we_are_hibernating()) { log_info(LD_OR, diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index a78518fd02..119892d710 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -157,8 +157,9 @@ connection_cpu_process_inbuf(connection_t *conn) tag_unpack(buf, &chan_id, &circ_id); circ = NULL; log_debug(LD_OR, - "Unpacking cpuworker reply, chan_id is %lu, circ_id is %d", - chan_id, circ_id); + "Unpacking cpuworker reply, chan_id is " U64_FORMAT + ", circ_id is %d", + U64_PRINTF_ARG(chan_id), circ_id); p_chan = channel_find_by_global_id(chan_id); if (p_chan) -- cgit v1.2.3-54-g00ecf From 89a00ee63ae61e707343432dd9f74702cf60ac3c Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Mon, 8 Oct 2012 20:49:19 -0700 Subject: Use typedefs for function pointer return values and s/listener/listener_fn/ for distinctness --- src/or/channel.c | 25 +++++++++++-------------- src/or/channel.h | 32 +++++++++++++++++++------------- src/or/command.c | 2 +- 3 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/or/command.c') diff --git a/src/or/channel.c b/src/or/channel.c index cdb0830c87..9fbfecb1d9 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -823,9 +823,8 @@ channel_force_free(channel_t *chan) * @return Function pointer to an incoming channel handler */ -void -(* channel_get_listener(channel_t *chan)) - (channel_t *, channel_t *) +channel_listener_fn_ptr +channel_get_listener_fn(channel_t *chan) { tor_assert(chan); tor_assert(chan->is_listener); @@ -847,8 +846,8 @@ void */ void -channel_set_listener(channel_t *chan, - void (*listener)(channel_t *, channel_t *) ) +channel_set_listener_fn(channel_t *chan, + channel_listener_fn_ptr listener) { tor_assert(chan); tor_assert(chan->is_listener); @@ -872,9 +871,8 @@ channel_set_listener(channel_t *chan, * @return A function pointer to chan's fixed-length cell handler, if any. */ -void -(* channel_get_cell_handler(channel_t *chan)) - (channel_t *, cell_t *) +channel_cell_handler_fn_ptr +channel_get_cell_handler(channel_t *chan) { tor_assert(chan); tor_assert(!(chan->is_listener)); @@ -897,9 +895,8 @@ void * @return A function pointer to chan's variable-length cell handler, if any. */ -void -(* channel_get_var_cell_handler(channel_t *chan)) - (channel_t *, var_cell_t *) +channel_var_cell_handler_fn_ptr +channel_get_var_cell_handler(channel_t *chan) { tor_assert(chan); tor_assert(!(chan->is_listener)); @@ -927,9 +924,9 @@ void void channel_set_cell_handlers(channel_t *chan, - void (*cell_handler)(channel_t *, cell_t *), - void (*var_cell_handler)(channel_t *, - var_cell_t *)) + channel_cell_handler_fn_ptr cell_handler, + channel_var_cell_handler_fn_ptr + var_cell_handler) { int try_again = 0; diff --git a/src/or/channel.h b/src/or/channel.h index 696ae07c0f..70ea30fcf1 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -11,6 +11,11 @@ #include "or.h" +/* Channel handler function pointer typedefs */ +typedef void (*channel_listener_fn_ptr)(channel_t *, channel_t *); +typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); +typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); + /* * Channel struct; see the channel_t typedef in or.h. A channel is an * abstract interface for the OR-to-OR connection, similar to connection_or_t, @@ -65,7 +70,7 @@ struct channel_s { union { struct { /* Registered listen handler to call on incoming connection */ - void (*listener)(channel_t *, channel_t *); + channel_listener_fn_ptr listener; /* List of pending incoming connections */ smartlist_t *incoming_list; @@ -78,8 +83,8 @@ struct channel_s { } listener; struct { /* Registered handlers for incoming cells */ - void (*cell_handler)(channel_t *, cell_t *); - void (*var_cell_handler)(channel_t *, var_cell_t *); + channel_cell_handler_fn_ptr cell_handler; + channel_var_cell_handler_fn_ptr var_cell_handler; /* Methods implemented by the lower layer */ @@ -238,19 +243,20 @@ void channel_write_var_cell(channel_t *chan, var_cell_t *cell); /* Channel callback registrations */ /* Listener callback */ -void (* channel_get_listener(channel_t *chan))(channel_t *, channel_t *); -void channel_set_listener(channel_t *chan, - void (*listener)(channel_t *, channel_t *) ); +channel_listener_fn_ptr channel_get_listener_fn(channel_t *chan); +void channel_set_listener_fn(channel_t *chan, + channel_listener_fn_ptr listener); /* Incoming cell callbacks */ -void (* channel_get_cell_handler(channel_t *chan)) - (channel_t *, cell_t *); -void (* channel_get_var_cell_handler(channel_t *chan)) - (channel_t *, var_cell_t *); +channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan); + +channel_var_cell_handler_fn_ptr +channel_get_var_cell_handler(channel_t *chan); + void channel_set_cell_handlers(channel_t *chan, - void (*cell_handler)(channel_t *, cell_t *), - void (*var_cell_handler)(channel_t *, - var_cell_t *)); + channel_cell_handler_fn_ptr cell_handler, + channel_var_cell_handler_fn_ptr + var_cell_handler); /* Clean up closed channels periodically; called from run_scheduled_events() * in main.c diff --git a/src/or/command.c b/src/or/command.c index 351ab08549..2fb70b5887 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -505,6 +505,6 @@ command_setup_listener(channel_t *listener) tor_assert(listener); tor_assert(listener->state == CHANNEL_STATE_LISTENING); - channel_set_listener(listener, command_handle_incoming_channel); + channel_set_listener_fn(listener, command_handle_incoming_channel); } -- cgit v1.2.3-54-g00ecf From 3f4b95b1a32787464b5877c7d21474801d4b944c Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Tue, 9 Oct 2012 00:51:33 -0700 Subject: Split channel_t into channel_t and channel_listener_t; get rid of that big union --- src/or/channel.c | 2123 ++++++++++++++++++++++++++++------------------ src/or/channel.h | 419 +++++---- src/or/channeltls.c | 241 +++--- src/or/channeltls.h | 4 +- src/or/circuitbuild.c | 31 +- src/or/circuitlist.c | 19 +- src/or/circuituse.c | 5 +- src/or/command.c | 17 +- src/or/command.h | 2 +- src/or/connection_edge.c | 3 +- src/or/connection_or.c | 14 +- src/or/main.c | 2 + src/or/or.h | 65 +- src/or/relay.c | 68 +- 14 files changed, 1788 insertions(+), 1225 deletions(-) (limited to 'src/or/command.c') diff --git a/src/or/channel.c b/src/or/channel.c index 57b9e4feb5..278daa6263 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -55,12 +55,18 @@ static smartlist_t *all_channels = NULL; /* All channel_t instances not in ERROR or CLOSED states */ static smartlist_t *active_channels = NULL; -/* All channel_t instances in LISTENING state */ -static smartlist_t *listening_channels = NULL; - /* All channel_t instances in ERROR or CLOSED states */ static smartlist_t *finished_channels = NULL; +/* All channel_listener_t instances */ +static smartlist_t *all_listeners = NULL; + +/* All channel_listener_t instances in LISTENING state */ +static smartlist_t *active_listeners = NULL; + +/* All channel_listener_t instances in LISTENING state */ +static smartlist_t *finished_listeners = NULL; + /* Counter for ID numbers */ static uint64_t n_channels_allocated = 0; @@ -89,6 +95,11 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, ssize_t num_cells); static void channel_force_free(channel_t *chan); static void +channel_free_list(smartlist_t *channels, int mark_for_close); +static void +channel_listener_free_list(smartlist_t *channels, int mark_for_close); +static void channel_listener_force_free(channel_listener_t *chan_l); +static void channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q); /*********************************** @@ -108,7 +119,6 @@ channel_state_is_valid(channel_state_t state) case CHANNEL_STATE_CLOSED: case CHANNEL_STATE_CLOSING: case CHANNEL_STATE_ERROR: - case CHANNEL_STATE_LISTENING: case CHANNEL_STATE_MAINT: case CHANNEL_STATE_OPENING: case CHANNEL_STATE_OPEN: @@ -122,6 +132,30 @@ channel_state_is_valid(channel_state_t state) return is_valid; } +/** + * Indicate whether a given channel listener state is valid + */ + +int +channel_listener_state_is_valid(channel_listener_state_t state) +{ + int is_valid; + + switch (state) { + case CHANNEL_LISTENER_STATE_CLOSED: + case CHANNEL_LISTENER_STATE_LISTENING: + case CHANNEL_LISTENER_STATE_CLOSING: + case CHANNEL_LISTENER_STATE_ERROR: + is_valid = 1; + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + /** * Indicate whether a channel state transition is valid * @@ -137,8 +171,7 @@ channel_state_can_transition(channel_state_t from, channel_state_t to) switch (from) { case CHANNEL_STATE_CLOSED: - is_valid = (to == CHANNEL_STATE_LISTENING || - to == CHANNEL_STATE_OPENING); + is_valid = (to == CHANNEL_STATE_OPENING); break; case CHANNEL_STATE_CLOSING: is_valid = (to == CHANNEL_STATE_CLOSED || @@ -147,10 +180,6 @@ channel_state_can_transition(channel_state_t from, channel_state_t to) case CHANNEL_STATE_ERROR: is_valid = 0; break; - case CHANNEL_STATE_LISTENING: - is_valid = (to == CHANNEL_STATE_CLOSING || - to == CHANNEL_STATE_ERROR); - break; case CHANNEL_STATE_MAINT: is_valid = (to == CHANNEL_STATE_CLOSING || to == CHANNEL_STATE_ERROR || @@ -174,6 +203,43 @@ channel_state_can_transition(channel_state_t from, channel_state_t to) return is_valid; } +/** + * Indicate whether a channel listener state transition is valid + * + * This function takes two channel listener states and indicates whether a + * transition between them is permitted (see the state definitions and + * transition table in or.h at the channel_listener_state_t typedef). + */ + +int +channel_listener_state_can_transition(channel_listener_state_t from, + channel_listener_state_t to) +{ + int is_valid; + + switch (from) { + case CHANNEL_LISTENER_STATE_CLOSED: + is_valid = (to == CHANNEL_LISTENER_STATE_LISTENING); + break; + case CHANNEL_LISTENER_STATE_CLOSING: + is_valid = (to == CHANNEL_LISTENER_STATE_CLOSED || + to == CHANNEL_LISTENER_STATE_ERROR); + break; + case CHANNEL_LISTENER_STATE_ERROR: + is_valid = 0; + break; + case CHANNEL_LISTENER_STATE_LISTENING: + is_valid = (to == CHANNEL_LISTENER_STATE_CLOSING || + to == CHANNEL_LISTENER_STATE_ERROR); + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + /** * Return a human-readable description for a channel state */ @@ -193,9 +259,6 @@ channel_state_to_string(channel_state_t state) case CHANNEL_STATE_ERROR: descr = "channel error"; break; - case CHANNEL_STATE_LISTENING: - descr = "listening"; - break; case CHANNEL_STATE_MAINT: descr = "temporarily suspended for maintenance"; break; @@ -213,6 +276,36 @@ channel_state_to_string(channel_state_t state) return descr; } +/** + * Return a human-readable description for a channel listenier state + */ + +const char * +channel_listener_state_to_string(channel_listener_state_t state) +{ + const char *descr; + + switch (state) { + case CHANNEL_LISTENER_STATE_CLOSED: + descr = "closed"; + break; + case CHANNEL_LISTENER_STATE_CLOSING: + descr = "closing"; + break; + case CHANNEL_LISTENER_STATE_ERROR: + descr = "channel listener error"; + break; + case CHANNEL_LISTENER_STATE_LISTENING: + descr = "listening"; + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + descr = "unknown or invalid channel listener state"; + } + + return descr; +} + /*************************************** * Channel registration/unregistration * ***************************************/ @@ -232,20 +325,12 @@ channel_register(channel_t *chan) /* No-op if already registered */ if (chan->registered) return; - if (chan->is_listener) { - log_debug(LD_CHANNEL, - "Registering listener channel %p (ID " U64_FORMAT ") " - "in state %s (%d)", - chan, U64_PRINTF_ARG(chan->global_identifier), - channel_state_to_string(chan->state), chan->state); - } else { - log_debug(LD_CHANNEL, - "Registering cell channel %p (ID " U64_FORMAT ") " - "in state %s (%d) with digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), - channel_state_to_string(chan->state), chan->state, - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); - } + log_debug(LD_CHANNEL, + "Registering channel %p (ID " U64_FORMAT ") " + "in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state, + hex_str(chan->identity_digest, DIGEST_LEN)); /* Make sure we have all_channels, then add it */ if (!all_channels) all_channels = smartlist_new(); @@ -262,25 +347,17 @@ channel_register(channel_t *chan) if (!active_channels) active_channels = smartlist_new(); smartlist_add(active_channels, chan); - /* Is it a listener? */ - if (chan->is_listener && - chan->state == CHANNEL_STATE_LISTENING) { - /* Put it in the listening list, creating it if necessary */ - if (!listening_channels) listening_channels = smartlist_new(); - smartlist_add(listening_channels, chan); - } else if (chan->state != CHANNEL_STATE_CLOSING) { - if (!(chan->is_listener)) { - /* It should have a digest set */ - if (!tor_digest_is_zero(chan->u.cell_chan.identity_digest)) { - /* Yeah, we're good, add it to the map */ - channel_add_to_digest_map(chan); - } else { - log_info(LD_CHANNEL, - "Channel %p (global ID " U64_FORMAT ") " - "in state %s (%d) registered with no identity digest", - chan, U64_PRINTF_ARG(chan->global_identifier), - channel_state_to_string(chan->state), chan->state); - } + if (chan->state != CHANNEL_STATE_CLOSING) { + /* It should have a digest set */ + if (!tor_digest_is_zero(chan->identity_digest)) { + /* Yeah, we're good, add it to the map */ + channel_add_to_digest_map(chan); + } else { + log_info(LD_CHANNEL, + "Channel %p (global ID " U64_FORMAT ") " + "in state %s (%d) registered with no identity digest", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state); } } } @@ -312,12 +389,6 @@ channel_unregister(channel_t *chan) } else { /* Get it out of the active list */ if (active_channels) smartlist_remove(active_channels, chan); - - /* Is it listening? */ - if (chan->state == CHANNEL_STATE_LISTENING) { - /* Get it out of the listening list */ - if (listening_channels) smartlist_remove(listening_channels, chan); - } } /* Get it out of all_channels */ @@ -326,17 +397,88 @@ channel_unregister(channel_t *chan) /* Mark it as unregistered */ chan->registered = 0; - if (!(chan->is_listener)) { - /* Should it be in the digest map? */ - if (!tor_digest_is_zero(chan->u.cell_chan.identity_digest) && - !(chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || - chan->state == CHANNEL_STATE_CLOSED || - chan->state == CHANNEL_STATE_ERROR)) { - /* Remove it */ - channel_remove_from_digest_map(chan); - } + /* Should it be in the digest map? */ + if (!tor_digest_is_zero(chan->identity_digest) && + !(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)) { + /* Remove it */ + channel_remove_from_digest_map(chan); + } +} + +/** + * Register a channel listener + * + * This function registers a newly created channel listner in the global + * lists/maps of active channel listeners. + */ + +void +channel_listener_register(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* No-op if already registered */ + if (chan_l->registered) return; + + log_debug(LD_CHANNEL, + "Registering channel listener %p (ID " U64_FORMAT ") " + "in state %s (%d)", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + channel_listener_state_to_string(chan_l->state), + chan_l->state); + + /* Make sure we have all_channels, then add it */ + if (!all_listeners) all_listeners = smartlist_new(); + smartlist_add(all_listeners, chan_l); + + /* Is it finished? */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { + /* Put it in the finished list, creating it if necessary */ + if (!finished_listeners) finished_listeners = smartlist_new(); + smartlist_add(finished_listeners, chan_l); + } else { + /* Put it in the active list, creating it if necessary */ + if (!active_listeners) active_listeners = smartlist_new(); + smartlist_add(active_listeners, chan_l); + } + + /* Mark it as registered */ + chan_l->registered = 1; +} + +/** + * Unregister a channel listener + * + * This function removes a channel listener from the global lists and maps + * and is used when freeing a closed/errored channel listener. + */ + +void +channel_listener_unregister(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* No-op if not registered */ + if (!(chan_l->registered)) return; + + /* Is it finished? */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { + /* Get it out of the finished list */ + if (finished_listeners) smartlist_remove(finished_listeners, chan_l); + } else { + /* Get it out of the active list */ + if (active_listeners) smartlist_remove(active_listeners, chan_l); } + + /* Get it out of all_channels */ + if (all_listeners) smartlist_remove(all_listeners, chan_l); + + /* Mark it as unregistered */ + chan_l->registered = 0; } /********************************* @@ -357,34 +499,31 @@ channel_add_to_digest_map(channel_t *chan) channel_t *tmp; tor_assert(chan); - tor_assert(!(chan->is_listener)); /* Assert that the state makes sense */ - tor_assert(!(chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || + tor_assert(!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)); /* Assert that there is a digest */ - tor_assert(!tor_digest_is_zero(chan->u.cell_chan.identity_digest)); + tor_assert(!tor_digest_is_zero(chan->identity_digest)); /* Allocate the identity map if we have to */ if (!channel_identity_map) channel_identity_map = digestmap_new(); /* Insert it */ tmp = digestmap_set(channel_identity_map, - chan->u.cell_chan.identity_digest, + chan->identity_digest, chan); if (tmp) { - tor_assert(!(tmp->is_listener)); /* There already was one, this goes at the head of the list */ - chan->u.cell_chan.next_with_same_id = tmp; - chan->u.cell_chan.prev_with_same_id = NULL; - tmp->u.cell_chan.prev_with_same_id = chan; + chan->next_with_same_id = tmp; + chan->prev_with_same_id = NULL; + tmp->prev_with_same_id = chan; } else { /* First with this digest */ - chan->u.cell_chan.next_with_same_id = NULL; - chan->u.cell_chan.prev_with_same_id = NULL; + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; } log_debug(LD_CHANNEL, @@ -392,7 +531,7 @@ channel_add_to_digest_map(channel_t *chan) "to identity map in state %s (%d) with digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); + hex_str(chan->identity_digest, DIGEST_LEN)); } /** @@ -408,10 +547,9 @@ channel_remove_from_digest_map(channel_t *chan) channel_t *tmp, *head; tor_assert(chan); - tor_assert(!(chan->is_listener)); /* Assert that there is a digest */ - tor_assert(!tor_digest_is_zero(chan->u.cell_chan.identity_digest)); + tor_assert(!tor_digest_is_zero(chan->identity_digest)); /* Make sure we have a map */ if (!channel_identity_map) { @@ -424,72 +562,62 @@ channel_remove_from_digest_map(channel_t *chan) "with digest %s from identity map, but didn't have any identity " "map", chan, U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); + hex_str(chan->identity_digest, DIGEST_LEN)); /* Clear out its next/prev pointers */ - if (chan->u.cell_chan.next_with_same_id) { - tor_assert(!(chan->u.cell_chan.next_with_same_id->is_listener)); - chan->u.cell_chan.next_with_same_id->u.cell_chan.prev_with_same_id - = chan->u.cell_chan.prev_with_same_id; + if (chan->next_with_same_id) { + chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; } - if (chan->u.cell_chan.prev_with_same_id) { - tor_assert(!(chan->u.cell_chan.prev_with_same_id->is_listener)); - chan->u.cell_chan.prev_with_same_id->u.cell_chan.next_with_same_id - = chan->u.cell_chan.next_with_same_id; + if (chan->prev_with_same_id) { + chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; } - chan->u.cell_chan.next_with_same_id = NULL; - chan->u.cell_chan.prev_with_same_id = NULL; + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; return; } /* Look for it in the map */ - tmp = digestmap_get(channel_identity_map, chan->u.cell_chan.identity_digest); + tmp = digestmap_get(channel_identity_map, chan->identity_digest); if (tmp) { /* Okay, it's here */ head = tmp; /* Keep track of list head */ /* Look for this channel */ while (tmp && tmp != chan) { - tor_assert(!(tmp->is_listener)); - tmp = tmp->u.cell_chan.next_with_same_id; + tmp = tmp->next_with_same_id; } if (tmp == chan) { /* Found it, good */ - if (chan->u.cell_chan.next_with_same_id) { - tor_assert(!(chan->u.cell_chan.next_with_same_id->is_listener)); - chan->u.cell_chan.next_with_same_id->u.cell_chan.prev_with_same_id - = chan->u.cell_chan.prev_with_same_id; + if (chan->next_with_same_id) { + chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; } /* else we're the tail of the list */ - if (chan->u.cell_chan.prev_with_same_id) { - tor_assert(!(chan->u.cell_chan.prev_with_same_id->is_listener)); + if (chan->prev_with_same_id) { /* We're not the head of the list, so we can *just* unlink */ - chan->u.cell_chan.prev_with_same_id->u.cell_chan.next_with_same_id - = chan->u.cell_chan.next_with_same_id; + chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; } else { /* We're the head, so we have to point the digest map entry at our * next if we have one, or remove it if we're also the tail */ - if (chan->u.cell_chan.next_with_same_id) { - tor_assert(!(chan->u.cell_chan.next_with_same_id->is_listener)); + if (chan->next_with_same_id) { digestmap_set(channel_identity_map, - chan->u.cell_chan.identity_digest, - chan->u.cell_chan.next_with_same_id); + chan->identity_digest, + chan->next_with_same_id); } else { digestmap_remove(channel_identity_map, - chan->u.cell_chan.identity_digest); + chan->identity_digest); } } /* NULL out its next/prev pointers, and we're finished */ - chan->u.cell_chan.next_with_same_id = NULL; - chan->u.cell_chan.prev_with_same_id = NULL; + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; log_debug(LD_CHANNEL, "Removed channel %p (global ID " U64_FORMAT ") from " "identity map in state %s (%d) with digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); + hex_str(chan->identity_digest, DIGEST_LEN)); } else { /* This is not good */ log_warn(LD_BUG, @@ -497,20 +625,16 @@ channel_remove_from_digest_map(channel_t *chan) "with digest %s from identity map, but couldn't find it in " "the list for that digest", chan, U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); + hex_str(chan->identity_digest, DIGEST_LEN)); /* Unlink it and hope for the best */ - if (chan->u.cell_chan.next_with_same_id) { - tor_assert(!(chan->u.cell_chan.next_with_same_id->is_listener)); - chan->u.cell_chan.next_with_same_id->u.cell_chan.prev_with_same_id - = chan->u.cell_chan.prev_with_same_id; + if (chan->next_with_same_id) { + chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; } - if (chan->u.cell_chan.prev_with_same_id) { - tor_assert(!(chan->u.cell_chan.prev_with_same_id->is_listener)); - chan->u.cell_chan.prev_with_same_id->u.cell_chan.next_with_same_id - = chan->u.cell_chan.next_with_same_id; + if (chan->prev_with_same_id) { + chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; } - chan->u.cell_chan.next_with_same_id = NULL; - chan->u.cell_chan.prev_with_same_id = NULL; + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; } } else { /* Shouldn't happen */ @@ -519,19 +643,16 @@ channel_remove_from_digest_map(channel_t *chan) "digest %s from identity map, but couldn't find any with " "that digest", chan, U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); + hex_str(chan->identity_digest, DIGEST_LEN)); /* Clear out its next/prev pointers */ - if (chan->u.cell_chan.next_with_same_id) { - tor_assert(!(chan->u.cell_chan.next_with_same_id->is_listener)); - chan->u.cell_chan.next_with_same_id->u.cell_chan.prev_with_same_id - = chan->u.cell_chan.prev_with_same_id; + if (chan->next_with_same_id) { + chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; } - if (chan->u.cell_chan.prev_with_same_id) { - chan->u.cell_chan.prev_with_same_id->u.cell_chan.next_with_same_id - = chan->u.cell_chan.next_with_same_id; + if (chan->prev_with_same_id) { + chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; } - chan->u.cell_chan.next_with_same_id = NULL; - chan->u.cell_chan.prev_with_same_id = NULL; + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; } } @@ -599,9 +720,8 @@ channel_t * channel_next_with_digest(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.next_with_same_id; + return chan->next_with_same_id; } /** @@ -614,19 +734,13 @@ channel_next_with_digest(channel_t *chan) channel_t * channel_prev_with_digest(channel_t *chan) { - channel_t *rv = NULL; - tor_assert(chan); - tor_assert(!(chan->is_listener)); - if (chan->u.cell_chan.prev_with_same_id) - rv = chan->u.cell_chan.prev_with_same_id; - - return rv; + return chan->prev_with_same_id; } /** - * Initialize a cell channel + * Initialize a channel * * This function should be called by subclasses to set up some per-channel * variables. I.e., this is the superclass constructor. Before this, the @@ -634,47 +748,41 @@ channel_prev_with_digest(channel_t *chan) */ void -channel_init_for_cells(channel_t *chan) +channel_init(channel_t *chan) { tor_assert(chan); /* Assign an ID and bump the counter */ chan->global_identifier = n_channels_allocated++; - /* Mark as a non-listener */ - chan->is_listener = 0; - /* Init timestamp */ - chan->u.cell_chan.timestamp_last_added_nonpadding = time(NULL); + chan->timestamp_last_added_nonpadding = time(NULL); /* Init next_circ_id */ - chan->u.cell_chan.next_circ_id = crypto_rand_int(1 << 15); + chan->next_circ_id = crypto_rand_int(1 << 15); /* Timestamp it */ channel_timestamp_created(chan); } /** - * Initialize a listener channel + * Initialize a channel listener * * This function should be called by subclasses to set up some per-channel * variables. I.e., this is the superclass constructor. Before this, the - * channel should be allocated with tor_malloc_zero(). + * channel listener should be allocated with tor_malloc_zero(). */ void -channel_init_listener(channel_t *chan) +channel_init_listener(channel_listener_t *chan_l) { - tor_assert(chan); + tor_assert(chan_l); /* Assign an ID and bump the counter */ - chan->global_identifier = n_channels_allocated++; - - /* Mark as a listener */ - chan->is_listener = 1; + chan_l->global_identifier = n_channels_allocated++; /* Timestamp it */ - channel_timestamp_created(chan); + channel_listener_timestamp_created(chan_l); } /** @@ -696,13 +804,11 @@ channel_free(channel_t *chan) /* Call a free method if there is one */ if (chan->free) chan->free(chan); - if (!(chan->is_listener)) { - channel_clear_remote_end(chan); + channel_clear_remote_end(chan); - if (chan->u.cell_chan.active_circuit_pqueue) { - smartlist_free(chan->u.cell_chan.active_circuit_pqueue); - chan->u.cell_chan.active_circuit_pqueue = NULL; - } + if (chan->active_circuit_pqueue) { + smartlist_free(chan->active_circuit_pqueue); + chan->active_circuit_pqueue = NULL; } /* We're in CLOSED or ERROR, so the cell queue is already empty */ @@ -711,7 +817,35 @@ channel_free(channel_t *chan) } /** - * Free a channel and skip the state/reigstration asserts; this internal- + * Free a channel listener; nothing outside of channel.c and subclasses + * should call this - it frees channel listeners after they have closed and + * been unregistered. + */ + +void +channel_listener_free(channel_listener_t *chan_l) +{ + if (!chan_l) return; + + /* It must be closed or errored */ + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR); + /* It must be deregistered */ + tor_assert(!(chan_l->registered)); + + /* Call a free method if there is one */ + if (chan_l->free) chan_l->free(chan_l); + + /* + * We're in CLOSED or ERROR, so the incoming channel queue is already + * empty. + */ + + tor_free(chan_l); +} + +/** + * Free a channel and skip the state/registration asserts; this internal- * use-only function should be called only from channel_free_all() when * shutting down the Tor process. */ @@ -724,96 +858,111 @@ channel_force_free(channel_t *chan) /* Call a free method if there is one */ if (chan->free) chan->free(chan); - if (chan->is_listener) { - /* - * The incoming list just gets emptied and freed; we request close on - * any channels we find there, but since we got called while shutting - * down they will get deregistered and freed elsewhere anyway. - */ - if (chan->u.listener.incoming_list) { - SMARTLIST_FOREACH_BEGIN(chan->u.listener.incoming_list, - channel_t *, qchan) { - channel_mark_for_close(qchan); - } SMARTLIST_FOREACH_END(qchan); - - smartlist_free(chan->u.listener.incoming_list); - chan->u.listener.incoming_list = NULL; - } - } else { - channel_clear_remote_end(chan); - smartlist_free(chan->u.cell_chan.active_circuit_pqueue); - - /* We might still have a cell queue; kill it */ - if (chan->u.cell_chan.incoming_queue) { - SMARTLIST_FOREACH_BEGIN(chan->u.cell_chan.incoming_queue, - cell_queue_entry_t *, q) { - tor_free(q); - } SMARTLIST_FOREACH_END(q); - - smartlist_free(chan->u.cell_chan.incoming_queue); - chan->u.cell_chan.incoming_queue = NULL; - } + channel_clear_remote_end(chan); + smartlist_free(chan->active_circuit_pqueue); + + /* We might still have a cell queue; kill it */ + if (chan->incoming_queue) { + SMARTLIST_FOREACH_BEGIN(chan->incoming_queue, + cell_queue_entry_t *, q) { + tor_free(q); + } SMARTLIST_FOREACH_END(q); + + smartlist_free(chan->incoming_queue); + chan->incoming_queue = NULL; + } - /* Outgoing cell queue is similar, but we can have to free packed cells */ - if (chan->u.cell_chan.outgoing_queue) { - SMARTLIST_FOREACH_BEGIN(chan->u.cell_chan.outgoing_queue, - cell_queue_entry_t *, q) { - if (q->type == CELL_QUEUE_PACKED) { - if (q->u.packed.packed_cell) { - packed_cell_free(q->u.packed.packed_cell); - } + /* Outgoing cell queue is similar, but we can have to free packed cells */ + if (chan->outgoing_queue) { + SMARTLIST_FOREACH_BEGIN(chan->outgoing_queue, + cell_queue_entry_t *, q) { + if (q->type == CELL_QUEUE_PACKED) { + if (q->u.packed.packed_cell) { + packed_cell_free(q->u.packed.packed_cell); } - tor_free(q); - } SMARTLIST_FOREACH_END(q); + } + tor_free(q); + } SMARTLIST_FOREACH_END(q); - smartlist_free(chan->u.cell_chan.outgoing_queue); - chan->u.cell_chan.outgoing_queue = NULL; - } + smartlist_free(chan->outgoing_queue); + chan->outgoing_queue = NULL; } tor_free(chan); } /** - * Return the current registered listener for a channel + * Free a channel listener and skip the state/reigstration asserts; this + * internal-use-only function should be called only from channel_free_all() + * when shutting down the Tor process. + */ + +static void +channel_listener_force_free(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* Call a free method if there is one */ + if (chan_l->free) chan_l->free(chan_l); + + /* + * The incoming list just gets emptied and freed; we request close on + * any channels we find there, but since we got called while shutting + * down they will get deregistered and freed elsewhere anyway. + */ + if (chan_l->incoming_list) { + SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list, + channel_t *, qchan) { + channel_mark_for_close(qchan); + } SMARTLIST_FOREACH_END(qchan); + + smartlist_free(chan_l->incoming_list); + chan_l->incoming_list = NULL; + } + + tor_free(chan_l); +} + +/** + * Return the current registered listener for a channel listener * * This function returns a function pointer to the current registered - * handler for new incoming channels on a listener channel. + * handler for new incoming channels on a channel listener. */ channel_listener_fn_ptr -channel_get_listener_fn(channel_t *chan) +channel_listener_get_listener_fn(channel_listener_t *chan_l) { - tor_assert(chan); - tor_assert(chan->is_listener); + tor_assert(chan_l); - if (chan->state == CHANNEL_STATE_LISTENING) - return chan->u.listener.listener; + if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING) + return chan_l->listener; return NULL; } /** - * Set the listener for a channel + * Set the listener for a channel listener * - * This function sets the handler for new incoming channels on a listener - * channel. + * This function sets the handler for new incoming channels on a channel + * listener. */ void -channel_set_listener_fn(channel_t *chan, - channel_listener_fn_ptr listener) +channel_listener_set_listener_fn(channel_listener_t *chan_l, + channel_listener_fn_ptr listener) { - tor_assert(chan); - tor_assert(chan->is_listener); - tor_assert(chan->state == CHANNEL_STATE_LISTENING); + tor_assert(chan_l); + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_LISTENING); log_debug(LD_CHANNEL, - "Setting listener callback for channel %p to %p", - chan, listener); + "Setting listener callback for channel listener %p " + "(global ID " U64_FORMAT ") to %p", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + listener); - chan->u.listener.listener = listener; - if (chan->u.listener.listener) channel_process_incoming(chan); + chan_l->listener = listener; + if (chan_l->listener) channel_listener_process_incoming(chan_l); } /** @@ -827,12 +976,11 @@ channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); if (chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT) - return chan->u.cell_chan.cell_handler; + return chan->cell_handler; return NULL; } @@ -848,12 +996,11 @@ channel_var_cell_handler_fn_ptr channel_get_var_cell_handler(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); if (chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT) - return chan->u.cell_chan.var_cell_handler; + return chan->var_cell_handler; return NULL; } @@ -875,7 +1022,6 @@ channel_set_cell_handlers(channel_t *chan, int try_again = 0; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT); @@ -889,20 +1035,20 @@ channel_set_cell_handlers(channel_t *chan, /* Should we try the queue? */ if (cell_handler && - cell_handler != chan->u.cell_chan.cell_handler) try_again = 1; + cell_handler != chan->cell_handler) try_again = 1; if (var_cell_handler && - var_cell_handler != chan->u.cell_chan.var_cell_handler) try_again = 1; + var_cell_handler != chan->var_cell_handler) try_again = 1; /* Change them */ - chan->u.cell_chan.cell_handler = cell_handler; - chan->u.cell_chan.var_cell_handler = var_cell_handler; + chan->cell_handler = cell_handler; + chan->var_cell_handler = var_cell_handler; /* Re-run the queue if we have one and there's any reason to */ - if (chan->u.cell_chan.incoming_queue && - (smartlist_len(chan->u.cell_chan.incoming_queue) > 0) && + if (chan->incoming_queue && + (smartlist_len(chan->incoming_queue) > 0) && try_again && - (chan->u.cell_chan.cell_handler || - chan->u.cell_chan.var_cell_handler)) channel_process_cells(chan); + (chan->cell_handler || + chan->var_cell_handler)) channel_process_cells(chan); } /** @@ -925,8 +1071,9 @@ channel_mark_for_close(channel_t *chan) chan->state == CHANNEL_STATE_ERROR) return; log_debug(LD_CHANNEL, - "Closing channel %p by request", - chan); + "Closing channel %p (global ID " U64_FORMAT ") " + "by request", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* Note closing by request from above */ chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED; @@ -945,6 +1092,47 @@ channel_mark_for_close(channel_t *chan) */ } +/** + * Mark a channel listener for closure + * + * This function tries to close a channel_listener_t; it will go into the + * CLOSING state, and eventually the lower layer should put it into the CLOSED + * or ERROR state. Then, channel_run_cleanup() will eventually free it. + */ + +void +channel_listener_mark_for_close(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + tor_assert(chan_l->close != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "by request", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by request from above */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); + + /* Tell the lower layer */ + chan_l->close(chan_l); + + /* + * It's up to the lower layer to change state to CLOSED or ERROR when we're + * ready; we'll try to free channels that are in the finished list from + * channel_run_cleanup(). The lower layer should do this by calling + * channel_listener_closed(). + */ +} + /** * Close a channel from the lower layer * @@ -964,8 +1152,9 @@ channel_close_from_lower_layer(channel_t *chan) chan->state == CHANNEL_STATE_ERROR) return; log_debug(LD_CHANNEL, - "Closing channel %p due to lower-layer event", - chan); + "Closing channel %p (global ID " U64_FORMAT ") " + "due to lower-layer event", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* Note closing by event from below */ chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW; @@ -974,6 +1163,36 @@ channel_close_from_lower_layer(channel_t *chan) channel_change_state(chan, CHANNEL_STATE_CLOSING); } +/** + * Close a channel listener from the lower layer + * + * Notify the channel code that the channel listener is being closed due to a + * non-error condition in the lower layer. This does not call the close() + * method, since the lower layer already knows. + */ + +void +channel_listener_close_from_lower_layer(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "due to lower-layer event", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by event from below */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); +} + /** * Notify that the channel is being closed due to an error condition * @@ -1003,6 +1222,37 @@ channel_close_for_error(channel_t *chan) channel_change_state(chan, CHANNEL_STATE_CLOSING); } +/** + * Notify that the channel listener is being closed due to an error condition + * + * This function is called by the lower layer implementing the transport + * when a channel listener must be closed due to an error condition. This + * does not call the channel listener's close method, since the lower layer + * already knows. + */ + +void +channel_listener_close_for_error(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "due to lower-layer error", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by event from below */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); +} + /** * Notify that the lower layer is finished closing the channel * @@ -1038,6 +1288,33 @@ channel_closed(channel_t *chan) } } +/** + * Notify that the lower layer is finished closing the channel listener + * + * This function should be called by the lower layer when a channel listener + * is finished closing and it should be regarded as inactive and + * freed by the channel code. + */ + +void +channel_listener_closed(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR); + + /* No-op if already inactive */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED); + } else { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR); + } +} + /** * Clear the identity_digest of a channel * @@ -1051,7 +1328,6 @@ channel_clear_identity_digest(channel_t *chan) int state_not_in_map; tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, "Clearing remote endpoint digest on channel %p with " @@ -1059,18 +1335,17 @@ channel_clear_identity_digest(channel_t *chan) chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = - (chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || + (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); if (!state_not_in_map && chan->registered && - !tor_digest_is_zero(chan->u.cell_chan.identity_digest)) + !tor_digest_is_zero(chan->identity_digest)) /* if it's registered get it out of the digest map */ channel_remove_from_digest_map(chan); - memset(chan->u.cell_chan.identity_digest, 0, - sizeof(chan->u.cell_chan.identity_digest)); + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); } /** @@ -1087,7 +1362,6 @@ channel_set_identity_digest(channel_t *chan, int was_in_digest_map, should_be_in_digest_map, state_not_in_map; tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, "Setting remote endpoint digest on channel %p with " @@ -1097,14 +1371,13 @@ channel_set_identity_digest(channel_t *chan, hex_str(identity_digest, DIGEST_LEN) : "(null)"); state_not_in_map = - (chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || + (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); was_in_digest_map = !state_not_in_map && chan->registered && - !tor_digest_is_zero(chan->u.cell_chan.identity_digest); + !tor_digest_is_zero(chan->identity_digest); should_be_in_digest_map = !state_not_in_map && chan->registered && @@ -1118,12 +1391,12 @@ channel_set_identity_digest(channel_t *chan, channel_remove_from_digest_map(chan); if (identity_digest) { - memcpy(chan->u.cell_chan.identity_digest, + memcpy(chan->identity_digest, identity_digest, - sizeof(chan->u.cell_chan.identity_digest)); + sizeof(chan->identity_digest)); } else { - memset(chan->u.cell_chan.identity_digest, 0, - sizeof(chan->u.cell_chan.identity_digest)); + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); } /* Put it in the digest map if we should */ @@ -1144,7 +1417,6 @@ channel_clear_remote_end(channel_t *chan) int state_not_in_map; tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, "Clearing remote endpoint identity on channel %p with " @@ -1152,19 +1424,18 @@ channel_clear_remote_end(channel_t *chan) chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = - (chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || + (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); if (!state_not_in_map && chan->registered && - !tor_digest_is_zero(chan->u.cell_chan.identity_digest)) + !tor_digest_is_zero(chan->identity_digest)) /* if it's registered get it out of the digest map */ channel_remove_from_digest_map(chan); - memset(chan->u.cell_chan.identity_digest, 0, - sizeof(chan->u.cell_chan.identity_digest)); - tor_free(chan->u.cell_chan.nickname); + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); + tor_free(chan->nickname); } /** @@ -1182,7 +1453,6 @@ channel_set_remote_end(channel_t *chan, int was_in_digest_map, should_be_in_digest_map, state_not_in_map; tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, "Setting remote endpoint identity on channel %p with " @@ -1193,14 +1463,13 @@ channel_set_remote_end(channel_t *chan, hex_str(identity_digest, DIGEST_LEN) : "(null)"); state_not_in_map = - (chan->state == CHANNEL_STATE_LISTENING || - chan->state == CHANNEL_STATE_CLOSING || + (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); was_in_digest_map = !state_not_in_map && chan->registered && - !tor_digest_is_zero(chan->u.cell_chan.identity_digest); + !tor_digest_is_zero(chan->identity_digest); should_be_in_digest_map = !state_not_in_map && chan->registered && @@ -1214,18 +1483,18 @@ channel_set_remote_end(channel_t *chan, channel_remove_from_digest_map(chan); if (identity_digest) { - memcpy(chan->u.cell_chan.identity_digest, + memcpy(chan->identity_digest, identity_digest, - sizeof(chan->u.cell_chan.identity_digest)); + sizeof(chan->identity_digest)); } else { - memset(chan->u.cell_chan.identity_digest, 0, - sizeof(chan->u.cell_chan.identity_digest)); + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); } - tor_free(chan->u.cell_chan.nickname); + tor_free(chan->nickname); if (nickname) - chan->u.cell_chan.nickname = tor_strdup(nickname); + chan->nickname = tor_strdup(nickname); /* Put it in the digest map if we should */ if (should_be_in_digest_map) @@ -1275,7 +1544,6 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) cell_queue_entry_t *tmp = NULL; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(q); /* Assert that the state makes sense for a cell write */ @@ -1285,31 +1553,29 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) /* Increment the timestamp unless it's padding */ if (!cell_queue_entry_is_padding(q)) { - chan->u.cell_chan.timestamp_last_added_nonpadding = approx_time(); + chan->timestamp_last_added_nonpadding = approx_time(); } /* Can we send it right out? If so, try */ - if (!(chan->u.cell_chan.outgoing_queue && - (smartlist_len(chan->u.cell_chan.outgoing_queue) > 0)) && + if (!(chan->outgoing_queue && + (smartlist_len(chan->outgoing_queue) > 0)) && chan->state == CHANNEL_STATE_OPEN) { /* Pick the right write function for this cell type and save the result */ switch (q->type) { case CELL_QUEUE_FIXED: - tor_assert(chan->u.cell_chan.write_cell); + tor_assert(chan->write_cell); tor_assert(q->u.fixed.cell); - result = chan->u.cell_chan.write_cell(chan, q->u.fixed.cell); + result = chan->write_cell(chan, q->u.fixed.cell); break; case CELL_QUEUE_PACKED: - tor_assert(chan->u.cell_chan.write_packed_cell); + tor_assert(chan->write_packed_cell); tor_assert(q->u.packed.packed_cell); - result = chan-> - u.cell_chan.write_packed_cell(chan, - q->u.packed.packed_cell); + result = chan->write_packed_cell(chan, q->u.packed.packed_cell); break; case CELL_QUEUE_VAR: - tor_assert(chan->u.cell_chan.write_var_cell); + tor_assert(chan->write_var_cell); tor_assert(q->u.var.var_cell); - result = chan->u.cell_chan.write_var_cell(chan, q->u.var.var_cell); + result = chan->write_var_cell(chan, q->u.var.var_cell); break; default: tor_assert(1); @@ -1323,21 +1589,21 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) /* If we're here the queue is empty, so it's drained too */ channel_timestamp_drained(chan); /* Update the counter */ - ++(chan->u.cell_chan.n_cells_xmitted); + ++(chan->n_cells_xmitted); } } if (!sent) { /* Not sent, queue it */ - if (!(chan->u.cell_chan.outgoing_queue)) - chan->u.cell_chan.outgoing_queue = smartlist_new(); + if (!(chan->outgoing_queue)) + chan->outgoing_queue = smartlist_new(); /* * We have to copy the queue entry passed in, since the caller probably * used the stack. */ tmp = tor_malloc(sizeof(*tmp)); memcpy(tmp, q, sizeof(*tmp)); - smartlist_add(chan->u.cell_chan.outgoing_queue, tmp); + smartlist_add(chan->outgoing_queue, tmp); /* Try to process the queue? */ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan); } @@ -1432,7 +1698,7 @@ void channel_change_state(channel_t *chan, channel_state_t to_state) { channel_state_t from_state; - unsigned char was_active, is_active, was_listening, is_listening; + unsigned char was_active, is_active; unsigned char was_in_id_map, is_in_id_map; tor_assert(chan); @@ -1442,26 +1708,13 @@ channel_change_state(channel_t *chan, channel_state_t to_state) tor_assert(channel_state_is_valid(to_state)); tor_assert(channel_state_can_transition(chan->state, to_state)); - if (chan->is_listener) { - tor_assert(from_state == CHANNEL_STATE_LISTENING || - from_state == CHANNEL_STATE_CLOSING || - from_state == CHANNEL_STATE_CLOSED || - from_state == CHANNEL_STATE_ERROR); - tor_assert(to_state == CHANNEL_STATE_LISTENING || - to_state == CHANNEL_STATE_CLOSING || - to_state == CHANNEL_STATE_CLOSED || - to_state == CHANNEL_STATE_ERROR); - } else { - tor_assert(from_state != CHANNEL_STATE_LISTENING); - tor_assert(to_state != CHANNEL_STATE_LISTENING); - } - /* Check for no-op transitions */ if (from_state == to_state) { log_debug(LD_CHANNEL, - "Got no-op transition from \"%s\" to itself on channel %p", + "Got no-op transition from \"%s\" to itself on channel %p" + "(global ID " U64_FORMAT ")", channel_state_to_string(to_state), - chan); + chan, U64_PRINTF_ARG(chan->global_identifier)); return; } @@ -1482,8 +1735,10 @@ channel_change_state(channel_t *chan, channel_state_t to_state) */ log_debug(LD_CHANNEL, - "Changing state of channel %p from \"%s\" to \"%s\"", + "Changing state of channel %p (global ID " U64_FORMAT + ") from \"%s\" to \"%s\"", chan, + U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), channel_state_to_string(to_state)); @@ -1509,28 +1764,12 @@ channel_change_state(channel_t *chan, channel_state_t to_state) smartlist_add(active_channels, chan); } - was_listening = (from_state == CHANNEL_STATE_LISTENING); - is_listening = (to_state == CHANNEL_STATE_LISTENING); - - /* Need to put on listening list? */ - if (!was_listening && is_listening) { - if (!listening_channels) listening_channels = smartlist_new(); - smartlist_add(listening_channels, chan); - } - /* Need to remove from listening list? */ - else if (was_listening && !is_listening) { - if (listening_channels) smartlist_remove(listening_channels, chan); - } - - if (!(chan->is_listener) && - !tor_digest_is_zero(chan->u.cell_chan.identity_digest)) { + if (!tor_digest_is_zero(chan->identity_digest)) { /* Now we need to handle the identity map */ - was_in_id_map = !(from_state == CHANNEL_STATE_LISTENING || - from_state == CHANNEL_STATE_CLOSING || + was_in_id_map = !(from_state == CHANNEL_STATE_CLOSING || from_state == CHANNEL_STATE_CLOSED || from_state == CHANNEL_STATE_ERROR); - is_in_id_map = !(to_state == CHANNEL_STATE_LISTENING || - to_state == CHANNEL_STATE_CLOSING || + is_in_id_map = !(to_state == CHANNEL_STATE_CLOSING || to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR); @@ -1541,30 +1780,110 @@ channel_change_state(channel_t *chan, channel_state_t to_state) } /* Tell circuits if we opened and stuff */ - if (to_state == CHANNEL_STATE_OPEN) channel_do_open_actions(chan); + if (to_state == CHANNEL_STATE_OPEN) { + channel_do_open_actions(chan); - if (!(chan->is_listener) && - to_state == CHANNEL_STATE_OPEN) { /* Check for queued cells to process */ - if (chan->u.cell_chan.incoming_queue && - smartlist_len(chan->u.cell_chan.incoming_queue) > 0) + if (chan->incoming_queue && + smartlist_len(chan->incoming_queue) > 0) channel_process_cells(chan); - if (chan->u.cell_chan.outgoing_queue && - smartlist_len(chan->u.cell_chan.outgoing_queue) > 0) + if (chan->outgoing_queue && + smartlist_len(chan->outgoing_queue) > 0) channel_flush_cells(chan); } else if (to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR) { /* Assert that all queues are empty */ - if (chan->is_listener) { - tor_assert(!(chan->u.listener.incoming_list) || - smartlist_len(chan->u.listener.incoming_list) == 0); - } else { - tor_assert(!(chan->u.cell_chan.incoming_queue) || - smartlist_len(chan->u.cell_chan.incoming_queue) == 0); - tor_assert(!(chan->u.cell_chan.outgoing_queue) || - smartlist_len(chan->u.cell_chan.outgoing_queue) == 0); + tor_assert(!(chan->incoming_queue) || + smartlist_len(chan->incoming_queue) == 0); + tor_assert(!(chan->outgoing_queue) || + smartlist_len(chan->outgoing_queue) == 0); + } +} + +/** + * Change channel listener state + * + * This internal and subclass use only function is used to change channel + * listener state, performing all transition validity checks and whatever + * actions are appropriate to the state transition in question. + */ + +void +channel_listener_change_state(channel_listener_t *chan_l, + channel_listener_state_t to_state) +{ + channel_listener_state_t from_state; + unsigned char was_active, is_active; + + tor_assert(chan_l); + from_state = chan_l->state; + + tor_assert(channel_listener_state_is_valid(from_state)); + tor_assert(channel_listener_state_is_valid(to_state)); + tor_assert(channel_listener_state_can_transition(chan_l->state, to_state)); + + /* Check for no-op transitions */ + if (from_state == to_state) { + log_debug(LD_CHANNEL, + "Got no-op transition from \"%s\" to itself on channel " + "listener %p (global ID " U64_FORMAT ")", + channel_listener_state_to_string(to_state), + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + return; + } + + /* If we're going to a closing or closed state, we must have a reason set */ + if (to_state == CHANNEL_LISTENER_STATE_CLOSING || + to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR) { + tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING); + } + + /* + * We need to maintain the queues here for some transitions: + * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT) + * we may have a backlog of cells to transmit, so drain the queues in + * that case, and when going to CHANNEL_STATE_CLOSED the subclass + * should have made sure to finish sending things (or gone to + * CHANNEL_STATE_ERROR if not possible), so we assert for that here. + */ + + log_debug(LD_CHANNEL, + "Changing state of channel listener %p (global ID " U64_FORMAT + "from \"%s\" to \"%s\"", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + channel_listener_state_to_string(chan_l->state), + channel_listener_state_to_string(to_state)); + + chan_l->state = to_state; + + /* Need to add to the right lists if the channel listener is registered */ + if (chan_l->registered) { + was_active = !(from_state == CHANNEL_LISTENER_STATE_CLOSED || + from_state == CHANNEL_LISTENER_STATE_ERROR); + is_active = !(to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR); + + /* Need to take off active list and put on finished list? */ + if (was_active && !is_active) { + if (active_listeners) smartlist_remove(active_listeners, chan_l); + if (!finished_listeners) finished_listeners = smartlist_new(); + smartlist_add(finished_listeners, chan_l); + } + /* Need to put on active list? */ + else if (!was_active && is_active) { + if (finished_listeners) smartlist_remove(finished_listeners, chan_l); + if (!active_listeners) active_listeners = smartlist_new(); + smartlist_add(active_listeners, chan_l); } } + + if (to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR) { + /* Assert that the queue is empty */ + tor_assert(!(chan_l->incoming_list) || + smartlist_len(chan_l->incoming_list) == 0); + } } /** @@ -1586,7 +1905,6 @@ channel_flush_some_cells(channel_t *chan, ssize_t num_cells) int num_cells_from_circs; tor_assert(chan); - tor_assert(!(chan->is_listener)); if (num_cells < 0) unlimited = 1; if (!unlimited && num_cells <= flushed) goto done; @@ -1598,7 +1916,7 @@ channel_flush_some_cells(channel_t *chan, ssize_t num_cells) (unlimited ? -1 : num_cells - flushed)); if (!unlimited && num_cells <= flushed) goto done; - if (chan->u.cell_chan.active_circuits) { + if (chan->active_circuits) { /* Try to get more cells from any active circuits */ num_cells_from_circs = channel_flush_from_first_active_circuit(chan, @@ -1633,10 +1951,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, cell_queue_entry_t *q = NULL; tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.write_cell); - tor_assert(chan->u.cell_chan.write_packed_cell); - tor_assert(chan->u.cell_chan.write_var_cell); + tor_assert(chan->write_cell); + tor_assert(chan->write_packed_cell); + tor_assert(chan->write_var_cell); if (num_cells < 0) unlimited = 1; if (!unlimited && num_cells <= flushed) return 0; @@ -1644,15 +1961,15 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ if (chan->state == CHANNEL_STATE_OPEN) { while ((unlimited || num_cells > flushed) && - (chan->u.cell_chan.outgoing_queue && - (smartlist_len(chan->u.cell_chan.outgoing_queue) > 0))) { + (chan->outgoing_queue && + (smartlist_len(chan->outgoing_queue) > 0))) { /* * Ewww, smartlist_del_keeporder() is O(n) in list length; maybe a * a linked list would make more sense for the queue. */ /* Get the head of the queue */ - q = smartlist_get(chan->u.cell_chan.outgoing_queue, 0); + q = smartlist_get(chan->outgoing_queue, 0); if (q) { /* * Okay, we have a good queue entry, try to give it to the lower @@ -1661,60 +1978,63 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, switch (q->type) { case CELL_QUEUE_FIXED: if (q->u.fixed.cell) { - if (chan->u.cell_chan.write_cell(chan, + if (chan->write_cell(chan, q->u.fixed.cell)) { tor_free(q); ++flushed; channel_timestamp_xmit(chan); - ++(chan->u.cell_chan.n_cells_xmitted); + ++(chan->n_cells_xmitted); } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_FIXED " - "with no cell on channel %p.", - chan); + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ tor_free(q); } break; case CELL_QUEUE_PACKED: if (q->u.packed.packed_cell) { - if (chan->u.cell_chan.write_packed_cell(chan, + if (chan->write_packed_cell(chan, q->u.packed.packed_cell)) { tor_free(q); ++flushed; channel_timestamp_xmit(chan); - ++(chan->u.cell_chan.n_cells_xmitted); + ++(chan->n_cells_xmitted); } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_PACKED " - "with no cell on channel %p.", - chan); + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ tor_free(q); } break; case CELL_QUEUE_VAR: if (q->u.var.var_cell) { - if (chan->u.cell_chan.write_var_cell(chan, + if (chan->write_var_cell(chan, q->u.var.var_cell)) { tor_free(q); ++flushed; channel_timestamp_xmit(chan); - ++(chan->u.cell_chan.n_cells_xmitted); + ++(chan->n_cells_xmitted); } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_VAR " - "with no cell on channel %p.", - chan); + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ tor_free(q); } @@ -1722,30 +2042,31 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, default: /* Unknown type, log and free it */ log_info(LD_CHANNEL, - "Saw an unknown cell queue entry type %d on channel %p; " - "ignoring it. Someone should fix this.", - q->type, chan); + "Saw an unknown cell queue entry type %d on channel %p " + "(global ID " U64_FORMAT "; ignoring it." + " Someone should fix this.", + q->type, chan, U64_PRINTF_ARG(chan->global_identifier)); tor_free(q); /* tor_free() NULLs it out */ } } else { /* This shouldn't happen; log and throw it away */ log_info(LD_CHANNEL, - "Saw a NULL entry in the outgoing cell queue on channel %p; " - "this is definitely a bug.", - chan); + "Saw a NULL entry in the outgoing cell queue on channel %p " + "(global ID " U64_FORMAT "); this is definitely a bug.", + chan, U64_PRINTF_ARG(chan->global_identifier)); /* q is already NULL, so we know to delete that queue entry */ } /* if q got NULLed out, we used it and should remove the queue entry */ - if (!q) smartlist_del_keeporder(chan->u.cell_chan.outgoing_queue, 0); + if (!q) smartlist_del_keeporder(chan->outgoing_queue, 0); /* No cell removed from list, so we can't go on any further */ else break; } } /* Did we drain the queue? */ - if (!(chan->u.cell_chan.outgoing_queue) || - smartlist_len(chan->u.cell_chan.outgoing_queue) == 0) { + if (!(chan->outgoing_queue) || + smartlist_len(chan->outgoing_queue) == 0) { /* Timestamp it */ channel_timestamp_drained(chan); } @@ -1778,14 +2099,13 @@ int channel_more_to_flush(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); /* Check if we have any queued */ - if (chan->u.cell_chan.incoming_queue && - smartlist_len(chan->u.cell_chan.incoming_queue) > 0) return 1; + if (chan->incoming_queue && + smartlist_len(chan->incoming_queue) > 0) return 1; /* Check if any circuits would like to queue some */ - if (chan->u.cell_chan.active_circuits) return 1; + if (chan->active_circuits) return 1; /* Else no */ return 0; @@ -1802,10 +2122,9 @@ void channel_notify_flushed(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - if (chan->u.cell_chan.dirreq_id != 0) - geoip_change_dirreq_state(chan->u.cell_chan.dirreq_id, + if (chan->dirreq_id != 0) + geoip_change_dirreq_state(chan->dirreq_id, DIRREQ_TUNNELED, DIRREQ_CHANNEL_BUFFER_FLUSHED); } @@ -1818,32 +2137,31 @@ channel_notify_flushed(channel_t *chan) */ void -channel_process_incoming(channel_t *listener) +channel_listener_process_incoming(channel_listener_t *listener) { tor_assert(listener); - tor_assert(listener->is_listener); + /* - * CHANNEL_STATE_CLOSING permitted because we drain the queue while - * closing a listener. + * CHANNEL_LISTENER_STATE_CLOSING permitted because we drain the queue + * while closing a listener. */ - tor_assert(listener->state == CHANNEL_STATE_LISTENING || - listener->state == CHANNEL_STATE_CLOSING); - tor_assert(listener->u.listener.listener); + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING || + listener->state == CHANNEL_LISTENER_STATE_CLOSING); + tor_assert(listener->listener); log_debug(LD_CHANNEL, - "Processing queue of incoming connections for listening " - "channel %p (global ID " U64_FORMAT ")", + "Processing queue of incoming connections for channel " + "listener %p (global ID " U64_FORMAT ")", listener, U64_PRINTF_ARG(listener->global_identifier)); - if (!(listener->u.listener.incoming_list)) return; + if (!(listener->incoming_list)) return; - SMARTLIST_FOREACH_BEGIN(listener->u.listener.incoming_list, + SMARTLIST_FOREACH_BEGIN(listener->incoming_list, channel_t *, chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CHANNEL, - "Handling incoming connection %p (" U64_FORMAT ") " + "Handling incoming channel %p (" U64_FORMAT ") " "for listener %p (" U64_FORMAT ")", chan, U64_PRINTF_ARG(chan->global_identifier), @@ -1851,11 +2169,11 @@ channel_process_incoming(channel_t *listener) U64_PRINTF_ARG(listener->global_identifier)); /* Make sure this is set correctly */ channel_mark_incoming(chan); - listener->u.listener.listener(listener, chan); + listener->listener(listener, chan); } SMARTLIST_FOREACH_END(chan); - smartlist_free(listener->u.listener.incoming_list); - listener->u.listener.incoming_list = NULL; + smartlist_free(listener->incoming_list); + listener->incoming_list = NULL; } /** @@ -1879,15 +2197,14 @@ channel_do_open_actions(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - tor_assert(!(chan->is_listener)); started_here = channel_is_outgoing(chan); if (started_here) { circuit_build_times_network_is_live(&circ_times); - rep_hist_note_connect_succeeded(chan->u.cell_chan.identity_digest, now); + rep_hist_note_connect_succeeded(chan->identity_digest, now); if (entry_guard_register_connect_status( - chan->u.cell_chan.identity_digest, 1, 0, now) < 0) { + chan->identity_digest, 1, 0, now) < 0) { /* Close any circuits pending on this channel. We leave it in state * 'open' though, because it didn't actually *fail* -- we just * chose not to use it. */ @@ -1897,10 +2214,10 @@ channel_do_open_actions(channel_t *chan) circuit_n_chan_done(chan, 0); not_using = 1; } - router_set_status(chan->u.cell_chan.identity_digest, 1); + router_set_status(chan->identity_digest, 1); } else { /* only report it to the geoip module if it's not a known router */ - if (!router_get_by_id_digest(chan->u.cell_chan.identity_digest)) { + if (!router_get_by_id_digest(chan->identity_digest)) { if (channel_get_addr_if_possible(chan, &remote_addr)) { geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &remote_addr, now); @@ -1916,60 +2233,55 @@ channel_do_open_actions(channel_t *chan) * Queue an incoming channel on a listener * * Internal and subclass use only function to queue an incoming channel from - * a listening one. A subclass of channel_t should call this when a new + * a listener. A subclass of channel_listener_t should call this when a new * incoming channel is created. */ void -channel_queue_incoming(channel_t *listener, channel_t *incoming) +channel_listener_queue_incoming(channel_listener_t *listener, + channel_t *incoming) { int need_to_queue = 0; tor_assert(listener); - tor_assert(listener->is_listener); - tor_assert(listener->state == CHANNEL_STATE_LISTENING); + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING); tor_assert(incoming); - tor_assert(!(incoming->is_listener)); - /* - * Other states are permitted because subclass might process activity - * on a channel at any time while it's queued, but a listener returning - * another listener makes no sense. - */ - tor_assert(incoming->state != CHANNEL_STATE_LISTENING); log_debug(LD_CHANNEL, - "Queueing incoming channel %p on listening channel %p", - incoming, listener); + "Queueing incoming channel %p (global ID " U64_FORMAT ") on " + "channel listener %p (global ID " U64_FORMAT ")", + incoming, U64_PRINTF_ARG(incoming->global_identifier), + listener, U64_PRINTF_ARG(listener->global_identifier)); /* Do we need to queue it, or can we just call the listener right away? */ - if (!(listener->u.listener.listener)) need_to_queue = 1; - if (listener->u.listener.incoming_list && - (smartlist_len(listener->u.listener.incoming_list) > 0)) + if (!(listener->listener)) need_to_queue = 1; + if (listener->incoming_list && + (smartlist_len(listener->incoming_list) > 0)) need_to_queue = 1; /* If we need to queue and have no queue, create one */ - if (need_to_queue && !(listener->u.listener.incoming_list)) { - listener->u.listener.incoming_list = smartlist_new(); + if (need_to_queue && !(listener->incoming_list)) { + listener->incoming_list = smartlist_new(); } /* Bump the counter and timestamp it */ - channel_timestamp_active(listener); - channel_timestamp_accepted(listener); - ++(listener->u.listener.n_accepted); + channel_listener_timestamp_active(listener); + channel_listener_timestamp_accepted(listener); + ++(listener->n_accepted); /* If we don't need to queue, process it right away */ if (!need_to_queue) { - tor_assert(listener->u.listener.listener); - listener->u.listener.listener(listener, incoming); + tor_assert(listener->listener); + listener->listener(listener, incoming); } /* * Otherwise, we need to queue; queue and then process the queue if * we can. */ else { - tor_assert(listener->u.listener.incoming_list); - smartlist_add(listener->u.listener.incoming_list, incoming); - if (listener->u.listener.listener) channel_process_incoming(listener); + tor_assert(listener->incoming_list); + smartlist_add(listener->incoming_list, incoming); + if (listener->listener) channel_listener_process_incoming(listener); } } @@ -1984,7 +2296,6 @@ void channel_process_cells(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_MAINT || chan->state == CHANNEL_STATE_OPEN); @@ -1994,40 +2305,44 @@ channel_process_cells(channel_t *chan) chan); /* Nothing we can do if we have no registered cell handlers */ - if (!(chan->u.cell_chan.cell_handler || - chan->u.cell_chan.var_cell_handler)) return; + if (!(chan->cell_handler || + chan->var_cell_handler)) return; /* Nothing we can do if we have no cells */ - if (!(chan->u.cell_chan.incoming_queue)) return; + if (!(chan->incoming_queue)) return; /* * Process cells until we're done or find one we have no current handler * for. */ - SMARTLIST_FOREACH_BEGIN(chan->u.cell_chan.incoming_queue, + SMARTLIST_FOREACH_BEGIN(chan->incoming_queue, cell_queue_entry_t *, q) { tor_assert(q); tor_assert(q->type == CELL_QUEUE_FIXED || q->type == CELL_QUEUE_VAR); if (q->type == CELL_QUEUE_FIXED && - chan->u.cell_chan.cell_handler) { + chan->cell_handler) { /* Handle a fixed-length cell */ tor_assert(q->u.fixed.cell); log_debug(LD_CHANNEL, - "Processing incoming cell_t %p for channel %p", - q->u.fixed.cell, chan); - chan->u.cell_chan.cell_handler(chan, q->u.fixed.cell); - SMARTLIST_DEL_CURRENT(chan->u.cell_chan.incoming_queue, q); + "Processing incoming cell_t %p for channel %p (global ID " + U64_FORMAT ")", + q->u.fixed.cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->cell_handler(chan, q->u.fixed.cell); + SMARTLIST_DEL_CURRENT(chan->incoming_queue, q); tor_free(q); } else if (q->type == CELL_QUEUE_VAR && - chan->u.cell_chan.var_cell_handler) { + chan->var_cell_handler) { /* Handle a variable-length cell */ tor_assert(q->u.var.var_cell); log_debug(LD_CHANNEL, - "Processing incoming var_cell_t %p for channel %p", - q->u.var.var_cell, chan); - chan->u.cell_chan.var_cell_handler(chan, q->u.var.var_cell); - SMARTLIST_DEL_CURRENT(chan->u.cell_chan.incoming_queue, q); + "Processing incoming var_cell_t %p for channel %p (global ID " + U64_FORMAT ")", + q->u.var.var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->var_cell_handler(chan, q->u.var.var_cell); + SMARTLIST_DEL_CURRENT(chan->incoming_queue, q); tor_free(q); } else { /* Can't handle this one */ @@ -2036,9 +2351,9 @@ channel_process_cells(channel_t *chan) } SMARTLIST_FOREACH_END(q); /* If the list is empty, free it */ - if (smartlist_len(chan->u.cell_chan.incoming_queue) == 0 ) { - smartlist_free(chan->u.cell_chan.incoming_queue); - chan->u.cell_chan.incoming_queue = NULL; + if (smartlist_len(chan->incoming_queue) == 0 ) { + smartlist_free(chan->incoming_queue); + chan->incoming_queue = NULL; } } @@ -2056,46 +2371,49 @@ channel_queue_cell(channel_t *chan, cell_t *cell) cell_queue_entry_t *q; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(cell); tor_assert(chan->state == CHANNEL_STATE_OPEN); /* Do we need to queue it, or can we just call the handler right away? */ - if (!(chan->u.cell_chan.cell_handler)) need_to_queue = 1; - if (chan->u.cell_chan.incoming_queue && - (smartlist_len(chan->u.cell_chan.incoming_queue) > 0)) + if (!(chan->cell_handler)) need_to_queue = 1; + if (chan->incoming_queue && + (smartlist_len(chan->incoming_queue) > 0)) need_to_queue = 1; /* If we need to queue and have no queue, create one */ - if (need_to_queue && !(chan->u.cell_chan.incoming_queue)) { - chan->u.cell_chan.incoming_queue = smartlist_new(); + if (need_to_queue && !(chan->incoming_queue)) { + chan->incoming_queue = smartlist_new(); } /* Timestamp for receiving */ channel_timestamp_recv(chan); /* Update the counter */ - ++(chan->u.cell_chan.n_cells_recved); + ++(chan->n_cells_recved); /* If we don't need to queue we can just call cell_handler */ if (!need_to_queue) { - tor_assert(chan->u.cell_chan.cell_handler); + tor_assert(chan->cell_handler); log_debug(LD_CHANNEL, - "Directly handling incoming cell_t %p for channel %p", - cell, chan); - chan->u.cell_chan.cell_handler(chan, cell); + "Directly handling incoming cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->cell_handler(chan, cell); } else { /* Otherwise queue it and then process the queue if possible. */ - tor_assert(chan->u.cell_chan.incoming_queue); + tor_assert(chan->incoming_queue); q = tor_malloc(sizeof(*q)); q->type = CELL_QUEUE_FIXED; q->u.fixed.cell = cell; log_debug(LD_CHANNEL, - "Queueing incoming cell_t %p for channel %p", - cell, chan); - smartlist_add(chan->u.cell_chan.incoming_queue, q); - if (chan->u.cell_chan.cell_handler || - chan->u.cell_chan.var_cell_handler) { + "Queueing incoming cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + smartlist_add(chan->incoming_queue, q); + if (chan->cell_handler || + chan->var_cell_handler) { channel_process_cells(chan); } } @@ -2115,46 +2433,49 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) cell_queue_entry_t *q; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(var_cell); tor_assert(chan->state == CHANNEL_STATE_OPEN); /* Do we need to queue it, or can we just call the handler right away? */ - if (!(chan->u.cell_chan.var_cell_handler)) need_to_queue = 1; - if (chan->u.cell_chan.incoming_queue && - (smartlist_len(chan->u.cell_chan.incoming_queue) > 0)) + if (!(chan->var_cell_handler)) need_to_queue = 1; + if (chan->incoming_queue && + (smartlist_len(chan->incoming_queue) > 0)) need_to_queue = 1; /* If we need to queue and have no queue, create one */ - if (need_to_queue && !(chan->u.cell_chan.incoming_queue)) { - chan->u.cell_chan.incoming_queue = smartlist_new(); + if (need_to_queue && !(chan->incoming_queue)) { + chan->incoming_queue = smartlist_new(); } /* Timestamp for receiving */ channel_timestamp_recv(chan); /* Update the counter */ - ++(chan->u.cell_chan.n_cells_recved); + ++(chan->n_cells_recved); /* If we don't need to queue we can just call cell_handler */ if (!need_to_queue) { - tor_assert(chan->u.cell_chan.var_cell_handler); + tor_assert(chan->var_cell_handler); log_debug(LD_CHANNEL, - "Directly handling incoming var_cell_t %p for channel %p", - var_cell, chan); - chan->u.cell_chan.var_cell_handler(chan, var_cell); + "Directly handling incoming var_cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->var_cell_handler(chan, var_cell); } else { /* Otherwise queue it and then process the queue if possible. */ - tor_assert(chan->u.cell_chan.incoming_queue); + tor_assert(chan->incoming_queue); q = tor_malloc(sizeof(*q)); q->type = CELL_QUEUE_VAR; q->u.var.var_cell = var_cell; log_debug(LD_CHANNEL, - "Queueing incoming var_cell_t %p for channel %p", - var_cell, chan); - smartlist_add(chan->u.cell_chan.incoming_queue, q); - if (chan->u.cell_chan.cell_handler || - chan->u.cell_chan.var_cell_handler) { + "Queueing incoming var_cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + smartlist_add(chan->incoming_queue, q); + if (chan->cell_handler || + chan->var_cell_handler) { channel_process_cells(chan); } } @@ -2174,13 +2495,16 @@ channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) cell_t cell; tor_assert(chan); - tor_assert(!(chan->is_listener)); memset(&cell, 0, sizeof(cell_t)); cell.circ_id = circ_id; cell.command = CELL_DESTROY; cell.payload[0] = (uint8_t) reason; - log_debug(LD_OR,"Sending destroy (circID %d).", circ_id); + log_debug(LD_OR, + "Sending destroy (circID %d) on channel %p " + "(global ID " U64_FORMAT ")", + circ_id, chan, + U64_PRINTF_ARG(chan->global_identifier)); channel_write_cell(chan, &cell); @@ -2202,23 +2526,52 @@ channel_dumpstats(int severity) "Dumping statistics about %d channels:", smartlist_len(all_channels)); log(severity, LD_GENERAL, - "%d are active, %d are listeners, and %d are done and " - "waiting for cleanup", + "%d are active, and %d are done and waiting for cleanup", (active_channels != NULL) ? smartlist_len(active_channels) : 0, - (listening_channels != NULL) ? - smartlist_len(listening_channels) : 0, (finished_channels != NULL) ? smartlist_len(finished_channels) : 0); - SMARTLIST_FOREACH(all_channels, channel_t *, chan, - channel_dump_statistics(chan, severity)); + SMARTLIST_FOREACH(all_channels, channel_t *, chan, + channel_dump_statistics(chan, severity)); + + log(severity, LD_GENERAL, + "Done spamming about channels now"); + } else { + log(severity, LD_GENERAL, + "No channels to dump"); + } +} + +/** + * Dump channel listener statistics to the log + * + * This is called from dumpstats() in main.c and spams the log with + * statistics on channel listeners. + */ + +void +channel_listener_dumpstats(int severity) +{ + if (all_listeners && smartlist_len(all_listeners) > 0) { + log(severity, LD_GENERAL, + "Dumping statistics about %d channel listeners:", + smartlist_len(all_listeners)); + log(severity, LD_GENERAL, + "%d are active and %d are done and waiting for cleanup", + (active_listeners != NULL) ? + smartlist_len(active_listeners) : 0, + (finished_listeners != NULL) ? + smartlist_len(finished_listeners) : 0); + + SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l, + channel_listener_dump_statistics(chan_l, severity)); log(severity, LD_GENERAL, - "Done spamming about channels now"); + "Done spamming about channel listeners now"); } else { log(severity, LD_GENERAL, - "No channels to dump"); + "No channel listeners to dump"); } } @@ -2249,6 +2602,91 @@ channel_run_cleanup(void) } SMARTLIST_FOREACH_END(curr); } +/** + * Clean up channel listeners + * + * This gets called periodically from run_scheduled_events() in main.c; + * it cleans up after closed channel listeners. + */ + +void +channel_listener_run_cleanup(void) +{ + channel_listener_t *tmp = NULL; + + /* Check if we need to do anything */ + if (!finished_listeners || smartlist_len(finished_listeners) == 0) return; + + /* Iterate through finished_channels and get rid of them */ + SMARTLIST_FOREACH_BEGIN(finished_listeners, channel_listener_t *, curr) { + tmp = curr; + /* Remove it from the list */ + SMARTLIST_DEL_CURRENT(finished_listeners, curr); + /* Also unregister it */ + channel_listener_unregister(tmp); + /* ... and free it */ + channel_listener_free(tmp); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Free a list of channels for channel_free_all() + */ + +static void +channel_free_list(smartlist_t *channels, int mark_for_close) +{ + if (!channels) return; + + SMARTLIST_FOREACH_BEGIN(channels, channel_t *, curr) { + /* Deregister and free it */ + tor_assert(curr); + log_debug(LD_CHANNEL, + "Cleaning up channel %p (global ID " U64_FORMAT ") " + "in state %s (%d)", + curr, U64_PRINTF_ARG(curr->global_identifier), + channel_state_to_string(curr->state), curr->state); + channel_unregister(curr); + if (mark_for_close) { + if (!(curr->state == CHANNEL_STATE_CLOSING || + curr->state == CHANNEL_STATE_CLOSED || + curr->state == CHANNEL_STATE_ERROR)) { + channel_mark_for_close(curr); + } + channel_force_free(curr); + } else channel_free(curr); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Free a list of channel listeners for channel_free_all() + */ + +static void +channel_listener_free_list(smartlist_t *listeners, int mark_for_close) +{ + if (!listeners) return; + + SMARTLIST_FOREACH_BEGIN(listeners, channel_listener_t *, curr) { + /* Deregister and free it */ + tor_assert(curr); + log_debug(LD_CHANNEL, + "Cleaning up channel listener %p (global ID " U64_FORMAT ") " + "in state %s (%d)", + curr, U64_PRINTF_ARG(curr->global_identifier), + channel_listener_state_to_string(curr->state), curr->state); + channel_listener_unregister(curr); + if (mark_for_close) { + if (!(curr->state == CHANNEL_LISTENER_STATE_CLOSING || + curr->state == CHANNEL_LISTENER_STATE_CLOSED || + curr->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_mark_for_close(curr); + } + channel_listener_force_free(curr); + } else channel_listener_free(curr); + } SMARTLIST_FOREACH_END(curr); +} + /** * Close all channels and free everything * @@ -2266,91 +2704,46 @@ channel_free_all(void) /* First, let's go for finished channels */ if (finished_channels) { - SMARTLIST_FOREACH_BEGIN(finished_channels, channel_t *, curr) { - /* Deregister and free it */ - tor_assert(curr); - log_debug(LD_CHANNEL, - "Cleaning up finished channel %p (ID " U64_FORMAT ") " - "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), - channel_state_to_string(curr->state), curr->state); - channel_unregister(curr); - channel_free(curr); - } SMARTLIST_FOREACH_END(curr); - + channel_free_list(finished_channels, 0); smartlist_free(finished_channels); finished_channels = NULL; } - /* Now the listeners */ - if (listening_channels) { - SMARTLIST_FOREACH_BEGIN(listening_channels, channel_t *, curr) { - /* Close, deregister and free it */ - tor_assert(curr); - log_debug(LD_CHANNEL, - "Cleaning up listening channel %p (ID " U64_FORMAT ") " - "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), - channel_state_to_string(curr->state), curr->state); - /* - * We have to unregister first so we don't put it in finished_channels - * and allocate that again on close. - */ - channel_unregister(curr); - channel_mark_for_close(curr); - channel_force_free(curr); - } SMARTLIST_FOREACH_END(curr); - - smartlist_free(listening_channels); - listening_channels = NULL; + /* Now the finished listeners */ + if (finished_listeners) { + channel_listener_free_list(finished_listeners, 0); + smartlist_free(finished_listeners); + finished_listeners = NULL; } /* Now all active channels */ if (active_channels) { - SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) { - /* Close, deregister and free it */ - tor_assert(curr); - log_debug(LD_CHANNEL, - "Cleaning up active channel %p (ID " U64_FORMAT ") " - "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), - channel_state_to_string(curr->state), curr->state); - /* - * We have to unregister first so we don't put it in finished_channels - * and allocate that again on close. - */ - channel_unregister(curr); - channel_mark_for_close(curr); - channel_force_free(curr); - } SMARTLIST_FOREACH_END(curr); - + channel_free_list(active_channels, 1); smartlist_free(active_channels); active_channels = NULL; } + /* Now all active listeners */ + if (active_listeners) { + channel_listener_free_list(active_listeners, 1); + smartlist_free(active_listeners); + active_listeners = NULL; + } + /* Now all channels, in case any are left over */ if (all_channels) { - SMARTLIST_FOREACH_BEGIN(all_channels, channel_t *, curr) { - /* Close, deregister and free it */ - tor_assert(curr); - log_debug(LD_CHANNEL, - "Cleaning up leftover channel %p (ID " U64_FORMAT ") " - "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), - channel_state_to_string(curr->state), curr->state); - channel_unregister(curr); - if (!(curr->state == CHANNEL_STATE_CLOSING || - curr->state == CHANNEL_STATE_CLOSED || - curr->state == CHANNEL_STATE_ERROR)) { - channel_mark_for_close(curr); - } - channel_force_free(curr); - } SMARTLIST_FOREACH_END(curr); - + channel_free_list(all_channels, 1); smartlist_free(all_channels); all_channels = NULL; } + /* Now all listeners, in case any are left over */ + if (all_listeners) { + channel_listener_free_list(all_listeners, 1); + smartlist_free(all_listeners); + all_listeners = NULL; + } + /* Now free channel_identity_map */ if (channel_identity_map) { log_debug(LD_CHANNEL, @@ -2409,8 +2802,6 @@ channel_is_better(time_t now, channel_t *a, channel_t *b, tor_assert(a); tor_assert(b); - tor_assert(!(a->is_listener)); - tor_assert(!(b->is_listener)); /* Check if one is canonical and the other isn't first */ a_is_canonical = channel_is_canonical(a); @@ -2426,8 +2817,8 @@ channel_is_better(time_t now, channel_t *a, channel_t *b, * one that has no circuits is in its grace period. */ - a_has_circs = (a->u.cell_chan.n_circuits > 0); - b_has_circs = (b->u.cell_chan.n_circuits > 0); + a_has_circs = (a->n_circuits > 0); + b_has_circs = (b->n_circuits > 0); a_grace = (forgive_new_connections && (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD)); b_grace = (forgive_new_connections && @@ -2479,14 +2870,12 @@ channel_get_for_extend(const char *digest, * iteration. */ for (; chan; chan = channel_next_with_digest(chan)) { - tor_assert(!(chan->is_listener)); - tor_assert(tor_memeq(chan->u.cell_chan.identity_digest, + tor_assert(tor_memeq(chan->identity_digest, digest, DIGEST_LEN)); if (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || - chan->state == CHANNEL_STATE_ERROR || - chan->state == CHANNEL_STATE_LISTENING) + chan->state == CHANNEL_STATE_ERROR) continue; /* Never return a channel on which the other end appears to be @@ -2562,7 +2951,7 @@ channel_get_for_extend(const char *digest, } /** - * Describe the transport subclass + * Describe the transport subclass for a channel * * Invoke a method to get a string description of the lower-layer * transport for this channel. @@ -2577,6 +2966,22 @@ channel_describe_transport(channel_t *chan) return chan->describe_transport(chan); } +/** + * Describe the transport subclass for a channel listener + * + * Invoke a method to get a string description of the lower-layer + * transport for this channel listener. + */ + +const char * +channel_listener_describe_transport(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + tor_assert(chan_l->describe_transport); + + return chan_l->describe_transport(chan_l); +} + /** * Dump channel statistics * @@ -2598,13 +3003,10 @@ channel_dump_statistics(channel_t *chan, int severity) log(severity, LD_GENERAL, "Channel " U64_FORMAT " (at %p) with transport %s is in state " - "%s (%d) and %s", + "%s (%d)", U64_PRINTF_ARG(chan->global_identifier), chan, channel_describe_transport(chan), - channel_state_to_string(chan->state), chan->state, - chan->is_listener ? - "listens for incoming connections" : - "transports cells"); + channel_state_to_string(chan->state), chan->state); log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was created at " U64_FORMAT " (" U64_FORMAT " seconds ago) " @@ -2614,204 +3016,239 @@ channel_dump_statistics(channel_t *chan, int severity) U64_PRINTF_ARG(now - chan->timestamp_created), U64_PRINTF_ARG(chan->timestamp_active), U64_PRINTF_ARG(now - chan->timestamp_active)); - if (chan->is_listener) { + + /* Handle digest and nickname */ + if (!tor_digest_is_zero(chan->identity_digest)) { + if (chan->nickname) { + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and nickname %s", + U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN), + chan->nickname); + } else { + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and no known nickname", + U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN)); + } + } else { + if (chan->nickname) { + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know the digest" + " of the OR it is connected to, but reports its nickname is %s", + U64_PRINTF_ARG(chan->global_identifier), + chan->nickname); + } else { + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know the digest" + " or the nickname of the OR it is connected to", + U64_PRINTF_ARG(chan->global_identifier)); + } + } + + /* Handle remote address and descriptions */ + have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); + if (have_remote_addr) { + remote_addr_str = tor_dup_addr(&remote_addr); log(severity, LD_GENERAL, - " * Listener channel " U64_FORMAT " last accepted an incoming " - "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " - "and has accepted " U64_FORMAT " channels in total", + " * Channel " U64_FORMAT " says its remote address" + " is %s, and gives a canonical description of \"%s\" and an " + "actual description of \"%s\"", + U64_PRINTF_ARG(chan->global_identifier), + remote_addr_str, + channel_get_canonical_remote_descr(chan), + channel_get_actual_remote_descr(chan)); + tor_free(remote_addr_str); + } else { + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know its remote " + "address, but gives a canonical description of \"%s\" and an " + "actual description of \"%s\"", U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.listener.timestamp_accepted), - U64_PRINTF_ARG(now - chan->u.listener.timestamp_accepted), - U64_PRINTF_ARG(chan->u.listener.n_accepted)); + channel_get_canonical_remote_descr(chan), + channel_get_actual_remote_descr(chan)); + } - /* - * If it's sensible to do so, get the rate of incoming channels on this - * listener - */ - if (now > chan->timestamp_created && - chan->timestamp_created > 0 && - chan->u.listener.n_accepted > 0) { - avg = (double)(chan->u.listener.n_accepted) / age; + /* Handle marks */ + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has these marks: %s %s %s " + "%s %s %s", + U64_PRINTF_ARG(chan->global_identifier), + channel_is_bad_for_new_circs(chan) ? + "bad_for_new_circs" : "!bad_for_new_circs", + channel_is_canonical(chan) ? + "canonical" : "!canonical", + channel_is_canonical_is_reliable(chan) ? + "is_canonical_is_reliable" : + "!is_canonical_is_reliable", + channel_is_client(chan) ? + "client" : "!client", + channel_is_local(chan) ? + "local" : "!local", + channel_is_incoming(chan) ? + "incoming" : "outgoing"); + + /* Describe queues */ + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has %d queued incoming cells" + " and %d queued outgoing cells", + U64_PRINTF_ARG(chan->global_identifier), + (chan->incoming_queue != NULL) ? + smartlist_len(chan->incoming_queue) : 0, + (chan->outgoing_queue != NULL) ? + smartlist_len(chan->outgoing_queue) : 0); + + /* Describe circuits */ + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has %d active circuits out of" + " %d in total", + U64_PRINTF_ARG(chan->global_identifier), + (chan->active_circuit_pqueue != NULL) ? + smartlist_len(chan->active_circuit_pqueue) : 0, + chan->n_circuits); + + /* Describe timestamps */ + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " was last used by a " + "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_client), + U64_PRINTF_ARG(now - chan->timestamp_client)); + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " was last drained at " + U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_drained), + U64_PRINTF_ARG(now - chan->timestamp_drained)); + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " last received a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_recv), + U64_PRINTF_ARG(now - chan->timestamp_recv)); + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " last trasmitted a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_xmit), + U64_PRINTF_ARG(now - chan->timestamp_xmit)); + + /* Describe counters and rates */ + log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has received " + U64_FORMAT " cells and transmitted " U64_FORMAT, + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->n_cells_recved), + U64_PRINTF_ARG(chan->n_cells_xmitted)); + if (now > chan->timestamp_created && + chan->timestamp_created > 0) { + if (chan->n_cells_recved > 0) { + avg = (double)(chan->n_cells_recved) / age; if (avg >= 1.0) { log(severity, LD_GENERAL, - " * Listener channel " U64_FORMAT " has averaged %f incoming " - "channels per second", + " * Channel " U64_FORMAT " has averaged %f " + "cells received per second", U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; log(severity, LD_GENERAL, - " * Listener channel " U64_FORMAT " has averaged %f seconds " - "between incoming channels", + " * Channel " U64_FORMAT " has averaged %f " + "seconds between received cells", U64_PRINTF_ARG(chan->global_identifier), interval); } } - } else { - /* Handle digest and nickname */ - if (!tor_digest_is_zero(chan->u.cell_chan.identity_digest)) { - if (chan->u.cell_chan.nickname) { - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " says it is connected " - "to an OR with digest %s and nickname %s", - U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN), - chan->u.cell_chan.nickname); - } else { - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " says it is connected " - "to an OR with digest %s and no known nickname", - U64_PRINTF_ARG(chan->global_identifier), - hex_str(chan->u.cell_chan.identity_digest, DIGEST_LEN)); - } - } else { - if (chan->u.cell_chan.nickname) { + if (chan->n_cells_xmitted > 0) { + avg = (double)(chan->n_cells_xmitted) / age; + if (avg >= 1.0) { log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " does not know the digest" - " of the OR it is connected to, but reports its nickname is %s", - U64_PRINTF_ARG(chan->global_identifier), - chan->u.cell_chan.nickname); - } else { + " * Channel " U64_FORMAT " has averaged %f " + "cells transmitted per second", + U64_PRINTF_ARG(chan->global_identifier), avg); + } else if (avg >= 0.0) { + interval = 1.0 / avg; log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " does not know the digest" - " or the nickname of the OR it is connected to", - U64_PRINTF_ARG(chan->global_identifier)); + " * Channel " U64_FORMAT " has averaged %f " + "seconds between transmitted cells", + U64_PRINTF_ARG(chan->global_identifier), interval); } } + } - /* Handle remote address and descriptions */ - have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); - if (have_remote_addr) { - remote_addr_str = tor_dup_addr(&remote_addr); - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " says its remote address" - " is %s, and gives a canonical description of \"%s\" and an " - "actual description of \"%s\"", - U64_PRINTF_ARG(chan->global_identifier), - remote_addr_str, - channel_get_canonical_remote_descr(chan), - channel_get_actual_remote_descr(chan)); - tor_free(remote_addr_str); - } else { - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " does not know its remote " - "address, but gives a canonical description of \"%s\" and an " - "actual description of \"%s\"", - U64_PRINTF_ARG(chan->global_identifier), - channel_get_canonical_remote_descr(chan), - channel_get_actual_remote_descr(chan)); - } + /* Dump anything the lower layer has to say */ + channel_dump_transport_statistics(chan, severity); +} - /* Handle marks */ - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has these marks: %s %s %s " - "%s %s %s", - U64_PRINTF_ARG(chan->global_identifier), - channel_is_bad_for_new_circs(chan) ? - "bad_for_new_circs" : "!bad_for_new_circs", - channel_is_canonical(chan) ? - "canonical" : "!canonical", - channel_is_canonical_is_reliable(chan) ? - "is_canonical_is_reliable" : - "!is_canonical_is_reliable", - channel_is_client(chan) ? - "client" : "!client", - channel_is_local(chan) ? - "local" : "!local", - channel_is_incoming(chan) ? - "incoming" : "outgoing"); - - /* Describe queues */ - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has %d queued incoming cells" - " and %d queued outgoing cells", - U64_PRINTF_ARG(chan->global_identifier), - (chan->u.cell_chan.incoming_queue != NULL) ? - smartlist_len(chan->u.cell_chan.incoming_queue) : 0, - (chan->u.cell_chan.outgoing_queue != NULL) ? - smartlist_len(chan->u.cell_chan.outgoing_queue) : 0); +/** + * Dump channel listener statistics + * + * Dump statistics for one channel listener to the log + */ - /* Describe circuits */ - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has %d active circuits out of" - " %d in total", - U64_PRINTF_ARG(chan->global_identifier), - (chan->u.cell_chan.active_circuit_pqueue != NULL) ? - smartlist_len(chan->u.cell_chan.active_circuit_pqueue) : 0, - chan->u.cell_chan.n_circuits); +void +channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) +{ + double avg, interval, age; + time_t now = time(NULL); - /* Describe timestamps */ - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " was last used by a " - "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.cell_chan.timestamp_client), - U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_client)); - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " was last drained at " - U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.cell_chan.timestamp_drained), - U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_drained)); - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " last received a cell " - "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.cell_chan.timestamp_recv), - U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_recv)); - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " last trasmitted a cell " - "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.cell_chan.timestamp_xmit), - U64_PRINTF_ARG(now - chan->u.cell_chan.timestamp_xmit)); + tor_assert(chan_l); - /* Describe counters and rates */ - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has received " - U64_FORMAT " cells and transmitted " U64_FORMAT, - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->u.cell_chan.n_cells_recved), - U64_PRINTF_ARG(chan->u.cell_chan.n_cells_xmitted)); - if (now > chan->timestamp_created && - chan->timestamp_created > 0) { - if (chan->u.cell_chan.n_cells_recved > 0) { - avg = (double)(chan->u.cell_chan.n_cells_recved) / age; - if (avg >= 1.0) { - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has averaged %f " - "cells received per second", - U64_PRINTF_ARG(chan->global_identifier), avg); - } else if (avg >= 0.0) { - interval = 1.0 / avg; - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has averaged %f " - "seconds between received cells", - U64_PRINTF_ARG(chan->global_identifier), interval); - } - } - if (chan->u.cell_chan.n_cells_xmitted > 0) { - avg = (double)(chan->u.cell_chan.n_cells_xmitted) / age; - if (avg >= 1.0) { - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has averaged %f " - "cells transmitted per second", - U64_PRINTF_ARG(chan->global_identifier), avg); - } else if (avg >= 0.0) { - interval = 1.0 / avg; - log(severity, LD_GENERAL, - " * Cell-bearing channel " U64_FORMAT " has averaged %f " - "seconds between transmitted cells", - U64_PRINTF_ARG(chan->global_identifier), interval); - } - } + age = (double)(now - chan_l->timestamp_created); + + log(severity, LD_GENERAL, + "Channel listener " U64_FORMAT " (at %p) with transport %s is in " + "state %s (%d)", + U64_PRINTF_ARG(chan_l->global_identifier), chan_l, + channel_listener_describe_transport(chan_l), + channel_listener_state_to_string(chan_l->state), chan_l->state); + log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " was created at " U64_FORMAT + " (" U64_FORMAT " seconds ago) " + "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan_l->global_identifier), + U64_PRINTF_ARG(chan_l->timestamp_created), + U64_PRINTF_ARG(now - chan_l->timestamp_created), + U64_PRINTF_ARG(chan_l->timestamp_active), + U64_PRINTF_ARG(now - chan_l->timestamp_active)); + + log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " last accepted an incoming " + "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " + "and has accepted " U64_FORMAT " channels in total", + U64_PRINTF_ARG(chan_l->global_identifier), + U64_PRINTF_ARG(chan_l->timestamp_accepted), + U64_PRINTF_ARG(now - chan_l->timestamp_accepted), + U64_PRINTF_ARG(chan_l->n_accepted)); + + /* + * If it's sensible to do so, get the rate of incoming channels on this + * listener + */ + if (now > chan_l->timestamp_created && + chan_l->timestamp_created > 0 && + chan_l->n_accepted > 0) { + avg = (double)(chan_l->n_accepted) / age; + if (avg >= 1.0) { + log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " has averaged %f incoming " + "channels per second", + U64_PRINTF_ARG(chan_l->global_identifier), avg); + } else if (avg >= 0.0) { + interval = 1.0 / avg; + log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " has averaged %f seconds " + "between incoming channels", + U64_PRINTF_ARG(chan_l->global_identifier), interval); } } /* Dump anything the lower layer has to say */ - channel_dump_transport_statistics(chan, severity); + channel_listener_dump_transport_statistics(chan_l, severity); } /** - * Invoke transport-specific stats dump + * Invoke transport-specific stats dump for channel * * If there is a lower-layer statistics dump method, invoke it */ @@ -2824,6 +3261,21 @@ channel_dump_transport_statistics(channel_t *chan, int severity) if (chan->dumpstats) chan->dumpstats(chan, severity); } +/** + * Invoke transport-specific stats dump for channel listener + * + * If there is a lower-layer statistics dump method, invoke it + */ + +void +channel_listener_dump_transport_statistics(channel_listener_t *chan_l, + int severity) +{ + tor_assert(chan_l); + + if (chan_l->dumpstats) chan_l->dumpstats(chan_l, severity); +} + /** * Return text description of the remote endpoint * @@ -2836,11 +3288,10 @@ const char * channel_get_actual_remote_descr(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.get_remote_descr); + tor_assert(chan->get_remote_descr); /* Param 1 indicates the actual description */ - return chan->u.cell_chan.get_remote_descr(chan, 1); + return chan->get_remote_descr(chan, 1); } /** @@ -2855,11 +3306,10 @@ const char * channel_get_canonical_remote_descr(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.get_remote_descr); + tor_assert(chan->get_remote_descr); /* Param 0 indicates the canonicalized description */ - return chan->u.cell_chan.get_remote_descr(chan, 0); + return chan->get_remote_descr(chan, 0); } /** @@ -2873,11 +3323,10 @@ int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out) { tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(addr_out); - if (chan->u.cell_chan.get_remote_addr) - return chan->u.cell_chan.get_remote_addr(chan, addr_out); + if (chan->get_remote_addr) + return chan->get_remote_addr(chan, addr_out); /* Else no support, method not implemented */ else return 0; } @@ -2895,15 +3344,14 @@ channel_has_queued_writes(channel_t *chan) int has_writes = 0; tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.has_queued_writes); + tor_assert(chan->has_queued_writes); - if (chan->u.cell_chan.outgoing_queue && - smartlist_len(chan->u.cell_chan.outgoing_queue) > 0) { + if (chan->outgoing_queue && + smartlist_len(chan->outgoing_queue) > 0) { has_writes = 1; } else { /* Check with the lower layer */ - has_writes = chan->u.cell_chan.has_queued_writes(chan); + has_writes = chan->has_queued_writes(chan); } return has_writes; @@ -2920,9 +3368,8 @@ int channel_is_bad_for_new_circs(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.is_bad_for_new_circs; + return chan->is_bad_for_new_circs; } /** @@ -2935,9 +3382,8 @@ void channel_mark_bad_for_new_circs(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.is_bad_for_new_circs = 1; + chan->is_bad_for_new_circs = 1; } /** @@ -2952,9 +3398,8 @@ int channel_is_client(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.is_client; + return chan->is_client; } /** @@ -2967,9 +3412,8 @@ void channel_mark_client(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.is_client = 1; + chan->is_client = 1; } /** @@ -2983,10 +3427,9 @@ int channel_is_canonical(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.is_canonical); + tor_assert(chan->is_canonical); - return chan->u.cell_chan.is_canonical(chan, 0); + return chan->is_canonical(chan, 0); } /** @@ -3000,10 +3443,9 @@ int channel_is_canonical_is_reliable(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.is_canonical); + tor_assert(chan->is_canonical); - return chan->u.cell_chan.is_canonical(chan, 1); + return chan->is_canonical(chan, 1); } /** @@ -3017,9 +3459,8 @@ int channel_is_incoming(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.is_incoming; + return chan->is_incoming; } /** @@ -3033,9 +3474,8 @@ void channel_mark_incoming(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.is_incoming = 1; + chan->is_incoming = 1; } /** @@ -3052,9 +3492,8 @@ int channel_is_local(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.is_local; + return chan->is_local; } /** @@ -3069,9 +3508,8 @@ void channel_mark_local(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.is_local = 1; + chan->is_local = 1; } /** @@ -3086,9 +3524,8 @@ int channel_is_outgoing(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return !(chan->u.cell_chan.is_incoming); + return !(chan->is_incoming); } /** @@ -3102,9 +3539,8 @@ void channel_mark_outgoing(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.is_incoming = 0; + chan->is_incoming = 0; } /********************* @@ -3112,7 +3548,7 @@ channel_mark_outgoing(channel_t *chan) ********************/ /** - * Update the created timestamp + * Update the created timestamp for a channel * * This updates the channel's created timestamp and should only be called * from channel_init(). @@ -3129,7 +3565,24 @@ channel_timestamp_created(channel_t *chan) } /** - * Update the last active timestamp. + * Update the created timestamp for a channel listener + * + * This updates the channel listener's created timestamp and should only be + * called from channel_init_listener(). + */ + +void +channel_listener_timestamp_created(channel_listener_t *chan_l) +{ + time_t now = time(NULL); + + tor_assert(chan_l); + + chan_l->timestamp_created = now; +} + +/** + * Update the last active timestamp for a channel * * This function updates the channel's last active timestamp; it should be * called by the lower layer whenever there is activity on the channel which @@ -3149,22 +3602,37 @@ channel_timestamp_active(channel_t *chan) chan->timestamp_active = now; } +/** + * Update the last active timestamp for a channel listener + */ + +void +channel_listener_timestamp_active(channel_listener_t *chan_l) +{ + time_t now = time(NULL); + + tor_assert(chan_l); + + chan_l->timestamp_active = now; +} + /** * Update the last accepted timestamp. * - * This function updates the channel's last accepted timestamp; it should be - * called whenever a new incoming channel is accepted on a listener. + * This function updates the channel listener's last accepted timestamp; it + * should be called whenever a new incoming channel is accepted on a + * listener. */ void -channel_timestamp_accepted(channel_t *chan) +channel_listener_timestamp_accepted(channel_listener_t *chan_l) { time_t now = time(NULL); - tor_assert(chan); - tor_assert(chan->is_listener); + tor_assert(chan_l); - chan->u.listener.timestamp_accepted = now; + chan_l->timestamp_active = now; + chan_l->timestamp_accepted = now; } /** @@ -3180,9 +3648,8 @@ channel_timestamp_client(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - tor_assert(!(chan->is_listener)); - chan->u.cell_chan.timestamp_client = now; + chan->timestamp_client = now; } /** @@ -3198,11 +3665,10 @@ channel_timestamp_drained(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - tor_assert(!(chan->is_listener)); chan->timestamp_active = now; - chan->u.cell_chan.timestamp_drained = now; - chan->u.cell_chan.timestamp_xmit = now; + chan->timestamp_drained = now; + chan->timestamp_xmit = now; } /** @@ -3218,10 +3684,9 @@ channel_timestamp_recv(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - tor_assert(!(chan->is_listener)); chan->timestamp_active = now; - chan->u.cell_chan.timestamp_recv = now; + chan->timestamp_recv = now; } /** @@ -3236,10 +3701,9 @@ channel_timestamp_xmit(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - tor_assert(!(chan->is_listener)); chan->timestamp_active = now; - chan->u.cell_chan.timestamp_xmit = now; + chan->timestamp_xmit = now; } /*************************************************************** @@ -3247,7 +3711,7 @@ channel_timestamp_xmit(channel_t *chan) **************************************************************/ /** - * Query created timestamp + * Query created timestamp for a channel */ time_t @@ -3259,7 +3723,19 @@ channel_when_created(channel_t *chan) } /** - * Query last active timestamp + * Query created timestamp for a channel listener + */ + +time_t +channel_listener_when_created(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return chan_l->timestamp_created; +} + +/** + * Query last active timestamp for a channel */ time_t @@ -3271,16 +3747,27 @@ channel_when_last_active(channel_t *chan) } /** - * Query last accepted timestamp + * Query last active timestamp for a channel listener */ time_t -channel_when_last_accepted(channel_t *chan) +channel_listener_when_last_active(channel_listener_t *chan_l) { - tor_assert(chan); - tor_assert(chan->is_listener); + tor_assert(chan_l); + + return chan_l->timestamp_active; +} + +/** + * Query last accepted timestamp for a channel listener + */ + +time_t +channel_listener_when_last_accepted(channel_listener_t *chan_l) +{ + tor_assert(chan_l); - return chan->u.listener.timestamp_accepted; + return chan_l->timestamp_accepted; } /** @@ -3291,9 +3778,8 @@ time_t channel_when_last_client(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.timestamp_client; + return chan->timestamp_client; } /** @@ -3304,9 +3790,8 @@ time_t channel_when_last_drained(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.timestamp_drained; + return chan->timestamp_drained; } /** @@ -3317,9 +3802,8 @@ time_t channel_when_last_recv(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.timestamp_recv; + return chan->timestamp_recv; } /** @@ -3330,9 +3814,8 @@ time_t channel_when_last_xmit(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return chan->u.cell_chan.timestamp_xmit; + return chan->timestamp_xmit; } /** @@ -3340,12 +3823,11 @@ channel_when_last_xmit(channel_t *chan) */ uint64_t -channel_count_accepted(channel_t *chan) +channel_listener_count_accepted(channel_listener_t *chan_l) { - tor_assert(chan); + tor_assert(chan_l); - if (chan->is_listener) return chan->u.listener.n_accepted; - else return 0; + return chan_l->n_accepted; } /** @@ -3357,8 +3839,7 @@ channel_count_recved(channel_t *chan) { tor_assert(chan); - if (!(chan->is_listener)) return chan->u.cell_chan.n_cells_recved; - else return 0; + return chan->n_cells_recved; } /** @@ -3370,8 +3851,7 @@ channel_count_xmitted(channel_t *chan) { tor_assert(chan); - if (!(chan->is_listener)) return chan->u.cell_chan.n_cells_xmitted; - else return 0; + return chan->n_cells_xmitted; } /** @@ -3385,11 +3865,10 @@ int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.matches_extend_info); + tor_assert(chan->matches_extend_info); tor_assert(extend_info); - return chan->u.cell_chan.matches_extend_info(chan, extend_info); + return chan->matches_extend_info(chan, extend_info); } /** @@ -3404,11 +3883,10 @@ channel_matches_target_addr_for_extend(channel_t *chan, const tor_addr_t *target) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - tor_assert(chan->u.cell_chan.matches_target); + tor_assert(chan->matches_target); tor_assert(target); - return chan->u.cell_chan.matches_target(chan, target); + return chan->matches_target(chan, target); } /** @@ -3425,7 +3903,6 @@ channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd) crypto_pk_t *our_identity; tor_assert(chan); - tor_assert(!(chan->is_listener)); started_here = channel_is_outgoing(chan); our_identity = started_here ? @@ -3433,12 +3910,12 @@ channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd) if (identity_rcvd) { if (crypto_pk_cmp_keys(our_identity, identity_rcvd) < 0) { - chan->u.cell_chan.circ_id_type = CIRC_ID_TYPE_LOWER; + chan->circ_id_type = CIRC_ID_TYPE_LOWER; } else { - chan->u.cell_chan.circ_id_type = CIRC_ID_TYPE_HIGHER; + chan->circ_id_type = CIRC_ID_TYPE_HIGHER; } } else { - chan->u.cell_chan.circ_id_type = CIRC_ID_TYPE_NEITHER; + chan->circ_id_type = CIRC_ID_TYPE_NEITHER; } } diff --git a/src/or/channel.h b/src/or/channel.h index 70ea30fcf1..c31806cbd4 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -12,7 +12,7 @@ #include "or.h" /* Channel handler function pointer typedefs */ -typedef void (*channel_listener_fn_ptr)(channel_t *, channel_t *); +typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); @@ -37,12 +37,6 @@ struct channel_s { /* Should we expect to see this channel in the channel lists? */ unsigned char registered:1; - /** Set this if this channel is created in CHANNEL_STATE_LISTEN, so - * lower-layer close methods that see the channel in CHANNEL_STATE_CLOSING - * know. - */ - unsigned int is_listener:1; - /** Why did we close? */ enum { @@ -67,171 +61,210 @@ struct channel_s { /* Optional method to dump transport-specific statistics on the channel */ void (*dumpstats)(channel_t *, int); - union { - struct { - /* Registered listen handler to call on incoming connection */ - channel_listener_fn_ptr listener; - - /* List of pending incoming connections */ - smartlist_t *incoming_list; - - /* Timestamps for listeners */ - time_t timestamp_accepted; - - /* Counters for listeners */ - uint64_t n_accepted; - } listener; - struct { - /* Registered handlers for incoming cells */ - channel_cell_handler_fn_ptr cell_handler; - channel_var_cell_handler_fn_ptr var_cell_handler; - - /* Methods implemented by the lower layer */ - - /* - * Ask the underlying transport what the remote endpoint address is, in - * a tor_addr_t. This is optional and subclasses may leave this NULL. - * If they implement it, they should write the address out to the - * provided tor_addr_t *, and return 1 if successful or 0 if no address - * available. - */ - int (*get_remote_addr)(channel_t *, tor_addr_t *); - /* - * Get a text description of the remote endpoint; canonicalized if the - * arg is 0, or the one we originally connected to/received from if it's - * 1. - */ - const char * (*get_remote_descr)(channel_t *, int); - /* Check if the lower layer has queued writes */ - int (*has_queued_writes)(channel_t *); - /* - * If the second param is zero, ask the lower layer if this is - * 'canonical', for a transport-specific definition of canonical; if - * it is 1, ask if the answer to the preceding query is safe to rely - * on. - */ - int (*is_canonical)(channel_t *, int); - /* Check if this channel matches a specified extend_info_t */ - int (*matches_extend_info)(channel_t *, extend_info_t *); - /* Check if this channel matches a target address when extending */ - int (*matches_target)(channel_t *, const tor_addr_t *); - /* Write a cell to an open channel */ - int (*write_cell)(channel_t *, cell_t *); - /* Write a packed cell to an open channel */ - int (*write_packed_cell)(channel_t *, packed_cell_t *); - /* Write a variable-length cell to an open channel */ - int (*write_var_cell)(channel_t *, var_cell_t *); - - /* - * Hash of the public RSA key for the other side's identity key, or - * zeroes if the other side hasn't shown us a valid identity key. - */ - char identity_digest[DIGEST_LEN]; - /* Nickname of the OR on the other side, or NULL if none. */ - char *nickname; - - /* - * Linked list of channels with the same identity digest, for the - * digest->channel map - */ - channel_t *next_with_same_id, *prev_with_same_id; - - /* List of incoming cells to handle */ - smartlist_t *incoming_queue; - - /* List of queued outgoing cells */ - smartlist_t *outgoing_queue; - - /* Circuit stuff for use by relay.c */ - - /* - * Double-linked ring of circuits with queued cells waiting for room to - * free up on this connection's outbuf. Every time we pull cells from - * a circuit, we advance this pointer to the next circuit in the ring. - */ - struct circuit_t *active_circuits; - /* - * Priority queue of cell_ewma_t for circuits with queued cells waiting - * for room to free up on this connection's outbuf. Kept in heap order - * according to EWMA. - * - * This is redundant with active_circuits; if we ever decide only to use - * the cell_ewma algorithm for choosing circuits, we can remove - * active_circuits. - */ - smartlist_t *active_circuit_pqueue; - /* - * The tick on which the cell_ewma_ts in active_circuit_pqueue last had - * their ewma values rescaled. - */ - unsigned active_circuit_pqueue_last_recalibrated; - - /* Circuit ID generation stuff for use by circuitbuild.c */ - - /* - * When we send CREATE cells along this connection, which half of the - * space should we use? - */ - circ_id_type_t circ_id_type:2; - /* - * Which circ_id do we try to use next on this connection? This is - * always in the range 0..1<<15-1. - */ - circid_t next_circ_id; - - /* How many circuits use this connection as p_chan or n_chan? */ - int n_circuits; - - /* - * True iff this channel shouldn't get any new circs attached to it, - * because the connection is too old, or because there's a better one. - * More generally, this flag is used to note an unhealthy connection; - * for example, if a bad connection fails we shouldn't assume that the - * router itself has a problem. - */ - unsigned int is_bad_for_new_circs:1; - - /** True iff we have decided that the other end of this connection - * is a client. Channels with this flag set should never be used - * to satisfy an EXTEND request. */ - unsigned int is_client:1; - - /** Set if the channel was initiated remotely (came from a listener) */ - unsigned int is_incoming:1; - - /** Set by lower layer if this is local; i.e., everything it communicates - * with for this channel returns true for is_local_addr(). This is used - * to decide whether to declare reachability when we receive something on - * this channel in circuitbuild.c - */ - unsigned int is_local:1; - - /** Channel timestamps for cell channels */ - time_t timestamp_client; /* Client used this, according to relay.c */ - time_t timestamp_drained; /* Output queue empty */ - time_t timestamp_recv; /* Cell received from lower layer */ - time_t timestamp_xmit; /* Cell sent to lower layer */ - - /* Timestamp for relay.c */ - time_t timestamp_last_added_nonpadding; - - /** Unique ID for measuring direct network status requests;vtunneled ones - * come over a circuit_t, which has a dirreq_id field as well, but is a - * distinct namespace. */ - uint64_t dirreq_id; - - /** Channel counters for cell channels */ - uint64_t n_cells_recved; - uint64_t n_cells_xmitted; - } cell_chan; - } u; + /* Registered handlers for incoming cells */ + channel_cell_handler_fn_ptr cell_handler; + channel_var_cell_handler_fn_ptr var_cell_handler; + + /* Methods implemented by the lower layer */ + + /* + * Ask the underlying transport what the remote endpoint address is, in + * a tor_addr_t. This is optional and subclasses may leave this NULL. + * If they implement it, they should write the address out to the + * provided tor_addr_t *, and return 1 if successful or 0 if no address + * available. + */ + int (*get_remote_addr)(channel_t *, tor_addr_t *); + /* + * Get a text description of the remote endpoint; canonicalized if the + * arg is 0, or the one we originally connected to/received from if it's + * 1. + */ + const char * (*get_remote_descr)(channel_t *, int); + /* Check if the lower layer has queued writes */ + int (*has_queued_writes)(channel_t *); + /* + * If the second param is zero, ask the lower layer if this is + * 'canonical', for a transport-specific definition of canonical; if + * it is 1, ask if the answer to the preceding query is safe to rely + * on. + */ + int (*is_canonical)(channel_t *, int); + /* Check if this channel matches a specified extend_info_t */ + int (*matches_extend_info)(channel_t *, extend_info_t *); + /* Check if this channel matches a target address when extending */ + int (*matches_target)(channel_t *, const tor_addr_t *); + /* Write a cell to an open channel */ + int (*write_cell)(channel_t *, cell_t *); + /* Write a packed cell to an open channel */ + int (*write_packed_cell)(channel_t *, packed_cell_t *); + /* Write a variable-length cell to an open channel */ + int (*write_var_cell)(channel_t *, var_cell_t *); + + /* + * Hash of the public RSA key for the other side's identity key, or + * zeroes if the other side hasn't shown us a valid identity key. + */ + char identity_digest[DIGEST_LEN]; + /* Nickname of the OR on the other side, or NULL if none. */ + char *nickname; + + /* + * Linked list of channels with the same identity digest, for the + * digest->channel map + */ + channel_t *next_with_same_id, *prev_with_same_id; + + /* List of incoming cells to handle */ + smartlist_t *incoming_queue; + + /* List of queued outgoing cells */ + smartlist_t *outgoing_queue; + + /* Circuit stuff for use by relay.c */ + + /* + * Double-linked ring of circuits with queued cells waiting for room to + * free up on this connection's outbuf. Every time we pull cells from + * a circuit, we advance this pointer to the next circuit in the ring. + */ + struct circuit_t *active_circuits; + /* + * Priority queue of cell_ewma_t for circuits with queued cells waiting + * for room to free up on this connection's outbuf. Kept in heap order + * according to EWMA. + * + * This is redundant with active_circuits; if we ever decide only to use + * the cell_ewma algorithm for choosing circuits, we can remove + * active_circuits. + */ + smartlist_t *active_circuit_pqueue; + /* + * The tick on which the cell_ewma_ts in active_circuit_pqueue last had + * their ewma values rescaled. + */ + unsigned active_circuit_pqueue_last_recalibrated; + + /* Circuit ID generation stuff for use by circuitbuild.c */ + + /* + * When we send CREATE cells along this connection, which half of the + * space should we use? + */ + circ_id_type_t circ_id_type:2; + /* + * Which circ_id do we try to use next on this connection? This is + * always in the range 0..1<<15-1. + */ + circid_t next_circ_id; + + /* How many circuits use this connection as p_chan or n_chan? */ + int n_circuits; + + /* + * True iff this channel shouldn't get any new circs attached to it, + * because the connection is too old, or because there's a better one. + * More generally, this flag is used to note an unhealthy connection; + * for example, if a bad connection fails we shouldn't assume that the + * router itself has a problem. + */ + unsigned int is_bad_for_new_circs:1; + + /** True iff we have decided that the other end of this connection + * is a client. Channels with this flag set should never be used + * to satisfy an EXTEND request. */ + unsigned int is_client:1; + + /** Set if the channel was initiated remotely (came from a listener) */ + unsigned int is_incoming:1; + + /** Set by lower layer if this is local; i.e., everything it communicates + * with for this channel returns true for is_local_addr(). This is used + * to decide whether to declare reachability when we receive something on + * this channel in circuitbuild.c + */ + unsigned int is_local:1; + + /** Channel timestamps for cell channels */ + time_t timestamp_client; /* Client used this, according to relay.c */ + time_t timestamp_drained; /* Output queue empty */ + time_t timestamp_recv; /* Cell received from lower layer */ + time_t timestamp_xmit; /* Cell sent to lower layer */ + + /* Timestamp for relay.c */ + time_t timestamp_last_added_nonpadding; + + /** Unique ID for measuring direct network status requests;vtunneled ones + * come over a circuit_t, which has a dirreq_id field as well, but is a + * distinct namespace. */ + uint64_t dirreq_id; + + /** Channel counters for cell channels */ + uint64_t n_cells_recved; + uint64_t n_cells_xmitted; +}; + +struct channel_listener_s { + /* Current channel listener state */ + channel_listener_state_t state; + + /* Globally unique ID number for a channel over the lifetime of a Tor + * process. + */ + uint64_t global_identifier; + + /* Should we expect to see this channel in the channel lists? */ + unsigned char registered:1; + + /** Why did we close? + */ + enum { + CHANNEL_LISTENER_NOT_CLOSING = 0, + CHANNEL_LISTENER_CLOSE_REQUESTED, + CHANNEL_LISTENER_CLOSE_FROM_BELOW, + CHANNEL_LISTENER_CLOSE_FOR_ERROR + } reason_for_closing; + + /* Timestamps for both cell channels and listeners */ + time_t timestamp_created; /* Channel created */ + time_t timestamp_active; /* Any activity */ + + /* Methods implemented by the lower layer */ + + /* Free a channel */ + void (*free)(channel_listener_t *); + /* Close an open channel */ + void (*close)(channel_listener_t *); + /* Describe the transport subclass for this channel */ + const char * (*describe_transport)(channel_listener_t *); + /* Optional method to dump transport-specific statistics on the channel */ + void (*dumpstats)(channel_listener_t *, int); + + /* Registered listen handler to call on incoming connection */ + channel_listener_fn_ptr listener; + + /* List of pending incoming connections */ + smartlist_t *incoming_list; + + /* Timestamps for listeners */ + time_t timestamp_accepted; + + /* Counters for listeners */ + uint64_t n_accepted; }; /* Channel state manipulations */ int channel_state_is_valid(channel_state_t state); +int channel_listener_state_is_valid(channel_listener_state_t state); + int channel_state_can_transition(channel_state_t from, channel_state_t to); +int channel_listener_state_can_transition(channel_listener_state_t from, + channel_listener_state_t to); + const char * channel_state_to_string(channel_state_t state); +const char * +channel_listener_state_to_string(channel_listener_state_t state); /* Abstract channel operations */ @@ -240,12 +273,16 @@ void channel_write_cell(channel_t *chan, cell_t *cell); void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell); void channel_write_var_cell(channel_t *chan, var_cell_t *cell); +void channel_listener_mark_for_close(channel_listener_t *chan_l); + /* Channel callback registrations */ /* Listener callback */ -channel_listener_fn_ptr channel_get_listener_fn(channel_t *chan); -void channel_set_listener_fn(channel_t *chan, - channel_listener_fn_ptr listener); +channel_listener_fn_ptr +channel_listener_get_listener_fn(channel_listener_t *chan); + +void channel_listener_set_listener_fn(channel_listener_t *chan, + channel_listener_fn_ptr listener); /* Incoming cell callbacks */ channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan); @@ -258,16 +295,18 @@ void channel_set_cell_handlers(channel_t *chan, channel_var_cell_handler_fn_ptr var_cell_handler); -/* Clean up closed channels periodically; called from run_scheduled_events() - * in main.c +/* Clean up closed channels and channel listeners periodically; these are + * called from run_scheduled_events() in main.c. */ void channel_run_cleanup(void); +void channel_listener_run_cleanup(void); /* Close all channels and deallocate everything */ void channel_free_all(void); /* Dump some statistics in the log */ void channel_dumpstats(int severity); +void channel_listener_dumpstats(int severity); #ifdef _TOR_CHANNEL_INTERNAL @@ -277,20 +316,29 @@ void channel_dumpstats(int severity); * constructors. */ -void channel_init_for_cells(channel_t *chan); -void channel_init_listener(channel_t *chan); +void channel_init(channel_t *chan); +void channel_init_listener(channel_listener_t *chan); /* Channel registration/unregistration */ void channel_register(channel_t *chan); void channel_unregister(channel_t *chan); +/* Channel listener registration/unregistration */ +void channel_listener_register(channel_listener_t *chan_l); +void channel_listener_unregister(channel_listener_t *chan_l); + /* Close from below */ void channel_close_from_lower_layer(channel_t *chan); void channel_close_for_error(channel_t *chan); void channel_closed(channel_t *chan); +void channel_listener_close_from_lower_layer(channel_listener_t *chan_l); +void channel_listener_close_for_error(channel_listener_t *chan_l); +void channel_listener_closed(channel_listener_t *chan_l); + /* Free a channel */ void channel_free(channel_t *chan); +void channel_listener_free(channel_listener_t *chan_l); /* State/metadata setters */ @@ -306,17 +354,24 @@ void channel_set_remote_end(channel_t *chan, const char *identity_digest, const char *nickname); +void channel_listener_change_state(channel_listener_t *chan_l, + channel_listener_state_t to_state); + /* Timestamp updates */ void channel_timestamp_created(channel_t *chan); -void channel_timestamp_accepted(channel_t *chan); void channel_timestamp_active(channel_t *chan); void channel_timestamp_drained(channel_t *chan); void channel_timestamp_recv(channel_t *chan); void channel_timestamp_xmit(channel_t *chan); +void channel_listener_timestamp_created(channel_listener_t *chan_l); +void channel_listener_timestamp_active(channel_listener_t *chan_l); +void channel_listener_timestamp_accepted(channel_listener_t *chan_l); + /* Incoming channel handling */ -void channel_process_incoming(channel_t *listener); -void channel_queue_incoming(channel_t *listener, channel_t *incoming); +void channel_listener_process_incoming(channel_listener_t *listener); +void channel_listener_queue_incoming(channel_listener_t *listener, + channel_t *incoming); /* Incoming cell handling */ void channel_process_cells(channel_t *chan); @@ -401,19 +456,29 @@ int channel_matches_target_addr_for_extend(channel_t *chan, void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd); void channel_timestamp_client(channel_t *chan); +const char * channel_listener_describe_transport(channel_listener_t *chan_l); +void channel_listener_dump_statistics(channel_listener_t *chan_l, + int severity); +void channel_listener_dump_transport_statistics(channel_listener_t *chan_l, + int severity); + /* Timestamp queries */ time_t channel_when_created(channel_t *chan); -time_t channel_when_last_accepted(channel_t *chan); time_t channel_when_last_active(channel_t *chan); time_t channel_when_last_client(channel_t *chan); time_t channel_when_last_drained(channel_t *chan); time_t channel_when_last_recv(channel_t *chan); time_t channel_when_last_xmit(channel_t *chan); +time_t channel_listener_when_created(channel_listener_t *chan_l); +time_t channel_listener_when_last_active(channel_listener_t *chan_l); +time_t channel_listener_when_last_accepted(channel_listener_t *chan_l); + /* Counter queries */ -uint64_t channel_count_accepted(channel_t *chan); uint64_t channel_count_recved(channel_t *chan); uint64_t channel_count_xmitted(channel_t *chan); +uint64_t channel_listener_count_accepted(channel_listener_t *chan_l); + #endif diff --git a/src/or/channeltls.c b/src/or/channeltls.c index bb90ce5e49..93e06364de 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -42,7 +42,7 @@ uint64_t stats_n_authenticate_cells_processed = 0; uint64_t stats_n_authorize_cells_processed = 0; /** Active listener, if any */ -channel_tls_t *channel_tls_listener = NULL; +channel_listener_t *channel_tls_listener = NULL; /* channel_tls_t method declarations */ @@ -66,6 +66,12 @@ static int channel_tls_write_packed_cell_method(channel_t *chan, static int channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell); +/* channel_listener_tls_t method declarations */ + +static void channel_tls_listener_close_method(channel_listener_t *chan_l); +static const char * +channel_tls_listener_describe_transport_method(channel_listener_t *chan_l); + /** Handle incoming cells for the handshake stuff here rather than * passing them on up. */ @@ -97,20 +103,19 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, { channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); channel_t *chan = TLS_CHAN_TO_BASE(tlschan); - channel_init_for_cells(chan); + channel_init(chan); chan->state = CHANNEL_STATE_OPENING; chan->close = channel_tls_close_method; chan->describe_transport = channel_tls_describe_transport_method; - chan->u.cell_chan.get_remote_addr = channel_tls_get_remote_addr_method; - chan->u.cell_chan.get_remote_descr = channel_tls_get_remote_descr_method; - chan->u.cell_chan.has_queued_writes = channel_tls_has_queued_writes_method; - chan->u.cell_chan.is_canonical = channel_tls_is_canonical_method; - chan->u.cell_chan.matches_extend_info = - channel_tls_matches_extend_info_method; - chan->u.cell_chan.matches_target = channel_tls_matches_target_method; - chan->u.cell_chan.write_cell = channel_tls_write_cell_method; - chan->u.cell_chan.write_packed_cell = channel_tls_write_packed_cell_method; - chan->u.cell_chan.write_var_cell = channel_tls_write_var_cell_method; + chan->get_remote_addr = channel_tls_get_remote_addr_method; + chan->get_remote_descr = channel_tls_get_remote_descr_method; + chan->has_queued_writes = channel_tls_has_queued_writes_method; + chan->is_canonical = channel_tls_is_canonical_method; + chan->matches_extend_info = channel_tls_matches_extend_info_method; + chan->matches_target = channel_tls_matches_target_method; + chan->write_cell = channel_tls_write_cell_method; + chan->write_packed_cell = channel_tls_write_packed_cell_method; + chan->write_var_cell = channel_tls_write_var_cell_method; log_debug(LD_CHANNEL, "In channel_tls_connect() for channel %p " @@ -121,9 +126,8 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, if (is_local_addr(addr)) channel_mark_local(chan); channel_mark_outgoing(chan); - chan->u.cell_chan.active_circuit_pqueue = smartlist_new(); - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated = - cell_ewma_get_tick(); + chan->active_circuit_pqueue = smartlist_new(); + chan->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick(); /* Set up or_connection stuff */ tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan); @@ -140,7 +144,7 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, goto done; err: - smartlist_free(chan->u.cell_chan.active_circuit_pqueue); + smartlist_free(chan->active_circuit_pqueue); tor_free(tlschan); chan = NULL; @@ -154,14 +158,14 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, /** * Return the current channel_tls_t listener * - * Returns the current listening channel for incoming TLS connections, or + * Returns the current channel listener for incoming TLS connections, or * NULL if none has been established */ -channel_t * +channel_listener_t * channel_tls_get_listener(void) { - return TLS_CHAN_TO_BASE(channel_tls_listener); + return channel_tls_listener; } /** @@ -171,30 +175,29 @@ channel_tls_get_listener(void) * and return that. */ -channel_t * +channel_listener_t * channel_tls_start_listener(void) { - channel_tls_t *listener; - channel_t *lchan; + channel_listener_t *listener; if (!channel_tls_listener) { listener = tor_malloc_zero(sizeof(*listener)); - lchan = TLS_CHAN_TO_BASE(listener); - channel_init_listener(lchan); - lchan->state = CHANNEL_STATE_LISTENING; - lchan->close = channel_tls_close_method; - lchan->describe_transport = channel_tls_describe_transport_method; + channel_init_listener(listener); + listener->state = CHANNEL_LISTENER_STATE_LISTENING; + listener->close = channel_tls_listener_close_method; + listener->describe_transport = + channel_tls_listener_describe_transport_method; channel_tls_listener = listener; log_debug(LD_CHANNEL, - "Starting TLS listener channel %p with global id " U64_FORMAT, - lchan, U64_PRINTF_ARG(lchan->global_identifier)); + "Starting TLS channel listener %p with global id " U64_FORMAT, + listener, U64_PRINTF_ARG(listener->global_identifier)); - channel_register(lchan); - } else lchan = TLS_CHAN_TO_BASE(channel_tls_listener); + channel_listener_register(listener); + } else listener = channel_tls_listener; - return lchan; + return listener; } /** @@ -207,16 +210,13 @@ channel_tls_start_listener(void) void channel_tls_free_all(void) { - channel_t *base = NULL; - log_debug(LD_CHANNEL, "Shutting down TLS channels..."); if (channel_tls_listener) { - base = TLS_CHAN_TO_BASE(channel_tls_listener); - channel_unregister(base); - channel_mark_for_close(base); - channel_free(base); + channel_listener_unregister(channel_tls_listener); + channel_listener_mark_for_close(channel_tls_listener); + channel_listener_free(channel_tls_listener); channel_tls_listener = NULL; } @@ -237,19 +237,18 @@ channel_tls_handle_incoming(or_connection_t *orconn) tor_assert(orconn); tor_assert(!(orconn->chan)); - channel_init_for_cells(chan); + channel_init(chan); chan->state = CHANNEL_STATE_OPENING; chan->close = channel_tls_close_method; chan->describe_transport = channel_tls_describe_transport_method; - chan->u.cell_chan.get_remote_descr = channel_tls_get_remote_descr_method; - chan->u.cell_chan.has_queued_writes = channel_tls_has_queued_writes_method; - chan->u.cell_chan.is_canonical = channel_tls_is_canonical_method; - chan->u.cell_chan.matches_extend_info = - channel_tls_matches_extend_info_method; - chan->u.cell_chan.matches_target = channel_tls_matches_target_method; - chan->u.cell_chan.write_cell = channel_tls_write_cell_method; - chan->u.cell_chan.write_packed_cell = channel_tls_write_packed_cell_method; - chan->u.cell_chan.write_var_cell = channel_tls_write_var_cell_method; + chan->get_remote_descr = channel_tls_get_remote_descr_method; + chan->has_queued_writes = channel_tls_has_queued_writes_method; + chan->is_canonical = channel_tls_is_canonical_method; + chan->matches_extend_info = channel_tls_matches_extend_info_method; + chan->matches_target = channel_tls_matches_target_method; + chan->write_cell = channel_tls_write_cell_method; + chan->write_packed_cell = channel_tls_write_packed_cell_method; + chan->write_var_cell = channel_tls_write_var_cell_method; /* Link the channel and orconn to each other */ tlschan->conn = orconn; @@ -258,9 +257,8 @@ channel_tls_handle_incoming(or_connection_t *orconn) if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan); channel_mark_incoming(chan); - chan->u.cell_chan.active_circuit_pqueue = smartlist_new(); - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated = - cell_ewma_get_tick(); + chan->active_circuit_pqueue = smartlist_new(); + chan->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick(); /* If we got one, we should register it */ if (chan) channel_register(chan); @@ -285,43 +283,13 @@ channel_tls_close_method(channel_t *chan) tor_assert(tlschan); - if (chan->is_listener) { - /* - * Listeners we just go ahead and change state through to CLOSED, but - * make sure to check if they're channel_tls_listener to NULL it out. - */ - if (chan == TLS_CHAN_TO_BASE(channel_tls_listener)) - channel_tls_listener = NULL; - - if (!(chan->state == CHANNEL_STATE_CLOSING || - chan->state == CHANNEL_STATE_CLOSED || - chan->state == CHANNEL_STATE_ERROR)) { - channel_change_state(chan, CHANNEL_STATE_CLOSING); - } - - if (chan->u.listener.incoming_list) { - SMARTLIST_FOREACH_BEGIN(chan->u.listener.incoming_list, - channel_t *, ichan) { - channel_mark_for_close(ichan); - } SMARTLIST_FOREACH_END(ichan); - - smartlist_free(chan->u.listener.incoming_list); - chan->u.listener.incoming_list = NULL; - } - - if (!(chan->state == CHANNEL_STATE_CLOSED || - chan->state == CHANNEL_STATE_ERROR)) { - channel_change_state(chan, CHANNEL_STATE_CLOSED); - } - } else { - if (tlschan->conn) connection_or_close_normally(tlschan->conn, 1); - else { - /* Weird - we'll have to change the state ourselves, I guess */ - log_info(LD_CHANNEL, - "Tried to close channel_tls_t %p with NULL conn", - tlschan); - channel_change_state(chan, CHANNEL_STATE_ERROR); - } + if (tlschan->conn) connection_or_close_normally(tlschan->conn, 1); + else { + /* Weird - we'll have to change the state ourselves, I guess */ + log_info(LD_CHANNEL, + "Tried to close channel_tls_t %p with NULL conn", + tlschan); + channel_change_state(chan, CHANNEL_STATE_ERROR); } } @@ -342,23 +310,19 @@ channel_tls_describe_transport_method(channel_t *chan) tor_assert(chan); - if (chan->is_listener) { - rv = "TLS channel (listening)"; - } else { - tlschan = BASE_CHAN_TO_TLS(chan); + tlschan = BASE_CHAN_TO_TLS(chan); - if (tlschan->conn) { - id = TO_CONN(tlschan->conn)->global_identifier; + if (tlschan->conn) { + id = TO_CONN(tlschan->conn)->global_identifier; - if (buf) tor_free(buf); - tor_asprintf(&buf, - "TLS channel (connection " U64_FORMAT ")", - U64_PRINTF_ARG(id)); + if (buf) tor_free(buf); + tor_asprintf(&buf, + "TLS channel (connection " U64_FORMAT ")", + U64_PRINTF_ARG(id)); - rv = buf; - } else { - rv = "TLS channel (no connection)"; - } + rv = buf; + } else { + rv = "TLS channel (no connection)"; } return rv; @@ -603,6 +567,65 @@ channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell) return 1; } +/************************************************* + * Method implementations for channel_listener_t * + ************************************************/ + +/** + * Close a channel_listener_t + * + * This implements the close method for channel_listener_t + */ + +static void +channel_tls_listener_close_method(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* + * Listeners we just go ahead and change state through to CLOSED, but + * make sure to check if they're channel_tls_listener to NULL it out. + */ + if (chan_l == channel_tls_listener) + channel_tls_listener = NULL; + + if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); + } + + if (chan_l->incoming_list) { + SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list, + channel_t *, ichan) { + channel_mark_for_close(ichan); + } SMARTLIST_FOREACH_END(ichan); + + smartlist_free(chan_l->incoming_list); + chan_l->incoming_list = NULL; + } + + if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED); + } +} + +/** + * Describe the transport for a channel_listener_t + * + * This returns the string "TLS channel (listening)" to the upper + * layer. + */ + +static const char * +channel_tls_listener_describe_transport_method(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return "TLS channel (listening)"; +} + /******************************************************* * Functions for handling events on an or_connection_t * ******************************************************/ @@ -782,8 +805,6 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) return; } - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); - handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN); if (conn->_base.marked_for_close) @@ -892,8 +913,6 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn) return; } - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); - handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN); if (TO_CONN(conn)->marked_for_close) @@ -1049,7 +1068,6 @@ enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); started_here = connection_or_nonopen_was_started_here(chan->conn); @@ -1091,7 +1109,6 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); started_here = connection_or_nonopen_was_started_here(chan->conn); @@ -1247,7 +1264,6 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); if (chan->conn->link_proto < 2) { @@ -1386,7 +1402,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) safe_str_client(chan->conn->_base.address), chan->conn->_base.port, (int)(chan->conn->link_proto), - hex_str(TLS_CHAN_TO_BASE(chan)->u.cell_chan.identity_digest, + hex_str(TLS_CHAN_TO_BASE(chan)->identity_digest, DIGEST_LEN), tor_addr_is_null(&my_apparent_addr) ? "" : fmt_and_decorate_addr(&my_apparent_addr)); @@ -1422,7 +1438,6 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); #define ERR(s) \ @@ -1515,7 +1530,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) * _trying_ to connect to an authority, not necessarily if we _did_ connect * to one. */ if (router_digest_is_trusted_dir( - TLS_CHAN_TO_BASE(chan)->u.cell_chan.identity_digest)) + TLS_CHAN_TO_BASE(chan)->identity_digest)) severity = LOG_WARN; else severity = LOG_PROTOCOL_WARN; @@ -1616,7 +1631,6 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); #define ERR(s) \ @@ -1714,7 +1728,6 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(TLS_CHAN_TO_BASE(chan)->is_listener)); tor_assert(chan->conn); #define ERR(s) \ diff --git a/src/or/channeltls.h b/src/or/channeltls.h index 3b7d6a7a1f..b38e12adcc 100644 --- a/src/or/channeltls.h +++ b/src/or/channeltls.h @@ -28,8 +28,8 @@ struct channel_tls_s { channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest); -channel_t * channel_tls_get_listener(void); -channel_t * channel_tls_start_listener(void); +channel_listener_t * channel_tls_get_listener(void); +channel_listener_t * channel_tls_start_listener(void); channel_t * channel_tls_handle_incoming(or_connection_t *orconn); /* Things for connection_or.c to call back into */ diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 5ef67bd9df..749985f904 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1711,23 +1711,22 @@ get_unique_circ_id_by_chan(channel_t *chan) circid_t high_bit; tor_assert(chan); - tor_assert(!(chan->is_listener)); - if (chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_NEITHER) { + if (chan->circ_id_type == CIRC_ID_TYPE_NEITHER) { log_warn(LD_BUG, "Trying to pick a circuit ID for a connection from " "a client with no identity."); return 0; } high_bit = - (chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0; + (chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0; do { /* Sequentially iterate over test_circ_id=1...1<<15-1 until we find a * circID such that (high_bit|test_circ_id) is not already used. */ - test_circ_id = chan->u.cell_chan.next_circ_id++; + test_circ_id = chan->next_circ_id++; if (test_circ_id == 0 || test_circ_id >= 1<<15) { test_circ_id = 1; - chan->u.cell_chan.next_circ_id = 2; + chan->next_circ_id = 2; } if (++attempts > 1<<15) { /* Make sure we don't loop forever if all circ_id's are used. This @@ -2039,11 +2038,9 @@ circuit_n_chan_done(channel_t *chan, int status) int err_reason = 0; tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_CIRC,"chan to %s/%s, status=%d", - chan->u.cell_chan.nickname ? - chan->u.cell_chan.nickname : "NULL", + chan->nickname ? chan->nickname : "NULL", channel_get_canonical_remote_descr(chan), status); pending_circs = smartlist_new(); @@ -2064,7 +2061,7 @@ circuit_n_chan_done(channel_t *chan, int status) continue; } else { /* We expected a key. See if it's the right one. */ - if (tor_memneq(chan->u.cell_chan.identity_digest, + if (tor_memneq(chan->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) continue; } @@ -2247,8 +2244,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) else control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0); - tor_assert(!(circ->_base.n_chan->is_listener)); - node = node_get_by_id(circ->_base.n_chan->u.cell_chan.identity_digest); + node = node_get_by_id(circ->_base.n_chan->identity_digest); fast = should_use_create_fast_for_circuit(circ); if (!fast) { /* We are an OR and we know the right onion key: we should @@ -2487,10 +2483,8 @@ circuit_extend(cell_t *cell, circuit_t *circ) /* Next, check if we're being asked to connect to the hop that the * extend cell came from. There isn't any reason for that, and it can * assist circular-path attacks. */ - tor_assert(!(TO_OR_CIRCUIT(circ)->p_chan->is_listener)); if (tor_memeq(id_digest, - TO_OR_CIRCUIT(circ)->p_chan-> - u.cell_chan.identity_digest, + TO_OR_CIRCUIT(circ)->p_chan->identity_digest, DIGEST_LEN)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend back to the previous hop."); @@ -2733,9 +2727,8 @@ pathbias_count_first_hop(origin_circuit_t *circ) if (!circ->has_opened) { entry_guard_t *guard; - tor_assert(!(circ->_base.n_chan->is_listener)); - guard = entry_guard_get_by_id_digest( - circ->_base.n_chan->u.cell_chan.identity_digest); + guard = + entry_guard_get_by_id_digest(circ->_base.n_chan->identity_digest); if (guard) { if (circ->path_state == PATH_STATE_NEW_CIRC) { circ->path_state = PATH_STATE_DID_FIRST_HOP; @@ -2840,10 +2833,8 @@ pathbias_count_success(origin_circuit_t *circ) /* Don't count cannibalized/reused circs for path bias */ if (!circ->has_opened) { - tor_assert(!(circ->_base.n_chan->is_listener)); guard = - entry_guard_get_by_id_digest(circ->_base.n_chan-> - u.cell_chan.identity_digest); + entry_guard_get_by_id_digest(circ->_base.n_chan->identity_digest); if (guard) { if (circ->path_state == PATH_STATE_DID_FIRST_HOP) { diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 68cd19e152..cf6020de06 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -102,8 +102,6 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction, circid_t old_id, *circid_ptr; int was_active, make_active; - if (chan) tor_assert(!(chan->is_listener)); - if (direction == CELL_DIRECTION_OUT) { chan_ptr = &circ->n_chan; circid_ptr = &circ->n_circ_id; @@ -131,13 +129,12 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction, } if (old_chan) { /* we may need to remove it from the conn-circid map */ - tor_assert(!(old_chan->is_listener)); search.circ_id = old_id; search.chan = old_chan; found = HT_REMOVE(chan_circid_map, &chan_circid_map, &search); if (found) { tor_free(found); - --old_chan->u.cell_chan.n_circuits; + --old_chan->n_circuits; } if (was_active && old_chan != chan) make_circuit_inactive_on_chan(circ, old_chan); @@ -167,7 +164,7 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction, if (make_active && old_chan != chan) make_circuit_active_on_chan(circ,chan); - ++chan->u.cell_chan.n_circuits; + ++chan->n_circuits; } /** Set the p_conn field of a circuit circ, along @@ -242,7 +239,6 @@ circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan) { tor_assert(out); tor_assert(chan); - tor_assert(!(chan->is_listener)); if (!circuits_pending_chans) return; @@ -259,8 +255,8 @@ circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan) continue; } else { /* We expected a key. See if it's the right one. */ - if (tor_memneq(chan->u.cell_chan.identity_digest, - circ->n_hop->identity_digest, DIGEST_LEN)) + if (tor_memneq(chan->identity_digest, + circ->n_hop->identity_digest, DIGEST_LEN)) continue; } smartlist_add(out, circ); @@ -276,14 +272,12 @@ circuit_count_pending_on_channel(channel_t *chan) smartlist_t *sl = smartlist_new(); tor_assert(chan); - tor_assert(!(chan->is_listener)); circuit_get_all_pending_on_channel(sl, chan); cnt = smartlist_len(sl); smartlist_free(sl); log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs", - chan->u.cell_chan.nickname ? - chan->u.cell_chan.nickname : "NULL", + chan->nickname ? chan->nickname : "NULL", channel_get_canonical_remote_descr(chan), cnt); return cnt; @@ -839,7 +833,6 @@ circuit_dump_by_chan(channel_t *chan, int severity) circuit_t *circ; tor_assert(chan); - tor_assert(!(chan->is_listener)); for (circ = global_circuitlist; circ; circ = circ->next) { circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; @@ -865,7 +858,7 @@ circuit_dump_by_chan(channel_t *chan, int severity) if (!circ->n_chan && circ->n_hop && channel_matches_extend_info(chan, circ->n_hop) && - tor_memeq(chan->u.cell_chan.identity_digest, + tor_memeq(chan->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) { circuit_dump_chan_details(severity, circ, chan, (circ->state == CIRCUIT_STATE_OPEN && diff --git a/src/or/circuituse.c b/src/or/circuituse.c index e4e1b8ab63..be79b30bc9 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1185,9 +1185,8 @@ circuit_build_failed(origin_circuit_t *circ) int already_marked = 0; if (circ->_base.n_chan) { n_chan = circ->_base.n_chan; - tor_assert(!(n_chan->is_listener)); - if (n_chan->u.cell_chan.is_bad_for_new_circs) { + if (n_chan->is_bad_for_new_circs) { /* We only want to blame this router when a fresh healthy * connection fails. So don't mark this router as newly failed, * since maybe this was just an old circuit attempt that's @@ -1201,7 +1200,7 @@ circuit_build_failed(origin_circuit_t *circ) "Our circuit failed to get a response from the first hop " "(%s). I'm going to try to rotate to a better connection.", channel_get_canonical_remote_descr(n_chan)); - n_chan->u.cell_chan.is_bad_for_new_circs = 1; + n_chan->is_bad_for_new_circs = 1; } else { log_info(LD_OR, "Our circuit died before the first hop with no connection"); diff --git a/src/or/command.c b/src/or/command.c index 2fb70b5887..e175e23ca9 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -44,7 +44,7 @@ uint64_t stats_n_relay_cells_processed = 0; uint64_t stats_n_destroy_cells_processed = 0; /* Handle an incoming channel */ -static void command_handle_incoming_channel(channel_t *listener, +static void command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan); /* These are the main functions for processing cells */ @@ -190,7 +190,6 @@ command_process_create_cell(cell_t *cell, channel_t *chan) tor_assert(cell); tor_assert(chan); - tor_assert(!(chan->is_listener)); log_debug(LD_OR, "Got a CREATE cell for circ_id %d on channel " U64_FORMAT @@ -223,9 +222,9 @@ command_process_create_cell(cell_t *cell, channel_t *chan) * circ. */ id_is_high = cell->circ_id & (1<<15); if ((id_is_high && - chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_HIGHER) || + chan->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && - chan->u.cell_chan.circ_id_type == CIRC_ID_TYPE_LOWER)) { + chan->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); @@ -235,7 +234,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan) } if (circuit_id_in_use_on_channel(cell->circ_id, chan)) { - const node_t *node = node_get_by_id(chan->u.cell_chan.identity_digest); + const node_t *node = node_get_by_id(chan->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", @@ -473,7 +472,7 @@ command_process_destroy_cell(cell_t *cell, channel_t *chan) */ static void -command_handle_incoming_channel(channel_t *listener, channel_t *chan) +command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan) { tor_assert(listener); tor_assert(chan); @@ -500,11 +499,11 @@ command_setup_channel(channel_t *chan) */ void -command_setup_listener(channel_t *listener) +command_setup_listener(channel_listener_t *listener) { tor_assert(listener); - tor_assert(listener->state == CHANNEL_STATE_LISTENING); + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING); - channel_set_listener_fn(listener, command_handle_incoming_channel); + channel_listener_set_listener_fn(listener, command_handle_incoming_channel); } diff --git a/src/or/command.h b/src/or/command.h index eddce8741b..f9a0ef20b7 100644 --- a/src/or/command.h +++ b/src/or/command.h @@ -17,7 +17,7 @@ void command_process_cell(channel_t *chan, cell_t *cell); void command_process_var_cell(channel_t *chan, var_cell_t *cell); void command_setup_channel(channel_t *chan); -void command_setup_listener(channel_t *chan); +void command_setup_listener(channel_listener_t *chan_l); extern uint64_t stats_n_padding_cells_processed; extern uint64_t stats_n_create_cells_processed; diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 834f9707ce..45f3a06f38 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -3070,11 +3070,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) return 0; } if (or_circ && or_circ->p_chan) { - tor_assert(!(or_circ->p_chan->is_listener)); if (!options->AllowSingleHopExits && (or_circ->is_first_hop || (!connection_or_digest_is_known_relay( - or_circ->p_chan->u.cell_chan.identity_digest) && + or_circ->p_chan->identity_digest) && should_refuse_unknown_exits(options)))) { /* Don't let clients use us as a single-hop proxy, unless the user * has explicitly allowed that in the config. It attracts attackers diff --git a/src/or/connection_or.c b/src/or/connection_or.c index a3df7759e0..bf69711691 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -336,8 +336,7 @@ connection_or_get_num_circuits(or_connection_t *conn) tor_assert(conn); if (conn->chan) { - tor_assert(!(TLS_CHAN_TO_BASE(conn->chan)->is_listener)); - return TLS_CHAN_TO_BASE(conn->chan)->u.cell_chan.n_circuits; + return TLS_CHAN_TO_BASE(conn->chan)->n_circuits; } else return 0; } @@ -1001,8 +1000,6 @@ connection_or_notify_error(or_connection_t *conn, /* Tell the controlling channel if we have one */ if (conn->chan) { chan = TLS_CHAN_TO_BASE(conn->chan); - /* This shouldn't ever happen in the listening state */ - tor_assert(chan->state != CHANNEL_STATE_LISTENING); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || @@ -1148,8 +1145,6 @@ connection_or_close_normally(or_connection_t *orconn, int flush) else connection_mark_for_close(TO_CONN(orconn)); if (orconn->chan) { chan = TLS_CHAN_TO_BASE(orconn->chan); - /* This shouldn't ever happen in the listening state */ - tor_assert(chan->state != CHANNEL_STATE_LISTENING); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || @@ -1173,8 +1168,6 @@ connection_or_close_for_error(or_connection_t *orconn, int flush) else connection_mark_for_close(TO_CONN(orconn)); if (orconn->chan) { chan = TLS_CHAN_TO_BASE(orconn->chan); - /* This shouldn't ever happen in the listening state */ - tor_assert(chan->state != CHANNEL_STATE_LISTENING); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || @@ -1195,7 +1188,8 @@ connection_or_close_for_error(or_connection_t *orconn, int flush) int connection_tls_start_handshake(or_connection_t *conn, int receiving) { - channel_t *chan_listener, *chan; + channel_listener_t *chan_listener; + channel_t *chan; /* Incoming connections will need a new channel passed to the * channel_tls_listener */ @@ -1208,7 +1202,7 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving) command_setup_listener(chan_listener); } chan = channel_tls_handle_incoming(conn); - channel_queue_incoming(chan_listener, chan); + channel_listener_queue_incoming(chan_listener, chan); } connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING); diff --git a/src/or/main.c b/src/or/main.c index 2a3e0e140e..e0c89a919b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1539,6 +1539,7 @@ run_scheduled_events(time_t now) /** 8c. Do channel cleanup just like for connections */ channel_run_cleanup(); + channel_listener_run_cleanup(); /** 9. and if we're a server, check whether our DNS is telling stories to * us. */ @@ -2172,6 +2173,7 @@ dumpstats(int severity) } SMARTLIST_FOREACH_END(conn); channel_dumpstats(severity); + channel_listener_dumpstats(severity); log(severity, LD_NET, "Cells processed: "U64_FORMAT" padding\n" diff --git a/src/or/or.h b/src/or/or.h index 4d2ab21d7d..5987eefd88 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -883,6 +883,10 @@ typedef uint16_t streamid_t; typedef struct channel_s channel_t; +/* channel_listener_t typedef; struct channel_listener_s is in channel.h */ + +typedef struct channel_listener_s channel_listener_t; + /* channel states for channel_t */ typedef enum { @@ -892,20 +896,9 @@ typedef enum { * Permitted transitions from: * - CHANNEL_STATE_CLOSING * Permitted transitions to: - * - CHANNEL_STATE_LISTENING * - CHANNEL_STATE_OPENING */ CHANNEL_STATE_CLOSED = 0, - /* - * Listening state - channel is listening for incoming connections - * - * Permitted transitions from: - * - CHANNEL_STATE_CLOSED - * Permitted transitions to: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_ERROR - */ - CHANNEL_STATE_LISTENING, /* * Opening state - channel is trying to connect * @@ -957,7 +950,6 @@ typedef enum { * * Permitted transitions from: * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_LISTENING * - CHANNEL_STATE_MAINT * - CHANNEL_STATE_OPENING * - CHANNEL_STATE_OPEN @@ -971,6 +963,55 @@ typedef enum { CHANNEL_STATE_LAST } channel_state_t; +/* channel listener states for channel_listener_t */ + +typedef enum { + /* + * Closed state - channel listener is inactive + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_LISTENING + */ + CHANNEL_LISTENER_STATE_CLOSED = 0, + /* + * Listening state - channel listener is listening for incoming + * connections + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSED + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSING + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_LISTENING, + /* + * Closing state - channel listener is shutting down + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_LISTENING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSED, + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_CLOSING, + /* + * Error state - channel listener has experienced a permanent error + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_LISTENING + * Permitted transitions to: + * - None + */ + CHANNEL_LISTENER_STATE_ERROR, + /* + * Placeholder for maximum state value + */ + CHANNEL_LISTENER_STATE_LAST +} channel_listener_state_t; + /* TLS channel stuff */ typedef struct channel_tls_s channel_tls_t; diff --git a/src/or/relay.c b/src/or/relay.c index 3850562917..60f696cd47 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -1096,8 +1096,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, * and linked. */ static uint64_t next_id = 0; circ->dirreq_id = ++next_id; - tor_assert(!(TO_OR_CIRCUIT(circ)->p_chan->is_listener)); - TO_OR_CIRCUIT(circ)->p_chan->u.cell_chan.dirreq_id = circ->dirreq_id; + TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id; } return connection_exit_begin_conn(cell, circ); @@ -2179,23 +2178,22 @@ scale_active_circuits(channel_t *chan, unsigned cur_tick) double factor; tor_assert(chan); - tor_assert(!(chan->is_listener)); factor = get_scale_factor( - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated, + chan->active_circuit_pqueue_last_recalibrated, cur_tick); /** Ordinarily it isn't okay to change the value of an element in a heap, * but it's okay here, since we are preserving the order. */ SMARTLIST_FOREACH_BEGIN( - chan->u.cell_chan.active_circuit_pqueue, + chan->active_circuit_pqueue, cell_ewma_t *, e) { tor_assert(e->last_adjusted_tick == - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated); + chan->active_circuit_pqueue_last_recalibrated); e->cell_count *= factor; e->last_adjusted_tick = cur_tick; } SMARTLIST_FOREACH_END(e); - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated = cur_tick; + chan->active_circuit_pqueue_last_recalibrated = cur_tick; } /** Rescale ewma to the same scale as chan, and add it to @@ -2204,15 +2202,14 @@ static void add_cell_ewma_to_chan(channel_t *chan, cell_ewma_t *ewma) { tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(ewma); tor_assert(ewma->heap_index == -1); scale_single_cell_ewma( ewma, - chan->u.cell_chan.active_circuit_pqueue_last_recalibrated); + chan->active_circuit_pqueue_last_recalibrated); - smartlist_pqueue_add(chan->u.cell_chan.active_circuit_pqueue, + smartlist_pqueue_add(chan->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index), ewma); @@ -2223,11 +2220,10 @@ static void remove_cell_ewma_from_chan(channel_t *chan, cell_ewma_t *ewma) { tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(ewma); tor_assert(ewma->heap_index != -1); - smartlist_pqueue_remove(chan->u.cell_chan.active_circuit_pqueue, + smartlist_pqueue_remove(chan->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index), ewma); @@ -2239,9 +2235,8 @@ static cell_ewma_t * pop_first_cell_ewma_from_chan(channel_t *chan) { tor_assert(chan); - tor_assert(!(chan->is_listener)); - return smartlist_pqueue_pop(chan->u.cell_chan.active_circuit_pqueue, + return smartlist_pqueue_pop(chan->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index)); } @@ -2254,7 +2249,6 @@ make_circuit_active_on_chan(circuit_t *circ, channel_t *chan) circuit_t **nextp = NULL, **prevp = NULL; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(circ); nextp = next_circ_on_chan_p(circ, chan); @@ -2267,11 +2261,11 @@ make_circuit_active_on_chan(circuit_t *circ, channel_t *chan) assert_active_circuits_ok_paranoid(chan); - if (!(chan->u.cell_chan.active_circuits)) { - chan->u.cell_chan.active_circuits = circ; + if (!(chan->active_circuits)) { + chan->active_circuits = circ; *prevp = *nextp = circ; } else { - circuit_t *head = chan->u.cell_chan.active_circuits; + circuit_t *head = chan->active_circuits; circuit_t *old_tail = *prev_circ_on_chan_p(head, chan); *next_circ_on_chan_p(old_tail, chan) = circ; *nextp = head; @@ -2299,7 +2293,6 @@ make_circuit_inactive_on_chan(circuit_t *circ, channel_t *chan) circuit_t *next = NULL, *prev = NULL; tor_assert(chan); - tor_assert(!(chan->is_listener)); tor_assert(circ); nextp = next_circ_on_chan_p(circ, chan); @@ -2319,12 +2312,12 @@ make_circuit_inactive_on_chan(circuit_t *circ, channel_t *chan) tor_assert(*next_circ_on_chan_p(prev, chan) == circ); if (next == circ) { - chan->u.cell_chan.active_circuits = NULL; + chan->active_circuits = NULL; } else { *prev_circ_on_chan_p(next, chan) = prev; *next_circ_on_chan_p(prev, chan) = next; - if (chan->u.cell_chan.active_circuits == circ) - chan->u.cell_chan.active_circuits = next; + if (chan->active_circuits == circ) + chan->active_circuits = next; } *prevp = *nextp = NULL; @@ -2347,9 +2340,8 @@ channel_unlink_all_active_circs(channel_t *chan) circuit_t *head = NULL, *cur = NULL; tor_assert(chan); - tor_assert(!(chan->is_listener)); - cur = head = chan->u.cell_chan.active_circuits; + cur = head = chan->active_circuits; if (! head) return; do { @@ -2358,12 +2350,12 @@ channel_unlink_all_active_circs(channel_t *chan) *next_circ_on_chan_p(cur, chan) = NULL; cur = next; } while (cur != head); - chan->u.cell_chan.active_circuits = NULL; + chan->active_circuits = NULL; - SMARTLIST_FOREACH(chan->u.cell_chan.active_circuit_pqueue, + SMARTLIST_FOREACH(chan->active_circuit_pqueue, cell_ewma_t *, e, e->heap_index = -1); - smartlist_clear(chan->u.cell_chan.active_circuit_pqueue); + smartlist_clear(chan->active_circuit_pqueue); } /** Block (if block is true) or unblock (if block is false) @@ -2440,9 +2432,8 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) double ewma_increment = -1; tor_assert(chan); - tor_assert(!(chan->is_listener)); - circ = chan->u.cell_chan.active_circuits; + circ = chan->active_circuits; if (!circ) return 0; assert_active_circuits_ok_paranoid(chan); @@ -2453,13 +2444,13 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) tor_gettimeofday_cached(&now_hires); tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick); - if (tick != chan->u.cell_chan.active_circuit_pqueue_last_recalibrated) { + if (tick != chan->active_circuit_pqueue_last_recalibrated) { scale_active_circuits(chan, tick); } ewma_increment = pow(ewma_scale_factor, -fractional_tick); - cell_ewma = smartlist_get(chan->u.cell_chan.active_circuit_pqueue, 0); + cell_ewma = smartlist_get(chan->active_circuit_pqueue, 0); circ = cell_ewma_to_circuit(cell_ewma); } @@ -2511,8 +2502,8 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) /* If we just flushed our queue and this circuit is used for a * tunneled directory request, possibly advance its state. */ - if (queue->n == 0 && chan->u.cell_chan.dirreq_id) - geoip_change_dirreq_state(chan->u.cell_chan.dirreq_id, + if (queue->n == 0 && chan->dirreq_id) + geoip_change_dirreq_state(chan->dirreq_id, DIRREQ_TUNNELED, DIRREQ_CIRC_QUEUE_FLUSHED); @@ -2534,7 +2525,7 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) tor_assert(tmp == cell_ewma); add_cell_ewma_to_chan(chan, cell_ewma); } - if (!ewma_enabled && circ != chan->u.cell_chan.active_circuits) { + if (!ewma_enabled && circ != chan->active_circuits) { /* If this happens, the current circuit just got made inactive by * a call in connection_write_to_buf(). That's nothing to worry about: * circuit_make_inactive_on_conn() already advanced chan->active_circuits @@ -2546,7 +2537,7 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) } tor_assert(*next_circ_on_chan_p(circ, chan)); assert_active_circuits_ok_paranoid(chan); - chan->u.cell_chan.active_circuits = *next_circ_on_chan_p(circ, chan); + chan->active_circuits = *next_circ_on_chan_p(circ, chan); /* Is the cell queue low enough to unblock all the streams that are waiting * to write to this circuit? */ @@ -2701,9 +2692,8 @@ assert_active_circuits_ok(channel_t *chan) int n = 0; tor_assert(chan); - tor_assert(!(chan->is_listener)); - cur = head = chan->u.cell_chan.active_circuits; + cur = head = chan->active_circuits; if (! head) return; @@ -2723,13 +2713,13 @@ assert_active_circuits_ok(channel_t *chan) tor_assert(ewma->is_for_p_chan); } tor_assert(ewma->heap_index != -1); - tor_assert(ewma == smartlist_get(chan->u.cell_chan.active_circuit_pqueue, + tor_assert(ewma == smartlist_get(chan->active_circuit_pqueue, ewma->heap_index)); n++; cur = next; } while (cur != head); - tor_assert(n == smartlist_len(chan->u.cell_chan.active_circuit_pqueue)); + tor_assert(n == smartlist_len(chan->active_circuit_pqueue)); } /** Return 1 if we shouldn't restart reading on this circuit, even if -- cgit v1.2.3-54-g00ecf