tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

dispatch_new.c (5254B)


      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 max_in_u16_sl(const smartlist_t *sl, int dflt)
     32 {
     33  uint16_t *maxptr = NULL;
     34  SMARTLIST_FOREACH_BEGIN(sl, uint16_t *, u) {
     35    if (!maxptr)
     36      maxptr = u;
     37    else if (u && *u > *maxptr)
     38      maxptr = u;
     39  } SMARTLIST_FOREACH_END(u);
     40 
     41  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 type_fmt_nop(msg_aux_data_t arg)
     55 {
     56  (void)arg;
     57  return tor_strdup("<>");
     58 }
     59 
     60 /** Helper: Free an unfreeable message auxiliary data item: do nothing. */
     61 static void
     62 type_free_nop(msg_aux_data_t arg)
     63 {
     64  (void)arg;
     65 }
     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 alert_fn_nop(dispatch_t *d, channel_id_t ch, void *arg)
     78 {
     79  (void)d;
     80  (void)ch;
     81  (void)arg;
     82 }
     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 dtbl_entry_from_lst(smartlist_t *receivers)
     90 {
     91  if (!receivers)
     92    return NULL;
     93 
     94  size_t n_recv = smartlist_len(receivers);
     95  dtbl_entry_t *ent;
     96  ent = tor_malloc_zero(offsetof(dtbl_entry_t, rcv) +
     97                        sizeof(dispatch_rcv_t) * n_recv);
     98 
     99  ent->n_fns = n_recv;
    100 
    101  SMARTLIST_FOREACH_BEGIN(receivers, const dispatch_rcv_t *, rcv) {
    102    memcpy(&ent->rcv[rcv_sl_idx], rcv, sizeof(*rcv));
    103    if (rcv->enabled) {
    104      ++ent->n_enabled;
    105    }
    106  } 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 dispatch_new(const dispatch_cfg_t *cfg)
    114 {
    115  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  const size_t n_msgs = MAX(smartlist_len(cfg->type_by_msg),
    119                            smartlist_len(cfg->recv_by_msg)) + 1;
    120 
    121  /* Any channel that any message has counts towards the number of channels. */
    122  const size_t n_chans = (size_t)
    123    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  const size_t n_types = (size_t) MAX(max_in_u16_sl(cfg->type_by_msg,0),
    128                                      smartlist_len(cfg->fns_by_type)) + 1;
    129 
    130  d->n_msgs = n_msgs;
    131  d->n_queues = n_chans;
    132  d->n_types = n_types;
    133 
    134  /* Initialize the array of type-functions. */
    135  d->typefns = tor_calloc(n_types, sizeof(dispatch_typefns_t));
    136  for (size_t i = 0; i < n_types; ++i) {
    137    /* Default to no-op for everything... */
    138    memcpy(&d->typefns[i], &nop_typefns, sizeof(dispatch_typefns_t));
    139  }
    140  SMARTLIST_FOREACH_BEGIN(cfg->fns_by_type, dispatch_typefns_t *, fns) {
    141    /* Set the functions if they are provided. */
    142    if (fns) {
    143      if (fns->free_fn)
    144        d->typefns[fns_sl_idx].free_fn = fns->free_fn;
    145      if (fns->fmt_fn)
    146        d->typefns[fns_sl_idx].fmt_fn = fns->fmt_fn;
    147    }
    148  } SMARTLIST_FOREACH_END(fns);
    149 
    150  /* Initialize the message queues: one for each channel. */
    151  d->queues = tor_calloc(d->n_queues, sizeof(dqueue_t));
    152  for (size_t i = 0; i < d->n_queues; ++i) {
    153    TOR_SIMPLEQ_INIT(&d->queues[i].queue);
    154    d->queues[i].alert_fn = alert_fn_nop;
    155  }
    156 
    157  /* Build the dispatch tables mapping message IDs to receivers. */
    158  d->table = tor_calloc(d->n_msgs, sizeof(dtbl_entry_t *));
    159  SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, rcv) {
    160    d->table[rcv_sl_idx] = dtbl_entry_from_lst(rcv);
    161  } SMARTLIST_FOREACH_END(rcv);
    162 
    163  /* Fill in the empty entries in the dispatch tables:
    164   * types and channels for each message. */
    165  SMARTLIST_FOREACH_BEGIN(cfg->type_by_msg, msg_type_id_t *, type) {
    166    if (d->table[type_sl_idx])
    167      d->table[type_sl_idx]->type = *type;
    168  } SMARTLIST_FOREACH_END(type);
    169 
    170  SMARTLIST_FOREACH_BEGIN(cfg->chan_by_msg, channel_id_t *, chan) {
    171    if (d->table[chan_sl_idx])
    172      d->table[chan_sl_idx]->channel = *chan;
    173  } SMARTLIST_FOREACH_END(chan);
    174 
    175  return d;
    176 }