diff options
Diffstat (limited to 'src/or/connection.c')
-rw-r--r-- | src/or/connection.c | 536 |
1 files changed, 189 insertions, 347 deletions
diff --git a/src/or/connection.c b/src/or/connection.c index 88346f8aad..3135c61584 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -16,12 +16,10 @@ const char connection_c_id[] = static connection_t *connection_create_listener(const char *listenaddress, uint16_t listenport, int type); -static int connection_init_accepted_conn(connection_t *conn, - uint8_t listener_type); +static int connection_init_accepted_conn(connection_t *conn); static int connection_handle_listener_read(connection_t *conn, int new_type); -static int connection_receiver_bucket_should_increase(or_connection_t *conn); +static int connection_receiver_bucket_should_increase(connection_t *conn); static int connection_finished_flushing(connection_t *conn); -static int connection_flushed_some(connection_t *conn); static int connection_finished_connecting(connection_t *conn); static int connection_reached_eof(connection_t *conn); static int connection_read_to_buf(connection_t *conn, int *max_to_read); @@ -45,7 +43,6 @@ conn_type_to_string(int type) case CONN_TYPE_OR: return "OR"; case CONN_TYPE_EXIT: return "Exit"; case CONN_TYPE_AP_LISTENER: return "Socks listener"; - case CONN_TYPE_AP_TRANS_LISTENER: return "Transparent listener"; case CONN_TYPE_AP: return "Socks"; case CONN_TYPE_DIR_LISTENER: return "Directory listener"; case CONN_TYPE_DIR: return "Directory"; @@ -71,7 +68,6 @@ conn_state_to_string(int type, int state) switch (type) { case CONN_TYPE_OR_LISTENER: case CONN_TYPE_AP_LISTENER: - case CONN_TYPE_AP_TRANS_LISTENER: case CONN_TYPE_DIR_LISTENER: case CONN_TYPE_CONTROL_LISTENER: if (state == LISTENER_STATE_READY) @@ -96,7 +92,6 @@ conn_state_to_string(int type, int state) break; case CONN_TYPE_AP: switch (state) { - case AP_CONN_STATE_ORIGDST_WAIT: case AP_CONN_STATE_SOCKS_WAIT: return "waiting for dest info"; case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc"; case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller"; @@ -149,7 +144,7 @@ conn_state_to_string(int type, int state) /** Allocate space for a new connection_t. This function just initializes * conn; you must call connection_add() to link it into the main array. * - * Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>conn_array_index to + * Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>poll_index to * -1 to signify they are not yet assigned. * * If conn is not a listener type, allocate buffers for it. If it's @@ -162,40 +157,15 @@ conn_state_to_string(int type, int state) connection_t * connection_new(int type) { - static uint32_t n_connections_allocated = 1; + static uint32_t n_connections_allocated = 0; connection_t *conn; time_t now = time(NULL); - size_t length; - uint32_t magic; - switch (type) { - case CONN_TYPE_OR: - length = sizeof(or_connection_t); - magic = OR_CONNECTION_MAGIC; - break; - case CONN_TYPE_EXIT: - case CONN_TYPE_AP: - length = sizeof(edge_connection_t); - magic = EDGE_CONNECTION_MAGIC; - break; - case CONN_TYPE_DIR: - length = sizeof(dir_connection_t); - magic = DIR_CONNECTION_MAGIC; - break; - case CONN_TYPE_CONTROL: - length = sizeof(control_connection_t); - magic = CONTROL_CONNECTION_MAGIC; - break; - default: - length = sizeof(connection_t); - magic = BASE_CONNECTION_MAGIC; - break; - } - - conn = tor_malloc_zero(length); - conn->magic = magic; + conn = tor_malloc_zero(sizeof(connection_t)); + conn->magic = CONNECTION_MAGIC; conn->s = -1; /* give it a default of 'not used' */ - conn->conn_array_index = -1; /* also default to 'not used' */ + conn->poll_index = -1; /* also default to 'not used' */ + conn->global_identifier = n_connections_allocated++; conn->type = type; if (!connection_is_listener(conn)) { /* listeners never use their buf */ @@ -203,14 +173,10 @@ connection_new(int type) conn->outbuf = buf_new(); } if (type == CONN_TYPE_AP) { - TO_EDGE_CONN(conn)->socks_request = - tor_malloc_zero(sizeof(socks_request_t)); - } - if (CONN_IS_EDGE(conn)) { - TO_EDGE_CONN(conn)->global_identifier = n_connections_allocated++; + conn->socks_request = tor_malloc_zero(sizeof(socks_request_t)); } - if (type == CONN_TYPE_OR) - TO_OR_CONN(conn)->next_circ_id = crypto_rand_int(1<<15); + + conn->next_circ_id = crypto_rand_int(1<<15); conn->timestamp_created = now; conn->timestamp_lastread = now; @@ -242,72 +208,30 @@ connection_unregister(connection_t *conn) static void _connection_free(connection_t *conn) { - void *mem; - switch (conn->type) { - case CONN_TYPE_OR: - tor_assert(conn->magic == OR_CONNECTION_MAGIC); - mem = TO_OR_CONN(conn); - break; - case CONN_TYPE_AP: - case CONN_TYPE_EXIT: - tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); - mem = TO_EDGE_CONN(conn); - break; - case CONN_TYPE_DIR: - tor_assert(conn->magic == DIR_CONNECTION_MAGIC); - mem = TO_DIR_CONN(conn); - break; - case CONN_TYPE_CONTROL: - tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); - mem = TO_CONTROL_CONN(conn); - break; - default: - tor_assert(conn->magic == BASE_CONNECTION_MAGIC); - mem = conn; - break; - } + tor_assert(conn->magic == CONNECTION_MAGIC); if (!connection_is_listener(conn)) { buf_free(conn->inbuf); buf_free(conn->outbuf); } - tor_free(conn->address); + tor_free(conn->chosen_exit_name); if (connection_speaks_cells(conn)) { - or_connection_t *or_conn = TO_OR_CONN(conn); - if (or_conn->tls) { - tor_tls_free(or_conn->tls); - or_conn->tls = NULL; + if (conn->tls) { + tor_tls_free(conn->tls); + conn->tls = NULL; } - - tor_free(or_conn->nickname); - } - if (CONN_IS_EDGE(conn)) { - edge_connection_t *edge_conn = TO_EDGE_CONN(conn); - tor_free(edge_conn->chosen_exit_name); - tor_free(edge_conn->socks_request); - } - if (conn->type == CONN_TYPE_CONTROL) { - control_connection_t *control_conn = TO_CONTROL_CONN(conn); - tor_free(control_conn->incoming_cmd); } + if (conn->identity_pkey) + crypto_free_pk_env(conn->identity_pkey); + tor_free(conn->nickname); + tor_free(conn->socks_request); + tor_free(conn->incoming_cmd); tor_free(conn->read_event); /* Probably already freed by connection_free. */ tor_free(conn->write_event); /* Probably already freed by connection_free. */ - - if (conn->type == CONN_TYPE_DIR) { - dir_connection_t *dir_conn = TO_DIR_CONN(conn); - tor_free(dir_conn->requested_resource); - if (dir_conn->zlib_state) - tor_zlib_free(dir_conn->zlib_state); - if (dir_conn->fingerprint_stack) { - SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp)); - smartlist_free(dir_conn->fingerprint_stack); - } - if (dir_conn->cached_dir) - cached_dir_decref(dir_conn->cached_dir); - } + tor_free(conn->requested_resource); if (conn->s >= 0) { log_debug(LD_NET,"closing fd %d.",conn->s); @@ -315,13 +239,13 @@ _connection_free(connection_t *conn) } if (conn->type == CONN_TYPE_OR && - !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { + !tor_digest_is_zero(conn->identity_digest)) { log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest"); - connection_or_remove_from_identity_map(TO_OR_CONN(conn)); + connection_or_remove_from_identity_map(conn); } memset(conn, 0xAA, sizeof(connection_t)); /* poison memory */ - tor_free(mem); + tor_free(conn); } /** Make sure <b>conn</b> isn't in any of the global conn lists; then free it. @@ -335,12 +259,12 @@ connection_free(connection_t *conn) if (connection_speaks_cells(conn)) { if (conn->state == OR_CONN_STATE_OPEN) directory_set_dirty(); - if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { - connection_or_remove_from_identity_map(TO_OR_CONN(conn)); + if (!tor_digest_is_zero(conn->identity_digest)) { + connection_or_remove_from_identity_map(conn); } } if (conn->type == CONN_TYPE_CONTROL) { - TO_CONTROL_CONN(conn)->event_mask = 0; + conn->event_mask = 0; control_update_global_event_mask(); } connection_unregister(conn); @@ -366,7 +290,7 @@ connection_free_all(void) /* We don't want to log any messages to controllers. */ for (i=0;i<n;i++) if (carray[i]->type == CONN_TYPE_CONTROL) - TO_CONTROL_CONN(carray[i])->event_mask = 0; + carray[i]->event_mask = 0; control_update_global_event_mask(); /* Unlink everything from the identity map. */ @@ -395,14 +319,11 @@ void connection_about_to_close_connection(connection_t *conn) { circuit_t *circ; - dir_connection_t *dir_conn; - or_connection_t *or_conn; - edge_connection_t *edge_conn; assert(conn->marked_for_close); if (CONN_IS_EDGE(conn)) { - if (!conn->edge_has_sent_end) { + if (!conn->has_sent_end) { log_warn(LD_BUG, "Harmless bug: Edge connection (marked at %s:%d) " "hasn't sent end yet?", conn->marked_for_close_file, conn->marked_for_close); @@ -412,25 +333,23 @@ connection_about_to_close_connection(connection_t *conn) switch (conn->type) { case CONN_TYPE_DIR: - dir_conn = TO_DIR_CONN(conn); if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) { /* It's a directory connection and connecting or fetching * failed: forget about this router, and maybe try again. */ - connection_dir_request_failed(dir_conn); + connection_dir_request_failed(conn); // XXX if it's rend desc we may want to retry -RD } if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) - rend_client_desc_here(dir_conn->rend_query); /* give it a try */ + rend_client_desc_here(conn->rend_query); /* give it a try */ break; case CONN_TYPE_OR: - or_conn = TO_OR_CONN(conn); /* Remember why we're closing this connection. */ if (conn->state != OR_CONN_STATE_OPEN) { - if (connection_or_nonopen_was_started_here(or_conn)) { - rep_hist_note_connect_failed(or_conn->identity_digest, time(NULL)); - entry_guard_set_status(or_conn->identity_digest, 0); - router_set_status(or_conn->identity_digest, 0); - control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED); + if (connection_or_nonopen_was_started_here(conn)) { + rep_hist_note_connect_failed(conn->identity_digest, time(NULL)); + entry_guard_set_status(conn->identity_digest, 0); + router_set_status(conn->identity_digest, 0); + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); } } else if (conn->hold_open_until_flushed) { /* XXXX009 We used to have an arg that told us whether we closed the @@ -442,32 +361,30 @@ connection_about_to_close_connection(connection_t *conn) * flushing still get noted as dead, not disconnected. But this is an * improvement. -NM */ - rep_hist_note_disconnect(or_conn->identity_digest, time(NULL)); - control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED); - } else if (or_conn->identity_digest) { - rep_hist_note_connection_died(or_conn->identity_digest, time(NULL)); - control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED); + rep_hist_note_disconnect(conn->identity_digest, time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED); + } else if (conn->identity_digest) { + rep_hist_note_connection_died(conn->identity_digest, time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED); } break; case CONN_TYPE_AP: - edge_conn = TO_EDGE_CONN(conn); - if (edge_conn->socks_request->has_finished == 0) { + if (conn->socks_request->has_finished == 0) { /* since conn gets removed right after this function finishes, * there's no point trying to send back a reply at this point. */ log_warn(LD_BUG,"Bug: Closing stream (marked at %s:%d) without sending" " back a socks reply.", conn->marked_for_close_file, conn->marked_for_close); } else { - control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED); + control_event_stream_status(conn, STREAM_EVENT_CLOSED); } break; case CONN_TYPE_EXIT: - edge_conn = TO_EDGE_CONN(conn); if (conn->state == EXIT_CONN_STATE_RESOLVING) { - circ = circuit_get_by_edge_conn(edge_conn); + circ = circuit_get_by_edge_conn(conn); if (circ) - circuit_detach_stream(circ, edge_conn); - connection_dns_remove(edge_conn); + circuit_detach_stream(circ, conn); + connection_dns_remove(conn); } break; case CONN_TYPE_DNSWORKER: @@ -598,7 +515,7 @@ connection_create_listener(const char *listenaddress, uint16_t listenport, #endif memset(&listenaddr,0,sizeof(struct sockaddr_in)); - if (parse_addr_port(LOG_WARN, listenaddress, &address, &addr, &usePort)<0) { + if (parse_addr_port(listenaddress, &address, &addr, &usePort)<0) { log_warn(LD_CONFIG, "Error parsing/resolving ListenAddress %s", listenaddress); return NULL; @@ -617,6 +534,10 @@ connection_create_listener(const char *listenaddress, uint16_t listenport, if (s < 0) { log_warn(LD_NET,"Socket creation failed."); goto err; + } else if (!SOCKET_IS_POLLABLE(s)) { + log_warn(LD_NET,"Too many connections; can't create pollable listener."); + tor_close_socket(s); + goto err; } #ifndef MS_WINDOWS @@ -716,8 +637,16 @@ connection_handle_listener_read(connection_t *conn, int new_type) memset(addrbuf, 0, sizeof(addrbuf)); news = accept(conn->s,(struct sockaddr *)&addrbuf,&remotelen); - if (news < 0) { /* accept() error */ - int e = tor_socket_errno(conn->s); + if (!SOCKET_IS_POLLABLE(news)) { + /* accept() error, or too many conns to poll */ + int e; + if (news>=0) { + /* Too many conns to poll. */ + log_warn(LD_NET,"Too many connections; couldn't accept connection."); + tor_close_socket(news); + return 0; + } + e = tor_socket_errno(conn->s); if (ERRNO_IS_ACCEPT_EAGAIN(e)) { return 0; /* he hung up before we could accept(). that's fine. */ } else if (ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e)) { @@ -790,7 +719,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) return 0; /* no need to tear down the parent */ } - if (connection_init_accepted_conn(newconn, conn->type) < 0) { + if (connection_init_accepted_conn(newconn) < 0) { connection_mark_for_close(newconn); return 0; } @@ -801,23 +730,16 @@ connection_handle_listener_read(connection_t *conn, int new_type) * If conn is an OR, start the tls handshake. */ static int -connection_init_accepted_conn(connection_t *conn, uint8_t listener_type) +connection_init_accepted_conn(connection_t *conn) { connection_start_reading(conn); switch (conn->type) { case CONN_TYPE_OR: - control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW); - return connection_tls_start_handshake(TO_OR_CONN(conn), 1); + control_event_or_conn_status(conn, OR_CONN_EVENT_NEW); + return connection_tls_start_handshake(conn, 1); case CONN_TYPE_AP: - switch (listener_type) { - case CONN_TYPE_AP_LISTENER: - conn->state = AP_CONN_STATE_SOCKS_WAIT; - break; - case CONN_TYPE_AP_TRANS_LISTENER: - conn->state = AP_CONN_STATE_ORIGDST_WAIT; - break; - } + conn->state = AP_CONN_STATE_SOCKS_WAIT; break; case CONN_TYPE_DIR: conn->purpose = DIR_PURPOSE_SERVER; @@ -851,6 +773,12 @@ connection_connect(connection_t *conn, char *address, log_warn(LD_NET,"Error creating network socket: %s", tor_socket_strerror(tor_socket_errno(-1))); return -1; + } else if (!SOCKET_IS_POLLABLE(s)) { + log_warn(LD_NET, + "Too many connections; can't create pollable connection to %s", + escaped_safe_str(address)); + tor_close_socket(s); + return -1; } if (options->OutboundBindAddress) { @@ -975,7 +903,7 @@ retry_listeners(int type, config_line_t *cfg, { char *address=NULL; uint16_t port; - if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) { + if (! parse_addr_port(wanted->value, &address, NULL, &port)) { int addr_matches = !strcasecmp(address, conn->address); tor_free(address); if (! port) @@ -1057,10 +985,6 @@ retry_all_listeners(int force, smartlist_t *replaced_conns, options->SocksPort, "127.0.0.1", force, replaced_conns, new_conns, 0)<0) return -1; - if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress, - options->TransPort, "127.0.0.1", force, - replaced_conns, new_conns, 0)<0) - return -1; if (retry_listeners(CONN_TYPE_CONTROL_LISTENER, options->ControlListenAddress, options->ControlPort, "127.0.0.1", force, @@ -1093,11 +1017,9 @@ connection_bucket_read_limit(connection_t *conn) if (at_most > global_read_bucket) at_most = global_read_bucket; - if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) { - or_connection_t *or_conn = TO_OR_CONN(conn); - if (at_most > or_conn->receiver_bucket) - at_most = or_conn->receiver_bucket; - } + if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) + if (at_most > conn->receiver_bucket) + at_most = conn->receiver_bucket; if (at_most < 0) return 0; @@ -1140,8 +1062,10 @@ static void connection_read_bucket_decrement(connection_t *conn, int num_read) { global_read_bucket -= num_read; + //tor_assert(global_read_bucket >= 0); if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) { - TO_OR_CONN(conn)->receiver_bucket -= num_read; + conn->receiver_bucket -= num_read; + //tor_assert(conn->receiver_bucket >= 0); } } @@ -1158,7 +1082,7 @@ connection_consider_empty_buckets(connection_t *conn) } if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN && - TO_OR_CONN(conn)->receiver_bucket <= 0) { + conn->receiver_bucket <= 0) { LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,"receiver bucket exhausted. Pausing.")); conn->wants_to_read = 1; @@ -1166,7 +1090,8 @@ connection_consider_empty_buckets(connection_t *conn) } } -/** Initialize the global read bucket to options->BandwidthBurst. */ +/** Initialize the global read bucket to options->BandwidthBurst, + * and current_time to the current time. */ void connection_bucket_init(void) { @@ -1184,9 +1109,6 @@ connection_bucket_refill(struct timeval *now) connection_t *conn; connection_t **carray; or_options_t *options = get_options(); - /* Not used, but it should be! We might have rolled over more than one - * second! XXXX */ - (void) now; /* refill the global buckets */ if (global_read_bucket < (int)options->BandwidthBurst) { @@ -1203,15 +1125,10 @@ connection_bucket_refill(struct timeval *now) for (i=0;i<n;i++) { conn = carray[i]; - if (connection_speaks_cells(conn)) { - or_connection_t *or_conn = TO_OR_CONN(conn); - if (connection_receiver_bucket_should_increase(or_conn)) { - or_conn->receiver_bucket += or_conn->bandwidthrate; - if (or_conn->receiver_bucket > or_conn->bandwidthburst) - or_conn->receiver_bucket = or_conn->bandwidthburst; - //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i, - // conn->receiver_bucket); - } + if (connection_receiver_bucket_should_increase(conn)) { + conn->receiver_bucket = conn->bandwidth; + //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i, + // conn->receiver_bucket); } if (conn->wants_to_read == 1 /* it's marked to turn reading back on now */ @@ -1220,7 +1137,7 @@ connection_bucket_refill(struct timeval *now) * not the best place to check this.) */ && (!connection_speaks_cells(conn) || conn->state != OR_CONN_STATE_OPEN || - TO_OR_CONN(conn)->receiver_bucket > 0)) { + conn->receiver_bucket > 0)) { /* and either a non-cell conn or a cell conn with non-empty bucket */ LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,"waking up conn (fd %d)",conn->s)); conn->wants_to_read = 0; @@ -1237,13 +1154,16 @@ connection_bucket_refill(struct timeval *now) * should add another pile of tokens to it? */ static int -connection_receiver_bucket_should_increase(or_connection_t *conn) +connection_receiver_bucket_should_increase(connection_t *conn) { tor_assert(conn); - if (conn->_base.state != OR_CONN_STATE_OPEN) + if (!connection_speaks_cells(conn)) + return 0; /* edge connections don't use receiver_buckets */ + if (conn->state != OR_CONN_STATE_OPEN) return 0; /* only open connections play the rate limiting game */ - if (conn->receiver_bucket >= conn->bandwidthburst) + + if (conn->receiver_bucket >= conn->bandwidth) return 0; return 1; @@ -1275,7 +1195,6 @@ connection_handle_read(connection_t *conn) case CONN_TYPE_OR_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_OR); case CONN_TYPE_AP_LISTENER: - case CONN_TYPE_AP_TRANS_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_AP); case CONN_TYPE_DIR_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_DIR); @@ -1290,15 +1209,15 @@ loop_again: /* There's a read error; kill the connection.*/ connection_close_immediate(conn); /* Don't flush; connection is dead. */ if (CONN_IS_EDGE(conn)) { - edge_connection_t *edge_conn = TO_EDGE_CONN(conn); - connection_edge_end_errno(edge_conn, edge_conn->cpath_layer); - if (edge_conn->socks_request) /* broken, don't send a socks reply back */ - edge_conn->socks_request->has_finished = 1; + connection_edge_end_errno(conn, conn->cpath_layer); + if (conn->socks_request) /* broken, so don't send a socks reply back */ + conn->socks_request->has_finished = 1; } connection_mark_for_close(conn); return -1; } - if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) { + if (CONN_IS_EDGE(conn) && + try_to_read != max_to_read) { /* instruct it not to try to package partial cells. */ if (connection_process_inbuf(conn, 0) < 0) { return -1; @@ -1355,32 +1274,29 @@ connection_read_to_buf(connection_t *conn, int *max_to_read) if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_READING) { int pending; - or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_HANDSHAKING) { /* continue handshaking even if global token bucket is empty */ - return connection_tls_continue_handshake(or_conn); + return connection_tls_continue_handshake(conn); } log_debug(LD_NET, "%d: starting, inbuf_datalen %d (%d pending in tls object)." " at_most %d.", conn->s,(int)buf_datalen(conn->inbuf), - tor_tls_get_pending_bytes(or_conn->tls), at_most); + tor_tls_get_pending_bytes(conn->tls), at_most); /* else open, or closing */ - result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf); + result = read_to_buf_tls(conn->tls, at_most, conn->inbuf); switch (result) { case TOR_TLS_CLOSE: log_info(LD_NET,"TLS connection closed on read. Closing. " "(Nickname %s, address %s", - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + conn->nickname ? conn->nickname : "not set", conn->address); return -1; case TOR_TLS_ERROR: log_info(LD_NET,"tls error. breaking (nickname %s, address %s).", - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + conn->nickname ? conn->nickname : "not set", conn->address); return -1; case TOR_TLS_WANTWRITE: connection_start_writing(conn); @@ -1392,12 +1308,12 @@ connection_read_to_buf(connection_t *conn, int *max_to_read) default: break; } - pending = tor_tls_get_pending_bytes(or_conn->tls); + pending = tor_tls_get_pending_bytes(conn->tls); if (pending) { /* XXXX If we have any pending bytes, read them now. This *can* * take us over our read allotment, but really we shouldn't be * believing that SSL bytes are the same as TCP bytes anyway. */ - int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf); + int r2 = read_to_buf_tls(conn->tls, pending, conn->inbuf); if (r2<0) { log_warn(LD_BUG, "Bug: apparently, reading pending bytes can fail."); return -1; @@ -1407,11 +1323,9 @@ connection_read_to_buf(connection_t *conn, int *max_to_read) } } else { - int reached_eof = 0; CONN_LOG_PROTECT(conn, - result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof)); - if (reached_eof) - conn->inbuf_reached_eof = 1; + result = read_to_buf(conn->s, at_most, conn->inbuf, + &conn->inbuf_reached_eof)); // log_fn(LOG_DEBUG,"read_to_buf returned %d.",read_result); @@ -1504,8 +1418,7 @@ connection_handle_write(connection_t *conn) log_warn(LD_BUG, "getsockopt() syscall failed?! Please report to tor-ops."); if (CONN_IS_EDGE(conn)) - connection_edge_end_errno(TO_EDGE_CONN(conn), - TO_EDGE_CONN(conn)->cpath_layer); + connection_edge_end_errno(conn, conn->cpath_layer); connection_mark_for_close(conn); return -1; } @@ -1514,8 +1427,7 @@ connection_handle_write(connection_t *conn) if (!ERRNO_IS_CONN_EINPROGRESS(e)) { log_info(LD_NET,"in-progress connect failed. Removing."); if (CONN_IS_EDGE(conn)) - connection_edge_end_errno(TO_EDGE_CONN(conn), - TO_EDGE_CONN(conn)->cpath_layer); + connection_edge_end_errno(conn, conn->cpath_layer); connection_close_immediate(conn); connection_mark_for_close(conn); @@ -1523,7 +1435,7 @@ connection_handle_write(connection_t *conn) * ignores unrecognized routers */ if (conn->type == CONN_TYPE_OR && !get_options()->HttpsProxy) - router_set_status(TO_OR_CONN(conn)->identity_digest, 0); + router_set_status(conn->identity_digest, 0); return -1; } else { return 0; /* no change, see if next time is better */ @@ -1538,10 +1450,9 @@ connection_handle_write(connection_t *conn) if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_READING) { - or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_HANDSHAKING) { connection_stop_writing(conn); - if (connection_tls_continue_handshake(or_conn) < 0) { + if (connection_tls_continue_handshake(conn) < 0) { /* Don't flush; connection is dead. */ connection_close_immediate(conn); connection_mark_for_close(conn); @@ -1551,7 +1462,7 @@ connection_handle_write(connection_t *conn) } /* else open, or closing */ - result = flush_buf_tls(or_conn->tls, conn->outbuf, + result = flush_buf_tls(conn->tls, conn->outbuf, max_to_write, &conn->outbuf_flushlen); switch (result) { case TOR_TLS_ERROR: @@ -1589,8 +1500,7 @@ connection_handle_write(connection_t *conn) max_to_write, &conn->outbuf_flushlen)); if (result < 0) { if (CONN_IS_EDGE(conn)) - connection_edge_end_errno(TO_EDGE_CONN(conn), - TO_EDGE_CONN(conn)->cpath_layer); + connection_edge_end_errno(conn, conn->cpath_layer); connection_close_immediate(conn); /* Don't flush; connection is dead. */ connection_mark_for_close(conn); @@ -1598,13 +1508,9 @@ connection_handle_write(connection_t *conn) } } - if (result > 0) { - if (!is_local_IP(conn->addr)) { /* remember it */ - rep_hist_note_bytes_written(result, time(NULL)); - global_write_bucket -= result; - } - if (connection_flushed_some(conn) < 0) - connection_mark_for_close(conn); + if (result > 0 && !is_local_IP(conn->addr)) { /* remember it */ + rep_hist_note_bytes_written(result, now); + global_write_bucket -= result; } if (!connection_wants_to_flush(conn)) { /* it's done flushing */ @@ -1620,17 +1526,16 @@ connection_handle_write(connection_t *conn) /* A controller event has just happened with such urgency that we * need to write it onto controller <b>conn</b> immediately. */ void -_connection_controller_force_write(control_connection_t *control_conn) +_connection_controller_force_write(connection_t *conn) { /* XXX This is hideous code duplication, but raising it seems a little * tricky for now. Think more about this one. We only call it for * EVENT_ERR_MSG, so messing with buckets a little isn't such a big problem. */ int result; - connection_t *conn; - tor_assert(control_conn); - conn = TO_CONN(control_conn); - + tor_assert(conn); + tor_assert(!conn->tls); + tor_assert(conn->type == CONN_TYPE_CONTROL); if (conn->marked_for_close || conn->s < 0) return; @@ -1643,13 +1548,9 @@ _connection_controller_force_write(control_connection_t *control_conn) return; } - if (result > 0) { - if (!is_local_IP(conn->addr)) { /* remember it */ - rep_hist_note_bytes_written(result, time(NULL)); - global_write_bucket -= result; - } - if (connection_flushed_some(conn) < 0) - connection_mark_for_close(conn); + if (result > 0 && !is_local_IP(conn->addr)) { /* remember it */ + rep_hist_note_bytes_written(result, time(NULL)); + global_write_bucket -= result; } if (!connection_wants_to_flush(conn)) { /* it's done flushing */ @@ -1680,7 +1581,7 @@ connection_write_to_buf(const char *string, size_t len, connection_t *conn) wrong compared to our max outbuf size. close the whole circuit. */ log_warn(LD_NET, "write_to_buf failed. Closing circuit (fd %d).", conn->s); - circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), + circuit_mark_for_close(circuit_get_by_edge_conn(conn), END_CIRC_REASON_INTERNAL); } else { log_warn(LD_NET, @@ -1694,45 +1595,13 @@ connection_write_to_buf(const char *string, size_t len, connection_t *conn) conn->outbuf_flushlen += len; } -void -connection_write_to_buf_zlib(dir_connection_t *dir_conn, - const char *data, size_t data_len, - int done) -{ - int r; - size_t old_datalen; - connection_t *conn; - if (!data_len) - return; - conn = TO_CONN(dir_conn); - /* if it's marked for close, only allow write if we mean to flush it */ - if (conn->marked_for_close && !conn->hold_open_until_flushed) - return; - - old_datalen = buf_datalen(conn->outbuf); - /* XXXX TOO much duplicate code! XXXX012NM */ - CONN_LOG_PROTECT(conn, r = write_to_buf_zlib( - conn->outbuf, dir_conn->zlib_state, - data, data_len, done)); - if (r < 0) { - log_warn(LD_NET, - "write_to_buf failed. Closing connection (fd %d).", conn->s); - connection_mark_for_close(conn); - return; - } - - connection_start_writing(conn); - conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen; -} - /** Return the conn to addr/port that has the most recent * timestamp_created, or NULL if no such conn exists. */ -or_connection_t * +connection_t * connection_or_exact_get_by_addr_port(uint32_t addr, uint16_t port) { int i, n; - connection_t *conn; - or_connection_t *best=NULL; + connection_t *conn, *best=NULL; connection_t **carray; get_connection_array(&carray,&n); @@ -1742,8 +1611,8 @@ connection_or_exact_get_by_addr_port(uint32_t addr, uint16_t port) conn->addr == addr && conn->port == port && !conn->marked_for_close && - (!best || best->_base.timestamp_created < conn->timestamp_created)) - best = TO_OR_CONN(conn); + (!best || best->timestamp_created < conn->timestamp_created)) + best = conn; } return best; } @@ -1775,7 +1644,7 @@ connection_get_by_type_addr_port_purpose(int type, /** Return the connection with id <b>id</b> if it is not already marked for * close. */ -edge_connection_t * +connection_t * connection_get_by_global_id(uint32_t id) { int i, n; @@ -1785,9 +1654,9 @@ connection_get_by_global_id(uint32_t id) get_connection_array(&carray,&n); for (i=0;i<n;i++) { conn = carray[i]; - if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->global_identifier == id) { + if (conn->global_identifier == id) { if (!conn->marked_for_close) - return TO_EDGE_CONN(conn); + return conn; else return NULL; } @@ -1865,22 +1734,14 @@ connection_get_by_type_state_rendquery(int type, int state, connection_t *conn; connection_t **carray; - tor_assert(type == CONN_TYPE_DIR || - type == CONN_TYPE_AP || type == CONN_TYPE_EXIT); - get_connection_array(&carray,&n); for (i=0;i<n;i++) { conn = carray[i]; if (conn->type == type && !conn->marked_for_close && - (!state || state == conn->state)) { - if (type == CONN_TYPE_DIR && - rend_cmp_service_ids(rendquery, TO_DIR_CONN(conn)->rend_query)) - return conn; - else if (CONN_IS_EDGE(conn) && - rend_cmp_service_ids(rendquery, TO_EDGE_CONN(conn)->rend_query)) - return conn; - } + (!state || state == conn->state) && + !rend_cmp_service_ids(rendquery, conn->rend_query)) + return conn; } return NULL; } @@ -1911,7 +1772,6 @@ connection_is_listener(connection_t *conn) { if (conn->type == CONN_TYPE_OR_LISTENER || conn->type == CONN_TYPE_AP_LISTENER || - conn->type == CONN_TYPE_AP_TRANS_LISTENER || conn->type == CONN_TYPE_DIR_LISTENER || conn->type == CONN_TYPE_CONTROL_LISTENER) return 1; @@ -1999,7 +1859,7 @@ client_check_address_changed(int sock) uint32_t *ip; if (!last_interface_ip) - get_interface_address(LOG_INFO, &last_interface_ip); + get_interface_address(&last_interface_ip); if (!outgoing_addrs) outgoing_addrs = smartlist_create(); @@ -2017,7 +1877,7 @@ client_check_address_changed(int sock) /* Uh-oh. We haven't connected from this address before. Has the interface * address changed? */ - if (get_interface_address(LOG_INFO, &iface_ip)<0) + if (get_interface_address(&iface_ip)<0) return; ip = tor_malloc(sizeof(uint32_t)); *ip = ip_out; @@ -2051,19 +1911,18 @@ connection_process_inbuf(connection_t *conn, int package_partial) switch (conn->type) { case CONN_TYPE_OR: - return connection_or_process_inbuf(TO_OR_CONN(conn)); + return connection_or_process_inbuf(conn); case CONN_TYPE_EXIT: case CONN_TYPE_AP: - return connection_edge_process_inbuf(TO_EDGE_CONN(conn), - package_partial); + return connection_edge_process_inbuf(conn, package_partial); case CONN_TYPE_DIR: - return connection_dir_process_inbuf(TO_DIR_CONN(conn)); + return connection_dir_process_inbuf(conn); case CONN_TYPE_DNSWORKER: return connection_dns_process_inbuf(conn); case CONN_TYPE_CPUWORKER: return connection_cpu_process_inbuf(conn); case CONN_TYPE_CONTROL: - return connection_control_process_inbuf(TO_CONTROL_CONN(conn)); + return connection_control_process_inbuf(conn); default: log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -2071,17 +1930,6 @@ connection_process_inbuf(connection_t *conn, int package_partial) } } -/** Called whenever we've written data on a connection. */ -static int -connection_flushed_some(connection_t *conn) -{ - if (conn->type == CONN_TYPE_DIR && - conn->state == DIR_CONN_STATE_SERVER_WRITING) - return connection_dirserv_flushed_some(TO_DIR_CONN(conn)); - else - return 0; -} - /** We just finished flushing bytes from conn-\>outbuf, and there * are no more bytes remaining. * @@ -2097,18 +1945,18 @@ connection_finished_flushing(connection_t *conn) switch (conn->type) { case CONN_TYPE_OR: - return connection_or_finished_flushing(TO_OR_CONN(conn)); + return connection_or_finished_flushing(conn); case CONN_TYPE_AP: case CONN_TYPE_EXIT: - return connection_edge_finished_flushing(TO_EDGE_CONN(conn)); + return connection_edge_finished_flushing(conn); case CONN_TYPE_DIR: - return connection_dir_finished_flushing(TO_DIR_CONN(conn)); + return connection_dir_finished_flushing(conn); case CONN_TYPE_DNSWORKER: return connection_dns_finished_flushing(conn); case CONN_TYPE_CPUWORKER: return connection_cpu_finished_flushing(conn); case CONN_TYPE_CONTROL: - return connection_control_finished_flushing(TO_CONTROL_CONN(conn)); + return connection_control_finished_flushing(conn); default: log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -2129,11 +1977,11 @@ connection_finished_connecting(connection_t *conn) switch (conn->type) { case CONN_TYPE_OR: - return connection_or_finished_connecting(TO_OR_CONN(conn)); + return connection_or_finished_connecting(conn); case CONN_TYPE_EXIT: - return connection_edge_finished_connecting(TO_EDGE_CONN(conn)); + return connection_edge_finished_connecting(conn); case CONN_TYPE_DIR: - return connection_dir_finished_connecting(TO_DIR_CONN(conn)); + return connection_dir_finished_connecting(conn); default: log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -2147,18 +1995,18 @@ connection_reached_eof(connection_t *conn) { switch (conn->type) { case CONN_TYPE_OR: - return connection_or_reached_eof(TO_OR_CONN(conn)); + return connection_or_reached_eof(conn); case CONN_TYPE_AP: case CONN_TYPE_EXIT: - return connection_edge_reached_eof(TO_EDGE_CONN(conn)); + return connection_edge_reached_eof(conn); case CONN_TYPE_DIR: - return connection_dir_reached_eof(TO_DIR_CONN(conn)); + return connection_dir_reached_eof(conn); case CONN_TYPE_DNSWORKER: return connection_dns_reached_eof(conn); case CONN_TYPE_CPUWORKER: return connection_cpu_reached_eof(conn); case CONN_TYPE_CONTROL: - return connection_control_reached_eof(TO_CONTROL_CONN(conn)); + return connection_control_reached_eof(conn); default: log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type); tor_fragile_assert(); @@ -2172,28 +2020,10 @@ connection_reached_eof(connection_t *conn) void assert_connection_ok(connection_t *conn, time_t now) { - (void) now; /* XXXX unused. */ tor_assert(conn); + tor_assert(conn->magic == CONNECTION_MAGIC); tor_assert(conn->type >= _CONN_TYPE_MIN); tor_assert(conn->type <= _CONN_TYPE_MAX); - switch (conn->type) { - case CONN_TYPE_OR: - tor_assert(conn->magic == OR_CONNECTION_MAGIC); - break; - case CONN_TYPE_AP: - case CONN_TYPE_EXIT: - tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); - break; - case CONN_TYPE_DIR: - tor_assert(conn->magic == DIR_CONNECTION_MAGIC); - break; - case CONN_TYPE_CONTROL: - tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); - break; - default: - tor_assert(conn->magic == BASE_CONNECTION_MAGIC); - break; - } if (conn->outbuf_flushlen > 0) { tor_assert(connection_is_writing(conn) || conn->wants_to_write); @@ -2202,7 +2032,7 @@ assert_connection_ok(connection_t *conn, time_t now) if (conn->hold_open_until_flushed) tor_assert(conn->marked_for_close); - /* XXX check: wants_to_read, wants_to_write, s, conn_array_index, + /* XXX check: wants_to_read, wants_to_write, s, poll_index, * marked_for_close. */ /* buffers */ @@ -2220,8 +2050,9 @@ assert_connection_ok(connection_t *conn, time_t now) */ #endif - if (conn->type == CONN_TYPE_OR) { - or_connection_t *or_conn = TO_OR_CONN(conn); + if (conn->type != CONN_TYPE_OR) { + tor_assert(!conn->tls); + } else { if (conn->state == OR_CONN_STATE_OPEN) { /* tor_assert(conn->bandwidth > 0); */ /* the above isn't necessarily true: if we just did a TLS @@ -2234,37 +2065,48 @@ assert_connection_ok(connection_t *conn, time_t now) // tor_assert(conn->addr && conn->port); tor_assert(conn->address); if (conn->state > OR_CONN_STATE_PROXY_READING) - tor_assert(or_conn->tls); + tor_assert(conn->tls); } - if (CONN_IS_EDGE(conn)) { - edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + if (! CONN_IS_EDGE(conn)) { + tor_assert(!conn->stream_id); + tor_assert(!conn->next_stream); + tor_assert(!conn->cpath_layer); + tor_assert(!conn->package_window); + tor_assert(!conn->deliver_window); +#if 0 + tor_assert(!conn->done_sending); + tor_assert(!conn->done_receiving); +#endif + } else { /* XXX unchecked: package window, deliver window. */ - if (conn->type == CONN_TYPE_AP) { - - tor_assert(edge_conn->socks_request); - if (conn->state == AP_CONN_STATE_OPEN) { - tor_assert(edge_conn->socks_request->has_finished); - if (!conn->marked_for_close) { - tor_assert(edge_conn->cpath_layer); - assert_cpath_layer_ok(edge_conn->cpath_layer); - } + } + if (conn->type == CONN_TYPE_AP) { + tor_assert(conn->socks_request); + if (conn->state == AP_CONN_STATE_OPEN) { + tor_assert(conn->socks_request->has_finished); + if (!conn->marked_for_close) { + tor_assert(conn->cpath_layer); + assert_cpath_layer_ok(conn->cpath_layer); } } - if (conn->type == CONN_TYPE_EXIT) { - tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || - conn->purpose == EXIT_PURPOSE_RESOLVE); - } + } else { + tor_assert(!conn->socks_request); + } + if (conn->type == CONN_TYPE_EXIT) { + tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || + conn->purpose == EXIT_PURPOSE_RESOLVE); } else if (conn->type != CONN_TYPE_DIR) { - /* Purpose is only used for dir and exit types currently */ - tor_assert(!conn->purpose); + tor_assert(!conn->purpose); /* only used for dir types currently */ + } + if (conn->type != CONN_TYPE_DIR) { + tor_assert(!conn->requested_resource); } switch (conn->type) { case CONN_TYPE_OR_LISTENER: case CONN_TYPE_AP_LISTENER: - case CONN_TYPE_AP_TRANS_LISTENER: case CONN_TYPE_DIR_LISTENER: case CONN_TYPE_CONTROL_LISTENER: tor_assert(conn->state == LISTENER_STATE_READY); @@ -2272,7 +2114,7 @@ assert_connection_ok(connection_t *conn, time_t now) case CONN_TYPE_OR: tor_assert(conn->state >= _OR_CONN_STATE_MIN); tor_assert(conn->state <= _OR_CONN_STATE_MAX); - tor_assert(TO_OR_CONN(conn)->n_circuits >= 0); + tor_assert(conn->n_circuits >= 0); break; case CONN_TYPE_EXIT: tor_assert(conn->state >= _EXIT_CONN_STATE_MIN); @@ -2283,7 +2125,7 @@ assert_connection_ok(connection_t *conn, time_t now) case CONN_TYPE_AP: tor_assert(conn->state >= _AP_CONN_STATE_MIN); tor_assert(conn->state <= _AP_CONN_STATE_MAX); - tor_assert(TO_EDGE_CONN(conn)->socks_request); + tor_assert(conn->socks_request); break; case CONN_TYPE_DIR: tor_assert(conn->state >= _DIR_CONN_STATE_MIN); |