Line data Source code
1 : /* Copyright (c) 2001, Matej Pfajfar. 2 : * Copyright (c) 2001-2004, Roger Dingledine. 3 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 : * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 : /* See LICENSE for licensing information */ 6 : 7 : /** 8 : * \file dispatch_new.c 9 : * \brief Code to construct a dispatch_t from a dispatch_cfg_t. 10 : **/ 11 : 12 : #define DISPATCH_NEW_PRIVATE 13 : #define DISPATCH_PRIVATE 14 : #include "orconfig.h" 15 : 16 : #include "lib/dispatch/dispatch.h" 17 : #include "lib/dispatch/dispatch_st.h" 18 : #include "lib/dispatch/dispatch_cfg.h" 19 : #include "lib/dispatch/dispatch_cfg_st.h" 20 : 21 : #include "lib/cc/ctassert.h" 22 : #include "lib/intmath/cmp.h" 23 : #include "lib/malloc/malloc.h" 24 : #include "lib/log/util_bug.h" 25 : 26 : #include <string.h> 27 : 28 : /** Given a smartlist full of (possibly NULL) pointers to uint16_t values, 29 : * return the largest value, or dflt if the list is empty. */ 30 : STATIC int 31 526 : max_in_u16_sl(const smartlist_t *sl, int dflt) 32 : { 33 526 : uint16_t *maxptr = NULL; 34 3083 : SMARTLIST_FOREACH_BEGIN(sl, uint16_t *, u) { 35 2557 : if (!maxptr) 36 : maxptr = u; 37 2020 : else if (u && *u > *maxptr) 38 1237 : maxptr = u; 39 2557 : } SMARTLIST_FOREACH_END(u); 40 : 41 526 : return maxptr ? *maxptr : dflt; 42 : } 43 : 44 : /* The above function is only safe to call if we are sure that channel_id_t 45 : * and msg_type_id_t are really uint16_t. They should be so defined in 46 : * msgtypes.h, but let's be extra cautious. 47 : */ 48 : CTASSERT(sizeof(uint16_t) == sizeof(msg_type_id_t)); 49 : CTASSERT(sizeof(uint16_t) == sizeof(channel_id_t)); 50 : 51 : /** Helper: Format an unformattable message auxiliary data item: just return a 52 : * copy of the string <>. */ 53 : static char * 54 6 : type_fmt_nop(msg_aux_data_t arg) 55 : { 56 6 : (void)arg; 57 6 : return tor_strdup("<>"); 58 : } 59 : 60 : /** Helper: Free an unfreeable message auxiliary data item: do nothing. */ 61 : static void 62 3 : type_free_nop(msg_aux_data_t arg) 63 : { 64 3 : (void)arg; 65 3 : } 66 : 67 : /** Type functions to use when no type functions are provided. */ 68 : static dispatch_typefns_t nop_typefns = { 69 : .free_fn = type_free_nop, 70 : .fmt_fn = type_fmt_nop 71 : }; 72 : 73 : /** 74 : * Alert function to use when none is configured: do nothing. 75 : **/ 76 : static void 77 5 : alert_fn_nop(dispatch_t *d, channel_id_t ch, void *arg) 78 : { 79 5 : (void)d; 80 5 : (void)ch; 81 5 : (void)arg; 82 5 : } 83 : 84 : /** 85 : * Given a list of recvfn_t, create and return a new dtbl_entry_t mapping 86 : * to each of those functions. 87 : **/ 88 : static dtbl_entry_t * 89 1270 : dtbl_entry_from_lst(smartlist_t *receivers) 90 : { 91 1270 : if (!receivers) 92 : return NULL; 93 : 94 1259 : size_t n_recv = smartlist_len(receivers); 95 1259 : dtbl_entry_t *ent; 96 1259 : ent = tor_malloc_zero(offsetof(dtbl_entry_t, rcv) + 97 : sizeof(dispatch_rcv_t) * n_recv); 98 : 99 1259 : ent->n_fns = n_recv; 100 : 101 7874 : SMARTLIST_FOREACH_BEGIN(receivers, const dispatch_rcv_t *, rcv) { 102 6615 : memcpy(&ent->rcv[rcv_sl_idx], rcv, sizeof(*rcv)); 103 6615 : if (rcv->enabled) { 104 6615 : ++ent->n_enabled; 105 : } 106 6615 : } SMARTLIST_FOREACH_END(rcv); 107 : 108 : return ent; 109 : } 110 : 111 : /** Create and return a new dispatcher from a given dispatch_cfg_t. */ 112 : dispatch_t * 113 260 : dispatch_new(const dispatch_cfg_t *cfg) 114 : { 115 260 : dispatch_t *d = tor_malloc_zero(sizeof(dispatch_t)); 116 : 117 : /* Any message that has a type or a receiver counts towards our messages */ 118 260 : const size_t n_msgs = MAX(smartlist_len(cfg->type_by_msg), 119 260 : smartlist_len(cfg->recv_by_msg)) + 1; 120 : 121 : /* Any channel that any message has counts towards the number of channels. */ 122 520 : const size_t n_chans = (size_t) 123 260 : MAX(1, max_in_u16_sl(cfg->chan_by_msg,0)) + 1; 124 : 125 : /* Any type that a message has, or that has functions, counts towards 126 : * the number of types. */ 127 780 : const size_t n_types = (size_t) MAX(max_in_u16_sl(cfg->type_by_msg,0), 128 260 : smartlist_len(cfg->fns_by_type)) + 1; 129 : 130 260 : d->n_msgs = n_msgs; 131 260 : d->n_queues = n_chans; 132 260 : d->n_types = n_types; 133 : 134 : /* Initialize the array of type-functions. */ 135 260 : d->typefns = tor_calloc(n_types, sizeof(dispatch_typefns_t)); 136 1766 : for (size_t i = 0; i < n_types; ++i) { 137 : /* Default to no-op for everything... */ 138 1506 : memcpy(&d->typefns[i], &nop_typefns, sizeof(dispatch_typefns_t)); 139 : } 140 1506 : SMARTLIST_FOREACH_BEGIN(cfg->fns_by_type, dispatch_typefns_t *, fns) { 141 : /* Set the functions if they are provided. */ 142 1246 : if (fns) { 143 1243 : if (fns->free_fn) 144 1237 : d->typefns[fns_sl_idx].free_fn = fns->free_fn; 145 1243 : if (fns->fmt_fn) 146 1243 : d->typefns[fns_sl_idx].fmt_fn = fns->fmt_fn; 147 : } 148 1246 : } SMARTLIST_FOREACH_END(fns); 149 : 150 : /* Initialize the message queues: one for each channel. */ 151 260 : d->queues = tor_calloc(d->n_queues, sizeof(dqueue_t)); 152 781 : for (size_t i = 0; i < d->n_queues; ++i) { 153 521 : TOR_SIMPLEQ_INIT(&d->queues[i].queue); 154 521 : d->queues[i].alert_fn = alert_fn_nop; 155 : } 156 : 157 : /* Build the dispatch tables mapping message IDs to receivers. */ 158 260 : d->table = tor_calloc(d->n_msgs, sizeof(dtbl_entry_t *)); 159 1530 : SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, rcv) { 160 1270 : d->table[rcv_sl_idx] = dtbl_entry_from_lst(rcv); 161 1270 : } SMARTLIST_FOREACH_END(rcv); 162 : 163 : /* Fill in the empty entries in the dispatch tables: 164 : * types and channels for each message. */ 165 1531 : SMARTLIST_FOREACH_BEGIN(cfg->type_by_msg, msg_type_id_t *, type) { 166 1271 : if (d->table[type_sl_idx]) 167 1259 : d->table[type_sl_idx]->type = *type; 168 1271 : } SMARTLIST_FOREACH_END(type); 169 : 170 1531 : SMARTLIST_FOREACH_BEGIN(cfg->chan_by_msg, channel_id_t *, chan) { 171 1271 : if (d->table[chan_sl_idx]) 172 1259 : d->table[chan_sl_idx]->channel = *chan; 173 1271 : } SMARTLIST_FOREACH_END(chan); 174 : 175 260 : return d; 176 : }