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