72 #define CIRCUITMUX_PRIVATE
80 #include "core/or/or_circuit_st.h"
108 unsigned int cell_count;
136 static inline unsigned int
162 return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
169 static inline unsigned int
172 return (((
unsigned int)(a->circ_id) << 8) ^
173 ((
unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
174 ((
unsigned int)(a->chan_id & 0xffffffff)));
195 circuitmux_t *rv = NULL;
197 rv = tor_malloc_zero(
sizeof(*rv));
198 rv->chanid_circid_map = tor_malloc_zero(
sizeof(*( rv->chanid_circid_map)));
199 HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
221 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
226 log_warn(
LD_BUG,
"Somehow, an HT iterator gave us a NULL pointer.");
243 if (to_remove->muxinfo.cell_count > 0) {
255 if (to_remove->muxinfo.cell_count > 0) {
264 "Circuit %u/channel %"PRIu64
" had direction == "
265 "CELL_DIRECTION_IN, but isn't an or_circuit_t",
266 (
unsigned)to_remove->circ_id,
267 (to_remove->chan_id));
271 if (to_remove->muxinfo.policy_data) {
279 cmux->policy->free_circ_data(cmux,
282 to_remove->muxinfo.policy_data);
283 to_remove->muxinfo.policy_data = NULL;
288 "Couldn't find circuit %u (for channel %"PRIu64
")",
289 (
unsigned)to_remove->circ_id,
290 (to_remove->chan_id));
295 "Couldn't find channel %"PRIu64
" (for circuit id %u)",
296 (to_remove->chan_id),
297 (
unsigned)to_remove->circ_id);
301 tor_assert(to_remove->muxinfo.policy_data == NULL);
304 i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
310 cmux->n_circuits = 0;
311 cmux->n_active_circuits = 0;
326 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
351 if (cmux->policy && cmux->policy->free_cmux_data) {
352 if (cmux->policy_data) {
353 cmux->policy->free_cmux_data(cmux, cmux->policy_data);
354 cmux->policy_data = NULL;
358 if (cmux->chanid_circid_map) {
359 HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
367 if (cmux->destroy_cell_queue.n > 0) {
368 cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
371 "Freeing cmux at %p with %u queued destroys; the last cmux "
372 "destroy balance was %"PRId64
", global is %"PRId64,
373 cmux, cmux->destroy_cell_queue.n,
378 "Freeing cmux at %p with no queued destroys, the cmux destroy "
379 "balance was %"PRId64
", global is %"PRId64,
434 uint64_t last_chan_id_searched = 0;
440 old_pol = cmux->policy;
441 old_pol_data = cmux->policy_data;
445 if (old_pol == new_pol)
return;
448 if (new_pol && new_pol->alloc_cmux_data) {
455 new_pol_data = new_pol->alloc_cmux_data(cmux);
460 cmux->policy = new_pol;
461 cmux->policy_data = new_pol_data;
464 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
473 if (!chan || last_chan_id_searched != (*i)->chan_id) {
475 last_chan_id_searched = (*i)->chan_id;
484 if (old_pol && old_pol->notify_circ_inactive &&
485 (*i)->muxinfo.cell_count > 0) {
486 old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
487 (*i)->muxinfo.policy_data);
491 if ((*i)->muxinfo.policy_data) {
496 old_pol->free_circ_data(cmux, old_pol_data, circ,
497 (*i)->muxinfo.policy_data);
498 (*i)->muxinfo.policy_data = NULL;
502 if (new_pol && new_pol->alloc_circ_data) {
509 (*i)->muxinfo.policy_data =
510 new_pol->alloc_circ_data(cmux, new_pol_data, circ,
511 (*i)->muxinfo.direction,
512 (*i)->muxinfo.cell_count);
516 if (new_pol && new_pol->notify_circ_active &&
517 (*i)->muxinfo.cell_count > 0) {
518 new_pol->notify_circ_active(cmux, new_pol_data, circ,
519 (*i)->muxinfo.policy_data);
523 i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
534 old_pol->free_cmux_data(cmux, old_pol_data);
562 return hashent->muxinfo.direction;
587 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
606 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
633 return (hashent != NULL);
653 is_active = (hashent->muxinfo.cell_count > 0);
668 unsigned int n_cells = 0;
677 n_cells = hashent->muxinfo.cell_count;
693 return cmux->n_cells + cmux->destroy_cell_queue.n;
705 return cmux->n_active_circuits;
717 return cmux->n_circuits;
736 unsigned int cell_count;
768 search.chan_id = channel_id;
769 search.circ_id = circ_id;
770 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
779 "Circuit %u on channel %"PRIu64
" was already attached to "
780 "(trying to attach to %p)",
781 (
unsigned)circ_id, (channel_id),
788 tor_assert(hashent->muxinfo.direction == direction);
793 if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
794 --(cmux->n_active_circuits);
796 }
else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
797 ++(cmux->n_active_circuits);
800 cmux->n_cells -= hashent->muxinfo.cell_count;
801 cmux->n_cells += cell_count;
802 hashent->muxinfo.cell_count = cell_count;
809 "Attaching circuit %u on channel %"PRIu64
" to cmux %p",
810 (
unsigned)circ_id, (channel_id), cmux);
813 hashent = tor_malloc_zero(
sizeof(*hashent));
814 hashent->chan_id = channel_id;
815 hashent->circ_id = circ_id;
816 hashent->muxinfo.cell_count = cell_count;
817 hashent->muxinfo.direction = direction;
819 if (cmux->policy->alloc_circ_data) {
823 hashent->muxinfo.policy_data =
824 cmux->policy->alloc_circ_data(cmux,
832 HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
836 ++(cmux->n_circuits);
837 if (cell_count > 0) {
838 ++(cmux->n_active_circuits);
841 cmux->n_cells += cell_count;
871 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
882 hashent = HT_FIND(chanid_circid_muxinfo_map,
883 cmux->chanid_circid_map,
899 --(cmux->n_circuits);
900 if (hashent->muxinfo.cell_count > 0) {
901 --(cmux->n_active_circuits);
905 cmux->n_cells -= hashent->muxinfo.cell_count;
908 if (hashent->muxinfo.policy_data) {
913 cmux->policy->free_circ_data(cmux,
916 hashent->muxinfo.policy_data);
917 hashent->muxinfo.policy_data = NULL;
921 tor_assert(last_searched_direction == hashent->muxinfo.direction);
924 HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
929 memwipe(hashent, 0xef,
sizeof(*hashent));
947 if (cmux->policy->notify_circ_active) {
953 cmux->policy->notify_circ_active(cmux, cmux->policy_data,
954 circ, hashent->muxinfo.policy_data);
971 if (cmux->policy->notify_circ_inactive) {
977 cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
978 circ, hashent->muxinfo.policy_data);
999 unsigned int n_cells)
1012 cmux->n_cells -= hashent->muxinfo.cell_count;
1013 cmux->n_cells += n_cells;
1016 if (cmux->policy->notify_set_n_cells) {
1018 cmux->policy->notify_set_n_cells(cmux,
1021 hashent->muxinfo.policy_data,
1029 if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
1030 --(cmux->n_active_circuits);
1031 hashent->muxinfo.cell_count = n_cells;
1034 }
else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
1035 ++(cmux->n_active_circuits);
1036 hashent->muxinfo.cell_count = n_cells;
1039 hashent->muxinfo.cell_count = n_cells;
1068 tor_assert(cmux->policy->pick_active_circuit);
1071 *destroy_queue_out = NULL;
1073 if (cmux->destroy_cell_queue.n &&
1074 (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) {
1080 *destroy_queue_out = &cmux->destroy_cell_queue;
1082 cmux->last_cell_was_destroy = 1;
1083 }
else if (cmux->n_active_circuits > 0) {
1087 circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
1088 cmux->last_cell_was_destroy = 0;
1104 unsigned int n_cells)
1107 int becomes_inactive = 0;
1112 if (n_cells == 0)
return;
1130 tor_assert(n_cells <= hashent->muxinfo.cell_count);
1131 hashent->muxinfo.cell_count -= n_cells;
1133 if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
1135 cmux->n_cells -= n_cells;
1141 if (cmux->policy->notify_xmit_cells) {
1142 cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
1143 hashent->muxinfo.policy_data,
1151 if (becomes_inactive) {
1152 --(cmux->n_active_circuits);
1167 --(cmux->destroy_ctr);
1170 "Cmux at %p sent a destroy, cmux counter is now %"PRId64
", "
1171 "global counter is now %"PRId64,
1173 (cmux->destroy_ctr),
1179 circuitmux_append_destroy_cell(
channel_t *chan,
1187 ++(cmux->destroy_ctr);
1190 "Cmux at %p queued a destroy for circ %u, cmux counter is now "
1191 "%"PRId64
", global counter is now %"PRId64,
1193 (cmux->destroy_ctr),
1209 circuitmux_count_queued_destroy_cells(
const channel_t *chan,
1210 const circuitmux_t *cmux)
1212 int64_t n_destroy_cells = cmux->destroy_ctr;
1213 int64_t destroy_queue_size = cmux->destroy_cell_queue.n;
1215 int64_t manual_total = 0;
1216 int64_t manual_total_in_map = 0;
1219 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
1225 ++manual_total_in_map;
1228 if (n_destroy_cells != destroy_queue_size ||
1229 n_destroy_cells != manual_total ||
1230 n_destroy_cells != manual_total_in_map) {
1231 log_warn(
LD_BUG,
" Discrepancy in counts for queued destroy cells on "
1232 "circuitmux. n=%"PRId64
". queue_size=%"PRId64
". "
1233 "manual_total=%"PRId64
". manual_total_in_map=%"PRId64
".",
1235 (destroy_queue_size),
1237 (manual_total_in_map));
1240 return n_destroy_cells;
1261 if (cmux_1 == cmux_2) {
1266 if (cmux_1->policy && cmux_2->policy) {
1267 if (cmux_1->policy == cmux_2->policy) {
1268 policy = cmux_1->policy;
1270 if (policy->cmp_cmux) {
1272 return policy->cmp_cmux(cmux_1, cmux_1->policy_data,
1273 cmux_2, cmux_2->policy_data);
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.
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
circuitmux_t * circuitmux_alloc(void)
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)
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)
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, destroy_cell_queue_t **destroy_queue_out)
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
unsigned int circuitmux_num_cells(circuitmux_t *cmux)
const circuitmux_policy_t * circuitmux_get_policy(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_free_(void *mem)
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
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)