static void * test_conn_get_rend_setup(const struct testcase_t *tc) { dir_connection_t *conn = DOWNCAST(dir_connection_t, test_conn_get_basic_setup(tc)); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); rend_cache_init(); /* TODO: use directory_initiate_command_rend() to do this - maybe? */ conn->rend_data = tor_malloc_zero(sizeof(rend_data_t)); tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32); memcpy(conn->rend_data->onion_address, TEST_CONN_REND_ADDR, REND_SERVICE_ID_LEN_BASE32+1); conn->rend_data->hsdirs_fp = smartlist_new(); conn->base_.purpose = TEST_CONN_REND_PURPOSE; assert_connection_ok(&conn->base_, time(NULL)); return conn; /* On failure */ done: test_conn_get_rend_teardown(tc, conn); /* Returning NULL causes the unit test to fail */ return NULL; }
/* Like connection_ap_make_link(), but does much less */ static connection_t * test_conn_get_linked_connection(connection_t *l_conn, uint8_t state) { tt_assert(l_conn); assert_connection_ok(l_conn, time(NULL)); /* AP connections don't seem to have purposes */ connection_t *conn = test_conn_get_connection(state, CONN_TYPE_AP, 0); tt_assert(conn); assert_connection_ok(conn, time(NULL)); conn->linked = 1; l_conn->linked = 1; conn->linked_conn = l_conn; l_conn->linked_conn = conn; /* we never opened a real socket, so we can just overwrite it */ conn->s = TOR_INVALID_SOCKET; l_conn->s = TOR_INVALID_SOCKET; assert_connection_ok(conn, time(NULL)); assert_connection_ok(l_conn, time(NULL)); return conn; done: test_conn_download_status_teardown(NULL, NULL); return NULL; }
static int test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg) { (void)tc; connection_t *conn = arg; tt_assert(conn); assert_connection_ok(conn, time(NULL)); /* teardown the connection as fast as possible */ if (conn->linked_conn) { assert_connection_ok(conn->linked_conn, time(NULL)); /* We didn't call tor_libevent_initialize(), so event_base was NULL, * so we can't rely on connection_unregister_events() use of event_del(). */ if (conn->linked_conn->read_event) { tor_free(conn->linked_conn->read_event); conn->linked_conn->read_event = NULL; } if (conn->linked_conn->write_event) { tor_free(conn->linked_conn->write_event); conn->linked_conn->write_event = NULL; } if (!conn->linked_conn->marked_for_close) { connection_close_immediate(conn->linked_conn); connection_mark_for_close(conn->linked_conn); } conn->linked_conn->linked_conn = NULL; connection_free(conn->linked_conn); conn->linked_conn = NULL; } /* We didn't set the events up properly, so we can't use event_del() in * close_closeable_connections() > connection_free() * > connection_unregister_events() */ if (conn->read_event) { tor_free(conn->read_event); conn->read_event = NULL; } if (conn->write_event) { tor_free(conn->write_event); conn->write_event = NULL; } if (!conn->marked_for_close) { connection_close_immediate(conn); connection_mark_for_close(conn); } close_closeable_connections(); /* The unit test will fail if we return 0 */ return 1; /* When conn == NULL, we can't cleanup anything */ done: return 0; }
static int test_conn_get_rsrc_teardown(const struct testcase_t *tc, void *arg) { int rv = 0; connection_t *conn = (connection_t *)arg; tt_assert(conn); assert_connection_ok(conn, time(NULL)); if (conn->type == CONN_TYPE_DIR) { dir_connection_t *dir_conn = DOWNCAST(dir_connection_t, arg); tt_assert(dir_conn); assert_connection_ok(&dir_conn->base_, time(NULL)); /* avoid a last-ditch attempt to refetch the consensus */ dir_conn->base_.state = TEST_CONN_RSRC_STATE_SUCCESSFUL; assert_connection_ok(&dir_conn->base_, time(NULL)); } /* connection_free_() cleans up requested_resource */ rv = test_conn_get_basic_teardown(tc, conn); done: return rv; }
static dir_connection_t * test_conn_download_status_add_a_connection(const char *resource) { dir_connection_t *conn = DOWNCAST(dir_connection_t, test_conn_get_connection( TEST_CONN_STATE, TEST_CONN_TYPE, TEST_CONN_RSRC_PURPOSE)); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); /* Replace the existing resource with the one we want */ if (resource) { if (conn->requested_resource) { tor_free(conn->requested_resource); } conn->requested_resource = tor_strdup(resource); assert_connection_ok(&conn->base_, time(NULL)); } return conn; done: test_conn_get_rsrc_teardown(NULL, conn); return NULL; }
static void test_conn_get_rend(void *arg) { dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); tt_assert(connection_get_by_type_state_rendquery( conn->base_.type, conn->base_.state, conn->rend_data->onion_address) == TO_CONN(conn)); tt_assert(connection_get_by_type_state_rendquery( TEST_CONN_TYPE, TEST_CONN_STATE, TEST_CONN_REND_ADDR) == TO_CONN(conn)); tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2, !conn->base_.state, "") == NULL); tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2, !TEST_CONN_STATE, TEST_CONN_REND_ADDR_2) == NULL); done: ; }
static void * test_conn_get_rsrc_setup(const struct testcase_t *tc) { dir_connection_t *conn = DOWNCAST(dir_connection_t, test_conn_get_basic_setup(tc)); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); /* TODO: use the canonical function to do this - maybe? */ conn->requested_resource = tor_strdup(TEST_CONN_RSRC); conn->base_.purpose = TEST_CONN_RSRC_PURPOSE; assert_connection_ok(&conn->base_, time(NULL)); return conn; /* On failure */ done: test_conn_get_rend_teardown(tc, conn); /* Returning NULL causes the unit test to fail */ return NULL; }
static dir_connection_t * test_conn_download_status_add_a_connection(void) { dir_connection_t *conn = DOWNCAST(dir_connection_t, test_conn_get_rsrc_setup(NULL)); tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); return conn; done: test_conn_download_status_teardown(NULL, NULL); return NULL; }
static void * test_conn_get_basic_setup(const struct testcase_t *tc) { connection_t *conn = NULL; tor_addr_t addr; int socket_err = 0; int in_progress = 0; (void)tc; MOCK(connection_connect_sockaddr, mock_connection_connect_sockaddr); init_connection_lists(); conn = connection_new(TEST_CONN_TYPE, TEST_CONN_FAMILY); tt_assert(conn); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); tt_assert(!tor_addr_is_null(&addr)); /* XXXX - connection_connect doesn't set these, should it? */ tor_addr_copy_tight(&conn->addr, &addr); conn->port = TEST_CONN_PORT; mock_connection_connect_sockaddr_called = 0; in_progress = connection_connect(conn, TEST_CONN_ADDRESS_PORT, &addr, TEST_CONN_PORT, &socket_err); tt_assert(mock_connection_connect_sockaddr_called == 1); tt_assert(!socket_err); tt_assert(in_progress == 0 || in_progress == 1); /* fake some of the attributes so the connection looks OK */ conn->state = TEST_CONN_STATE; conn->purpose = TEST_CONN_BASIC_PURPOSE; assert_connection_ok(conn, time(NULL)); UNMOCK(connection_connect_sockaddr); return conn; /* On failure */ done: UNMOCK(connection_connect_sockaddr); test_conn_get_basic_teardown(tc, conn); /* Returning NULL causes the unit test to fail */ return NULL; }
static int test_conn_get_rend_teardown(const struct testcase_t *tc, void *arg) { dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); int rv = 0; tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); /* avoid a last-ditch attempt to refetch the descriptor */ conn->base_.purpose = TEST_CONN_REND_PURPOSE_SUCCESSFUL; /* connection_free_() cleans up rend_data */ rv = test_conn_get_basic_teardown(tc, arg); done: rend_cache_free_all(); return rv; }
static connection_t * test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose) { connection_t *conn = NULL; tor_addr_t addr; int socket_err = 0; int in_progress = 0; MOCK(connection_connect_sockaddr, mock_connection_connect_sockaddr); MOCK(tor_close_socket, fake_close_socket); init_connection_lists(); conn = connection_new(type, TEST_CONN_FAMILY); tt_assert(conn); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); tt_assert(!tor_addr_is_null(&addr)); tor_addr_copy_tight(&conn->addr, &addr); conn->port = TEST_CONN_PORT; mock_connection_connect_sockaddr_called = 0; in_progress = connection_connect(conn, TEST_CONN_ADDRESS_PORT, &addr, TEST_CONN_PORT, &socket_err); tt_assert(mock_connection_connect_sockaddr_called == 1); tt_assert(!socket_err); tt_assert(in_progress == 0 || in_progress == 1); /* fake some of the attributes so the connection looks OK */ conn->state = state; conn->purpose = purpose; assert_connection_ok(conn, time(NULL)); UNMOCK(connection_connect_sockaddr); UNMOCK(tor_close_socket); return conn; /* On failure */ done: UNMOCK(connection_connect_sockaddr); UNMOCK(tor_close_socket); return NULL; }
static int test_conn_download_status_teardown(const struct testcase_t *tc, void *arg) { (void)arg; int rv = 0; /* Ignore arg, and just loop through the connection array */ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (conn) { assert_connection_ok(conn, time(NULL)); /* connection_free_() cleans up requested_resource */ rv = test_conn_get_rsrc_teardown(tc, conn); tt_assert(rv == 1); } } SMARTLIST_FOREACH_END(conn); done: return rv; }
/** 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; uint32_t my_apparent_addr = 0; 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) { my_apparent_addr = ntohl(get_uint32(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. */ (void)my_apparent_addr; 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", safe_str_client(conn->_base.address), conn->_base.port, (int)conn->link_proto, hex_str(conn->identity_digest, DIGEST_LEN)); } assert_connection_ok(TO_CONN(conn),time(NULL)); }
static void test_conn_get_rsrc(void *arg) { dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); smartlist_t *the_sl = NULL; tt_assert(conn); assert_connection_ok(&conn->base_, time(NULL)); tt_assert(connection_dir_get_by_purpose_and_resource( conn->base_.purpose, conn->requested_resource) == conn); tt_assert(connection_dir_get_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC) == conn); tt_assert(connection_dir_get_by_purpose_and_resource( !conn->base_.purpose, "") == NULL); tt_assert(connection_dir_get_by_purpose_and_resource( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2) == NULL); tt_assert(connection_dir_get_by_purpose_resource_and_state( conn->base_.purpose, conn->requested_resource, conn->base_.state) == conn); tt_assert(connection_dir_get_by_purpose_resource_and_state( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC, TEST_CONN_STATE) == conn); tt_assert(connection_dir_get_by_purpose_resource_and_state( !conn->base_.purpose, "", !conn->base_.state) == NULL); tt_assert(connection_dir_get_by_purpose_resource_and_state( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2, !TEST_CONN_STATE) == NULL); sl_is_conn_assert(connection_dir_list_by_purpose_and_resource( conn->base_.purpose, conn->requested_resource), conn); sl_is_conn_assert(connection_dir_list_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC), conn); sl_no_conn_assert(connection_dir_list_by_purpose_and_resource( !conn->base_.purpose, "")); sl_no_conn_assert(connection_dir_list_by_purpose_and_resource( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2)); sl_is_conn_assert(connection_dir_list_by_purpose_resource_and_state( conn->base_.purpose, conn->requested_resource, conn->base_.state), conn); sl_is_conn_assert(connection_dir_list_by_purpose_resource_and_state( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC, TEST_CONN_STATE), conn); sl_no_conn_assert(connection_dir_list_by_purpose_resource_and_state( !conn->base_.purpose, "", !conn->base_.state)); sl_no_conn_assert(connection_dir_list_by_purpose_resource_and_state( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2, !TEST_CONN_STATE)); tt_assert(connection_dir_count_by_purpose_and_resource( conn->base_.purpose, conn->requested_resource) == 1); tt_assert(connection_dir_count_by_purpose_and_resource( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC) == 1); tt_assert(connection_dir_count_by_purpose_and_resource( !conn->base_.purpose, "") == 0); tt_assert(connection_dir_count_by_purpose_and_resource( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2) == 0); tt_assert(connection_dir_count_by_purpose_resource_and_state( conn->base_.purpose, conn->requested_resource, conn->base_.state) == 1); tt_assert(connection_dir_count_by_purpose_resource_and_state( TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC, TEST_CONN_STATE) == 1); tt_assert(connection_dir_count_by_purpose_resource_and_state( !conn->base_.purpose, "", !conn->base_.state) == 0); tt_assert(connection_dir_count_by_purpose_resource_and_state( !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2, !TEST_CONN_STATE) == 0); done: smartlist_free(the_sl); }
static void test_conn_get_basic(void *arg) { connection_t *conn = (connection_t*)arg; tor_addr_t addr, addr2; tt_assert(conn); assert_connection_ok(conn, time(NULL)); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); tt_assert(!tor_addr_is_null(&addr)); test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY, &addr2); tt_assert(!tor_addr_is_null(&addr2)); /* Check that we get this connection back when we search for it by * its attributes, but get NULL when we supply a different value. */ tt_assert(connection_get_by_global_id(conn->global_identifier) == conn); tt_assert(connection_get_by_global_id(!conn->global_identifier) == NULL); tt_assert(connection_get_by_type(conn->type) == conn); tt_assert(connection_get_by_type(TEST_CONN_TYPE) == conn); tt_assert(connection_get_by_type(!conn->type) == NULL); tt_assert(connection_get_by_type(!TEST_CONN_TYPE) == NULL); tt_assert(connection_get_by_type_state(conn->type, conn->state) == conn); tt_assert(connection_get_by_type_state(TEST_CONN_TYPE, TEST_CONN_STATE) == conn); tt_assert(connection_get_by_type_state(!conn->type, !conn->state) == NULL); tt_assert(connection_get_by_type_state(!TEST_CONN_TYPE, !TEST_CONN_STATE) == NULL); /* Match on the connection fields themselves */ tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, conn->purpose) == conn); /* Match on the original inputs to the connection */ tt_assert(connection_get_by_type_addr_port_purpose(TEST_CONN_TYPE, &conn->addr, conn->port, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &addr, conn->port, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, TEST_CONN_PORT, conn->purpose) == conn); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, TEST_CONN_BASIC_PURPOSE) == conn); tt_assert(connection_get_by_type_addr_port_purpose(TEST_CONN_TYPE, &addr, TEST_CONN_PORT, TEST_CONN_BASIC_PURPOSE) == conn); /* Then try each of the not-matching combinations */ tt_assert(connection_get_by_type_addr_port_purpose(!conn->type, &conn->addr, conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &addr2, conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, !conn->port, conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(conn->type, &conn->addr, conn->port, !conn->purpose) == NULL); /* Then try everything not-matching */ tt_assert(connection_get_by_type_addr_port_purpose(!conn->type, &addr2, !conn->port, !conn->purpose) == NULL); tt_assert(connection_get_by_type_addr_port_purpose(!TEST_CONN_TYPE, &addr2, !TEST_CONN_PORT, !TEST_CONN_BASIC_PURPOSE) == NULL); done: ; }
static int test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg) { (void)tc; connection_t *conn = arg; tt_assert(conn); assert_connection_ok(conn, time(NULL)); /* teardown the connection as fast as possible */ if (conn->linked_conn) { assert_connection_ok(conn->linked_conn, time(NULL)); /* We didn't call tor_libevent_initialize(), so event_base was NULL, * so we can't rely on connection_unregister_events() use of event_del(). */ if (conn->linked_conn->read_event) { tor_free(conn->linked_conn->read_event); conn->linked_conn->read_event = NULL; } if (conn->linked_conn->write_event) { tor_free(conn->linked_conn->write_event); conn->linked_conn->write_event = NULL; } if (!conn->linked_conn->marked_for_close) { connection_close_immediate(conn->linked_conn); if (CONN_IS_EDGE(conn->linked_conn)) { /* Suppress warnings about all the stuff we didn't do */ TO_EDGE_CONN(conn->linked_conn)->edge_has_sent_end = 1; TO_EDGE_CONN(conn->linked_conn)->end_reason = END_STREAM_REASON_INTERNAL; if (conn->linked_conn->type == CONN_TYPE_AP) { TO_ENTRY_CONN(conn->linked_conn)->socks_request->has_finished = 1; } } connection_mark_for_close(conn->linked_conn); } close_closeable_connections(); } /* We didn't set the events up properly, so we can't use event_del() in * close_closeable_connections() > connection_free() * > connection_unregister_events() */ if (conn->read_event) { tor_free(conn->read_event); conn->read_event = NULL; } if (conn->write_event) { tor_free(conn->write_event); conn->write_event = NULL; } if (!conn->marked_for_close) { connection_close_immediate(conn); if (CONN_IS_EDGE(conn)) { /* Suppress warnings about all the stuff we didn't do */ TO_EDGE_CONN(conn)->edge_has_sent_end = 1; TO_EDGE_CONN(conn)->end_reason = END_STREAM_REASON_INTERNAL; if (conn->type == CONN_TYPE_AP) { TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; } } connection_mark_for_close(conn); } close_closeable_connections(); /* The unit test will fail if we return 0 */ return 1; /* When conn == NULL, we can't cleanup anything */ done: return 0; }