72#define CIRCUITMUX_PRIVATE
80#include "core/or/or_circuit_st.h"
108 unsigned int cell_count;
136static inline unsigned int
162 return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
169static inline unsigned int
175 return (
unsigned) siphash24g(data,
sizeof(data));
196 circuitmux_t *rv = NULL;
198 rv = tor_malloc_zero(
sizeof(*rv));
199 rv->chanid_circid_map = tor_malloc_zero(
sizeof(*( rv->chanid_circid_map)));
200 HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
222 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
227 log_warn(
LD_BUG,
"Somehow, an HT iterator gave us a NULL pointer.");
244 if (to_remove->muxinfo.cell_count > 0) {
256 if (to_remove->muxinfo.cell_count > 0) {
265 "Circuit %u/channel %"PRIu64
" had direction == "
266 "CELL_DIRECTION_IN, but isn't an or_circuit_t",
267 (
unsigned)to_remove->circ_id,
268 (to_remove->chan_id));
272 if (to_remove->muxinfo.policy_data) {
280 cmux->policy->free_circ_data(cmux,
283 to_remove->muxinfo.policy_data);
284 to_remove->muxinfo.policy_data = NULL;
289 "Couldn't find circuit %u (for channel %"PRIu64
")",
290 (
unsigned)to_remove->circ_id,
291 (to_remove->chan_id));
296 "Couldn't find channel %"PRIu64
" (for circuit id %u)",
297 (to_remove->chan_id),
298 (
unsigned)to_remove->circ_id);
302 tor_assert(to_remove->muxinfo.policy_data == NULL);
305 i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
311 cmux->n_circuits = 0;
312 cmux->n_active_circuits = 0;
327 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
352 if (cmux->policy && cmux->policy->free_cmux_data) {
353 if (cmux->policy_data) {
354 cmux->policy->free_cmux_data(cmux, cmux->policy_data);
355 cmux->policy_data = NULL;
359 if (cmux->chanid_circid_map) {
360 HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
368 if (cmux->destroy_cell_queue.n > 0) {
369 cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
372 "Freeing cmux at %p with %u queued destroys; the last cmux "
373 "destroy balance was %"PRId64
", global is %"PRId64,
374 cmux, cmux->destroy_cell_queue.n,
379 "Freeing cmux at %p with no queued destroys, the cmux destroy "
380 "balance was %"PRId64
", global is %"PRId64,
435 uint64_t last_chan_id_searched = 0;
441 old_pol = cmux->policy;
442 old_pol_data = cmux->policy_data;
446 if (old_pol == new_pol)
return;
449 if (new_pol && new_pol->alloc_cmux_data) {
456 new_pol_data = new_pol->alloc_cmux_data(cmux);
461 cmux->policy = new_pol;
462 cmux->policy_data = new_pol_data;
465 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
474 if (!chan || last_chan_id_searched != (*i)->chan_id) {
476 last_chan_id_searched = (*i)->chan_id;
485 if (old_pol && old_pol->notify_circ_inactive &&
486 (*i)->muxinfo.cell_count > 0) {
487 old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
488 (*i)->muxinfo.policy_data);
492 if ((*i)->muxinfo.policy_data) {
497 old_pol->free_circ_data(cmux, old_pol_data, circ,
498 (*i)->muxinfo.policy_data);
499 (*i)->muxinfo.policy_data = NULL;
503 if (new_pol && new_pol->alloc_circ_data) {
510 (*i)->muxinfo.policy_data =
511 new_pol->alloc_circ_data(cmux, new_pol_data, circ,
512 (*i)->muxinfo.direction,
513 (*i)->muxinfo.cell_count);
517 if (new_pol && new_pol->notify_circ_active &&
518 (*i)->muxinfo.cell_count > 0) {
519 new_pol->notify_circ_active(cmux, new_pol_data, circ,
520 (*i)->muxinfo.policy_data);
524 i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
535 old_pol->free_cmux_data(cmux, old_pol_data);
563 return hashent->muxinfo.direction;
588 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
607 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
634 return (hashent != NULL);
654 is_active = (hashent->muxinfo.cell_count > 0);
669 unsigned int n_cells = 0;
678 n_cells = hashent->muxinfo.cell_count;
694 return cmux->n_cells + cmux->destroy_cell_queue.n;
706 return cmux->n_active_circuits;
718 return cmux->n_circuits;
737 unsigned int cell_count;
769 search.chan_id = channel_id;
770 search.circ_id = circ_id;
771 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
780 "Circuit %u on channel %"PRIu64
" was already attached to "
781 "(trying to attach to %p)",
782 (
unsigned)circ_id, (channel_id),
789 tor_assert(hashent->muxinfo.direction == direction);
794 if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
795 --(cmux->n_active_circuits);
797 }
else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
798 ++(cmux->n_active_circuits);
801 cmux->n_cells -= hashent->muxinfo.cell_count;
802 cmux->n_cells += cell_count;
803 hashent->muxinfo.cell_count = cell_count;
810 "Attaching circuit %u on channel %"PRIu64
" to cmux %p",
811 (
unsigned)circ_id, (channel_id), cmux);
814 hashent = tor_malloc_zero(
sizeof(*hashent));
815 hashent->chan_id = channel_id;
816 hashent->circ_id = circ_id;
817 hashent->muxinfo.cell_count = cell_count;
818 hashent->muxinfo.direction = direction;
820 if (cmux->policy->alloc_circ_data) {
824 hashent->muxinfo.policy_data =
825 cmux->policy->alloc_circ_data(cmux,
833 HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
837 ++(cmux->n_circuits);
838 if (cell_count > 0) {
839 ++(cmux->n_active_circuits);
842 cmux->n_cells += cell_count;
872 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
883 hashent = HT_FIND(chanid_circid_muxinfo_map,
884 cmux->chanid_circid_map,
900 --(cmux->n_circuits);
901 if (hashent->muxinfo.cell_count > 0) {
902 --(cmux->n_active_circuits);
906 cmux->n_cells -= hashent->muxinfo.cell_count;
909 if (hashent->muxinfo.policy_data) {
914 cmux->policy->free_circ_data(cmux,
917 hashent->muxinfo.policy_data);
918 hashent->muxinfo.policy_data = NULL;
922 tor_assert(last_searched_direction == hashent->muxinfo.direction);
925 HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
930 memwipe(hashent, 0xef,
sizeof(*hashent));
948 if (cmux->policy->notify_circ_active) {
954 cmux->policy->notify_circ_active(cmux, cmux->policy_data,
955 circ, hashent->muxinfo.policy_data);
972 if (cmux->policy->notify_circ_inactive) {
978 cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
979 circ, hashent->muxinfo.policy_data);
1000 unsigned int n_cells)
1013 cmux->n_cells -= hashent->muxinfo.cell_count;
1014 cmux->n_cells += n_cells;
1017 if (cmux->policy->notify_set_n_cells) {
1019 cmux->policy->notify_set_n_cells(cmux,
1022 hashent->muxinfo.policy_data,
1030 if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
1031 --(cmux->n_active_circuits);
1032 hashent->muxinfo.cell_count = n_cells;
1035 }
else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
1036 ++(cmux->n_active_circuits);
1037 hashent->muxinfo.cell_count = n_cells;
1040 hashent->muxinfo.cell_count = n_cells;
1069 tor_assert(cmux->policy->pick_active_circuit);
1072 *destroy_queue_out = NULL;
1074 if (cmux->destroy_cell_queue.n &&
1075 (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) {
1081 *destroy_queue_out = &cmux->destroy_cell_queue;
1083 cmux->last_cell_was_destroy = 1;
1084 }
else if (cmux->n_active_circuits > 0) {
1088 circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
1089 cmux->last_cell_was_destroy = 0;
1105 unsigned int n_cells)
1108 int becomes_inactive = 0;
1113 if (n_cells == 0)
return;
1131 tor_assert(n_cells <= hashent->muxinfo.cell_count);
1132 hashent->muxinfo.cell_count -= n_cells;
1134 if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
1136 cmux->n_cells -= n_cells;
1142 if (cmux->policy->notify_xmit_cells) {
1143 cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
1144 hashent->muxinfo.policy_data,
1152 if (becomes_inactive) {
1153 --(cmux->n_active_circuits);
1168 --(cmux->destroy_ctr);
1171 "Cmux at %p sent a destroy, cmux counter is now %"PRId64
", "
1172 "global counter is now %"PRId64,
1174 (cmux->destroy_ctr),
1180circuitmux_append_destroy_cell(
channel_t *chan,
1188 ++(cmux->destroy_ctr);
1191 "Cmux at %p queued a destroy for circ %u, cmux counter is now "
1192 "%"PRId64
", global counter is now %"PRId64,
1194 (cmux->destroy_ctr),
1210circuitmux_count_queued_destroy_cells(
const channel_t *chan,
1211 const circuitmux_t *cmux)
1213 int64_t n_destroy_cells = cmux->destroy_ctr;
1214 int64_t destroy_queue_size = cmux->destroy_cell_queue.n;
1216 int64_t manual_total = 0;
1217 int64_t manual_total_in_map = 0;
1220 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
1226 ++manual_total_in_map;
1229 if (n_destroy_cells != destroy_queue_size ||
1230 n_destroy_cells != manual_total ||
1231 n_destroy_cells != manual_total_in_map) {
1232 log_warn(
LD_BUG,
" Discrepancy in counts for queued destroy cells on "
1233 "circuitmux. n=%"PRId64
". queue_size=%"PRId64
". "
1234 "manual_total=%"PRId64
". manual_total_in_map=%"PRId64
".",
1236 (destroy_queue_size),
1238 (manual_total_in_map));
1241 return n_destroy_cells;
1262 if (cmux_1 == cmux_2) {
1267 if (cmux_1->policy && cmux_2->policy) {
1268 if (cmux_1->policy == cmux_2->policy) {
1269 policy = cmux_1->policy;
1271 if (policy->cmp_cmux) {
1273 return policy->cmp_cmux(cmux_1, cmux_1->policy_data,
1274 cmux_2, cmux_2->policy_data);
static void set_uint64(void *cp, uint64_t v)
static void set_uint32(void *cp, uint32_t v)
int channel_has_queued_writes(channel_t *chan)
channel_t * channel_find_by_global_id(uint64_t global_identifier)
Header file for channel.c.
circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan)
int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
void channel_mark_circid_usable(channel_t *chan, circid_t id)
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Header file for circuitlist.c.
const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux)
cell_direction_t circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
void circuitmux_clear_policy(circuitmux_t *cmux)
static unsigned int chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
void circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
static void circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
void circuitmux_set_policy(circuitmux_t *cmux, const circuitmux_policy_t *pol)
int circuitmux_compare_muxes(circuitmux_t *cmux_1, circuitmux_t *cmux_2)
static void circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux)
void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, cell_direction_t direction)
unsigned int circuitmux_num_circuits(circuitmux_t *cmux)
void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
static chanid_circid_muxinfo_t * circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
static int64_t global_destroy_ctr
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
void circuitmux_free_(circuitmux_t *cmux)
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
circuitmux_t * circuitmux_alloc(void)
int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
static int chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, chanid_circid_muxinfo_t *b)
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, destroy_cell_queue_t **destroy_queue_out)
unsigned int circuitmux_num_cells(circuitmux_t *cmux)
Header file for circuitmux.c.
void memwipe(void *mem, uint8_t byte, size_t sz)
Common functions for cryptographic routines.
HT_PROTOTYPE(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, hs_circuit_hash_token, hs_circuits_have_same_token)
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
void tor_free_(void *mem)
Master header file for Tor-specific functionality.
int channel_flush_from_first_active_circuit(channel_t *chan, int max)
void destroy_cell_queue_init(destroy_cell_queue_t *queue)
void destroy_cell_queue_clear(destroy_cell_queue_t *queue)
void destroy_cell_queue_append(destroy_cell_queue_t *queue, circid_t circid, uint8_t reason)
void smartlist_add(smartlist_t *sl, void *element)
uint64_t global_identifier
cell_queue_t n_chan_cells
cell_queue_t p_chan_cells
#define MOCK_IMPL(rv, funcname, arglist)