dispatch_new.c 5.1 KB

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