LCOV - code coverage report
Current view: top level - lib/dispatch - dispatch_new.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 68 68 100.0 %
Date: 2021-11-24 03:28:48 Functions: 6 6 100.0 %

          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             : }

Generated by: LCOV version 1.14