1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * lws System Message Distribution
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci#include <assert.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci/* comment me to remove extra debug and sanity checks */
29d4afb5ceSopenharmony_ci// #define LWS_SMD_DEBUG
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_ci#if defined(LWS_SMD_DEBUG)
33d4afb5ceSopenharmony_ci#define lwsl_smd lwsl_notice
34d4afb5ceSopenharmony_ci#else
35d4afb5ceSopenharmony_ci#define lwsl_smd(_s, ...)
36d4afb5ceSopenharmony_ci#endif
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_civoid *
39d4afb5ceSopenharmony_cilws_smd_msg_alloc(struct lws_context *ctx, lws_smd_class_t _class, size_t len)
40d4afb5ceSopenharmony_ci{
41d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg;
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_ci	/* only allow it if someone wants to consume this class of event */
44d4afb5ceSopenharmony_ci
45d4afb5ceSopenharmony_ci	if (!(ctx->smd._class_filter & _class)) {
46d4afb5ceSopenharmony_ci		lwsl_cx_info(ctx, "rejecting class 0x%x as no participant wants",
47d4afb5ceSopenharmony_ci				(unsigned int)_class);
48d4afb5ceSopenharmony_ci		return NULL;
49d4afb5ceSopenharmony_ci	}
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	assert(len <= LWS_SMD_MAX_PAYLOAD);
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci	/*
55d4afb5ceSopenharmony_ci	 * If SS configured, over-allocate LWS_SMD_SS_RX_HEADER_LEN behind
56d4afb5ceSopenharmony_ci	 * payload, ie,  msg_t (gap LWS_SMD_SS_RX_HEADER_LEN) payload
57d4afb5ceSopenharmony_ci	 */
58d4afb5ceSopenharmony_ci	msg = lws_malloc(sizeof(*msg) + LWS_SMD_SS_RX_HEADER_LEN_EFF + len,
59d4afb5ceSopenharmony_ci			 __func__);
60d4afb5ceSopenharmony_ci	if (!msg)
61d4afb5ceSopenharmony_ci		return NULL;
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci	memset(msg, 0, sizeof(*msg));
64d4afb5ceSopenharmony_ci	msg->timestamp = lws_now_usecs();
65d4afb5ceSopenharmony_ci	msg->length = (uint16_t)len;
66d4afb5ceSopenharmony_ci	msg->_class = _class;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci	return ((uint8_t *)&msg[1]) + LWS_SMD_SS_RX_HEADER_LEN_EFF;
69d4afb5ceSopenharmony_ci}
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_civoid
72d4afb5ceSopenharmony_cilws_smd_msg_free(void **ppay)
73d4afb5ceSopenharmony_ci{
74d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg = (lws_smd_msg_t *)(((uint8_t *)*ppay) -
75d4afb5ceSopenharmony_ci				LWS_SMD_SS_RX_HEADER_LEN_EFF - sizeof(*msg));
76d4afb5ceSopenharmony_ci
77d4afb5ceSopenharmony_ci	/* if SS configured, actual alloc is LWS_SMD_SS_RX_HEADER_LEN behind */
78d4afb5ceSopenharmony_ci	lws_free(msg);
79d4afb5ceSopenharmony_ci	*ppay = NULL;
80d4afb5ceSopenharmony_ci}
81d4afb5ceSopenharmony_ci
82d4afb5ceSopenharmony_ci#if defined(LWS_SMD_DEBUG)
83d4afb5ceSopenharmony_cistatic void
84d4afb5ceSopenharmony_cilws_smd_dump(lws_smd_t *smd)
85d4afb5ceSopenharmony_ci{
86d4afb5ceSopenharmony_ci	int n = 1;
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
89d4afb5ceSopenharmony_ci				   smd->owner_messages.head) {
90d4afb5ceSopenharmony_ci		lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci		lwsl_info(" msg %d: %p: ref %d, lat %dms, cls: 0x%x, len %u: '%s'\n",
93d4afb5ceSopenharmony_ci			    n++, msg, msg->refcount,
94d4afb5ceSopenharmony_ci			    (unsigned int)((lws_now_usecs() - msg->timestamp) / 1000),
95d4afb5ceSopenharmony_ci			    msg->length, msg->_class,
96d4afb5ceSopenharmony_ci			    (const char *)&msg[1] + LWS_SMD_SS_RX_HEADER_LEN_EFF);
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci	n = 1;
101d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p, smd->owner_peers.head) {
102d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci		lwsl_info(" peer %d: %p: tail: %p, filt 0x%x\n",
105d4afb5ceSopenharmony_ci			    n++, pr, pr->tail, pr->_class_filter);
106d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
107d4afb5ceSopenharmony_ci}
108d4afb5ceSopenharmony_ci#endif
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_cistatic int
111d4afb5ceSopenharmony_ci_lws_smd_msg_peer_interested_in_msg(lws_smd_peer_t *pr, lws_smd_msg_t *msg)
112d4afb5ceSopenharmony_ci{
113d4afb5ceSopenharmony_ci    return !!(msg->_class & pr->_class_filter);
114d4afb5ceSopenharmony_ci}
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci/*
117d4afb5ceSopenharmony_ci * Figure out what to set the initial refcount for the message to
118d4afb5ceSopenharmony_ci */
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_cistatic int
121d4afb5ceSopenharmony_ci_lws_smd_msg_assess_peers_interested(lws_smd_t *smd, lws_smd_msg_t *msg,
122d4afb5ceSopenharmony_ci				     struct lws_smd_peer *exc)
123d4afb5ceSopenharmony_ci{
124d4afb5ceSopenharmony_ci	struct lws_context *ctx = lws_container_of(smd, struct lws_context, smd);
125d4afb5ceSopenharmony_ci	int interested = 0;
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
128d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		if (pr != exc && _lws_smd_msg_peer_interested_in_msg(pr, msg))
131d4afb5ceSopenharmony_ci			/*
132d4afb5ceSopenharmony_ci			 * This peer wants to consume it
133d4afb5ceSopenharmony_ci			 */
134d4afb5ceSopenharmony_ci			interested++;
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
137d4afb5ceSopenharmony_ci
138d4afb5ceSopenharmony_ci	return interested;
139d4afb5ceSopenharmony_ci}
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_cistatic int
142d4afb5ceSopenharmony_ci_lws_smd_class_mask_union(lws_smd_t *smd)
143d4afb5ceSopenharmony_ci{
144d4afb5ceSopenharmony_ci	uint32_t mask = 0;
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
147d4afb5ceSopenharmony_ci				   smd->owner_peers.head) {
148d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci		mask |= pr->_class_filter;
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
153d4afb5ceSopenharmony_ci
154d4afb5ceSopenharmony_ci	smd->_class_filter = mask;
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	return 0;
157d4afb5ceSopenharmony_ci}
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci/* Call with message lock held */
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_cistatic void
162d4afb5ceSopenharmony_ci_lws_smd_msg_destroy(struct lws_context *cx, lws_smd_t *smd, lws_smd_msg_t *msg)
163d4afb5ceSopenharmony_ci{
164d4afb5ceSopenharmony_ci	/*
165d4afb5ceSopenharmony_ci	 * We think we gave the message to everyone and can destroy it.
166d4afb5ceSopenharmony_ci	 * Sanity check that no peer holds a pointer to this guy
167d4afb5ceSopenharmony_ci	 */
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
170d4afb5ceSopenharmony_ci				   smd->owner_peers.head) {
171d4afb5ceSopenharmony_ci		lws_smd_peer_t *xpr = lws_container_of(p, lws_smd_peer_t, list);
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci		if (xpr->tail == msg) {
174d4afb5ceSopenharmony_ci			lwsl_cx_err(cx, "peer %p has msg %p "
175d4afb5ceSopenharmony_ci				 "we are about to destroy as tail", xpr, msg);
176d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS)
177d4afb5ceSopenharmony_ci			assert(0);
178d4afb5ceSopenharmony_ci#endif
179d4afb5ceSopenharmony_ci		}
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci	/*
184d4afb5ceSopenharmony_ci	 * We have fully delivered the message now, it
185d4afb5ceSopenharmony_ci	 * can be unlinked and destroyed
186d4afb5ceSopenharmony_ci	 */
187d4afb5ceSopenharmony_ci	lwsl_cx_info(cx, "destroy msg %p", msg);
188d4afb5ceSopenharmony_ci	lws_dll2_remove(&msg->list);
189d4afb5ceSopenharmony_ci	lws_free(msg);
190d4afb5ceSopenharmony_ci}
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci/*
193d4afb5ceSopenharmony_ci * This is wanting to be threadsafe, limiting the apis we can call
194d4afb5ceSopenharmony_ci */
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ciint
197d4afb5ceSopenharmony_ci_lws_smd_msg_send(struct lws_context *ctx, void *pay, struct lws_smd_peer *exc)
198d4afb5ceSopenharmony_ci{
199d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg = (lws_smd_msg_t *)(((uint8_t *)pay) -
200d4afb5ceSopenharmony_ci				LWS_SMD_SS_RX_HEADER_LEN_EFF - sizeof(*msg));
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci	if (ctx->smd.owner_messages.count >= ctx->smd_queue_depth) {
203d4afb5ceSopenharmony_ci		lwsl_cx_warn(ctx, "rejecting message on queue depth %d",
204d4afb5ceSopenharmony_ci				  (int)ctx->smd.owner_messages.count);
205d4afb5ceSopenharmony_ci		/* reject the message due to max queue depth reached */
206d4afb5ceSopenharmony_ci		return 1;
207d4afb5ceSopenharmony_ci	}
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	if (!ctx->smd.delivering &&
210d4afb5ceSopenharmony_ci	    lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++ peers */
211d4afb5ceSopenharmony_ci		return 1; /* For Coverity */
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_ci	if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++++++++++ messages */
214d4afb5ceSopenharmony_ci		goto bail;
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci	msg->refcount = (uint16_t)_lws_smd_msg_assess_peers_interested(
217d4afb5ceSopenharmony_ci							&ctx->smd, msg, exc);
218d4afb5ceSopenharmony_ci	if (!msg->refcount) {
219d4afb5ceSopenharmony_ci		/* possible, condsidering exc and no other participants */
220d4afb5ceSopenharmony_ci		lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci		lws_free(msg);
223d4afb5ceSopenharmony_ci		if (!ctx->smd.delivering)
224d4afb5ceSopenharmony_ci			lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci		return 0;
227d4afb5ceSopenharmony_ci	}
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	msg->exc = exc;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci	/* let's add him on the queue... */
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&msg->list, &ctx->smd.owner_messages);
234d4afb5ceSopenharmony_ci
235d4afb5ceSopenharmony_ci	/*
236d4afb5ceSopenharmony_ci	 * Any peer with no active tail needs to check our class to see if we
237d4afb5ceSopenharmony_ci	 * should become his tail
238d4afb5ceSopenharmony_ci	 */
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
241d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
242d4afb5ceSopenharmony_ci
243d4afb5ceSopenharmony_ci		if (pr != exc &&
244d4afb5ceSopenharmony_ci                   !pr->tail && _lws_smd_msg_peer_interested_in_msg(pr, msg)) {
245d4afb5ceSopenharmony_ci			pr->tail = msg;
246d4afb5ceSopenharmony_ci			/* tail message has to actually be of interest to the peer */
247d4afb5ceSopenharmony_ci			assert(!pr->tail || (pr->tail->_class & pr->_class_filter));
248d4afb5ceSopenharmony_ci		}
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci#if defined(LWS_SMD_DEBUG)
253d4afb5ceSopenharmony_ci	lwsl_smd("%s: added %p (refc %u) depth now %d\n", __func__,
254d4afb5ceSopenharmony_ci		 msg, msg->refcount, ctx->smd.owner_messages.count);
255d4afb5ceSopenharmony_ci	lws_smd_dump(&ctx->smd);
256d4afb5ceSopenharmony_ci#endif
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci	lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_cibail:
261d4afb5ceSopenharmony_ci	if (!ctx->smd.delivering)
262d4afb5ceSopenharmony_ci		lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci	/* we may be happening from another thread context */
265d4afb5ceSopenharmony_ci	lws_cancel_service(ctx);
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci	return 0;
268d4afb5ceSopenharmony_ci}
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci/*
271d4afb5ceSopenharmony_ci * This is wanting to be threadsafe, limiting the apis we can call
272d4afb5ceSopenharmony_ci */
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ciint
275d4afb5ceSopenharmony_cilws_smd_msg_send(struct lws_context *ctx, void *pay)
276d4afb5ceSopenharmony_ci{
277d4afb5ceSopenharmony_ci	return _lws_smd_msg_send(ctx, pay, NULL);
278d4afb5ceSopenharmony_ci}
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_ci/*
281d4afb5ceSopenharmony_ci * This is wanting to be threadsafe, limiting the apis we can call
282d4afb5ceSopenharmony_ci */
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ciint
285d4afb5ceSopenharmony_cilws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class,
286d4afb5ceSopenharmony_ci		   const char *format, ...)
287d4afb5ceSopenharmony_ci{
288d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg;
289d4afb5ceSopenharmony_ci	va_list ap;
290d4afb5ceSopenharmony_ci	void *p;
291d4afb5ceSopenharmony_ci	int n;
292d4afb5ceSopenharmony_ci
293d4afb5ceSopenharmony_ci	if (!(ctx->smd._class_filter & _class))
294d4afb5ceSopenharmony_ci		/*
295d4afb5ceSopenharmony_ci		 * There's nobody interested in messages of this class atm.
296d4afb5ceSopenharmony_ci		 * Don't bother generating it, and act like all is well.
297d4afb5ceSopenharmony_ci		 */
298d4afb5ceSopenharmony_ci		return 0;
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	va_start(ap, format);
301d4afb5ceSopenharmony_ci	n = vsnprintf(NULL, 0, format, ap);
302d4afb5ceSopenharmony_ci	va_end(ap);
303d4afb5ceSopenharmony_ci	if (n > LWS_SMD_MAX_PAYLOAD)
304d4afb5ceSopenharmony_ci		/* too large to send */
305d4afb5ceSopenharmony_ci		return 1;
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	p = lws_smd_msg_alloc(ctx, _class, (size_t)n + 2);
308d4afb5ceSopenharmony_ci	if (!p)
309d4afb5ceSopenharmony_ci		return 1;
310d4afb5ceSopenharmony_ci	msg = (lws_smd_msg_t *)(((uint8_t *)p) - LWS_SMD_SS_RX_HEADER_LEN_EFF -
311d4afb5ceSopenharmony_ci								sizeof(*msg));
312d4afb5ceSopenharmony_ci	msg->length = (uint16_t)n;
313d4afb5ceSopenharmony_ci	va_start(ap, format);
314d4afb5ceSopenharmony_ci	vsnprintf((char *)p, (unsigned int)n + 2, format, ap);
315d4afb5ceSopenharmony_ci	va_end(ap);
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci	/*
318d4afb5ceSopenharmony_ci	 * locks taken and released in here
319d4afb5ceSopenharmony_ci	 */
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	if (lws_smd_msg_send(ctx, p)) {
322d4afb5ceSopenharmony_ci		lws_smd_msg_free(&p);
323d4afb5ceSopenharmony_ci		return 1;
324d4afb5ceSopenharmony_ci	}
325d4afb5ceSopenharmony_ci
326d4afb5ceSopenharmony_ci	return 0;
327d4afb5ceSopenharmony_ci}
328d4afb5ceSopenharmony_ci
329d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS)
330d4afb5ceSopenharmony_ciint
331d4afb5ceSopenharmony_cilws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len,
332d4afb5ceSopenharmony_ci		      lws_smd_class_t _class, const char *format, ...)
333d4afb5ceSopenharmony_ci{
334d4afb5ceSopenharmony_ci	char *content = (char *)buf + LWS_SMD_SS_RX_HEADER_LEN;
335d4afb5ceSopenharmony_ci	va_list ap;
336d4afb5ceSopenharmony_ci	int n;
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci	if (*len < LWS_SMD_SS_RX_HEADER_LEN)
339d4afb5ceSopenharmony_ci		return 1;
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	lws_ser_wu64be(buf, _class);
342d4afb5ceSopenharmony_ci	lws_ser_wu64be(buf + 8, 0); /* valgrind notices uninitialized if left */
343d4afb5ceSopenharmony_ci
344d4afb5ceSopenharmony_ci	va_start(ap, format);
345d4afb5ceSopenharmony_ci	n = vsnprintf(content, (*len) - LWS_SMD_SS_RX_HEADER_LEN, format, ap);
346d4afb5ceSopenharmony_ci	va_end(ap);
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci	if (n > LWS_SMD_MAX_PAYLOAD ||
349d4afb5ceSopenharmony_ci	    (unsigned int)n > (*len) - LWS_SMD_SS_RX_HEADER_LEN)
350d4afb5ceSopenharmony_ci		/* too large to send */
351d4afb5ceSopenharmony_ci		return 1;
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci	*len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)n;
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_ci	lwsl_info("%s: %s send cl 0x%x, len %u\n", __func__, tag, (unsigned int)_class,
356d4afb5ceSopenharmony_ci			(unsigned int)n);
357d4afb5ceSopenharmony_ci
358d4afb5ceSopenharmony_ci	return 0;
359d4afb5ceSopenharmony_ci}
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci/*
362d4afb5ceSopenharmony_ci * This is a helper that user rx handler for LWS_SMD_STREAMTYPENAME SS can
363d4afb5ceSopenharmony_ci * call through to with the payload it received from the proxy.  It will then
364d4afb5ceSopenharmony_ci * forward the recieved SMD message to all local (same-context) participants
365d4afb5ceSopenharmony_ci * that are interested in that class (except ones with callback skip_cb, so
366d4afb5ceSopenharmony_ci * we don't loop).
367d4afb5ceSopenharmony_ci */
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_cistatic int
370d4afb5ceSopenharmony_ci_lws_smd_ss_rx_forward(struct lws_context *ctx, const char *tag,
371d4afb5ceSopenharmony_ci		       struct lws_smd_peer *pr, const uint8_t *buf, size_t len)
372d4afb5ceSopenharmony_ci{
373d4afb5ceSopenharmony_ci	lws_smd_class_t _class;
374d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg;
375d4afb5ceSopenharmony_ci	void *p;
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci	if (len < LWS_SMD_SS_RX_HEADER_LEN_EFF)
378d4afb5ceSopenharmony_ci		return 1;
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci	if (len >= LWS_SMD_MAX_PAYLOAD + LWS_SMD_SS_RX_HEADER_LEN_EFF)
381d4afb5ceSopenharmony_ci		return 1;
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci	_class = (lws_smd_class_t)lws_ser_ru64be(buf);
384d4afb5ceSopenharmony_ci
385d4afb5ceSopenharmony_ci	if (_class == LWSSMDCL_METRICS) {
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	}
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci	/* only locally forward messages that we care about in this process */
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_ci	if (!(ctx->smd._class_filter & _class))
392d4afb5ceSopenharmony_ci		/*
393d4afb5ceSopenharmony_ci		 * There's nobody interested in messages of this class atm.
394d4afb5ceSopenharmony_ci		 * Don't bother generating it, and act like all is well.
395d4afb5ceSopenharmony_ci		 */
396d4afb5ceSopenharmony_ci		return 0;
397d4afb5ceSopenharmony_ci
398d4afb5ceSopenharmony_ci	p = lws_smd_msg_alloc(ctx, _class, len);
399d4afb5ceSopenharmony_ci	if (!p)
400d4afb5ceSopenharmony_ci		return 1;
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci	msg = (lws_smd_msg_t *)(((uint8_t *)p) - LWS_SMD_SS_RX_HEADER_LEN_EFF -
403d4afb5ceSopenharmony_ci								sizeof(*msg));
404d4afb5ceSopenharmony_ci	msg->length = (uint16_t)(len - LWS_SMD_SS_RX_HEADER_LEN_EFF);
405d4afb5ceSopenharmony_ci	/* adopt the original source timestamp, not time we forwarded it */
406d4afb5ceSopenharmony_ci	msg->timestamp = (lws_usec_t)lws_ser_ru64be(buf + 8);
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	/* copy the message payload in */
409d4afb5ceSopenharmony_ci	memcpy(p, buf + LWS_SMD_SS_RX_HEADER_LEN_EFF, msg->length);
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	/*
412d4afb5ceSopenharmony_ci	 * locks taken and released in here
413d4afb5ceSopenharmony_ci	 */
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ci	if (_lws_smd_msg_send(ctx, p, pr)) {
416d4afb5ceSopenharmony_ci		/* we couldn't send it after all that... */
417d4afb5ceSopenharmony_ci		lws_smd_msg_free(&p);
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci		return 1;
420d4afb5ceSopenharmony_ci	}
421d4afb5ceSopenharmony_ci
422d4afb5ceSopenharmony_ci	lwsl_info("%s: %s send cl 0x%x, len %u, ts %llu\n", __func__,
423d4afb5ceSopenharmony_ci		    tag, (unsigned int)_class, msg->length,
424d4afb5ceSopenharmony_ci		    (unsigned long long)msg->timestamp);
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	return 0;
427d4afb5ceSopenharmony_ci}
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ciint
430d4afb5ceSopenharmony_cilws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len)
431d4afb5ceSopenharmony_ci{
432d4afb5ceSopenharmony_ci	struct lws_ss_handle *h = (struct lws_ss_handle *)
433d4afb5ceSopenharmony_ci					(((char *)ss_user) - sizeof(*h));
434d4afb5ceSopenharmony_ci	struct lws_context *ctx = lws_ss_get_context(h);
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci	return _lws_smd_ss_rx_forward(ctx, lws_ss_tag(h), h->u.smd.smd_peer, buf, len);
437d4afb5ceSopenharmony_ci}
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
440d4afb5ceSopenharmony_ciint
441d4afb5ceSopenharmony_cilws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len)
442d4afb5ceSopenharmony_ci{
443d4afb5ceSopenharmony_ci	struct lws_sspc_handle *h = (struct lws_sspc_handle *)
444d4afb5ceSopenharmony_ci					(((char *)ss_user) - sizeof(*h));
445d4afb5ceSopenharmony_ci	struct lws_context *ctx = lws_sspc_get_context(h);
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ci	return _lws_smd_ss_rx_forward(ctx, lws_sspc_tag(h), NULL, buf, len);
448d4afb5ceSopenharmony_ci}
449d4afb5ceSopenharmony_ci#endif
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci#endif
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci/*
454d4afb5ceSopenharmony_ci * Peers that deregister need to adjust the refcount of messages they would
455d4afb5ceSopenharmony_ci * have been interested in, but didn't take delivery of yet
456d4afb5ceSopenharmony_ci */
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_cistatic void
459d4afb5ceSopenharmony_ci_lws_smd_peer_destroy(lws_smd_peer_t *pr)
460d4afb5ceSopenharmony_ci{
461d4afb5ceSopenharmony_ci	lws_smd_t *smd = lws_container_of(pr->list.owner, lws_smd_t,
462d4afb5ceSopenharmony_ci					  owner_peers);
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ci	if (lws_mutex_lock(smd->lock_messages)) /* +++++++++ messages */
465d4afb5ceSopenharmony_ci		return; /* For Coverity */
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci	lws_dll2_remove(&pr->list);
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci	/*
470d4afb5ceSopenharmony_ci	 * We take the approach to adjust the refcount of every would-have-been
471d4afb5ceSopenharmony_ci	 * delivered message we were interested in
472d4afb5ceSopenharmony_ci	 */
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_ci	while (pr->tail) {
475d4afb5ceSopenharmony_ci
476d4afb5ceSopenharmony_ci		lws_smd_msg_t *m1 = lws_container_of(pr->tail->list.next,
477d4afb5ceSopenharmony_ci							lws_smd_msg_t, list);
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci		if (_lws_smd_msg_peer_interested_in_msg(pr, pr->tail)) {
480d4afb5ceSopenharmony_ci			if (!--pr->tail->refcount)
481d4afb5ceSopenharmony_ci				_lws_smd_msg_destroy(pr->ctx, smd, pr->tail);
482d4afb5ceSopenharmony_ci		}
483d4afb5ceSopenharmony_ci
484d4afb5ceSopenharmony_ci		pr->tail = m1;
485d4afb5ceSopenharmony_ci	}
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci	lws_free(pr);
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci	lws_mutex_unlock(smd->lock_messages); /* messages ------- */
490d4afb5ceSopenharmony_ci}
491d4afb5ceSopenharmony_ci
492d4afb5ceSopenharmony_cistatic lws_smd_msg_t *
493d4afb5ceSopenharmony_ci_lws_smd_msg_next_matching_filter(lws_smd_peer_t *pr)
494d4afb5ceSopenharmony_ci{
495d4afb5ceSopenharmony_ci	lws_dll2_t *tail = &pr->tail->list;
496d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg;
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci	do {
499d4afb5ceSopenharmony_ci		tail = tail->next;
500d4afb5ceSopenharmony_ci		if (!tail)
501d4afb5ceSopenharmony_ci			return NULL;
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci		msg = lws_container_of(tail, lws_smd_msg_t, list);
504d4afb5ceSopenharmony_ci		if (msg->exc != pr &&
505d4afb5ceSopenharmony_ci		    _lws_smd_msg_peer_interested_in_msg(pr, msg))
506d4afb5ceSopenharmony_ci			return msg;
507d4afb5ceSopenharmony_ci	} while (1);
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci	return NULL;
510d4afb5ceSopenharmony_ci}
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci/*
513d4afb5ceSopenharmony_ci * Delivers only one message to the peer and advances the tail, or sets to NULL
514d4afb5ceSopenharmony_ci * if no more filtered queued messages.  Returns nonzero if tail non-NULL.
515d4afb5ceSopenharmony_ci *
516d4afb5ceSopenharmony_ci * For Proxied SS, only asks for writeable and does not advance or change the
517d4afb5ceSopenharmony_ci * tail.
518d4afb5ceSopenharmony_ci *
519d4afb5ceSopenharmony_ci * This is done so if multiple messages queued, we don't get a situation where
520d4afb5ceSopenharmony_ci * one participant gets them all spammed, then the next etc.  Instead they are
521d4afb5ceSopenharmony_ci * delivered round-robin.
522d4afb5ceSopenharmony_ci *
523d4afb5ceSopenharmony_ci * Requires peer lock, may take message lock
524d4afb5ceSopenharmony_ci */
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_cistatic int
527d4afb5ceSopenharmony_ci_lws_smd_msg_deliver_peer(struct lws_context *ctx, lws_smd_peer_t *pr)
528d4afb5ceSopenharmony_ci{
529d4afb5ceSopenharmony_ci	lws_smd_msg_t *msg;
530d4afb5ceSopenharmony_ci
531d4afb5ceSopenharmony_ci	if (!pr->tail)
532d4afb5ceSopenharmony_ci		return 0;
533d4afb5ceSopenharmony_ci
534d4afb5ceSopenharmony_ci	msg = lws_container_of(pr->tail, lws_smd_msg_t, list);
535d4afb5ceSopenharmony_ci
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci	lwsl_cx_info(ctx, "deliver cl 0x%x, len %d, refc %d, to peer %p",
538d4afb5ceSopenharmony_ci		    (unsigned int)msg->_class, (int)msg->length,
539d4afb5ceSopenharmony_ci		    (int)msg->refcount, pr);
540d4afb5ceSopenharmony_ci
541d4afb5ceSopenharmony_ci	pr->cb(pr->opaque, msg->_class, msg->timestamp,
542d4afb5ceSopenharmony_ci	       ((uint8_t *)&msg[1]) + LWS_SMD_SS_RX_HEADER_LEN_EFF,
543d4afb5ceSopenharmony_ci	       (size_t)msg->length);
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci	assert(msg->refcount);
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci	/*
548d4afb5ceSopenharmony_ci	 * If there is one, move forward to the next queued
549d4afb5ceSopenharmony_ci	 * message that meets the filters of this peer
550d4afb5ceSopenharmony_ci	 */
551d4afb5ceSopenharmony_ci	pr->tail = _lws_smd_msg_next_matching_filter(pr);
552d4afb5ceSopenharmony_ci
553d4afb5ceSopenharmony_ci	/* tail message has to actually be of interest to the peer */
554d4afb5ceSopenharmony_ci	assert(!pr->tail || (pr->tail->_class & pr->_class_filter));
555d4afb5ceSopenharmony_ci
556d4afb5ceSopenharmony_ci	if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++ messages */
557d4afb5ceSopenharmony_ci		return 1; /* For Coverity */
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ci	if (!--msg->refcount)
560d4afb5ceSopenharmony_ci		_lws_smd_msg_destroy(ctx, &ctx->smd, msg);
561d4afb5ceSopenharmony_ci	lws_mutex_unlock(ctx->smd.lock_messages); /* messages ------- */
562d4afb5ceSopenharmony_ci
563d4afb5ceSopenharmony_ci	return !!pr->tail;
564d4afb5ceSopenharmony_ci}
565d4afb5ceSopenharmony_ci
566d4afb5ceSopenharmony_ci/*
567d4afb5ceSopenharmony_ci * Called when the event loop could deliver messages synchronously, eg, on
568d4afb5ceSopenharmony_ci * entry to idle
569d4afb5ceSopenharmony_ci */
570d4afb5ceSopenharmony_ci
571d4afb5ceSopenharmony_ciint
572d4afb5ceSopenharmony_cilws_smd_msg_distribute(struct lws_context *ctx)
573d4afb5ceSopenharmony_ci{
574d4afb5ceSopenharmony_ci	char more;
575d4afb5ceSopenharmony_ci
576d4afb5ceSopenharmony_ci	/* commonly, no messages and nothing to do... */
577d4afb5ceSopenharmony_ci
578d4afb5ceSopenharmony_ci	if (!ctx->smd.owner_messages.count)
579d4afb5ceSopenharmony_ci		return 0;
580d4afb5ceSopenharmony_ci
581d4afb5ceSopenharmony_ci	ctx->smd.delivering = 1;
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci	do {
584d4afb5ceSopenharmony_ci		more = 0;
585d4afb5ceSopenharmony_ci		if (lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++ peers */
586d4afb5ceSopenharmony_ci			return 1; /* For Coverity */
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_ci		lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
589d4afb5ceSopenharmony_ci					   ctx->smd.owner_peers.head) {
590d4afb5ceSopenharmony_ci			lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci			more = (char)(more | !!_lws_smd_msg_deliver_peer(ctx, pr));
593d4afb5ceSopenharmony_ci
594d4afb5ceSopenharmony_ci		} lws_end_foreach_dll_safe(p, p1);
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci		lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
597d4afb5ceSopenharmony_ci	} while (more);
598d4afb5ceSopenharmony_ci
599d4afb5ceSopenharmony_ci	ctx->smd.delivering = 0;
600d4afb5ceSopenharmony_ci
601d4afb5ceSopenharmony_ci	return 0;
602d4afb5ceSopenharmony_ci}
603d4afb5ceSopenharmony_ci
604d4afb5ceSopenharmony_cistruct lws_smd_peer *
605d4afb5ceSopenharmony_cilws_smd_register(struct lws_context *ctx, void *opaque, int flags,
606d4afb5ceSopenharmony_ci		 lws_smd_class_t _class_filter, lws_smd_notification_cb_t cb)
607d4afb5ceSopenharmony_ci{
608d4afb5ceSopenharmony_ci	lws_smd_peer_t *pr = lws_zalloc(sizeof(*pr), __func__);
609d4afb5ceSopenharmony_ci
610d4afb5ceSopenharmony_ci	if (!pr)
611d4afb5ceSopenharmony_ci		return NULL;
612d4afb5ceSopenharmony_ci
613d4afb5ceSopenharmony_ci	pr->cb = cb;
614d4afb5ceSopenharmony_ci	pr->opaque = opaque;
615d4afb5ceSopenharmony_ci	pr->_class_filter = _class_filter;
616d4afb5ceSopenharmony_ci	pr->ctx = ctx;
617d4afb5ceSopenharmony_ci
618d4afb5ceSopenharmony_ci	if (!ctx->smd.delivering &&
619d4afb5ceSopenharmony_ci	    lws_mutex_lock(ctx->smd.lock_peers)) { /* +++++++++++++++ peers */
620d4afb5ceSopenharmony_ci			lws_free(pr);
621d4afb5ceSopenharmony_ci			return NULL; /* For Coverity */
622d4afb5ceSopenharmony_ci		}
623d4afb5ceSopenharmony_ci
624d4afb5ceSopenharmony_ci	/*
625d4afb5ceSopenharmony_ci	 * Let's lock the message list before adding this peer... because...
626d4afb5ceSopenharmony_ci	 */
627d4afb5ceSopenharmony_ci
628d4afb5ceSopenharmony_ci	if (lws_mutex_lock(ctx->smd.lock_messages)) { /* +++++++++ messages */
629d4afb5ceSopenharmony_ci		lws_free(pr);
630d4afb5ceSopenharmony_ci		pr = NULL;
631d4afb5ceSopenharmony_ci		goto bail1; /* For Coverity */
632d4afb5ceSopenharmony_ci	}
633d4afb5ceSopenharmony_ci
634d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&pr->list, &ctx->smd.owner_peers);
635d4afb5ceSopenharmony_ci
636d4afb5ceSopenharmony_ci	/* update the global class mask union to account for new peer mask */
637d4afb5ceSopenharmony_ci	_lws_smd_class_mask_union(&ctx->smd);
638d4afb5ceSopenharmony_ci
639d4afb5ceSopenharmony_ci	/*
640d4afb5ceSopenharmony_ci	 * Now there's a new peer added, any messages we have stashed will try
641d4afb5ceSopenharmony_ci	 * to deliver to this guy too, if he's interested in that class.  So we
642d4afb5ceSopenharmony_ci	 * have to update the message refcounts for queued messages-he's-
643d4afb5ceSopenharmony_ci	 * interested-in accordingly.
644d4afb5ceSopenharmony_ci	 */
645d4afb5ceSopenharmony_ci
646d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
647d4afb5ceSopenharmony_ci				   ctx->smd.owner_messages.head) {
648d4afb5ceSopenharmony_ci		lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
649d4afb5ceSopenharmony_ci
650d4afb5ceSopenharmony_ci		if (_lws_smd_msg_peer_interested_in_msg(pr, msg))
651d4afb5ceSopenharmony_ci			msg->refcount++;
652d4afb5ceSopenharmony_ci
653d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
654d4afb5ceSopenharmony_ci
655d4afb5ceSopenharmony_ci	/* ... ok we are done adding the peer */
656d4afb5ceSopenharmony_ci
657d4afb5ceSopenharmony_ci	lws_mutex_unlock(ctx->smd.lock_messages); /* messages ------- */
658d4afb5ceSopenharmony_ci
659d4afb5ceSopenharmony_ci	lwsl_cx_info(ctx, "peer %p (count %u) registered", pr,
660d4afb5ceSopenharmony_ci			(unsigned int)ctx->smd.owner_peers.count);
661d4afb5ceSopenharmony_ci
662d4afb5ceSopenharmony_cibail1:
663d4afb5ceSopenharmony_ci	if (!ctx->smd.delivering)
664d4afb5ceSopenharmony_ci		lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
665d4afb5ceSopenharmony_ci
666d4afb5ceSopenharmony_ci	return pr;
667d4afb5ceSopenharmony_ci}
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_civoid
670d4afb5ceSopenharmony_cilws_smd_unregister(struct lws_smd_peer *pr)
671d4afb5ceSopenharmony_ci{
672d4afb5ceSopenharmony_ci	lws_smd_t *smd = lws_container_of(pr->list.owner, lws_smd_t, owner_peers);
673d4afb5ceSopenharmony_ci
674d4afb5ceSopenharmony_ci	if (!smd->delivering &&
675d4afb5ceSopenharmony_ci	    lws_mutex_lock(smd->lock_peers)) /* +++++++++++++++++++ peers */
676d4afb5ceSopenharmony_ci		return; /* For Coverity */
677d4afb5ceSopenharmony_ci	lwsl_cx_notice(pr->ctx, "destroying peer %p", pr);
678d4afb5ceSopenharmony_ci	_lws_smd_peer_destroy(pr);
679d4afb5ceSopenharmony_ci	if (!smd->delivering)
680d4afb5ceSopenharmony_ci		lws_mutex_unlock(smd->lock_peers); /* ----------------- peers */
681d4afb5ceSopenharmony_ci}
682d4afb5ceSopenharmony_ci
683d4afb5ceSopenharmony_ciint
684d4afb5ceSopenharmony_cilws_smd_message_pending(struct lws_context *ctx)
685d4afb5ceSopenharmony_ci{
686d4afb5ceSopenharmony_ci	int ret = 1;
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci	/*
689d4afb5ceSopenharmony_ci	 * First cheaply check the common case no messages pending, so there's
690d4afb5ceSopenharmony_ci	 * definitely nothing for this tsi or anything else
691d4afb5ceSopenharmony_ci	 */
692d4afb5ceSopenharmony_ci
693d4afb5ceSopenharmony_ci	if (!ctx->smd.owner_messages.count)
694d4afb5ceSopenharmony_ci		return 0;
695d4afb5ceSopenharmony_ci
696d4afb5ceSopenharmony_ci	/*
697d4afb5ceSopenharmony_ci	 * If there are any messages, check their age and expire ones that
698d4afb5ceSopenharmony_ci	 * have been hanging around too long
699d4afb5ceSopenharmony_ci	 */
700d4afb5ceSopenharmony_ci
701d4afb5ceSopenharmony_ci	if (lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++++++++++ peers */
702d4afb5ceSopenharmony_ci		return 1; /* For Coverity */
703d4afb5ceSopenharmony_ci	if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++++++++++ messages */
704d4afb5ceSopenharmony_ci		goto bail; /* For Coverity */
705d4afb5ceSopenharmony_ci
706d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
707d4afb5ceSopenharmony_ci				   ctx->smd.owner_messages.head) {
708d4afb5ceSopenharmony_ci		lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
709d4afb5ceSopenharmony_ci
710d4afb5ceSopenharmony_ci		if ((lws_now_usecs() - msg->timestamp) > ctx->smd_ttl_us) {
711d4afb5ceSopenharmony_ci			lwsl_cx_warn(ctx, "timing out queued message %p",
712d4afb5ceSopenharmony_ci					msg);
713d4afb5ceSopenharmony_ci
714d4afb5ceSopenharmony_ci			/*
715d4afb5ceSopenharmony_ci			 * We're forcibly yanking this guy, we can expect that
716d4afb5ceSopenharmony_ci			 * there might be peers that point to it as their tail.
717d4afb5ceSopenharmony_ci			 *
718d4afb5ceSopenharmony_ci			 * In that case, move their tails on to the next guy
719d4afb5ceSopenharmony_ci			 * they are interested in, if any.
720d4afb5ceSopenharmony_ci			 */
721d4afb5ceSopenharmony_ci
722d4afb5ceSopenharmony_ci			lws_start_foreach_dll_safe(struct lws_dll2 *, pp, pp1,
723d4afb5ceSopenharmony_ci						   ctx->smd.owner_peers.head) {
724d4afb5ceSopenharmony_ci				lws_smd_peer_t *pr = lws_container_of(pp,
725d4afb5ceSopenharmony_ci							lws_smd_peer_t, list);
726d4afb5ceSopenharmony_ci
727d4afb5ceSopenharmony_ci				if (pr->tail == msg)
728d4afb5ceSopenharmony_ci					pr->tail = _lws_smd_msg_next_matching_filter(pr);
729d4afb5ceSopenharmony_ci
730d4afb5ceSopenharmony_ci			} lws_end_foreach_dll_safe(pp, pp1);
731d4afb5ceSopenharmony_ci
732d4afb5ceSopenharmony_ci			/*
733d4afb5ceSopenharmony_ci			 * No peer should fall foul of the peer tail checks
734d4afb5ceSopenharmony_ci			 * when destroying the message now.
735d4afb5ceSopenharmony_ci			 */
736d4afb5ceSopenharmony_ci
737d4afb5ceSopenharmony_ci			_lws_smd_msg_destroy(ctx, &ctx->smd, msg);
738d4afb5ceSopenharmony_ci		}
739d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
740d4afb5ceSopenharmony_ci
741d4afb5ceSopenharmony_ci	lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
742d4afb5ceSopenharmony_ci
743d4afb5ceSopenharmony_ci	/*
744d4afb5ceSopenharmony_ci	 * Walk the peer list
745d4afb5ceSopenharmony_ci	 */
746d4afb5ceSopenharmony_ci
747d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
748d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
749d4afb5ceSopenharmony_ci
750d4afb5ceSopenharmony_ci		if (pr->tail)
751d4afb5ceSopenharmony_ci			goto bail;
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
754d4afb5ceSopenharmony_ci
755d4afb5ceSopenharmony_ci	/*
756d4afb5ceSopenharmony_ci	 * There's no message pending that we need to handle
757d4afb5ceSopenharmony_ci	 */
758d4afb5ceSopenharmony_ci
759d4afb5ceSopenharmony_ci	ret = 0;
760d4afb5ceSopenharmony_ci
761d4afb5ceSopenharmony_cibail:
762d4afb5ceSopenharmony_ci	lws_mutex_unlock(ctx->smd.lock_peers); /* --------------------- peers */
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci	return ret;
765d4afb5ceSopenharmony_ci}
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ciint
768d4afb5ceSopenharmony_ci_lws_smd_destroy(struct lws_context *ctx)
769d4afb5ceSopenharmony_ci{
770d4afb5ceSopenharmony_ci	/* stop any message creation */
771d4afb5ceSopenharmony_ci
772d4afb5ceSopenharmony_ci	ctx->smd._class_filter = 0;
773d4afb5ceSopenharmony_ci
774d4afb5ceSopenharmony_ci	/*
775d4afb5ceSopenharmony_ci	 * Walk the message list, destroying them
776d4afb5ceSopenharmony_ci	 */
777d4afb5ceSopenharmony_ci
778d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
779d4afb5ceSopenharmony_ci				   ctx->smd.owner_messages.head) {
780d4afb5ceSopenharmony_ci		lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci		lws_dll2_remove(&msg->list);
783d4afb5ceSopenharmony_ci		lws_free(msg);
784d4afb5ceSopenharmony_ci
785d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
786d4afb5ceSopenharmony_ci
787d4afb5ceSopenharmony_ci	/*
788d4afb5ceSopenharmony_ci	 * Walk the peer list, destroying them
789d4afb5ceSopenharmony_ci	 */
790d4afb5ceSopenharmony_ci
791d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
792d4afb5ceSopenharmony_ci				   ctx->smd.owner_peers.head) {
793d4afb5ceSopenharmony_ci		lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
794d4afb5ceSopenharmony_ci
795d4afb5ceSopenharmony_ci		pr->tail = NULL; /* we just nuked all the messages, ignore */
796d4afb5ceSopenharmony_ci		_lws_smd_peer_destroy(pr);
797d4afb5ceSopenharmony_ci
798d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, p1);
799d4afb5ceSopenharmony_ci
800d4afb5ceSopenharmony_ci	lws_mutex_destroy(ctx->smd.lock_messages);
801d4afb5ceSopenharmony_ci	lws_mutex_destroy(ctx->smd.lock_peers);
802d4afb5ceSopenharmony_ci
803d4afb5ceSopenharmony_ci	return 0;
804d4afb5ceSopenharmony_ci}
805