commit 5ee0cccd49e57fad8c810e817d912d4a61dbc96c Merge: 44010c6fc 7ca5f4bf0 Author: Nick Mathewson nickm@torproject.org Date: Fri Dec 8 14:58:43 2017 -0500
Merge branch 'macro_free_v2_squashed'
changes/bug24337 | 8 ++++ configure.ac | 1 - doc/HACKING/CodingStandards.md | 40 ++++++++++++++++++ src/common/address.c | 6 +-- src/common/address.h | 13 +++--- src/common/aes.c | 4 +- src/common/aes.h | 4 +- src/common/buffers.c | 2 +- src/common/buffers.h | 3 +- src/common/compat.c | 5 ++- src/common/compat_libevent.c | 4 +- src/common/compat_libevent.h | 8 +++- src/common/compat_threads.c | 4 +- src/common/compat_threads.h | 6 ++- src/common/compress.c | 2 +- src/common/compress.h | 4 +- src/common/compress_lzma.c | 2 +- src/common/compress_lzma.h | 5 ++- src/common/compress_zlib.c | 2 +- src/common/compress_zlib.h | 5 ++- src/common/compress_zstd.c | 2 +- src/common/compress_zstd.h | 5 ++- src/common/confline.c | 2 +- src/common/confline.h | 7 ++- src/common/container.c | 19 ++++++--- src/common/container.h | 27 +++++++++--- src/common/crypto.c | 10 ++--- src/common/crypto.h | 19 ++++++--- src/common/crypto_ed25519.c | 2 +- src/common/crypto_ed25519.h | 5 ++- src/common/di_ops.c | 2 +- src/common/di_ops.h | 7 ++- src/common/handles.h | 4 +- src/common/log.c | 11 +++-- src/common/memarea.c | 2 +- src/common/memarea.h | 7 ++- src/common/procmon.c | 2 +- src/common/procmon.h | 4 +- src/common/sandbox.c | 6 ++- src/common/storagedir.c | 2 +- src/common/storagedir.h | 5 ++- src/common/timers.c | 2 +- src/common/timers.h | 3 +- src/common/tortls.c | 4 +- src/common/tortls.h | 7 ++- src/common/util.c | 2 +- src/common/util.h | 25 ++++++++++- src/common/workqueue.c | 5 ++- src/or/addressmap.c | 35 ++++++++++----- src/or/bridges.c | 7 ++- src/or/channel.c | 26 ++++++------ src/or/channel.h | 9 +++- src/or/circuitbuild.c | 2 +- src/or/circuitbuild.h | 4 +- src/or/circuitlist.c | 4 +- src/or/circuitlist.h | 3 +- src/or/circuitmux.c | 2 +- src/or/circuitmux.h | 4 +- src/or/config.c | 10 +++-- src/or/config.h | 12 ++++-- src/or/confparse.c | 2 +- src/or/confparse.h | 7 ++- src/or/connection.c | 15 ++++--- src/or/connection.h | 6 ++- src/or/connection_edge.c | 12 +++--- src/or/connection_or.c | 8 ++-- src/or/connection_or.h | 7 ++- src/or/conscache.c | 2 +- src/or/conscache.h | 7 ++- src/or/consdiffmgr.c | 17 ++++++-- src/or/control.c | 5 ++- src/or/cpuworker.c | 19 +++++++-- src/or/dircollate.c | 7 ++- src/or/dircollate.h | 4 +- src/or/directory.c | 2 +- src/or/directory.h | 4 +- src/or/dirserv.c | 2 +- src/or/dirserv.h | 4 +- src/or/dirvote.c | 7 ++- src/or/dirvote.h | 4 +- src/or/dns.c | 10 ++--- src/or/dnsserv.c | 4 +- src/or/entrynodes.c | 8 ++-- src/or/entrynodes.h | 21 +++++++-- src/or/ext_orport.c | 2 +- src/or/ext_orport.h | 6 ++- src/or/fp_pair.c | 2 +- src/or/fp_pair.h | 7 ++- src/or/geoip.c | 5 ++- src/or/hs_cache.c | 44 ++++++++++++------- src/or/hs_circuitmap.c | 5 ++- src/or/hs_common.c | 2 +- src/or/hs_common.h | 4 +- src/or/hs_descriptor.c | 10 ++--- src/or/hs_descriptor.h | 21 ++++++--- src/or/hs_ident.c | 6 +-- src/or/hs_ident.h | 12 ++++-- src/or/hs_service.c | 12 +++--- src/or/hs_service.h | 23 ++++++---- src/or/microdesc.h | 6 ++- src/or/networkstatus.c | 8 ++-- src/or/networkstatus.h | 16 +++++-- src/or/nodelist.c | 6 ++- src/or/onion.c | 2 +- src/or/onion.h | 4 +- src/or/onion_fast.c | 2 +- src/or/onion_fast.h | 4 +- src/or/onion_ntor.c | 2 +- src/or/onion_ntor.h | 4 +- src/or/policies.c | 10 ++--- src/or/policies.h | 12 ++++-- src/or/proto_socks.c | 2 +- src/or/proto_socks.h | 4 +- src/or/protover.c | 2 +- src/or/protover.h | 4 +- src/or/relay.c | 4 +- src/or/relay.h | 8 +++- src/or/rendcache.c | 32 +++++++------- src/or/rendcache.h | 18 +++++--- src/or/rendclient.c | 14 +++--- src/or/rendcommon.c | 6 +-- src/or/rendcommon.h | 14 ++++-- src/or/rendservice.c | 18 ++++---- src/or/rendservice.h | 22 +++++++--- src/or/rephist.c | 20 ++++++--- src/or/replaycache.c | 2 +- src/or/replaycache.h | 4 +- src/or/router.c | 3 +- src/or/router.h | 4 +- src/or/routerlist.c | 40 ++++++++++++------ src/or/routerlist.h | 14 ++++-- src/or/routerset.c | 2 +- src/or/routerset.h | 3 +- src/or/scheduler_kist.c | 4 +- src/or/shared_random.c | 4 +- src/or/shared_random.h | 3 +- src/or/shared_random_state.c | 14 ++++-- src/or/shared_random_state.h | 2 +- src/or/statefile.c | 2 +- src/or/statefile.h | 3 +- src/or/torcert.c | 4 +- src/or/torcert.h | 7 ++- src/or/transports.c | 2 +- src/or/transports.h | 3 +- src/test/test-timers.c | 2 +- src/test/test.c | 6 +-- src/test/test_address.c | 16 +++---- src/test/test_cell_queue.c | 4 +- src/test/test_channel.c | 2 +- src/test/test_circuitlist.c | 28 ++++++------ src/test/test_dir.c | 6 +-- src/test/test_dir_handle_get.c | 96 +++++++++++++++++++++--------------------- src/test/test_dns.c | 6 +-- src/test/test_entryconn.c | 34 +++++++-------- src/test/test_entrynodes.c | 4 +- src/test/test_extorport.c | 10 ++--- src/test/test_handles.c | 2 + src/test/test_hs_cache.c | 2 +- src/test/test_hs_client.c | 12 +++--- src/test/test_hs_intropoint.c | 38 ++++++++--------- src/test/test_hs_service.c | 16 +++---- src/test/test_link_handshake.c | 14 +++--- src/test/test_oom.c | 2 +- src/test/test_policy.c | 8 ++-- src/test/test_rendcache.c | 8 ++-- src/test/test_replay.c | 2 +- src/test/test_routerlist.c | 2 +- src/test/test_routerset.c | 56 ++++++++++++------------ src/test/test_shared_random.c | 2 +- 169 files changed, 976 insertions(+), 555 deletions(-)
diff --cc src/or/channel.c index 5b9d860ba,90536b146..7fa976817 --- a/src/or/channel.c +++ b/src/or/channel.c @@@ -159,15 -202,39 +160,15 @@@ HT_PROTOTYPE(channel_idmap, channel_idm HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_)
-static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q); -#if 0 -static int cell_queue_entry_is_padding(cell_queue_entry_t *q); -#endif -static cell_queue_entry_t * -cell_queue_entry_new_fixed(cell_t *cell); -static cell_queue_entry_t * -cell_queue_entry_new_var(var_cell_t *var_cell); -static int is_destroy_cell(channel_t *chan, - const cell_queue_entry_t *q, circid_t *circid_out); - -static void channel_assert_counter_consistency(void); - /* Functions to maintain the digest map */ -static void channel_add_to_digest_map(channel_t *chan); static void channel_remove_from_digest_map(channel_t *chan);
- 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); -/* - * Flush cells from just the outgoing queue without trying to get them - * from circuits; used internall by channel_flush_some_cells(). - */ -static ssize_t -channel_flush_some_cells_from_outgoing_queue(channel_t *chan, - ssize_t num_cells); + static void channel_force_xfree(channel_t *chan); -static void channel_free_list(smartlist_t *channels, int mark_for_close); ++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); ++ int mark_for_close); + static void channel_listener_force_xfree(channel_listener_t *chan_l); -static size_t channel_get_cell_queue_entry_size(channel_t *chan, - cell_queue_entry_t *q); -static void -channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
/*********************************** * Channel state utility functions * @@@ -962,8 -1067,9 +963,8 @@@ channel_listener_free_(channel_listener */
static void - channel_force_free(channel_t *chan) + channel_force_xfree(channel_t *chan) { - cell_queue_entry_t *cell, *cell_tmp; tor_assert(chan);
log_debug(LD_CHANNEL, @@@ -1429,18 -1668,250 +1430,17 @@@ channel_clear_remote_end(channel_t *cha }
/** - * Set the remote end metadata (identity_digest/nickname) of a channel + * Write to a channel the given packed cell. * - * Return 0 on success or -1 on error. - * This function sets new remote end info on a channel; this is intended - * for use by the lower layer. - */ - -void -channel_set_remote_end(channel_t *chan, - const char *identity_digest, - const char *nickname) -{ - int was_in_digest_map, should_be_in_digest_map, state_not_in_map; - - tor_assert(chan); - - log_debug(LD_CHANNEL, - "Setting remote endpoint identity on channel %p with " - "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)"); - - state_not_in_map = CHANNEL_CONDEMNED(chan); - - was_in_digest_map = - !state_not_in_map && - chan->registered && - !tor_digest_is_zero(chan->identity_digest); - should_be_in_digest_map = - !state_not_in_map && - chan->registered && - (identity_digest && - !tor_digest_is_zero(identity_digest)); - - if (was_in_digest_map) - /* We should always remove it; we'll add it back if we're writing - * in a new digest. - */ - channel_remove_from_digest_map(chan); - - if (identity_digest) { - memcpy(chan->identity_digest, - identity_digest, - sizeof(chan->identity_digest)); - - } else { - memset(chan->identity_digest, 0, - sizeof(chan->identity_digest)); - } - - tor_free(chan->nickname); - if (nickname) - chan->nickname = tor_strdup(nickname); - - /* Put it in the digest map if we should */ - if (should_be_in_digest_map) - channel_add_to_digest_map(chan); -} - -/** - * Duplicate a cell queue entry; this is a shallow copy intended for use - * in channel_write_cell_queue_entry(). - */ - -static cell_queue_entry_t * -cell_queue_entry_dup(cell_queue_entry_t *q) -{ - cell_queue_entry_t *rv = NULL; - - tor_assert(q); - - rv = tor_malloc(sizeof(*rv)); - memcpy(rv, q, sizeof(*rv)); - - return rv; -} - -/** - * Free a cell_queue_entry_t; the handed_off parameter indicates whether - * the contents were passed to the lower layer (it is responsible for - * them) or not (we should free). - */ - -STATIC void -cell_queue_entry_xfree(cell_queue_entry_t *q, int handed_off) -{ - if (!q) return; - - if (!handed_off) { - /* - * If we handed it off, the recipient becomes responsible (or - * with packed cells the channel_t subclass calls packed_cell - * free after writing out its contents; see, e.g., - * channel_tls_write_packed_cell_method(). Otherwise, we have - * to take care of it here if possible. - */ - switch (q->type) { - case CELL_QUEUE_FIXED: - if (q->u.fixed.cell) { - /* - * There doesn't seem to be a cell_free() function anywhere in the - * pre-channel code; just use tor_free() - */ - tor_free(q->u.fixed.cell); - } - break; - case CELL_QUEUE_PACKED: - if (q->u.packed.packed_cell) { - packed_cell_free(q->u.packed.packed_cell); - } - break; - case CELL_QUEUE_VAR: - if (q->u.var.var_cell) { - /* - * This one's in connection_or.c; it'd be nice to figure out the - * whole flow of cells from one end to the other and factor the - * cell memory management functions like this out of the specific - * TLS lower layer. - */ - var_cell_free(q->u.var.var_cell); - } - break; - default: - /* - * Nothing we can do if we don't know the type; this will - * have been warned about elsewhere. - */ - break; - } - } - tor_free(q); -} - -#if 0 -/** - * Check whether a cell queue entry is padding; this is a helper function - * for channel_write_cell_queue_entry() - */ - -static int -cell_queue_entry_is_padding(cell_queue_entry_t *q) -{ - tor_assert(q); - - if (q->type == CELL_QUEUE_FIXED) { - if (q->u.fixed.cell) { - if (q->u.fixed.cell->command == CELL_PADDING || - q->u.fixed.cell->command == CELL_VPADDING) { - return 1; - } - } - } else if (q->type == CELL_QUEUE_VAR) { - if (q->u.var.var_cell) { - if (q->u.var.var_cell->command == CELL_PADDING || - q->u.var.var_cell->command == CELL_VPADDING) { - return 1; - } - } - } - - return 0; -} -#endif /* 0 */ - -/** - * Allocate a new cell queue entry for a fixed-size cell - */ - -static cell_queue_entry_t * -cell_queue_entry_new_fixed(cell_t *cell) -{ - cell_queue_entry_t *q = NULL; - - tor_assert(cell); - - q = tor_malloc(sizeof(*q)); - q->type = CELL_QUEUE_FIXED; - q->u.fixed.cell = cell; - - return q; -} - -/** - * Allocate a new cell queue entry for a variable-size cell - */ - -static cell_queue_entry_t * -cell_queue_entry_new_var(var_cell_t *var_cell) -{ - cell_queue_entry_t *q = NULL; - - tor_assert(var_cell); - - q = tor_malloc(sizeof(*q)); - q->type = CELL_QUEUE_VAR; - q->u.var.var_cell = var_cell; - - return q; -} - -/** - * Ask how big the cell contained in a cell_queue_entry_t is - */ - -static size_t -channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q) -{ - size_t rv = 0; - - tor_assert(chan); - tor_assert(q); - - switch (q->type) { - case CELL_QUEUE_FIXED: - rv = get_cell_network_size(chan->wide_circ_ids); - break; - case CELL_QUEUE_VAR: - rv = get_var_cell_header_size(chan->wide_circ_ids) + - (q->u.var.var_cell ? q->u.var.var_cell->payload_len : 0); - break; - case CELL_QUEUE_PACKED: - rv = get_cell_network_size(chan->wide_circ_ids); - break; - default: - tor_assert_nonfatal_unreached_once(); - } - - return rv; -} - -/** - * Write to a channel based on a cell_queue_entry_t * - * Given a cell_queue_entry_t filled out by the caller, try to send the cell - * and queue it if we can't. + * Two possible errors can happen. Either the channel is not opened or the + * lower layer (specialized channel) failed to write it. In both cases, it is + * the caller responsability to free the cell. */ - -static void -channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) +static int +write_packed_cell(channel_t *chan, packed_cell_t *cell) { - int result = 0, sent = 0; - cell_queue_entry_t *tmp = NULL; + int ret = -1; size_t cell_bytes;
tor_assert(chan); diff --cc src/or/channel.h index d88a77c9a,909813cee..0f685011a --- a/src/or/channel.h +++ b/src/or/channel.h @@@ -457,9 -511,16 +457,12 @@@ void channel_close_from_lower_layer(cha 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); + void channel_free_(channel_t *chan); + #define channel_free(chan) FREE_AND_NULL(channel_t, channel_free_, (chan)) + void channel_listener_free_(channel_listener_t *chan_l); + #define channel_listener_free(chan_l) \ + FREE_AND_NULL(channel_listener_t, channel_listener_free_, (chan_l))
/* State/metadata setters */
diff --cc src/or/protover.h index 83a728e62,2539c92c3..8bbc2fc71 --- a/src/or/protover.h +++ b/src/or/protover.h @@@ -82,10 -82,11 +82,12 @@@ STATIC smartlist_t *parse_protocol_list STATIC char *encode_protocol_list(const smartlist_t *sl); STATIC const char *protocol_type_to_str(protocol_type_t pr); STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out); - STATIC void proto_entry_free(proto_entry_t *entry); + STATIC void proto_entry_free_(proto_entry_t *entry); -#endif + #define proto_entry_free(entry) \ + FREE_AND_NULL(proto_entry_t, proto_entry_free_, (entry))
+#endif /* !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) */ + #endif /* defined(PROTOVER_PRIVATE) */
#endif /* !defined(TOR_PROTOVER_H) */ diff --cc src/or/rendservice.h index 15badce6a,70ebd8786..88da7b866 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@@ -183,11 -189,26 +189,17 @@@ void rend_service_init(void) rend_service_port_config_t *rend_service_parse_port_config(const char *string, const char *sep, char **err_msg_out); - void rend_service_port_config_free(rend_service_port_config_t *p); - - void rend_authorized_client_free(rend_authorized_client_t *client); + void rend_service_port_config_free_(rend_service_port_config_t *p); + #define rend_service_port_config_free(p) \ + FREE_AND_NULL(rend_service_port_config_t, rend_service_port_config_free_, \ + (p)) + + void rend_authorized_client_free_(rend_authorized_client_t *client); + #define rend_authorized_client_free(client) \ + FREE_AND_NULL(rend_authorized_client_t, rend_authorized_client_free_, \ + (client))
-/** Return value from rend_service_add_ephemeral. */ -typedef enum { - RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */ - RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */ - RSAE_ADDREXISTS = -3, /**< Onion address collision */ - RSAE_BADPRIVKEY = -2, /**< Invalid public key */ - RSAE_INTERNAL = -1, /**< Internal error */ - RSAE_OKAY = 0 /**< Service added as expected */ -} rend_service_add_ephemeral_status_t; -rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk, +hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk, smartlist_t *ports, int max_streams_per_circuit, int max_streams_close_circuit, diff --cc src/test/test_channel.c index 38b69a9ad,594372693..55d43a04e --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@@ -523,162 -640,152 +523,162 @@@ test_channel_dumpstats(void *arg return; }
+/* Test outbound cell. The callstack is: + * channel_flush_some_cells() + * -> channel_flush_from_first_active_circuit() + * -> channel_write_packed_cell() + * -> write_packed_cell() + * -> chan->write_packed_cell() fct ptr. + * + * This test goes from a cell in a circuit up to the channel write handler + * that should put them on the connection outbuf. */ static void -test_channel_flush(void *arg) +test_channel_outbound_cell(void *arg) { - channel_t *ch = NULL; - cell_t *cell = NULL; - packed_cell_t *p_cell = NULL; - var_cell_t *v_cell = NULL; - int init_count; - - (void)arg; + int old_count; + channel_t *chan = NULL; + packed_cell_t *p_cell = NULL, *p_cell2 = NULL; + origin_circuit_t *circ = NULL; + cell_queue_t *queue;
- ch = new_fake_channel(); - tt_assert(ch); + (void) arg;
- /* Cache the original count */ - init_count = test_cells_written; + /* The channel will be freed so we need to hijack this so the scheduler + * doesn't get confused. */ + MOCK(scheduler_release_channel, scheduler_release_channel_mock);
- /* Stop accepting so we can queue some */ - test_chan_accept_cells = 0; + /* Accept cells to lower layer */ + test_chan_accept_cells = 1;
- /* Queue a regular cell */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch, cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Queue a var cell */ - v_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(v_cell); - channel_write_var_cell(ch, v_cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Try a packed cell now */ + /* Setup a valid circuit to queue a cell. */ + circ = origin_circuit_new(); + tt_assert(circ); + /* Circuit needs an origin purpose to be considered origin. */ + TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + TO_CIRCUIT(circ)->n_circ_id = 42; + /* This is the outbound test so use the next channel queue. */ + queue = &TO_CIRCUIT(circ)->n_chan_cells; + /* Setup packed cell to queue on the circuit. */ p_cell = packed_cell_new(); tt_assert(p_cell); - channel_write_packed_cell(ch, p_cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Now allow writes through again */ - test_chan_accept_cells = 1; - - /* ...and flush */ - channel_flush_cells(ch); - - /* All three should have gone through */ - tt_int_op(test_cells_written, OP_EQ, init_count + 3); - - done: - tor_free(ch); - - return; -} - -/** - * Channel flush tests that require cmux mocking - */ - -static void -test_channel_flushmux(void *arg) -{ - channel_t *ch = NULL; - int old_count, q_len_before, q_len_after; - ssize_t result; - - (void)arg; - - /* Install mocks we need for this test */ - MOCK(channel_flush_from_first_active_circuit, - chan_test_channel_flush_from_first_active_circuit_mock); - MOCK(circuitmux_num_cells, - chan_test_circuitmux_num_cells_mock); - - ch = new_fake_channel(); - tt_assert(ch); - ch->cmux = circuitmux_alloc(); - + p_cell2 = packed_cell_new(); + tt_assert(p_cell2); + /* Setup a channel to put the circuit on. */ + chan = new_fake_channel(); + tt_assert(chan); + chan->state = CHANNEL_STATE_OPENING; + channel_change_state_open(chan); + /* Outbound channel. */ + channel_mark_outgoing(chan); + /* Try to register it so we can clean it through the channel cleanup + * process. */ + channel_register(chan); + tt_int_op(chan->registered, OP_EQ, 1); + /* Set EWMA policy so we can pick it when flushing. */ + channel_set_cmux_policy_everywhere(&ewma_policy); + tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy); + + /* Register circuit to the channel circid map which will attach the circuit + * to the channel's cmux as well. */ + circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan); + tt_int_op(channel_num_circuits(chan), OP_EQ, 1); + tt_assert(!TO_CIRCUIT(circ)->next_active_on_n_chan); + tt_assert(!TO_CIRCUIT(circ)->prev_active_on_n_chan); + /* Test the cmux state. */ + tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux); + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + + /* Flush the channel without any cell on it. */ old_count = test_cells_written; - - test_target_cmux = ch->cmux; - test_cmux_cells = 1; - - /* Enable cell acceptance */ - test_chan_accept_cells = 1; - - result = channel_flush_some_cells(ch, 1); - - tt_int_op(result, OP_EQ, 1); + ssize_t flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 0); + tt_int_op(test_cells_written, OP_EQ, old_count); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 0); + tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 0); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0); + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 0); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 0); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, 0); + + /* Queue cell onto the next queue that is the outbound direction. Than + * update its cmux so the circuit can be picked when flushing cells. */ + cell_queue_append(queue, p_cell); + p_cell = NULL; + tt_int_op(queue->n, OP_EQ, 1); + cell_queue_append(queue, p_cell2); + p_cell2 = NULL; + tt_int_op(queue->n, OP_EQ, 2); + + update_circuit_on_cmux(TO_CIRCUIT(circ), CELL_DIRECTION_OUT); + tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 1); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 2); + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + + /* From this point on, we have a queued cell on an active circuit attached + * to the channel's cmux. */ + + /* Flush the first cell. This is going to go down the call stack. */ + old_count = test_cells_written; + flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 1); tt_int_op(test_cells_written, OP_EQ, old_count + 1); - tt_int_op(test_cmux_cells, OP_EQ, 0); - - /* Now try it without accepting to force them into the queue */ - test_chan_accept_cells = 0; - test_cmux_cells = 1; - q_len_before = chan_cell_queue_len(&(ch->outgoing_queue)); - - result = channel_flush_some_cells(ch, 1); - - /* We should not have actually flushed any */ - tt_int_op(result, OP_EQ, 0); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 1); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 1); + /* Circuit should remain active because there is a second cell queued. */ + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + /* Should still be attached. */ + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 1); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0)); + + /* Flush second cell. This is going to go down the call stack. */ + old_count = test_cells_written; + flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 1); tt_int_op(test_cells_written, OP_EQ, old_count + 1); - /* But we should have gotten to the fake cellgen loop */ - tt_int_op(test_cmux_cells, OP_EQ, 0); - /* ...and we should have a queued cell */ - q_len_after = chan_cell_queue_len(&(ch->outgoing_queue)); - tt_int_op(q_len_after, OP_EQ, q_len_before + 1); - - /* Now accept cells again and drain the queue */ - test_chan_accept_cells = 1; - channel_flush_cells(ch); - tt_int_op(test_cells_written, OP_EQ, old_count + 2); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - test_target_cmux = NULL; - test_cmux_cells = 0; + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 0); + /* No more cells should make the circuit inactive. */ + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 0); + /* Should still be attached. */ + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 2); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0) * 2);
done: - if (ch) - circuitmux_free(ch->cmux); - tor_free(ch); - - UNMOCK(channel_flush_from_first_active_circuit); - UNMOCK(circuitmux_num_cells); - - test_chan_accept_cells = 0; - - return; + if (circ) { - circuit_free(TO_CIRCUIT(circ)); ++ circuit_free_(TO_CIRCUIT(circ)); + } + tor_free(p_cell); + channel_free_all(); + UNMOCK(scheduler_release_channel); }
+/* Test inbound cell. The callstack is: + * channel_process_cell() + * -> chan->cell_handler() + * + * This test is about checking if we can process an inbound cell down to the + * channel handler. */ static void -test_channel_incoming(void *arg) +test_channel_inbound_cell(void *arg) { - channel_t *ch = NULL; + channel_t *chan = NULL; cell_t *cell = NULL; - var_cell_t *var_cell = NULL; int old_count;
- (void)arg; + (void) arg;
- /* Mock these for duration of the test */ - MOCK(scheduler_channel_doesnt_want_writes, - scheduler_channel_doesnt_want_writes_mock); - MOCK(scheduler_release_channel, - scheduler_release_channel_mock); + /* The channel will be freed so we need to hijack this so the scheduler + * doesn't get confused. */ + MOCK(scheduler_release_channel, scheduler_release_channel_mock);
/* Accept cells to lower layer */ test_chan_accept_cells = 1;