aboutsummaryrefslogtreecommitdiff
path: root/src/lib/dispatch/dispatch_cfg.c
blob: a54188dcaaf78239f6f35dd7fafc998c9d2c3662 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* Copyright (c) 2001, Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file dispatch_cfg.c
 * \brief Create and configure a dispatch_cfg_t.
 *
 * A dispatch_cfg_t object is used to configure a set of messages and
 * associated information before creating a dispatch_t.
 */

#define DISPATCH_PRIVATE

#include "orconfig.h"
#include "lib/dispatch/dispatch_cfg.h"
#include "lib/dispatch/dispatch_cfg_st.h"
#include "lib/dispatch/dispatch.h"
#include "lib/dispatch/dispatch_st.h"

#include "lib/container/smartlist.h"
#include "lib/malloc/malloc.h"

/**
 * Create and return a new dispatch_cfg_t.
 **/
dispatch_cfg_t *
dcfg_new(void)
{
  dispatch_cfg_t *cfg = tor_malloc(sizeof(dispatch_cfg_t));
  cfg->type_by_msg = smartlist_new();
  cfg->chan_by_msg = smartlist_new();
  cfg->fns_by_type = smartlist_new();
  cfg->recv_by_msg = smartlist_new();
  return cfg;
}

/**
 * Associate a message with a datatype.  Return 0 on success, -1 if a
 * different type was previously associated with the message ID.
 **/
int
dcfg_msg_set_type(dispatch_cfg_t *cfg, message_id_t msg,
                  msg_type_id_t type)
{
  smartlist_grow(cfg->type_by_msg, msg+1);
  msg_type_id_t *oldval = smartlist_get(cfg->type_by_msg, msg);
  if (oldval != NULL && *oldval != type) {
    return -1;
  }
  if (!oldval)
    smartlist_set(cfg->type_by_msg, msg, tor_memdup(&type, sizeof(type)));
  return 0;
}

/**
 * Associate a message with a channel.  Return 0 on success, -1 if a
 * different channel was previously associated with the message ID.
 **/
int
dcfg_msg_set_chan(dispatch_cfg_t *cfg, message_id_t msg,
                  channel_id_t chan)
{
  smartlist_grow(cfg->chan_by_msg, msg+1);
  channel_id_t *oldval = smartlist_get(cfg->chan_by_msg, msg);
  if (oldval != NULL && *oldval != chan) {
    return -1;
  }
  if (!oldval)
    smartlist_set(cfg->chan_by_msg, msg, tor_memdup(&chan, sizeof(chan)));
  return 0;
}

/**
 * Associate a set of functions with a datatype. Return 0 on success, -1 if
 * different functions were previously associated with the type.
 **/
int
dcfg_type_set_fns(dispatch_cfg_t *cfg, msg_type_id_t type,
                  const dispatch_typefns_t *fns)
{
  smartlist_grow(cfg->fns_by_type, type+1);
  dispatch_typefns_t *oldfns = smartlist_get(cfg->fns_by_type, type);
  if (oldfns && (oldfns->free_fn != fns->free_fn ||
                 oldfns->fmt_fn != fns->fmt_fn))
    return -1;
  if (!oldfns)
    smartlist_set(cfg->fns_by_type, type, tor_memdup(fns, sizeof(*fns)));
  return 0;
}

/**
 * Associate a receiver with a message ID.  Multiple receivers may be
 * associated with a single messasge ID.
 *
 * Return 0 on success, on failure.
 **/
int
dcfg_add_recv(dispatch_cfg_t *cfg, message_id_t msg,
              subsys_id_t sys, recv_fn_t fn)
{
  smartlist_grow(cfg->recv_by_msg, msg+1);
  smartlist_t *receivers = smartlist_get(cfg->recv_by_msg, msg);
  if (!receivers) {
    receivers = smartlist_new();
    smartlist_set(cfg->recv_by_msg, msg, receivers);
  }

  dispatch_rcv_t *rcv = tor_malloc(sizeof(dispatch_rcv_t));
  rcv->sys = sys;
  rcv->enabled = true;
  rcv->fn = fn;
  smartlist_add(receivers, (void*)rcv);
  return 0;
}

/** Helper: release all storage held by <b>cfg</b>. */
void
dcfg_free_(dispatch_cfg_t *cfg)
{
  if (!cfg)
    return;

  SMARTLIST_FOREACH(cfg->type_by_msg, msg_type_id_t *, id, tor_free(id));
  SMARTLIST_FOREACH(cfg->chan_by_msg, channel_id_t *, id, tor_free(id));
  SMARTLIST_FOREACH(cfg->fns_by_type, dispatch_typefns_t *, f, tor_free(f));
  smartlist_free(cfg->type_by_msg);
  smartlist_free(cfg->chan_by_msg);
  smartlist_free(cfg->fns_by_type);
  SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, receivers) {
    if (!receivers)
      continue;
    SMARTLIST_FOREACH(receivers, dispatch_rcv_t *, rcv, tor_free(rcv));
    smartlist_free(receivers);
  } SMARTLIST_FOREACH_END(receivers);
  smartlist_free(cfg->recv_by_msg);

  tor_free(cfg);
}