| 1 | /* |
| 2 | * lws System Message Distribution |
| 3 | * |
| 4 | * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to |
| 8 | * deal in the Software without restriction, including without limitation the |
| 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| 10 | * sell copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 22 | * IN THE SOFTWARE. |
| 23 | */ |
| 24 | |
| 25 | #define LWS_SMD_MAX_PAYLOAD 384 |
| 26 | #define LWS_SMD_CLASS_BITFIELD_BYTES 4 |
| 27 | |
| 28 | #define LWS_SMD_STREAMTYPENAME "_lws_smd" |
| 29 | #define 16 |
| 30 | |
| 31 | typedef uint32_t lws_smd_class_t; |
| 32 | |
| 33 | struct lws_smd_msg; /* opaque */ |
| 34 | struct lws_smd_peer; /* opaque */ |
| 35 | |
| 36 | /* |
| 37 | * Well-known device classes |
| 38 | */ |
| 39 | |
| 40 | enum { |
| 41 | LWSSMDCL_INTERACTION = (1 << 0), |
| 42 | /**< |
| 43 | * Any kind of event indicating a user was interacting with the device, |
| 44 | * eg, press a button, touched the screen, lifted the device etc |
| 45 | */ |
| 46 | LWSSMDCL_SYSTEM_STATE = (1 << 1), |
| 47 | /**< |
| 48 | * The lws_system state changed, eg, to OPERATIONAL |
| 49 | */ |
| 50 | LWSSMDCL_NETWORK = (1 << 2), |
| 51 | /**< |
| 52 | * Something happened on the network, eg, link-up or DHCP, or captive |
| 53 | * portal state update |
| 54 | */ |
| 55 | LWSSMDCL_METRICS = (1 << 3), |
| 56 | /**< |
| 57 | * An SS client process is reporting a metric to the proxy (this class |
| 58 | * is special in that it is not rebroadcast by the proxy) |
| 59 | */ |
| 60 | |
| 61 | LWSSMDCL_USER_BASE_BITNUM = 24 |
| 62 | }; |
| 63 | |
| 64 | /** |
| 65 | * lws_smd_msg_alloc() - allocate a message of length len |
| 66 | * |
| 67 | * \param ctx: the lws_context |
| 68 | * \param _class: the smd message class, recipients filter on this |
| 69 | * \param len: the required payload length |
| 70 | * |
| 71 | * This helper returns an opaque lws_smd_msg pointer and sets *buf to a buffer |
| 72 | * associated with it of length \p len. |
| 73 | * |
| 74 | * In this way the lws_msg_smd type remains completely opaque and the allocated |
| 75 | * area can be prepared by the caller directly, without copying. |
| 76 | * |
| 77 | * On failure, it returns NULL... it may fail for OOM but it may also fail if |
| 78 | * you request to allocate for a message class that the system has no |
| 79 | * participant who is listening for that class of event currently... the event |
| 80 | * generation action at the caller should be bypassed without error then. |
| 81 | * |
| 82 | * This is useful if you have a message you know the length of. For text-based |
| 83 | * messages like JSON, lws_smd_msg_printf() is more convenient. |
| 84 | */ |
| 85 | LWS_VISIBLE LWS_EXTERN void * /* payload */ |
| 86 | lws_smd_msg_alloc(struct lws_context *ctx, lws_smd_class_t _class, size_t len); |
| 87 | |
| 88 | /** |
| 89 | * lws_smd_msg_free() - abandon a previously allocated message before sending |
| 90 | * |
| 91 | * \param payload: pointer the previously-allocated message payload |
| 92 | * |
| 93 | * Destroys a previously-allocated opaque message object and the requested |
| 94 | * buffer space, in the case that between allocating it and sending it, some |
| 95 | * condition was met that means it can no longer be sent, eg, an error |
| 96 | * generating the content. Otherwise there is no need to destroy allocated |
| 97 | * message objects with this, lws will take care of it. |
| 98 | */ |
| 99 | LWS_VISIBLE LWS_EXTERN void |
| 100 | lws_smd_msg_free(void **payload); |
| 101 | |
| 102 | /** |
| 103 | * lws_smd_msg_send() - queue a previously allocated message |
| 104 | * |
| 105 | * \param ctx: the lws_context |
| 106 | * \param msg: the prepared message |
| 107 | * |
| 108 | * Queues an allocated, prepared message for delivery to smd clients |
| 109 | * |
| 110 | * This is threadsafe to call from a non-service thread. |
| 111 | */ |
| 112 | LWS_VISIBLE LWS_EXTERN int |
| 113 | lws_smd_msg_send(struct lws_context *ctx, void *payload); |
| 114 | |
| 115 | /** |
| 116 | * lws_smd_msg_printf() - queue a previously allocated message |
| 117 | * |
| 118 | * \param ctx: the lws_context |
| 119 | * \param _class: the message class |
| 120 | * \param format: the format string to prepare the payload with |
| 121 | * \param ...: arguments for the format string, if any |
| 122 | * |
| 123 | * For string-based messages, eg, JSON, allows formatted creating of the payload |
| 124 | * size discovery, allocation and message send all in one step. |
| 125 | * |
| 126 | * Unlike lws_smd_msg_alloc() you do not need to know the length beforehand as |
| 127 | * this computes it and calls lws_smd_msg_alloc() with the correct length. |
| 128 | * |
| 129 | * To be clear this also calls through to lws_smd_msg_send(), it really does |
| 130 | * everything in one step. If there are no registered participants that want |
| 131 | * messages of \p _class, this function returns immediately without doing any |
| 132 | * allocation or anything else. |
| 133 | * |
| 134 | * This is threadsafe to call from a non-service thread. |
| 135 | */ |
| 136 | LWS_VISIBLE LWS_EXTERN int |
| 137 | lws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class, |
| 138 | const char *format, ...) LWS_FORMAT(3); |
| 139 | |
| 140 | /** |
| 141 | * lws_smd_ss_msg_printf() - helper to prepare smd ss message tx |
| 142 | * |
| 143 | * \param h: the ss handle |
| 144 | * \param buf: the ss tx buffer |
| 145 | * \param len: on entry, points to the ss tx buffer length, on exit, set to used |
| 146 | * \param _class: the message class |
| 147 | * \param format: the format string to prepare the payload with |
| 148 | * \param ...: arguments for the format string, if any |
| 149 | * |
| 150 | * This helper lets you produce SMD messages on an SS link of the builtin |
| 151 | * streamtype LWS_SMD_STREAMTYPENAME, using the same api format as |
| 152 | * lws_smd_msg_prinf(), but writing the message into the ss tx buffer from |
| 153 | * its tx() callback. |
| 154 | */ |
| 155 | |
| 156 | struct lws_ss_handle; |
| 157 | LWS_VISIBLE LWS_EXTERN int |
| 158 | lws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len, |
| 159 | lws_smd_class_t _class, const char *format, ...) |
| 160 | LWS_FORMAT(5); |
| 161 | |
| 162 | /** |
| 163 | * lws_smd_ss_rx_forward() - helper to forward smd messages that came in by SS |
| 164 | * |
| 165 | * \param ss_user: ss user pointer, as delivered to rx callback |
| 166 | * \param buf: the ss rx buffer |
| 167 | * \param len: the length of the ss rx buffer |
| 168 | * |
| 169 | * Proxied Secure Streams with the streamtype LWS_SMD_STREAMTYPENAME receive |
| 170 | * serialized SMD messages from the proxy, this helper allows them to be |
| 171 | * translated into deserialized SMD messages and forwarded to registered SMD |
| 172 | * participants in the local context in one step. |
| 173 | * |
| 174 | * Just pass through what arrived in the LWS_SMD_STREAMTYPENAME rx() callback |
| 175 | * to this api. |
| 176 | * |
| 177 | * Returns 0 if OK else nonzero if unable to queue the SMD message. |
| 178 | */ |
| 179 | LWS_VISIBLE LWS_EXTERN int |
| 180 | lws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len); |
| 181 | |
| 182 | LWS_VISIBLE LWS_EXTERN int |
| 183 | lws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len); |
| 184 | |
| 185 | typedef int (*lws_smd_notification_cb_t)(void *opaque, lws_smd_class_t _class, |
| 186 | lws_usec_t timestamp, void *buf, |
| 187 | size_t len); |
| 188 | |
| 189 | #define LWSSMDREG_FLAG_PROXIED_SS (1 << 0) |
| 190 | /**< It's actually a proxied SS connection registering, opaque is the ss h */ |
| 191 | |
| 192 | /* |
| 193 | * lws_smd_register() - register to receive smd messages |
| 194 | * |
| 195 | * \param ctx: the lws_context |
| 196 | * \param opaque: an opaque pointer handed to the callback |
| 197 | * \param flags: typically 0 |
| 198 | * \param _class_filter: bitmap of message classes we care about |
| 199 | * \param cb: the callback to receive messages |
| 200 | * |
| 201 | * Queues an allocated, prepared message for delivery to smd clients. |
| 202 | * |
| 203 | * Returns NULL on failure, or an opaque handle which may be given to |
| 204 | * lws_smd_unregister() to stop participating in the shared message queue. |
| 205 | * |
| 206 | * This is threadsafe to call from a non-service thread. |
| 207 | */ |
| 208 | |
| 209 | LWS_VISIBLE LWS_EXTERN struct lws_smd_peer * |
| 210 | lws_smd_register(struct lws_context *ctx, void *opaque, int flags, |
| 211 | lws_smd_class_t _class_filter, lws_smd_notification_cb_t cb); |
| 212 | |
| 213 | /* |
| 214 | * lws_smd_unregister() - unregister receiving smd messages |
| 215 | * |
| 216 | * \param pr: the handle returned from the registration |
| 217 | * |
| 218 | * Destroys the registration of the callback for messages and ability to send |
| 219 | * messages. |
| 220 | * |
| 221 | * It's not necessary to call this if the registration wants to survive for as |
| 222 | * long as the lws_context... lws_context_destroy will also clean up any |
| 223 | * registrations still active by then. |
| 224 | */ |
| 225 | |
| 226 | LWS_VISIBLE LWS_EXTERN void |
| 227 | lws_smd_unregister(struct lws_smd_peer *pr); |
| 228 | |