1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 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 27d4afb5ceSopenharmony_ciint 28d4afb5ceSopenharmony_ci_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa) 29d4afb5ceSopenharmony_ci{ 30d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_EVENT_LIBS) 31d4afb5ceSopenharmony_ci volatile struct lws_context_per_thread *vpt; 32d4afb5ceSopenharmony_ci#endif 33d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 34d4afb5ceSopenharmony_ci struct lws_context *context; 35d4afb5ceSopenharmony_ci int ret = 0, pa_events; 36d4afb5ceSopenharmony_ci struct lws_pollfd *pfd; 37d4afb5ceSopenharmony_ci int sampled_tid, tid; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci if (!wsi) 40d4afb5ceSopenharmony_ci return 0; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci assert(wsi->position_in_fds_table == LWS_NO_FDS_POS || 43d4afb5ceSopenharmony_ci wsi->position_in_fds_table >= 0); 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table == LWS_NO_FDS_POS) 46d4afb5ceSopenharmony_ci return 0; 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ci if (((volatile struct lws *)wsi)->handling_pollout && 49d4afb5ceSopenharmony_ci !_and && _or == LWS_POLLOUT) { 50d4afb5ceSopenharmony_ci /* 51d4afb5ceSopenharmony_ci * Happening alongside service thread handling POLLOUT. 52d4afb5ceSopenharmony_ci * The danger is when he is finished, he will disable POLLOUT, 53d4afb5ceSopenharmony_ci * countermanding what we changed here. 54d4afb5ceSopenharmony_ci * 55d4afb5ceSopenharmony_ci * Instead of changing the fds, inform the service thread 56d4afb5ceSopenharmony_ci * what happened, and ask it to leave POLLOUT active on exit 57d4afb5ceSopenharmony_ci */ 58d4afb5ceSopenharmony_ci ((volatile struct lws *)wsi)->leave_pollout_active = 1; 59d4afb5ceSopenharmony_ci /* 60d4afb5ceSopenharmony_ci * by definition service thread is not in poll wait, so no need 61d4afb5ceSopenharmony_ci * to cancel service 62d4afb5ceSopenharmony_ci */ 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "using leave_pollout_active"); 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci return 0; 67d4afb5ceSopenharmony_ci } 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci context = wsi->a.context; 70d4afb5ceSopenharmony_ci pt = &context->pt[(int)wsi->tsi]; 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci assert(wsi->position_in_fds_table < (int)pt->fds_count); 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_EVENT_LIBS) 75d4afb5ceSopenharmony_ci /* 76d4afb5ceSopenharmony_ci * This only applies when we use the default poll() event loop. 77d4afb5ceSopenharmony_ci * 78d4afb5ceSopenharmony_ci * BSD can revert pa->events at any time, when the kernel decides to 79d4afb5ceSopenharmony_ci * exit from poll(). We can't protect against it using locking. 80d4afb5ceSopenharmony_ci * 81d4afb5ceSopenharmony_ci * Therefore we must check first if the service thread is in poll() 82d4afb5ceSopenharmony_ci * wait; if so, we know we must be being called from a foreign thread, 83d4afb5ceSopenharmony_ci * and we must keep a strictly ordered list of changes we made instead 84d4afb5ceSopenharmony_ci * of trying to apply them, since when poll() exits, which may happen 85d4afb5ceSopenharmony_ci * at any time it would revert our changes. 86d4afb5ceSopenharmony_ci * 87d4afb5ceSopenharmony_ci * The plat code will apply them when it leaves the poll() wait 88d4afb5ceSopenharmony_ci * before doing anything else. 89d4afb5ceSopenharmony_ci */ 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci vpt = (volatile struct lws_context_per_thread *)pt; 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci vpt->foreign_spinlock = 1; 94d4afb5ceSopenharmony_ci lws_memory_barrier(); 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci if (vpt->inside_poll) { 97d4afb5ceSopenharmony_ci struct lws_foreign_thread_pollfd *ftp, **ftp1; 98d4afb5ceSopenharmony_ci /* 99d4afb5ceSopenharmony_ci * We are certainly a foreign thread trying to change events 100d4afb5ceSopenharmony_ci * while the service thread is in the poll() wait. 101d4afb5ceSopenharmony_ci * 102d4afb5ceSopenharmony_ci * Create a list of changes to be applied after poll() exit, 103d4afb5ceSopenharmony_ci * instead of trying to apply them now. 104d4afb5ceSopenharmony_ci */ 105d4afb5ceSopenharmony_ci ftp = lws_malloc(sizeof(*ftp), "ftp"); 106d4afb5ceSopenharmony_ci if (!ftp) { 107d4afb5ceSopenharmony_ci vpt->foreign_spinlock = 0; 108d4afb5ceSopenharmony_ci lws_memory_barrier(); 109d4afb5ceSopenharmony_ci ret = -1; 110d4afb5ceSopenharmony_ci goto bail; 111d4afb5ceSopenharmony_ci } 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci ftp->_and = _and; 114d4afb5ceSopenharmony_ci ftp->_or = _or; 115d4afb5ceSopenharmony_ci ftp->fd_index = wsi->position_in_fds_table; 116d4afb5ceSopenharmony_ci ftp->next = NULL; 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci /* place at END of list to maintain order */ 121d4afb5ceSopenharmony_ci ftp1 = (struct lws_foreign_thread_pollfd **) 122d4afb5ceSopenharmony_ci &vpt->foreign_pfd_list; 123d4afb5ceSopenharmony_ci while (*ftp1) 124d4afb5ceSopenharmony_ci ftp1 = &((*ftp1)->next); 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci *ftp1 = ftp; 127d4afb5ceSopenharmony_ci vpt->foreign_spinlock = 0; 128d4afb5ceSopenharmony_ci lws_memory_barrier(); 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci lws_cancel_service_pt(wsi); 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci return 0; 135d4afb5ceSopenharmony_ci } 136d4afb5ceSopenharmony_ci 137d4afb5ceSopenharmony_ci vpt->foreign_spinlock = 0; 138d4afb5ceSopenharmony_ci lws_memory_barrier(); 139d4afb5ceSopenharmony_ci#endif 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci#if !defined(__linux__) && !defined(WIN32) 142d4afb5ceSopenharmony_ci /* OSX couldn't see close on stdin pipe side otherwise; WSAPOLL 143d4afb5ceSopenharmony_ci * blows up if we give it POLLHUP 144d4afb5ceSopenharmony_ci */ 145d4afb5ceSopenharmony_ci _or |= LWS_POLLHUP; 146d4afb5ceSopenharmony_ci#endif 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci pfd = &pt->fds[wsi->position_in_fds_table]; 149d4afb5ceSopenharmony_ci pa->fd = wsi->desc.sockfd; 150d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "fd %d events %d -> %d", pa->fd, pfd->events, 151d4afb5ceSopenharmony_ci (pfd->events & ~_and) | _or); 152d4afb5ceSopenharmony_ci pa->prev_events = pfd->events; 153d4afb5ceSopenharmony_ci pa->events = pfd->events = (short)((pfd->events & ~_and) | _or); 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci if (wsi->mux_substream) 156d4afb5ceSopenharmony_ci return 0; 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci if (wsi->a.vhost && 161d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, 162d4afb5ceSopenharmony_ci LWS_CALLBACK_CHANGE_MODE_POLL_FD, 163d4afb5ceSopenharmony_ci wsi->user_space, (void *)pa, 0)) { 164d4afb5ceSopenharmony_ci ret = -1; 165d4afb5ceSopenharmony_ci goto bail; 166d4afb5ceSopenharmony_ci } 167d4afb5ceSopenharmony_ci#endif 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci if (context->event_loop_ops->io) { 170d4afb5ceSopenharmony_ci if (_and & LWS_POLLIN) 171d4afb5ceSopenharmony_ci context->event_loop_ops->io(wsi, 172d4afb5ceSopenharmony_ci LWS_EV_STOP | LWS_EV_READ); 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci if (_or & LWS_POLLIN) 175d4afb5ceSopenharmony_ci context->event_loop_ops->io(wsi, 176d4afb5ceSopenharmony_ci LWS_EV_START | LWS_EV_READ); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci if (_and & LWS_POLLOUT) 179d4afb5ceSopenharmony_ci context->event_loop_ops->io(wsi, 180d4afb5ceSopenharmony_ci LWS_EV_STOP | LWS_EV_WRITE); 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci if (_or & LWS_POLLOUT) 183d4afb5ceSopenharmony_ci context->event_loop_ops->io(wsi, 184d4afb5ceSopenharmony_ci LWS_EV_START | LWS_EV_WRITE); 185d4afb5ceSopenharmony_ci } 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci /* 188d4afb5ceSopenharmony_ci * if we changed something in this pollfd... 189d4afb5ceSopenharmony_ci * ... and we're running in a different thread context 190d4afb5ceSopenharmony_ci * than the service thread... 191d4afb5ceSopenharmony_ci * ... and the service thread is waiting ... 192d4afb5ceSopenharmony_ci * then cancel it to force a restart with our changed events 193d4afb5ceSopenharmony_ci */ 194d4afb5ceSopenharmony_ci pa_events = pa->prev_events != pa->events; 195d4afb5ceSopenharmony_ci pfd->events = (short)pa->events; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (pa_events) { 198d4afb5ceSopenharmony_ci if (lws_plat_change_pollfd(context, wsi, pfd)) { 199d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "failed"); 200d4afb5ceSopenharmony_ci ret = -1; 201d4afb5ceSopenharmony_ci goto bail; 202d4afb5ceSopenharmony_ci } 203d4afb5ceSopenharmony_ci sampled_tid = pt->service_tid; 204d4afb5ceSopenharmony_ci if (sampled_tid && wsi->a.vhost) { 205d4afb5ceSopenharmony_ci tid = wsi->a.vhost->protocols[0].callback(wsi, 206d4afb5ceSopenharmony_ci LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); 207d4afb5ceSopenharmony_ci if (tid == -1) { 208d4afb5ceSopenharmony_ci ret = -1; 209d4afb5ceSopenharmony_ci goto bail; 210d4afb5ceSopenharmony_ci } 211d4afb5ceSopenharmony_ci if (tid != sampled_tid) 212d4afb5ceSopenharmony_ci lws_cancel_service_pt(wsi); 213d4afb5ceSopenharmony_ci } 214d4afb5ceSopenharmony_ci } 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_cibail: 217d4afb5ceSopenharmony_ci return ret; 218d4afb5ceSopenharmony_ci} 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 221d4afb5ceSopenharmony_ci/* 222d4afb5ceSopenharmony_ci * Enable or disable listen sockets on this pt globally... 223d4afb5ceSopenharmony_ci * it's modulated according to the pt having space for a new accept. 224d4afb5ceSopenharmony_ci */ 225d4afb5ceSopenharmony_cistatic void 226d4afb5ceSopenharmony_cilws_accept_modulation(struct lws_context *context, 227d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt, int allow) 228d4afb5ceSopenharmony_ci{ 229d4afb5ceSopenharmony_ci struct lws_vhost *vh = context->vhost_list; 230d4afb5ceSopenharmony_ci struct lws_pollargs pa1; 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci while (vh) { 233d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, 234d4afb5ceSopenharmony_ci lws_dll2_get_head(&vh->listen_wsi)) { 235d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, 236d4afb5ceSopenharmony_ci listen_list); 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci _lws_change_pollfd(wsi, allow ? 0 : LWS_POLLIN, 239d4afb5ceSopenharmony_ci allow ? LWS_POLLIN : 0, &pa1); 240d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci vh = vh->vhost_next; 243d4afb5ceSopenharmony_ci } 244d4afb5ceSopenharmony_ci} 245d4afb5ceSopenharmony_ci#endif 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci#if _LWS_ENABLED_LOGS & LLL_WARN 248d4afb5ceSopenharmony_civoid 249d4afb5ceSopenharmony_ci__dump_fds(struct lws_context_per_thread *pt, const char *s) 250d4afb5ceSopenharmony_ci{ 251d4afb5ceSopenharmony_ci unsigned int n; 252d4afb5ceSopenharmony_ci 253d4afb5ceSopenharmony_ci lwsl_cx_warn(pt->context, "fds_count %u, %s", pt->fds_count, s); 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci for (n = 0; n < pt->fds_count; n++) { 256d4afb5ceSopenharmony_ci struct lws *wsi = wsi_from_fd(pt->context, pt->fds[n].fd); 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci lwsl_cx_warn(pt->context, " %d: fd %d, wsi %s, pos_in_fds: %d", 259d4afb5ceSopenharmony_ci n + 1, pt->fds[n].fd, lws_wsi_tag(wsi), 260d4afb5ceSopenharmony_ci wsi ? wsi->position_in_fds_table : -1); 261d4afb5ceSopenharmony_ci } 262d4afb5ceSopenharmony_ci} 263d4afb5ceSopenharmony_ci#else 264d4afb5ceSopenharmony_ci#define __dump_fds(x, y) 265d4afb5ceSopenharmony_ci#endif 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ciint 268d4afb5ceSopenharmony_ci__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi) 269d4afb5ceSopenharmony_ci{ 270d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 271d4afb5ceSopenharmony_ci struct lws_pollargs pa = { wsi->desc.sockfd, LWS_POLLIN, 0 }; 272d4afb5ceSopenharmony_ci#endif 273d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 274d4afb5ceSopenharmony_ci int ret = 0; 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci// __dump_fds(pt, "pre insert"); 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci lws_pt_assert_lock_held(pt); 279d4afb5ceSopenharmony_ci 280d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "tsi=%d, sock=%d, pos-in-fds=%d", 281d4afb5ceSopenharmony_ci wsi->tsi, wsi->desc.sockfd, pt->fds_count); 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) { 284d4afb5ceSopenharmony_ci lwsl_cx_err(context, "Too many fds (%d vs %d)", context->max_fds, 285d4afb5ceSopenharmony_ci context->fd_limit_per_thread); 286d4afb5ceSopenharmony_ci return 1; 287d4afb5ceSopenharmony_ci } 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci#if !defined(_WIN32) 290d4afb5ceSopenharmony_ci if (!wsi->a.context->max_fds_unrelated_to_ulimit && 291d4afb5ceSopenharmony_ci wsi->desc.sockfd - lws_plat_socket_offset() >= (int)context->max_fds) { 292d4afb5ceSopenharmony_ci lwsl_cx_err(context, "Socket fd %d is too high (%d) offset %d", 293d4afb5ceSopenharmony_ci wsi->desc.sockfd, context->max_fds, 294d4afb5ceSopenharmony_ci lws_plat_socket_offset()); 295d4afb5ceSopenharmony_ci return 1; 296d4afb5ceSopenharmony_ci } 297d4afb5ceSopenharmony_ci#endif 298d4afb5ceSopenharmony_ci 299d4afb5ceSopenharmony_ci assert(wsi); 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci#if defined(LWS_WITH_NETLINK) 302d4afb5ceSopenharmony_ci assert(wsi->event_pipe || wsi->a.vhost || wsi == pt->context->netlink); 303d4afb5ceSopenharmony_ci#else 304d4afb5ceSopenharmony_ci assert(wsi->event_pipe || wsi->a.vhost); 305d4afb5ceSopenharmony_ci#endif 306d4afb5ceSopenharmony_ci assert(lws_socket_is_valid(wsi->desc.sockfd)); 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci if (wsi->a.vhost && 311d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, 312d4afb5ceSopenharmony_ci wsi->user_space, (void *) &pa, 1)) 313d4afb5ceSopenharmony_ci return -1; 314d4afb5ceSopenharmony_ci#endif 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci if (insert_wsi(context, wsi)) 317d4afb5ceSopenharmony_ci return -1; 318d4afb5ceSopenharmony_ci pt->count_conns++; 319d4afb5ceSopenharmony_ci wsi->position_in_fds_table = (int)pt->fds_count; 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_ci pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd; 322d4afb5ceSopenharmony_ci pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN; 323d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 324d4afb5ceSopenharmony_ci pa.events = pt->fds[pt->fds_count].events; 325d4afb5ceSopenharmony_ci#endif 326d4afb5ceSopenharmony_ci 327d4afb5ceSopenharmony_ci lws_plat_insert_socket_into_fds(context, wsi); 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 330d4afb5ceSopenharmony_ci 331d4afb5ceSopenharmony_ci /* external POLL support via protocol 0 */ 332d4afb5ceSopenharmony_ci if (wsi->a.vhost && 333d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD, 334d4afb5ceSopenharmony_ci wsi->user_space, (void *) &pa, 0)) 335d4afb5ceSopenharmony_ci ret = -1; 336d4afb5ceSopenharmony_ci#endif 337d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 338d4afb5ceSopenharmony_ci /* if no more room, defeat accepts on this service thread */ 339d4afb5ceSopenharmony_ci if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1) 340d4afb5ceSopenharmony_ci lws_accept_modulation(context, pt, 0); 341d4afb5ceSopenharmony_ci#endif 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 344d4afb5ceSopenharmony_ci if (wsi->a.vhost && 345d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, 346d4afb5ceSopenharmony_ci wsi->user_space, (void *)&pa, 1)) 347d4afb5ceSopenharmony_ci ret = -1; 348d4afb5ceSopenharmony_ci#endif 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci// __dump_fds(pt, "post insert"); 351d4afb5ceSopenharmony_ci 352d4afb5ceSopenharmony_ci return ret; 353d4afb5ceSopenharmony_ci} 354d4afb5ceSopenharmony_ci 355d4afb5ceSopenharmony_ci/* requires pt lock */ 356d4afb5ceSopenharmony_ci 357d4afb5ceSopenharmony_ciint 358d4afb5ceSopenharmony_ci__remove_wsi_socket_from_fds(struct lws *wsi) 359d4afb5ceSopenharmony_ci{ 360d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 361d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 362d4afb5ceSopenharmony_ci struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 }; 363d4afb5ceSopenharmony_ci#endif 364d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 365d4afb5ceSopenharmony_ci struct lws *end_wsi; 366d4afb5ceSopenharmony_ci int v, m, ret = 0; 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ci lws_pt_assert_lock_held(pt); 369d4afb5ceSopenharmony_ci 370d4afb5ceSopenharmony_ci// __dump_fds(pt, "pre remove"); 371d4afb5ceSopenharmony_ci 372d4afb5ceSopenharmony_ci#if !defined(_WIN32) 373d4afb5ceSopenharmony_ci if (!wsi->a.context->max_fds_unrelated_to_ulimit && 374d4afb5ceSopenharmony_ci wsi->desc.sockfd - lws_plat_socket_offset() > (int)context->max_fds) { 375d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "fd %d too high (%d)", 376d4afb5ceSopenharmony_ci wsi->desc.sockfd, 377d4afb5ceSopenharmony_ci context->max_fds); 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci return 1; 380d4afb5ceSopenharmony_ci } 381d4afb5ceSopenharmony_ci#endif 382d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 383d4afb5ceSopenharmony_ci if (wsi->a.vhost && wsi->a.vhost->protocols && 384d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, 385d4afb5ceSopenharmony_ci wsi->user_space, (void *)&pa, 1)) 386d4afb5ceSopenharmony_ci return -1; 387d4afb5ceSopenharmony_ci#endif 388d4afb5ceSopenharmony_ci 389d4afb5ceSopenharmony_ci __lws_same_vh_protocol_remove(wsi); 390d4afb5ceSopenharmony_ci 391d4afb5ceSopenharmony_ci /* the guy who is to be deleted's slot index in pt->fds */ 392d4afb5ceSopenharmony_ci m = wsi->position_in_fds_table; 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci /* these are the only valid possibilities for position_in_fds_table */ 395d4afb5ceSopenharmony_ci assert(m == LWS_NO_FDS_POS || (m >= 0 && (unsigned int)m < pt->fds_count)); 396d4afb5ceSopenharmony_ci 397d4afb5ceSopenharmony_ci if (context->event_loop_ops->io) 398d4afb5ceSopenharmony_ci context->event_loop_ops->io(wsi, LWS_EV_STOP | LWS_EV_READ | 399d4afb5ceSopenharmony_ci LWS_EV_WRITE); 400d4afb5ceSopenharmony_ci/* 401d4afb5ceSopenharmony_ci lwsl_notice("%s: wsi=%s, skt=%d, fds pos=%d, end guy pos=%d, endfd=%d\n", 402d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi), wsi->desc.sockfd, wsi->position_in_fds_table, 403d4afb5ceSopenharmony_ci pt->fds_count, pt->fds[pt->fds_count - 1].fd); */ 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ci if (m != LWS_NO_FDS_POS) { 406d4afb5ceSopenharmony_ci char fixup = 0; 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci assert(pt->fds_count && (unsigned int)m != pt->fds_count); 409d4afb5ceSopenharmony_ci 410d4afb5ceSopenharmony_ci /* deletion guy's lws_lookup entry needs nuking */ 411d4afb5ceSopenharmony_ci delete_from_fd(context, wsi->desc.sockfd); 412d4afb5ceSopenharmony_ci 413d4afb5ceSopenharmony_ci if ((unsigned int)m != pt->fds_count - 1) { 414d4afb5ceSopenharmony_ci /* have the last guy take up the now vacant slot */ 415d4afb5ceSopenharmony_ci pt->fds[m] = pt->fds[pt->fds_count - 1]; 416d4afb5ceSopenharmony_ci fixup = 1; 417d4afb5ceSopenharmony_ci } 418d4afb5ceSopenharmony_ci 419d4afb5ceSopenharmony_ci pt->fds[pt->fds_count - 1].fd = -1; 420d4afb5ceSopenharmony_ci 421d4afb5ceSopenharmony_ci /* this decrements pt->fds_count */ 422d4afb5ceSopenharmony_ci lws_plat_delete_socket_from_fds(context, wsi, m); 423d4afb5ceSopenharmony_ci pt->count_conns--; 424d4afb5ceSopenharmony_ci if (fixup) { 425d4afb5ceSopenharmony_ci v = (int) pt->fds[m].fd; 426d4afb5ceSopenharmony_ci /* old end guy's "position in fds table" is now the 427d4afb5ceSopenharmony_ci * deletion guy's old one */ 428d4afb5ceSopenharmony_ci end_wsi = wsi_from_fd(context, v); 429d4afb5ceSopenharmony_ci if (!end_wsi) { 430d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "no wsi for fd %d pos %d, " 431d4afb5ceSopenharmony_ci "pt->fds_count=%d", 432d4afb5ceSopenharmony_ci (int)pt->fds[m].fd, m, 433d4afb5ceSopenharmony_ci pt->fds_count); 434d4afb5ceSopenharmony_ci // assert(0); 435d4afb5ceSopenharmony_ci } else 436d4afb5ceSopenharmony_ci end_wsi->position_in_fds_table = m; 437d4afb5ceSopenharmony_ci } 438d4afb5ceSopenharmony_ci 439d4afb5ceSopenharmony_ci /* removed wsi has no position any more */ 440d4afb5ceSopenharmony_ci wsi->position_in_fds_table = LWS_NO_FDS_POS; 441d4afb5ceSopenharmony_ci 442d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 443d4afb5ceSopenharmony_ci /* remove also from external POLL support via protocol 0 */ 444d4afb5ceSopenharmony_ci if (lws_socket_is_valid(wsi->desc.sockfd) && wsi->a.vhost && 445d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, 446d4afb5ceSopenharmony_ci LWS_CALLBACK_DEL_POLL_FD, 447d4afb5ceSopenharmony_ci wsi->user_space, 448d4afb5ceSopenharmony_ci (void *) &pa, 0)) 449d4afb5ceSopenharmony_ci ret = -1; 450d4afb5ceSopenharmony_ci#endif 451d4afb5ceSopenharmony_ci } 452d4afb5ceSopenharmony_ci 453d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 454d4afb5ceSopenharmony_ci if (!context->being_destroyed && 455d4afb5ceSopenharmony_ci /* if this made some room, accept connects on this thread */ 456d4afb5ceSopenharmony_ci (unsigned int)pt->fds_count < context->fd_limit_per_thread - 1) 457d4afb5ceSopenharmony_ci lws_accept_modulation(context, pt, 1); 458d4afb5ceSopenharmony_ci#endif 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 461d4afb5ceSopenharmony_ci if (wsi->a.vhost && 462d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, 463d4afb5ceSopenharmony_ci wsi->user_space, (void *) &pa, 1)) 464d4afb5ceSopenharmony_ci ret = -1; 465d4afb5ceSopenharmony_ci#endif 466d4afb5ceSopenharmony_ci 467d4afb5ceSopenharmony_ci// __dump_fds(pt, "post remove"); 468d4afb5ceSopenharmony_ci 469d4afb5ceSopenharmony_ci return ret; 470d4afb5ceSopenharmony_ci} 471d4afb5ceSopenharmony_ci 472d4afb5ceSopenharmony_ciint 473d4afb5ceSopenharmony_ci__lws_change_pollfd(struct lws *wsi, int _and, int _or) 474d4afb5ceSopenharmony_ci{ 475d4afb5ceSopenharmony_ci struct lws_context *context; 476d4afb5ceSopenharmony_ci struct lws_pollargs pa; 477d4afb5ceSopenharmony_ci int ret = 0; 478d4afb5ceSopenharmony_ci 479d4afb5ceSopenharmony_ci if (!wsi || (!wsi->a.protocol && !wsi->event_pipe) || 480d4afb5ceSopenharmony_ci wsi->position_in_fds_table == LWS_NO_FDS_POS) 481d4afb5ceSopenharmony_ci return 0; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci context = lws_get_context(wsi); 484d4afb5ceSopenharmony_ci if (!context) 485d4afb5ceSopenharmony_ci return 1; 486d4afb5ceSopenharmony_ci 487d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 488d4afb5ceSopenharmony_ci if (wsi->a.vhost && 489d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, 490d4afb5ceSopenharmony_ci wsi->user_space, (void *) &pa, 0)) 491d4afb5ceSopenharmony_ci return -1; 492d4afb5ceSopenharmony_ci#endif 493d4afb5ceSopenharmony_ci 494d4afb5ceSopenharmony_ci ret = _lws_change_pollfd(wsi, _and, _or, &pa); 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EXTERNAL_POLL) 497d4afb5ceSopenharmony_ci if (wsi->a.vhost && 498d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, 499d4afb5ceSopenharmony_ci wsi->user_space, (void *) &pa, 0)) 500d4afb5ceSopenharmony_ci ret = -1; 501d4afb5ceSopenharmony_ci#endif 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci return ret; 504d4afb5ceSopenharmony_ci} 505d4afb5ceSopenharmony_ci 506d4afb5ceSopenharmony_ciint 507d4afb5ceSopenharmony_cilws_change_pollfd(struct lws *wsi, int _and, int _or) 508d4afb5ceSopenharmony_ci{ 509d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 510d4afb5ceSopenharmony_ci int ret = 0; 511d4afb5ceSopenharmony_ci 512d4afb5ceSopenharmony_ci pt = &wsi->a.context->pt[(int)wsi->tsi]; 513d4afb5ceSopenharmony_ci 514d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 515d4afb5ceSopenharmony_ci ret = __lws_change_pollfd(wsi, _and, _or); 516d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 517d4afb5ceSopenharmony_ci 518d4afb5ceSopenharmony_ci return ret; 519d4afb5ceSopenharmony_ci} 520d4afb5ceSopenharmony_ci 521d4afb5ceSopenharmony_ciint 522d4afb5ceSopenharmony_cilws_callback_on_writable(struct lws *wsi) 523d4afb5ceSopenharmony_ci{ 524d4afb5ceSopenharmony_ci struct lws *w = wsi; 525d4afb5ceSopenharmony_ci 526d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_SHUTDOWN) 527d4afb5ceSopenharmony_ci return 0; 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_ci if (wsi->socket_is_permanently_unusable) 530d4afb5ceSopenharmony_ci return 0; 531d4afb5ceSopenharmony_ci 532d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_callback_on_writable)) { 533d4afb5ceSopenharmony_ci int q = lws_rops_func_fidx(wsi->role_ops, 534d4afb5ceSopenharmony_ci LWS_ROPS_callback_on_writable). 535d4afb5ceSopenharmony_ci callback_on_writable(wsi); 536d4afb5ceSopenharmony_ci if (q) 537d4afb5ceSopenharmony_ci return 1; 538d4afb5ceSopenharmony_ci w = lws_get_network_wsi(wsi); 539d4afb5ceSopenharmony_ci } else 540d4afb5ceSopenharmony_ci if (w->position_in_fds_table == LWS_NO_FDS_POS) { 541d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "failed to find socket %d", 542d4afb5ceSopenharmony_ci wsi->desc.sockfd); 543d4afb5ceSopenharmony_ci return -1; 544d4afb5ceSopenharmony_ci } 545d4afb5ceSopenharmony_ci 546d4afb5ceSopenharmony_ci if (__lws_change_pollfd(w, 0, LWS_POLLOUT)) 547d4afb5ceSopenharmony_ci return -1; 548d4afb5ceSopenharmony_ci 549d4afb5ceSopenharmony_ci return 1; 550d4afb5ceSopenharmony_ci} 551d4afb5ceSopenharmony_ci 552d4afb5ceSopenharmony_ci 553d4afb5ceSopenharmony_ci/* 554d4afb5ceSopenharmony_ci * stitch protocol choice into the vh protocol linked list 555d4afb5ceSopenharmony_ci * We always insert ourselves at the start of the list 556d4afb5ceSopenharmony_ci * 557d4afb5ceSopenharmony_ci * X <-> B 558d4afb5ceSopenharmony_ci * X <-> pAn <-> pB 559d4afb5ceSopenharmony_ci * 560d4afb5ceSopenharmony_ci * Illegal to attach more than once without detach inbetween 561d4afb5ceSopenharmony_ci */ 562d4afb5ceSopenharmony_civoid 563d4afb5ceSopenharmony_cilws_same_vh_protocol_insert(struct lws *wsi, int n) 564d4afb5ceSopenharmony_ci{ 565d4afb5ceSopenharmony_ci lws_context_lock(wsi->a.context, __func__); 566d4afb5ceSopenharmony_ci lws_vhost_lock(wsi->a.vhost); 567d4afb5ceSopenharmony_ci 568d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->same_vh_protocol); 569d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->same_vh_protocol, 570d4afb5ceSopenharmony_ci &wsi->a.vhost->same_vh_protocol_owner[n]); 571d4afb5ceSopenharmony_ci 572d4afb5ceSopenharmony_ci wsi->bound_vhost_index = (uint8_t)n; 573d4afb5ceSopenharmony_ci 574d4afb5ceSopenharmony_ci lws_vhost_unlock(wsi->a.vhost); 575d4afb5ceSopenharmony_ci lws_context_unlock(wsi->a.context); 576d4afb5ceSopenharmony_ci} 577d4afb5ceSopenharmony_ci 578d4afb5ceSopenharmony_civoid 579d4afb5ceSopenharmony_ci__lws_same_vh_protocol_remove(struct lws *wsi) 580d4afb5ceSopenharmony_ci{ 581d4afb5ceSopenharmony_ci if (wsi->a.vhost && wsi->a.vhost->same_vh_protocol_owner) 582d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->same_vh_protocol); 583d4afb5ceSopenharmony_ci} 584d4afb5ceSopenharmony_ci 585d4afb5ceSopenharmony_civoid 586d4afb5ceSopenharmony_cilws_same_vh_protocol_remove(struct lws *wsi) 587d4afb5ceSopenharmony_ci{ 588d4afb5ceSopenharmony_ci if (!wsi->a.vhost) 589d4afb5ceSopenharmony_ci return; 590d4afb5ceSopenharmony_ci 591d4afb5ceSopenharmony_ci lws_context_lock(wsi->a.context, __func__); 592d4afb5ceSopenharmony_ci lws_vhost_lock(wsi->a.vhost); 593d4afb5ceSopenharmony_ci 594d4afb5ceSopenharmony_ci __lws_same_vh_protocol_remove(wsi); 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci lws_vhost_unlock(wsi->a.vhost); 597d4afb5ceSopenharmony_ci lws_context_unlock(wsi->a.context); 598d4afb5ceSopenharmony_ci} 599d4afb5ceSopenharmony_ci 600d4afb5ceSopenharmony_ci 601d4afb5ceSopenharmony_ciint 602d4afb5ceSopenharmony_cilws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost, 603d4afb5ceSopenharmony_ci const struct lws_protocols *protocol) 604d4afb5ceSopenharmony_ci{ 605d4afb5ceSopenharmony_ci struct lws *wsi; 606d4afb5ceSopenharmony_ci int n; 607d4afb5ceSopenharmony_ci 608d4afb5ceSopenharmony_ci if (protocol < vhost->protocols || 609d4afb5ceSopenharmony_ci protocol >= (vhost->protocols + vhost->count_protocols)) { 610d4afb5ceSopenharmony_ci lwsl_vhost_err((struct lws_vhost *)vhost, 611d4afb5ceSopenharmony_ci "protocol %p is not from vhost %p (%p - %p)", 612d4afb5ceSopenharmony_ci protocol, vhost->protocols, vhost, 613d4afb5ceSopenharmony_ci (vhost->protocols + vhost->count_protocols)); 614d4afb5ceSopenharmony_ci 615d4afb5ceSopenharmony_ci return -1; 616d4afb5ceSopenharmony_ci } 617d4afb5ceSopenharmony_ci 618d4afb5ceSopenharmony_ci n = (int)(protocol - vhost->protocols); 619d4afb5ceSopenharmony_ci 620d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 621d4afb5ceSopenharmony_ci lws_dll2_get_head(&vhost->same_vh_protocol_owner[n])) { 622d4afb5ceSopenharmony_ci wsi = lws_container_of(d, struct lws, same_vh_protocol); 623d4afb5ceSopenharmony_ci 624d4afb5ceSopenharmony_ci assert(wsi->a.protocol == protocol); 625d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 626d4afb5ceSopenharmony_ci 627d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(d, d1); 628d4afb5ceSopenharmony_ci 629d4afb5ceSopenharmony_ci return 0; 630d4afb5ceSopenharmony_ci} 631d4afb5ceSopenharmony_ci 632d4afb5ceSopenharmony_ciint 633d4afb5ceSopenharmony_cilws_callback_on_writable_all_protocol(const struct lws_context *context, 634d4afb5ceSopenharmony_ci const struct lws_protocols *protocol) 635d4afb5ceSopenharmony_ci{ 636d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 637d4afb5ceSopenharmony_ci int n; 638d4afb5ceSopenharmony_ci 639d4afb5ceSopenharmony_ci if (!context) 640d4afb5ceSopenharmony_ci return 0; 641d4afb5ceSopenharmony_ci 642d4afb5ceSopenharmony_ci vhost = context->vhost_list; 643d4afb5ceSopenharmony_ci 644d4afb5ceSopenharmony_ci while (vhost) { 645d4afb5ceSopenharmony_ci for (n = 0; n < vhost->count_protocols; n++) 646d4afb5ceSopenharmony_ci if (protocol->callback == 647d4afb5ceSopenharmony_ci vhost->protocols[n].callback && 648d4afb5ceSopenharmony_ci !strcmp(protocol->name, vhost->protocols[n].name)) 649d4afb5ceSopenharmony_ci break; 650d4afb5ceSopenharmony_ci if (n != vhost->count_protocols) 651d4afb5ceSopenharmony_ci lws_callback_on_writable_all_protocol_vhost( 652d4afb5ceSopenharmony_ci vhost, &vhost->protocols[n]); 653d4afb5ceSopenharmony_ci 654d4afb5ceSopenharmony_ci vhost = vhost->vhost_next; 655d4afb5ceSopenharmony_ci } 656d4afb5ceSopenharmony_ci 657d4afb5ceSopenharmony_ci return 0; 658d4afb5ceSopenharmony_ci} 659