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 LWS_SMD_SS_RX_HEADER_LEN 16
30
31typedef uint32_t lws_smd_class_t;
32
33struct lws_smd_msg; /* opaque */
34struct lws_smd_peer; /* opaque */
35
36/*
37 * Well-known device classes
38 */
39
40enum {
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 */
85LWS_VISIBLE LWS_EXTERN void * /* payload */
86lws_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 */
99LWS_VISIBLE LWS_EXTERN void
100lws_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 */
112LWS_VISIBLE LWS_EXTERN int
113lws_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 */
136LWS_VISIBLE LWS_EXTERN int
137lws_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
156struct lws_ss_handle;
157LWS_VISIBLE LWS_EXTERN int
158lws_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 */
179LWS_VISIBLE LWS_EXTERN int
180lws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
181
182LWS_VISIBLE LWS_EXTERN int
183lws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
184
185typedef 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
209LWS_VISIBLE LWS_EXTERN struct lws_smd_peer *
210lws_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
226LWS_VISIBLE LWS_EXTERN void
227lws_smd_unregister(struct lws_smd_peer *pr);
228