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 | |