text: /* Copyright (c) 2001, Matej Pfajfar.
   * Copyright (c) 2001-2004, Roger Dingledine.
   * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
   * Copyright (c) 2007-2018, The Tor Project, Inc. */
  /* See LICENSE for licensing information */
  
  /**
   * \file pubsub_macros.h
   * \brief Macros to help with the publish/subscribe dispatch API.
   *
   * The dispatch API allows different subsystems of Tor to communicate with
   * another asynchronously via a shared "message" system.  Some subsystems
   * declare that they publish a given message, and others declare that they
   * subscribe to it.  Both subsystems depend on the message, but not upon one
   * another.
   *
   * To declare a message, use DECLARE_MESSAGE() (for messages that take their
   * data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their
   * data as an integer.  For example, you might say
   *
   *     DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *);
   * or
   *     DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool);
   *
   * Every message has a unique name, a "type name" that the dispatch system
   * uses to manage associated data, and a C type name.  You'll want to put
   * these declarations in a header, to be included by all publishers and all
   * subscribers.
   *
   * When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at
   * file scope to create necessary static functions.  Then, in its subsystem
   * initialization (in the "bind to dispatcher" callback) (TODO: name this
   * properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its
   * intent to publish.  When it actually wants to publish, it uses the
   * PUBLISH() macro.  For example:
   *
   *     // At file scope
   *     DECLARE_PUBLISH(shutdown_requested);
   *
   *     static void bind_to_dispatcher(pubsub_connector_t *con)
   *     {
   *         DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested);
   *     }
   *
   *     // somewhere in a function
   *        {
   *            PUBLISH(shutdown_requested, true);
   *        }
   *
   * When a subsystem wants to subscribe to a message, it uses
   * DECLARE_SUBSCRIBE() at file scope to declare static functions.  It must
   * declare a hook function that receives the message type.  Then, in its "bind
   * to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the
   * dispatcher about its intent to subscribe.  When another module publishes
   * the message, the dispatcher will call the provided hook function.
   *
   *     // At file scope.  The first argument is the message that you're
   *     // subscribing to; the second argument is the hook function to declare.
   *     DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb);
   *
   *     // You need to declare this function.
   *     static void on_shutdown_req_cb(const msg_t *msg,
   *                                    bool value)
   *     {
   *         // (do something here.)
   *     }
   *
   *     static void bind_to_dispatcher(pubsub_connector_t *con)
   *     {
   *         DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested);
   *     }
   *
   * Where did these types come from?  Somewhere in the code, you need to call
   * DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the
   * message auxiliary data.  It associates a vtbl-like structure with the
   * type name, so that the dispatcher knows how to manipulate the type you're
   * giving it.
   *
   * For example, the "boolean" type we're using above could be defined as:
   *
   *    static char *boolean_fmt(msg_aux_data_t d)
   *    {
   *        // This is used for debugging and dumping messages.
   *        if (d.u64)
   *            return tor_strdup("true");
   *        else
   *            return tor_strdup("false");
   *    }
   *
   *    static void boolean_free(msg_aux_data_t d)
   *    {
   *        // We don't actually need to do anything to free a boolean.
   *        // We could use "NULL" instead of this function, but I'm including
   *        // it as an example.
   *    }
   *
   *    static void bind_to_dispatcher(pubsub_connector_t *con)
   *    {
   *        dispatch_typefns_t boolean_fns = {
   *            .fmt_fn = boolean_fmt,
   *            .free_fn = boolean_free,
   *        };
   *        DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns);
   *    }
   *
   *
   *
   * So, how does this all work?  (You can stop reading here, unless you're
   * debugging something.)
   *
   * When you declare a message in a header with DECLARE_MESSAGE() or
   * DECLARE_MESSAGE_INT(), it creates five things:
   *
   *    * two typedefs for the message argument (constant and non-constant
   *      variants).
   *    * a constant string to hold the declared message type name
   *    * two inline functions, to coerce the message argument type to and from
   *      a "msg_aux_data_t" union.
   *
   * All of these declarations have names based on the message name.
   *
   * Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the
   * elements defined by DECLARE_MESSAGE() to make sure that the publish
   * function takes the correct argument type, and that the subscription hook is
   * declared with the right argument type.
   **/
  
  #ifndef TOR_DISPATCH_MSG_H
  #define TOR_DISPATCH_MSG_H
  
  #include "lib/cc/compat_compiler.h"
  #include "lib/dispatch/dispatch_naming.h"
  #include "lib/pubsub/pub_binding_st.h"
  #include "lib/pubsub/pubsub_connect.h"
  #include "lib/pubsub/pubsub_flags.h"
  #include "lib/pubsub/pubsub_publish.h"
  
  /* Implemenation notes:
   *
   * For a messagename "foo", the DECLARE_MESSAGE*() macros must declare:
   *
   * msg_arg_type__foo -- a typedef for the argument type of the foo message.
   * msg_arg_consttype__foo -- a typedef for the const argument type of the
   *     foo message.
   * msg_arg_name__foo[] -- a static string constant holding the unique
   *      identifier for the type of the foo message.
   * msg_arg_get__foo() -- an inline function taking a msg_aux_data_t and
   *      returning the C data type.
   * msg_arg_set__foo() -- an inline function taking a msg_aux_data_t and
   *      the C type, setting the msg_aux_data_t to hold the C type.
   *
   * For a messagename "foo", the DECLARE_PUBLISH() macro must declare:
   *
   * pub_binding__foo -- A static pub_binding_t object used to send messages
   *      from this module.
   * publish_fn__foo -- A function taking an argument of the appropriate
   *      C type, to be invoked by PUBLISH().
   *
   * For a messagename "foo", the DECLARE_SUBSCRIBE() macro must declare:
   *
   * hookfn -- A user-provided function name, with the correct signature.
   * recv_fn__foo -- A wrapper callback that takes a msg_t *, and calls
   *      hookfn with the appropriate arguments.
   */
  
  /* Macro to declare common elements shared by DECLARE_MESSAGE and
   * DECLARE_MESSAGE_INT.  Don't call this directly.
   *
   * Note that the "msg_arg_name" string constant is defined in each
   * translation unit.  This might be undesirable; we can tweak it in the
   * future if need be.
   */
  #define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)         \
    typedef c_type msg_arg_type__ ##messagename;                          \
    typedef const c_type msg_arg_consttype__ ##messagename;               \
    ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename;
  
  /**
   * Use this macro in a header to declare the existence of a given message,
   * taking a pointer as auxiliary data.
   *
   * "messagename" is a unique identifier for the message; it must be a valid
   * C identifier.
   *
   * "typename" is a unique identifier for the type of the auxiliary data.
   * It needs to be defined somewhere in Tor, using
   * "DISPATCH_REGISTER_TYPE."
   *
   * "c_ptr_type" is a C pointer type (like "char *" or "struct foo *").
   * The "*" needs to be included.
   */
  #define DECLARE_MESSAGE(messagename, typename, c_ptr_type)              \
    DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type)           \
    ATTR_UNUSED static inline c_ptr_type                                  \
    msg_arg_get__ ##messagename(msg_aux_data_t m)                         \
    {                                                                     \
      return m.ptr;                                                       \
    }                                                                     \
    ATTR_UNUSED static inline void                                        \
    msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v)          \
    {                                                                     \
      m->ptr = v;                                                         \
    }                                                                     \
    EAT_SEMICOLON
  
  /**
   * Use this macro in a header to declare the existence of a given message,
   * taking an integer as auxiliary data.
   *
   * "messagename" is a unique identifier for the message; it must be a valid
   * C identifier.
   *
   * "typename" is a unique identifier for the type of the auxiliary data.  It
   * needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."
   *
   * "c_type" is a C integer type, like "int" or "bool".  It needs to fit inside
   * a uint64_t.
   */
  #define DECLARE_MESSAGE_INT(messagename, typename, c_type)              \
    DECLARE_MESSAGE_COMMON__(messagename, typename, c_type)               \
    ATTR_UNUSED static inline c_type                                      \
    msg_arg_get__ ##messagename(msg_aux_data_t m)                         \
    {                                                                     \
      return (c_type)m.u64;                                               \
    }                                                                     \
    ATTR_UNUSED static inline void                                        \
    msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v)              \
    {                                                                     \
      m->u64 = (uint64_t)v;                                               \
    }                                                                     \
    EAT_SEMICOLON
  
  /**
   * Use this macro inside a C module declare that we'll be publishing a given
   * message type from within this module.
   *
   * It creates necessary functions and wrappers to publish a message whose
   * unique identifier is "messagename".
   *
   * Before you use this, you need to include the header where DECLARE_MESSAGE*()
   * was used for this message.
   *
   * You can only use this once per message in each subsystem.
   */
  #define DECLARE_PUBLISH(messagename)                                    \
    static pub_binding_t pub_binding__ ##messagename;                     \
    static void                                                           \
    publish_fn__ ##messagename(msg_arg_type__ ##messagename arg)          \
    {                                                                     \
      msg_aux_data_t data;                                                \
      msg_arg_set__ ##messagename(&data, arg);                            \
      pubsub_pub_(&pub_binding__ ##messagename, data);                    \
    }                                                                     \
    EAT_SEMICOLON
  
  /**
   * Use this macro inside a C file to declare that we're subscribing to a
   * given message and associating it with a given "hook function".  It
   * declares the hook function static, and helps with strong typing.
   *
   * Before you use this, you need to include the header where
   * DECLARE_MESSAGE*() was used for the message whose unique identifier is
   * "messagename".
   *
   * You will need to define a function with the name that you provide for
   * "hookfn".  The type of this function will be:
   *     static void hookfn(const msg_t *, const c_type)
   * where c_type is the c type that you declared in the header.
   *
   * You can only use this once per message in each subsystem.
   */
  #define DECLARE_SUBSCRIBE(messagename, hookfn) \
    static void hookfn(const msg_t *,                             \
                       const msg_arg_consttype__ ##messagename);  \
    static void recv_fn__ ## messagename(const msg_t *m)          \
    {                                                             \
      msg_arg_type__ ## messagename arg;                          \
      arg = msg_arg_get__ ##messagename(m->aux_data__);           \
      hookfn(m, arg);                                             \
    }                                                             \
    EAT_SEMICOLON
  
  /**
   * Add a fake use of the publish function for 'messagename', so that
   * the compiler does not call it unused.
   */
  #define DISPATCH__FAKE_USE_OF_PUBFN_(messagename)                       \
    ( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
      : 1)
  
  /*
   * This macro is for internal use.  It backs DISPATCH_ADD_PUB*()
   */
  #define DISPATCH_ADD_PUB_(connector, channel, messagename, flags)       \
    (                                                                     \
      DISPATCH__FAKE_USE_OF_PUBFN_(messagename),                          \
      pubsub_add_pub_((connector),                                        \
                        &pub_binding__ ##messagename,                     \
                        get_channel_id(# channel),                        \
                      get_message_id(# messagename),                      \
                        get_msg_type_id(msg_arg_name__ ## messagename),   \
                        (flags),                                          \
                        __FILE__,                                         \
                        __LINE__)                                         \
      )
  
  /**
   * Use a given connector and channel name to declare that this subsystem will
   * publish a given message type.
   *
   * Call this macro from within the add_subscriptions() function of a module.
   */
  #define DISPATCH_ADD_PUB(connector, channel, messagename)       \
      DISPATCH_ADD_PUB_(connector, channel, messagename, 0)
  
  /**
   * Use a given connector and channel name to declare that this subsystem will
   * publish a given message type, and that no other subsystem is allowed to.
   *
   * Call this macro from within the add_subscriptions() function of a module.
   */
  #define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename)  \
      DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
  
  /*
   * This macro is for internal use. It backs DISPATCH_ADD_SUB*()
   */
  #define DISPATCH_ADD_SUB_(connector, channel, messagename, flags)       \
    pubsub_add_sub_((connector),                                          \
                      recv_fn__ ##messagename,                            \
                      get_channel_id(#channel),                           \
                      get_message_id(# messagename),                      \
                      get_msg_type_id(msg_arg_name__ ##messagename),      \
                      (flags),                                            \
                      __FILE__,                                           \
                      __LINE__)
  /*
   * Use a given connector and channel name to declare that this subsystem will
   * receive a given message type.
   *
   * Call this macro from within the add_subscriptions() function of a module.
   */
  #define DISPATCH_ADD_SUB(connector, channel, messagename)       \
      DISPATCH_ADD_SUB_(connector, channel, messagename, 0)
  /**
   * Use a given connector and channel name to declare that this subsystem will
   * receive a given message type, and that no other subsystem is allowed to do
   * so.
   *
   * Call this macro from within the add_subscriptions() function of a module.
   */
  #define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename)  \
      DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)
  
  /**
   * Publish a given message with a given argument.  (Takes ownership of the
   * argument if it is a pointer.)
   */
  #define PUBLISH(messagename, arg)               \
    publish_fn__ ##messagename(arg)
  
  /**
   * Use a given connector to declare that the functions to be used to manipuate
   * a certain C type.
   **/
  #define DISPATCH_REGISTER_TYPE(con, type, fns)                  \
    pubsub_connector_register_type_((con),                        \
                                    get_msg_type_id(#type),       \
                                    (fns),                        \
                                    __FILE__,                     \
                                    __LINE__)
  
  #endif /* !defined(TOR_DISPATCH_MSG_H) */
  