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