tor

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

pubsub_macros.h (16235B)


      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 pubsub_macros.h
      9 * \brief Macros to help with the publish/subscribe dispatch API.
     10 *
     11 * The dispatch API allows different subsystems of Tor to communicate with
     12 * another asynchronously via a shared "message" system.  Some subsystems
     13 * declare that they publish a given message, and others declare that they
     14 * subscribe to it.  Both subsystems depend on the message, but not upon one
     15 * another.
     16 *
     17 * To declare a message, use DECLARE_MESSAGE() (for messages that take their
     18 * data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their
     19 * data as an integer.  For example, you might say
     20 *
     21 *     DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *);
     22 * or
     23 *     DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool);
     24 *
     25 * Every message has a unique name, a "type name" that the dispatch system
     26 * uses to manage associated data, and a C type name.  You'll want to put
     27 * these declarations in a header, to be included by all publishers and all
     28 * subscribers.
     29 *
     30 * When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at
     31 * file scope to create necessary static functions.  Then, in its subsystem
     32 * initialization (in the "bind to dispatcher" callback) (TODO: name this
     33 * properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its
     34 * intent to publish.  When it actually wants to publish, it uses the
     35 * PUBLISH() macro.  For example:
     36 *
     37 *     // At file scope
     38 *     DECLARE_PUBLISH(shutdown_requested);
     39 *
     40 *     static void bind_to_dispatcher(pubsub_connector_t *con)
     41 *     {
     42 *         DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested);
     43 *     }
     44 *
     45 *     // somewhere in a function
     46 *        {
     47 *            PUBLISH(shutdown_requested, true);
     48 *        }
     49 *
     50 * When a subsystem wants to subscribe to a message, it uses
     51 * DECLARE_SUBSCRIBE() at file scope to declare static functions.  It must
     52 * declare a hook function that receives the message type.  Then, in its "bind
     53 * to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the
     54 * dispatcher about its intent to subscribe.  When another module publishes
     55 * the message, the dispatcher will call the provided hook function.
     56 *
     57 *     // At file scope.  The first argument is the message that you're
     58 *     // subscribing to; the second argument is the hook function to declare.
     59 *     DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb);
     60 *
     61 *     // You need to declare this function.
     62 *     static void on_shutdown_req_cb(const msg_t *msg,
     63 *                                    bool value)
     64 *     {
     65 *         // (do something here.)
     66 *     }
     67 *
     68 *     static void bind_to_dispatcher(pubsub_connector_t *con)
     69 *     {
     70 *         DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested);
     71 *     }
     72 *
     73 * Where did these types come from?  Somewhere in the code, you need to call
     74 * DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the
     75 * message auxiliary data.  It associates a vtbl-like structure with the
     76 * type name, so that the dispatcher knows how to manipulate the type you're
     77 * giving it.
     78 *
     79 * For example, the "boolean" type we're using above could be defined as:
     80 *
     81 *    static char *boolean_fmt(msg_aux_data_t d)
     82 *    {
     83 *        // This is used for debugging and dumping messages.
     84 *        if (d.u64)
     85 *            return tor_strdup("true");
     86 *        else
     87 *            return tor_strdup("false");
     88 *    }
     89 *
     90 *    static void boolean_free(msg_aux_data_t d)
     91 *    {
     92 *        // We don't actually need to do anything to free a boolean.
     93 *        // We could use "NULL" instead of this function, but I'm including
     94 *        // it as an example.
     95 *    }
     96 *
     97 *    static void bind_to_dispatcher(pubsub_connector_t *con)
     98 *    {
     99 *        dispatch_typefns_t boolean_fns = {
    100 *            .fmt_fn = boolean_fmt,
    101 *            .free_fn = boolean_free,
    102 *        };
    103 *        DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns);
    104 *    }
    105 *
    106 *
    107 *
    108 * So, how does this all work?  (You can stop reading here, unless you're
    109 * debugging something.)
    110 *
    111 * When you declare a message in a header with DECLARE_MESSAGE() or
    112 * DECLARE_MESSAGE_INT(), it creates five things:
    113 *
    114 *    * two typedefs for the message argument (constant and non-constant
    115 *      variants).
    116 *    * a constant string to hold the declared message type name
    117 *    * two inline functions, to coerce the message argument type to and from
    118 *      a "msg_aux_data_t" union.
    119 *
    120 * All of these declarations have names based on the message name.
    121 *
    122 * Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the
    123 * elements defined by DECLARE_MESSAGE() to make sure that the publish
    124 * function takes the correct argument type, and that the subscription hook is
    125 * declared with the right argument type.
    126 **/
    127 
    128 #ifndef TOR_DISPATCH_MSG_H
    129 #define TOR_DISPATCH_MSG_H
    130 
    131 #include "lib/cc/compat_compiler.h"
    132 #include "lib/dispatch/dispatch_naming.h"
    133 #include "lib/pubsub/pub_binding_st.h"
    134 #include "lib/pubsub/pubsub_connect.h"
    135 #include "lib/pubsub/pubsub_flags.h"
    136 #include "lib/pubsub/pubsub_publish.h"
    137 
    138 /* Implementation notes:
    139 *
    140 * For a messagename "foo", the DECLARE_MESSAGE*() macros must declare:
    141 *
    142 * msg_arg_type__foo -- a typedef for the argument type of the foo message.
    143 * msg_arg_consttype__foo -- a typedef for the const argument type of the
    144 *     foo message.
    145 * msg_arg_name__foo[] -- a static string constant holding the unique
    146 *      identifier for the type of the foo message.
    147 * msg_arg_get__foo() -- an inline function taking a msg_aux_data_t and
    148 *      returning the C data type.
    149 * msg_arg_set__foo() -- an inline function taking a msg_aux_data_t and
    150 *      the C type, setting the msg_aux_data_t to hold the C type.
    151 *
    152 * For a messagename "foo", the DECLARE_PUBLISH() macro must declare:
    153 *
    154 * pub_binding__foo -- A static pub_binding_t object used to send messages
    155 *      from this module.
    156 * publish_fn__foo -- A function taking an argument of the appropriate
    157 *      C type, to be invoked by PUBLISH().
    158 *
    159 * For a messagename "foo", the DECLARE_SUBSCRIBE() macro must declare:
    160 *
    161 * hookfn -- A user-provided function name, with the correct signature.
    162 * recv_fn__foo -- A wrapper callback that takes a msg_t *, and calls
    163 *      hookfn with the appropriate arguments.
    164 */
    165 
    166 /** Macro to declare common elements shared by DECLARE_MESSAGE and
    167 * DECLARE_MESSAGE_INT.  Don't call this directly.
    168 *
    169 * Note that the "msg_arg_name" string constant is defined in each
    170 * translation unit.  This might be undesirable; we can tweak it in the
    171 * future if need be.
    172 */
    173 #define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)         \
    174  typedef c_type msg_arg_type__ ##messagename;                          \
    175  typedef const c_type msg_arg_consttype__ ##messagename;               \
    176  ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename;
    177 
    178 /**
    179 * Use this macro in a header to declare the existence of a given message,
    180 * taking a pointer as auxiliary data.
    181 *
    182 * "messagename" is a unique identifier for the message; it must be a valid
    183 * C identifier.
    184 *
    185 * "typename" is a unique identifier for the type of the auxiliary data.
    186 * It needs to be defined somewhere in Tor, using
    187 * "DISPATCH_REGISTER_TYPE."
    188 *
    189 * "c_ptr_type" is a C pointer type (like "char *" or "struct foo *").
    190 * The "*" needs to be included.
    191 */
    192 #define DECLARE_MESSAGE(messagename, typename, c_ptr_type)              \
    193  DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type)           \
    194  ATTR_UNUSED static inline c_ptr_type                                  \
    195  msg_arg_get__ ##messagename(msg_aux_data_t m)                         \
    196  {                                                                     \
    197    return m.ptr;                                                       \
    198  }                                                                     \
    199  ATTR_UNUSED static inline void                                        \
    200  msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v)          \
    201  {                                                                     \
    202    m->ptr = v;                                                         \
    203  }                                                                     \
    204  EAT_SEMICOLON
    205 
    206 /**
    207 * Use this macro in a header to declare the existence of a given message,
    208 * taking an integer as auxiliary data.
    209 *
    210 * "messagename" is a unique identifier for the message; it must be a valid
    211 * C identifier.
    212 *
    213 * "typename" is a unique identifier for the type of the auxiliary data.  It
    214 * needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."
    215 *
    216 * "c_type" is a C integer type, like "int" or "bool".  It needs to fit inside
    217 * a uint64_t.
    218 */
    219 #define DECLARE_MESSAGE_INT(messagename, typename, c_type)              \
    220  DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)               \
    221  ATTR_UNUSED static inline c_type                                      \
    222  msg_arg_get__ ##messagename(msg_aux_data_t m)                         \
    223  {                                                                     \
    224    return (c_type)m.u64;                                               \
    225  }                                                                     \
    226  ATTR_UNUSED static inline void                                        \
    227  msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v)              \
    228  {                                                                     \
    229    m->u64 = (uint64_t)v;                                               \
    230  }                                                                     \
    231  EAT_SEMICOLON
    232 
    233 /**
    234 * Use this macro inside a C module declare that we'll be publishing a given
    235 * message type from within this module.
    236 *
    237 * It creates necessary functions and wrappers to publish a message whose
    238 * unique identifier is "messagename".
    239 *
    240 * Before you use this, you need to include the header where DECLARE_MESSAGE*()
    241 * was used for this message.
    242 *
    243 * You can only use this once per message in each subsystem.
    244 */
    245 #define DECLARE_PUBLISH(messagename)                                    \
    246  static pub_binding_t pub_binding__ ##messagename;                     \
    247  static void                                                           \
    248  publish_fn__ ##messagename(msg_arg_type__ ##messagename arg)          \
    249  {                                                                     \
    250    msg_aux_data_t data;                                                \
    251    msg_arg_set__ ##messagename(&data, arg);                            \
    252    pubsub_pub_(&pub_binding__ ##messagename, data);                    \
    253  }                                                                     \
    254  EAT_SEMICOLON
    255 
    256 /**
    257 * Use this macro inside a C file to declare that we're subscribing to a
    258 * given message and associating it with a given "hook function".  It
    259 * declares the hook function static, and helps with strong typing.
    260 *
    261 * Before you use this, you need to include the header where
    262 * DECLARE_MESSAGE*() was used for the message whose unique identifier is
    263 * "messagename".
    264 *
    265 * You will need to define a function with the name that you provide for
    266 * "hookfn".  The type of this function will be:
    267 *     static void hookfn(const msg_t *, const c_type)
    268 * where c_type is the c type that you declared in the header.
    269 *
    270 * You can only use this once per message in each subsystem.
    271 */
    272 #define DECLARE_SUBSCRIBE(messagename, hookfn) \
    273  static void hookfn(const msg_t *,                             \
    274                     const msg_arg_consttype__ ##messagename);  \
    275  static void recv_fn__ ## messagename(const msg_t *m)          \
    276  {                                                             \
    277    msg_arg_type__ ## messagename arg;                          \
    278    arg = msg_arg_get__ ##messagename(m->aux_data__);           \
    279    hookfn(m, arg);                                             \
    280  }                                                             \
    281  EAT_SEMICOLON
    282 
    283 /**
    284 * Add a fake use of the publish function for 'messagename', so that
    285 * the compiler does not call it unused.
    286 */
    287 #define DISPATCH__FAKE_USE_OF_PUBFN_(messagename)                       \
    288  ( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
    289    : 1)
    290 
    291 /**
    292 * This macro is for internal use.  It backs DISPATCH_ADD_PUB*()
    293 */
    294 #define DISPATCH_ADD_PUB_(connector, channel, messagename, flags)       \
    295  (                                                                     \
    296    DISPATCH__FAKE_USE_OF_PUBFN_(messagename),                          \
    297    pubsub_add_pub_((connector),                                        \
    298                      &pub_binding__ ##messagename,                     \
    299                      get_channel_id(# channel),                        \
    300                    get_message_id(# messagename),                      \
    301                      get_msg_type_id(msg_arg_name__ ## messagename),   \
    302                      (flags),                                          \
    303                      __FILE__,                                         \
    304                      __LINE__)                                         \
    305    )
    306 
    307 /**
    308 * Use a given connector and channel name to declare that this subsystem will
    309 * publish a given message type.
    310 *
    311 * Call this macro from within the add_subscriptions() function of a module.
    312 */
    313 #define DISPATCH_ADD_PUB(connector, channel, messagename)       \
    314    DISPATCH_ADD_PUB_(connector, channel, messagename, 0)
    315 
    316 /**
    317 * Use a given connector and channel name to declare that this subsystem will
    318 * publish a given message type, and that no other subsystem is allowed to.
    319 *
    320 * Call this macro from within the add_subscriptions() function of a module.
    321 */
    322 #define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename)  \
    323    DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
    324 
    325 /**
    326 * This macro is for internal use. It backs DISPATCH_ADD_SUB*()
    327 */
    328 #define DISPATCH_ADD_SUB_(connector, channel, messagename, flags)       \
    329  pubsub_add_sub_((connector),                                          \
    330                    recv_fn__ ##messagename,                            \
    331                    get_channel_id(#channel),                           \
    332                    get_message_id(# messagename),                      \
    333                    get_msg_type_id(msg_arg_name__ ##messagename),      \
    334                    (flags),                                            \
    335                    __FILE__,                                           \
    336                    __LINE__)
    337 /**
    338 * Use a given connector and channel name to declare that this subsystem will
    339 * receive a given message type.
    340 *
    341 * Call this macro from within the add_subscriptions() function of a module.
    342 */
    343 #define DISPATCH_ADD_SUB(connector, channel, messagename)       \
    344    DISPATCH_ADD_SUB_(connector, channel, messagename, 0)
    345 /**
    346 * Use a given connector and channel name to declare that this subsystem will
    347 * receive a given message type, and that no other subsystem is allowed to do
    348 * so.
    349 *
    350 * Call this macro from within the add_subscriptions() function of a module.
    351 */
    352 #define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename)  \
    353    DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)
    354 
    355 /**
    356 * Publish a given message with a given argument.  (Takes ownership of the
    357 * argument if it is a pointer.)
    358 */
    359 #define PUBLISH(messagename, arg)               \
    360  publish_fn__ ##messagename(arg)
    361 
    362 /**
    363 * Use a given connector to declare that the functions to be used to manipuate
    364 * a certain C type.
    365 **/
    366 #define DISPATCH_REGISTER_TYPE(con, type, fns)                  \
    367  pubsub_connector_register_type_((con),                        \
    368                                  get_msg_type_id(#type),       \
    369                                  (fns),                        \
    370                                  __FILE__,                     \
    371                                  __LINE__)
    372 
    373 #endif /* !defined(TOR_DISPATCH_MSG_H) */