diff options
Diffstat (limited to 'src/or/relay.c')
-rw-r--r-- | src/or/relay.c | 333 |
1 files changed, 192 insertions, 141 deletions
diff --git a/src/or/relay.c b/src/or/relay.c index 8dbe4acc12..8d9ce04fb1 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -16,19 +16,19 @@ const char relay_c_id[] = static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, crypt_path_t **layer_hint, char *recognized); -static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, +static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction); static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, - connection_t *conn, + edge_connection_t *conn, crypt_path_t *layer_hint); static void circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint); static void circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); static int -circuit_resume_edge_reading_helper(connection_t *conn, +circuit_resume_edge_reading_helper(edge_connection_t *conn, circuit_t *circ, crypt_path_t *layer_hint); static int @@ -144,7 +144,7 @@ relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in, int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) { - connection_t *conn=NULL; + or_connection_t *or_conn=NULL; crypt_path_t *layer_hint=NULL; char recognized=0; int reason; @@ -162,7 +162,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) } if (recognized) { - conn = relay_lookup_conn(circ, cell, cell_direction); + edge_connection_t *conn = relay_lookup_conn(circ, cell, cell_direction); if (cell_direction == CELL_DIRECTION_OUT) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending away from origin."); @@ -190,19 +190,25 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) /* not recognized. pass it on. */ if (cell_direction == CELL_DIRECTION_OUT) { cell->circ_id = circ->n_circ_id; /* switch it */ - conn = circ->n_conn; + or_conn = circ->n_conn; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */ + or_conn = TO_OR_CIRCUIT(circ)->p_conn; } else { - cell->circ_id = circ->p_circ_id; /* switch it */ - conn = circ->p_conn; + // XXXX NM WARN. + return 0; } - if (!conn) { - if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { + if (!or_conn) { + // XXXX Can this splice stuff be done more cleanly? + if (! CIRCUIT_IS_ORIGIN(circ) && + TO_OR_CIRCUIT(circ)->rend_splice && + cell_direction == CELL_DIRECTION_OUT) { + or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice; tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); - tor_assert(circ->rend_splice->purpose == - CIRCUIT_PURPOSE_REND_ESTABLISHED); - cell->circ_id = circ->rend_splice->p_circ_id; - if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice, + tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + cell->circ_id = splice->p_circ_id; + if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice), CELL_DIRECTION_IN)) < 0) { log_warn(LD_REND, "Error relaying cell across rendezvous; closing " "circuits"); @@ -219,7 +225,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) log_debug(LD_OR,"Passing on unrecognized cell."); ++stats_n_relay_cells_relayed; - connection_or_write_cell_to_buf(cell, conn); + connection_or_write_cell_to_buf(cell, or_conn); return 0; } @@ -240,12 +246,10 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) * Return -1 to indicate that we should mark the circuit for close, * else return 0. */ -/* wrap this into receive_relay_cell one day */ static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, crypt_path_t **layer_hint, char *recognized) { - crypt_path_t *thishop; relay_header_t rh; tor_assert(circ); @@ -257,8 +261,8 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, if (cell_direction == CELL_DIRECTION_IN) { if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. * We'll want to do layered decrypts. */ - tor_assert(circ->cpath); - thishop = circ->cpath; + crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath; + thishop = cpath; if (thishop->state != CPATH_STATE_OPEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay cell before first created cell? Closing."); @@ -281,25 +285,27 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, } thishop = thishop->next; - } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN); - log_warn(LD_OR,"in-cell at OP not recognized. Closing."); + } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN); + log_warn(LD_OR,"in-cell at client not recognized. Closing."); return -1; } else { /* we're in the middle. Just one crypt. */ - if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, + cell->payload, 1) < 0) return -1; // log_fn(LOG_DEBUG,"Skipping recognized check, because we're not " -// "the OP."); +// "the client."); } } else /* cell_direction == CELL_DIRECTION_OUT */ { /* we're in the middle. Just one crypt. */ - if (relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto, + cell->payload, 0) < 0) return -1; relay_header_unpack(&rh, cell->payload); if (rh.recognized == 0) { /* it's possibly recognized. have to check digest to be sure. */ - if (relay_digest_matches(circ->n_digest, cell)) { + if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) { *recognized = 1; return 0; } @@ -308,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, return 0; } -/** Package a relay cell: +/** Package a relay cell from an edge: * - Encrypt it to the right layer * - connection_or_write_cell_to_buf to the right conn */ @@ -317,12 +323,12 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction, crypt_path_t *layer_hint) { - connection_t *conn; /* where to send the cell */ - crypt_path_t *thishop; /* counter for repeated crypts */ + or_connection_t *conn; /* where to send the cell */ if (cell_direction == CELL_DIRECTION_OUT) { + crypt_path_t *thishop; /* counter for repeated crypts */ conn = circ->n_conn; - if (!conn) { + if (!CIRCUIT_IS_ORIGIN(circ) || !conn) { log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping."); return 0; /* just drop it */ } @@ -339,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, } thishop = thishop->prev; - } while (thishop != circ->cpath->prev); + } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev); } else { /* incoming cell */ - conn = circ->p_conn; - if (!conn) { + or_circuit_t *or_circ; + if (CIRCUIT_IS_ORIGIN(circ)) { /* XXXX RD This is a bug, right? */ - log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping."); + log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping."); assert_circuit_ok(circ); return 0; /* just drop it */ } - relay_set_digest(circ->p_digest, cell); - if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + or_circ = TO_OR_CIRCUIT(circ); + conn = or_circ->p_conn; + relay_set_digest(or_circ->p_digest, cell); + if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0) return -1; } ++stats_n_relay_cells_relayed; @@ -361,10 +369,10 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, /** If cell's stream_id matches the stream_id of any conn that's * attached to circ, return that conn, else return NULL. */ -static connection_t * +static edge_connection_t * relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) { - connection_t *tmpconn; + edge_connection_t *tmpconn; relay_header_t rh; relay_header_unpack(&rh, cell->payload); @@ -376,25 +384,33 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) * that we allow rendezvous *to* an OP. */ - for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - if (cell_direction == CELL_DIRECTION_OUT || - connection_edge_is_rendezvous_stream(tmpconn)) + if (CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && + !tmpconn->_base.marked_for_close) { + log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); return tmpconn; + } } - } - for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); - return tmpconn; + } else { + for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && + !tmpconn->_base.marked_for_close) { + log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + if (cell_direction == CELL_DIRECTION_OUT || + connection_edge_is_rendezvous_stream(tmpconn)) + return tmpconn; + } } - } - for (tmpconn = circ->resolving_streams; tmpconn; - tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - return tmpconn; + for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && + !tmpconn->_base.marked_for_close) { + log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + return tmpconn; + } } } return NULL; /* probably a begin relay cell */ @@ -439,30 +455,32 @@ relay_header_unpack(relay_header_t *dest, const char *src) * return -1. Else return 0. */ int -connection_edge_send_command(connection_t *fromconn, circuit_t *circ, +connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ, int relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer) { cell_t cell; relay_header_t rh; int cell_direction; + /* XXXX NM Split this function into a separate versions per circuit type? */ - if (fromconn && fromconn->marked_for_close) { + if (fromconn && fromconn->_base.marked_for_close) { log_warn(LD_BUG, "Bug: called on conn that's already marked for close at %s:%d.", - fromconn->marked_for_close_file, fromconn->marked_for_close); + fromconn->_base.marked_for_close_file, + fromconn->_base.marked_for_close); return 0; } if (!circ) { tor_assert(fromconn); - if (fromconn->type == CONN_TYPE_AP) { + if (fromconn->_base.type == CONN_TYPE_AP) { log_info(LD_APP,"no circ. Closing conn."); connection_mark_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL); } else { log_info(LD_EXIT,"no circ. Closing conn."); - fromconn->has_sent_end = 1; /* no circ to send to */ - connection_mark_for_close(fromconn); + fromconn->_base.edge_has_sent_end = 1; /* no circ to send to */ + connection_mark_for_close(TO_CONN(fromconn)); } return -1; } @@ -472,9 +490,11 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ, if (cpath_layer) { cell.circ_id = circ->n_circ_id; cell_direction = CELL_DIRECTION_OUT; - } else { - cell.circ_id = circ->p_circ_id; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; cell_direction = CELL_DIRECTION_IN; + } else { + return -1; } memset(&rh, 0, sizeof(rh)); @@ -619,8 +639,8 @@ errno_to_end_reason(int e) E_CASE(EMFILE): return END_STREAM_REASON_RESOURCELIMIT; default: - log_info(LD_EXIT, "Didn't recognize errno %d (%s); telling the OP that " - "we are ending a stream for 'misc' reason.", + log_info(LD_EXIT, "Didn't recognize errno %d (%s); telling the client " + "that we are ending a stream for 'misc' reason.", e, tor_socket_strerror(e)); return END_STREAM_REASON_MISC; } @@ -648,15 +668,16 @@ edge_reason_is_retriable(int reason) */ static int connection_edge_process_end_not_open( - relay_header_t *rh, cell_t *cell, circuit_t *circ, - connection_t *conn, crypt_path_t *layer_hint) + relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint) { struct in_addr in; routerinfo_t *exitrouter; int reason = *(cell->payload+RELAY_HEADER_SIZE); + (void) layer_hint; /* unused */ if (rh->length > 0 && edge_reason_is_retriable(reason) && - conn->type == CONN_TYPE_AP) { + conn->_base.type == CONN_TYPE_AP) { log_info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.", safe_str(conn->socks_request->address), connection_edge_end_reason_str(reason)); @@ -696,19 +717,35 @@ connection_edge_process_end_not_open( /* rewrite it to an IP if we learned one. */ addressmap_rewrite(conn->socks_request->address, sizeof(conn->socks_request->address)); + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + } if (connection_ap_detach_retriable(conn, circ) >= 0) return 0; /* else, conn will get closed below */ break; + case END_STREAM_REASON_CONNECTREFUSED: + if (!conn->_base.chosen_exit_optional) + break; /* break means it'll close, below */ + /* Else fall through: expire this circuit, clear the + * chosen_exit_name field, and try again. */ case END_STREAM_REASON_RESOLVEFAILED: + case END_STREAM_REASON_TIMEOUT: case END_STREAM_REASON_MISC: if (client_dns_incr_failures(conn->socks_request->address) < MAX_RESOLVE_FAILURES) { /* We haven't retried too many times; reattach the connection. */ circuit_log_path(LOG_INFO,LD_APP,circ); - tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->_base.timestamp_dirty); + circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + } if (connection_ap_detach_retriable(conn, circ) >= 0) return 0; /* else, conn will get closed below */ @@ -729,6 +766,11 @@ connection_edge_process_end_not_open( exitrouter->exit_policy = router_parse_addr_policy_from_string("reject *:*", -1); } + if (conn->_base.chosen_exit_optional) { + /* stop wanting a specific exit */ + conn->_base.chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + } if (connection_ap_detach_retriable(conn, circ) >= 0) return 0; /* else, will close below */ @@ -740,12 +782,13 @@ connection_edge_process_end_not_open( log_info(LD_APP, "Edge got end (%s) before we're connected. Marking for close.", connection_edge_end_reason_str(rh->length > 0 ? reason : -1)); - if (conn->type == CONN_TYPE_AP) { + if (conn->_base.type == CONN_TYPE_AP) { circuit_log_path(LOG_INFO,LD_APP,circ); connection_mark_unattached_ap(conn, reason); } else { - conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */ - connection_mark_for_close(conn); + /* we just got an 'end', don't need to send one */ + conn->_base.edge_has_sent_end = 1; + connection_mark_for_close(TO_CONN(conn)); } return 0; } @@ -760,22 +803,29 @@ connection_edge_process_end_not_open( static int connection_edge_process_relay_cell_not_open( relay_header_t *rh, cell_t *cell, circuit_t *circ, - connection_t *conn, crypt_path_t *layer_hint) + edge_connection_t *conn, crypt_path_t *layer_hint) { - if (rh->command == RELAY_COMMAND_END) - return connection_edge_process_end_not_open(rh, cell, circ, conn, - layer_hint); + if (rh->command == RELAY_COMMAND_END) { + if (CIRCUIT_IS_ORIGIN(circ)) + return connection_edge_process_end_not_open(rh, cell, + TO_ORIGIN_CIRCUIT(circ), conn, + layer_hint); + else + return 0; + } - if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) { - if (conn->state != AP_CONN_STATE_CONNECT_WAIT) { + if (conn->_base.type == CONN_TYPE_AP && + rh->command == RELAY_COMMAND_CONNECTED) { + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) { log_warn(LD_APP,"Got 'connected' while not in state connect_wait. " "Dropping."); return 0; } // log_fn(LOG_INFO,"Connected! Notifying application."); - conn->state = AP_CONN_STATE_OPEN; + conn->_base.state = AP_CONN_STATE_OPEN; log_info(LD_APP,"'connected' received after %d seconds.", - (int)(time(NULL) - conn->timestamp_lastread)); + (int)(time(NULL) - conn->_base.timestamp_lastread)); if (rh->length >= 4) { uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE)); int ttl; @@ -794,25 +844,29 @@ connection_edge_process_relay_cell_not_open( client_dns_set_addressmap(conn->socks_request->address, addr, conn->chosen_exit_name, ttl); } - circuit_log_path(LOG_INFO,LD_APP,circ); - connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED); + circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ)); + /* don't send a socks reply to transparent conns */ + if (!conn->socks_request->has_finished) + connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED); /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1) < 0) { /* (We already sent an end cell if possible) */ - connection_mark_for_close(conn); + connection_mark_for_close(TO_CONN(conn)); return 0; } return 0; } - if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) { + if (conn->_base.type == CONN_TYPE_AP && + rh->command == RELAY_COMMAND_RESOLVED) { int ttl; int answer_len; - if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) { + if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) { log_warn(LD_APP,"Got a 'resolved' cell while not in state resolve_wait. " "Dropping."); return 0; } - tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE); + tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE || + conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR); answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) { log_warn(LD_PROTOCOL, "Dropping malformed 'resolved' cell"); @@ -836,8 +890,8 @@ connection_edge_process_relay_cell_not_open( log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an unexpected relay command %d, in state %d (%s). Dropping.", - rh->command, conn->state, - conn_state_to_string(conn->type, conn->state)); + rh->command, conn->_base.state, + conn_state_to_string(conn->_base.type, conn->_base.state)); return 0; /* for forward compatibility, don't kill the circuit */ // connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, // conn->cpath_layer); @@ -856,7 +910,7 @@ connection_edge_process_relay_cell_not_open( */ static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, - connection_t *conn, + edge_connection_t *conn, crypt_path_t *layer_hint) { static int num_seen=0; @@ -881,13 +935,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, /* either conn is NULL, in which case we've got a control cell, or else * conn points to the recognized stream. */ - if (conn && !connection_state_is_open(conn)) + if (conn && !connection_state_is_open(TO_CONN(conn))) return connection_edge_process_relay_cell_not_open( &rh, cell, circ, conn, layer_hint); switch (rh.command) { case RELAY_COMMAND_DROP: - log_info(domain,"Got a relay-level padding cell. Dropping."); +// log_info(domain,"Got a relay-level padding cell. Dropping."); return 0; case RELAY_COMMAND_BEGIN: if (layer_hint && @@ -909,7 +963,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, "(relay data) circ deliver_window below 0. Killing."); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer); - connection_mark_for_close(conn); + connection_mark_for_close(TO_CONN(conn)); return -END_CIRC_REASON_TORPROTOCOL; } log_debug(domain,"circ deliver_window now %d.", layer_hint ? @@ -930,7 +984,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, stats_n_data_bytes_received += rh.length; connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE, - rh.length, conn); + rh.length, TO_CONN(conn)); connection_edge_consider_sending_sendme(conn); return 0; case RELAY_COMMAND_END: @@ -942,32 +996,21 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } /* XXX add to this log_fn the exit node's nickname? */ log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.", - conn->s, + conn->_base.s, connection_edge_end_reason_str(rh.length > 0 ? *(char *)(cell->payload+RELAY_HEADER_SIZE) : -1), conn->stream_id); if (conn->socks_request && !conn->socks_request->has_finished) log_warn(LD_BUG, "Bug: open stream hasn't sent socks answer yet? Closing."); -#ifdef HALF_OPEN - conn->done_sending = 1; - shutdown(conn->s, 1); /* XXX check return; refactor NM */ - if (conn->done_receiving) { - /* We just *got* an end; no reason to send one. */ - conn->has_sent_end = 1; - connection_mark_for_close(conn); - conn->hold_open_until_flushed = 1; - } -#else /* We just *got* an end; no reason to send one. */ - conn->has_sent_end = 1; - if (!conn->marked_for_close) { + conn->_base.edge_has_sent_end = 1; + if (!conn->_base.marked_for_close) { /* only mark it if not already marked. it's possible to * get the 'end' right around when the client hangs up on us. */ - connection_mark_for_close(conn); - conn->hold_open_until_flushed = 1; + connection_mark_for_close(TO_CONN(conn)); + conn->_base.hold_open_until_flushed = 1; } -#endif return 0; case RELAY_COMMAND_EXTEND: if (conn) { @@ -982,12 +1025,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } log_debug(domain,"Got an extended cell! Yay."); - if ((reason = circuit_finish_handshake(circ, CELL_CREATED, + if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ), + CELL_CREATED, cell->payload+RELAY_HEADER_SIZE)) < 0) { log_warn(domain,"circuit_finish_handshake failed."); return reason; } - if ((reason=circuit_send_next_onion_skin(circ))<0) { + if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) { log_info(domain,"circuit_send_next_onion_skin() failed."); return reason; } @@ -1000,7 +1044,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (circ->n_conn) { uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE); connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, 0, NULL); } log_debug(LD_EXIT, "Processed 'truncate', replying."); { @@ -1015,7 +1059,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping."); return 0; } - circuit_truncated(circ, layer_hint); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { @@ -1045,11 +1089,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, conn->package_window += STREAMWINDOW_INCREMENT; log_debug(domain,"stream-level sendme, packagewindow now %d.", conn->package_window); - connection_start_reading(conn); + connection_start_reading(TO_CONN(conn)); /* handle whatever might still be on the inbuf */ if (connection_edge_package_raw_inbuf(conn, 1) < 0) { /* (We already sent an end cell if possible) */ - connection_mark_for_close(conn); + connection_mark_for_close(TO_CONN(conn)); return 0; } return 0; @@ -1065,7 +1109,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, circ->purpose); return 0; } - connection_exit_begin_resolve(cell, circ); + connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); return 0; case RELAY_COMMAND_RESOLVED: if (conn) { @@ -1108,7 +1152,7 @@ uint64_t stats_n_data_bytes_received = 0; * be marked for close, else return 0. */ int -connection_edge_package_raw_inbuf(connection_t *conn, int package_partial) +connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial) { size_t amount_to_process, length; char payload[CELL_PAYLOAD_SIZE]; @@ -1116,11 +1160,11 @@ connection_edge_package_raw_inbuf(connection_t *conn, int package_partial) unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT; tor_assert(conn); - tor_assert(!connection_speaks_cells(conn)); - if (conn->marked_for_close) { + + if (conn->_base.marked_for_close) { log_warn(LD_BUG, "Bug: called on conn that's already marked for close at %s:%d.", - conn->marked_for_close_file, conn->marked_for_close); + conn->_base.marked_for_close_file, conn->_base.marked_for_close); return 0; } @@ -1138,11 +1182,11 @@ repeat_connection_edge_package_raw_inbuf: if (conn->package_window <= 0) { log_info(domain,"called with package_window %d. Skipping.", conn->package_window); - connection_stop_reading(conn); + connection_stop_reading(TO_CONN(conn)); return 0; } - amount_to_process = buf_datalen(conn->inbuf); + amount_to_process = buf_datalen(conn->_base.inbuf); if (!amount_to_process) return 0; @@ -1158,10 +1202,10 @@ repeat_connection_edge_package_raw_inbuf: stats_n_data_bytes_packaged += length; stats_n_data_cells_packaged += 1; - connection_fetch_from_buf(payload, length, conn); + connection_fetch_from_buf(payload, length, TO_CONN(conn)); - log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->s, - (int)length, (int)buf_datalen(conn->inbuf)); + log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s, + (int)length, (int)buf_datalen(conn->_base.inbuf)); if (connection_edge_send_command(conn, circ, RELAY_COMMAND_DATA, payload, length, conn->cpath_layer) < 0) @@ -1177,7 +1221,7 @@ repeat_connection_edge_package_raw_inbuf: } if (--conn->package_window <= 0) { /* is it 0 after decrement? */ - connection_stop_reading(conn); + connection_stop_reading(TO_CONN(conn)); log_debug(domain,"conn->package_window reached 0."); circuit_consider_stop_edge_reading(circ, conn->cpath_layer); return 0; /* don't process the inbuf any more */ @@ -1195,11 +1239,11 @@ repeat_connection_edge_package_raw_inbuf: * low, send back a suitable number of stream-level sendme cells. */ void -connection_edge_consider_sending_sendme(connection_t *conn) +connection_edge_consider_sending_sendme(edge_connection_t *conn) { circuit_t *circ; - if (connection_outbuf_too_full(conn)) + if (connection_outbuf_too_full(TO_CONN(conn))) return; circ = circuit_get_by_edge_conn(conn); @@ -1213,7 +1257,7 @@ connection_edge_consider_sending_sendme(connection_t *conn) while (conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { log_debug(conn->cpath_layer?LD_APP:LD_EXIT, "Outbuf %d, Queueing stream sendme.", - (int)conn->outbuf_flushlen); + (int)conn->_base.outbuf_flushlen); conn->deliver_window += STREAMWINDOW_INCREMENT; if (connection_edge_send_command(conn, circ, RELAY_COMMAND_SENDME, NULL, 0, conn->cpath_layer) < 0) { @@ -1234,10 +1278,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) log_debug(layer_hint?LD_APP:LD_EXIT,"resuming"); - /* have to check both n_streams and p_streams, to handle rendezvous */ - if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint) - >= 0) - circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint); + if (CIRCUIT_IS_ORIGIN(circ)) + circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams, + circ, layer_hint); + else + circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams, + circ, layer_hint); } /** A helper function for circuit_resume_edge_reading() above. @@ -1245,21 +1291,21 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) * of a linked list of edge streams that should each be considered. */ static int -circuit_resume_edge_reading_helper(connection_t *conn, +circuit_resume_edge_reading_helper(edge_connection_t *conn, circuit_t *circ, crypt_path_t *layer_hint) { for ( ; conn; conn=conn->next_stream) { - if (conn->marked_for_close) + if (conn->_base.marked_for_close) continue; if ((!layer_hint && conn->package_window > 0) || (layer_hint && conn->package_window > 0 && conn->cpath_layer == layer_hint)) { - connection_start_reading(conn); + connection_start_reading(TO_CONN(conn)); /* handle whatever might still be on the inbuf */ if (connection_edge_package_raw_inbuf(conn, 1)<0) { /* (We already sent an end cell if possible) */ - connection_mark_for_close(conn); + connection_mark_for_close(TO_CONN(conn)); continue; } @@ -1282,16 +1328,17 @@ circuit_resume_edge_reading_helper(connection_t *conn, static int circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) { - connection_t *conn = NULL; + edge_connection_t *conn = NULL; unsigned domain = layer_hint ? LD_APP : LD_EXIT; if (!layer_hint) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); if (circ->package_window <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); - for (conn = circ->n_streams; conn; conn=conn->next_stream) - connection_stop_reading(conn); + for (conn = or_circ->n_streams; conn; conn=conn->next_stream) + connection_stop_reading(TO_CONN(conn)); return 1; } return 0; @@ -1301,12 +1348,16 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) layer_hint->package_window); if (layer_hint->package_window <= 0) { log_debug(domain,"yes, at-origin. stopped."); +#if 0 + // XXXX NM DEAD CODE. for (conn = circ->n_streams; conn; conn=conn->next_stream) if (conn->cpath_layer == layer_hint) connection_stop_reading(conn); - for (conn = circ->p_streams; conn; conn=conn->next_stream) +#endif + for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; + conn=conn->next_stream) if (conn->cpath_layer == layer_hint) - connection_stop_reading(conn); + connection_stop_reading(TO_CONN(conn)); return 1; } return 0; |