1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 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 27d4afb5ceSopenharmony_ci#if defined(_DEBUG) 28d4afb5ceSopenharmony_civoid 29d4afb5ceSopenharmony_cilws_service_assert_loop_thread(struct lws_context *cx, int tsi) 30d4afb5ceSopenharmony_ci{ 31d4afb5ceSopenharmony_ci if (!cx->event_loop_ops->foreign_thread) 32d4afb5ceSopenharmony_ci /* we can't judge it */ 33d4afb5ceSopenharmony_ci return; 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci if (!cx->event_loop_ops->foreign_thread(cx, tsi)) 36d4afb5ceSopenharmony_ci /* OK */ 37d4afb5ceSopenharmony_ci return; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci /* 40d4afb5ceSopenharmony_ci * Lws apis are NOT THREADSAFE with the sole exception of 41d4afb5ceSopenharmony_ci * lws_cancel_service(). If you look at the assert backtrace, you 42d4afb5ceSopenharmony_ci * should see you're illegally calling an lws api from another thread. 43d4afb5ceSopenharmony_ci */ 44d4afb5ceSopenharmony_ci assert(0); 45d4afb5ceSopenharmony_ci} 46d4afb5ceSopenharmony_ci#endif 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ciint 49d4afb5ceSopenharmony_cilws_callback_as_writeable(struct lws *wsi) 50d4afb5ceSopenharmony_ci{ 51d4afb5ceSopenharmony_ci int n, m; 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci n = wsi->role_ops->writeable_cb[lwsi_role_server(wsi)]; 54d4afb5ceSopenharmony_ci m = user_callback_handle_rxflow(wsi->a.protocol->callback, 55d4afb5ceSopenharmony_ci wsi, (enum lws_callback_reasons) n, 56d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0); 57d4afb5ceSopenharmony_ci 58d4afb5ceSopenharmony_ci return m; 59d4afb5ceSopenharmony_ci} 60d4afb5ceSopenharmony_ci 61d4afb5ceSopenharmony_ciint 62d4afb5ceSopenharmony_cilws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) 63d4afb5ceSopenharmony_ci{ 64d4afb5ceSopenharmony_ci volatile struct lws *vwsi = (volatile struct lws *)wsi; 65d4afb5ceSopenharmony_ci int n; 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_ci if (wsi->socket_is_permanently_unusable) 68d4afb5ceSopenharmony_ci return 0; 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci vwsi->leave_pollout_active = 0; 71d4afb5ceSopenharmony_ci vwsi->handling_pollout = 1; 72d4afb5ceSopenharmony_ci /* 73d4afb5ceSopenharmony_ci * if another thread wants POLLOUT on us, from here on while 74d4afb5ceSopenharmony_ci * handling_pollout is set, he will only set leave_pollout_active. 75d4afb5ceSopenharmony_ci * If we are going to disable POLLOUT, we will check that first. 76d4afb5ceSopenharmony_ci */ 77d4afb5ceSopenharmony_ci wsi->could_have_pending = 0; /* clear back-to-back write detection */ 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci /* 80d4afb5ceSopenharmony_ci * user callback is lowest priority to get these notifications 81d4afb5ceSopenharmony_ci * actually, since other pending things cannot be disordered 82d4afb5ceSopenharmony_ci * 83d4afb5ceSopenharmony_ci * Priority 1: pending truncated sends are incomplete ws fragments 84d4afb5ceSopenharmony_ci * If anything else sent first the protocol would be 85d4afb5ceSopenharmony_ci * corrupted. 86d4afb5ceSopenharmony_ci * 87d4afb5ceSopenharmony_ci * These are post- any compression transform 88d4afb5ceSopenharmony_ci */ 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_ci if (lws_has_buffered_out(wsi)) { 91d4afb5ceSopenharmony_ci if (lws_issue_raw(wsi, NULL, 0) < 0) { 92d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "signalling to close"); 93d4afb5ceSopenharmony_ci goto bail_die; 94d4afb5ceSopenharmony_ci } 95d4afb5ceSopenharmony_ci /* leave POLLOUT active either way */ 96d4afb5ceSopenharmony_ci goto bail_ok; 97d4afb5ceSopenharmony_ci } else 98d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { 99d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 100d4afb5ceSopenharmony_ci goto bail_die; /* retry closing now */ 101d4afb5ceSopenharmony_ci } 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci /* Priority 2: pre- compression transform */ 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 106d4afb5ceSopenharmony_ci if (wsi->http.comp_ctx.buflist_comp || 107d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more) { 108d4afb5ceSopenharmony_ci enum lws_write_protocol wp = LWS_WRITE_HTTP; 109d4afb5ceSopenharmony_ci 110d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "compl comp partial (buflist_comp %p, may %d)", 111d4afb5ceSopenharmony_ci wsi->http.comp_ctx.buflist_comp, 112d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more); 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) && 115d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol). 116d4afb5ceSopenharmony_ci write_role_protocol(wsi, NULL, 0, &wp) < 0) { 117d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "signalling to close"); 118d4afb5ceSopenharmony_ci goto bail_die; 119d4afb5ceSopenharmony_ci } 120d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci goto bail_ok; 123d4afb5ceSopenharmony_ci } 124d4afb5ceSopenharmony_ci#endif 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 127d4afb5ceSopenharmony_ci /* 128d4afb5ceSopenharmony_ci * A cgi connection's wire protocol remains h1 or h2. He is just 129d4afb5ceSopenharmony_ci * getting his data from his child cgis. 130d4afb5ceSopenharmony_ci */ 131d4afb5ceSopenharmony_ci if (wsi->http.cgi) { 132d4afb5ceSopenharmony_ci /* also one shot */ 133d4afb5ceSopenharmony_ci if (pollfd) 134d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { 135d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "failed at set pollfd"); 136d4afb5ceSopenharmony_ci return 1; 137d4afb5ceSopenharmony_ci } 138d4afb5ceSopenharmony_ci goto user_service_go_again; 139d4afb5ceSopenharmony_ci } 140d4afb5ceSopenharmony_ci#endif 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci /* if we got here, we should have wire protocol ops set on the wsi */ 143d4afb5ceSopenharmony_ci assert(wsi->role_ops); 144d4afb5ceSopenharmony_ci 145d4afb5ceSopenharmony_ci if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_handle_POLLOUT)) 146d4afb5ceSopenharmony_ci goto bail_ok; 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci n = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_handle_POLLOUT). 149d4afb5ceSopenharmony_ci handle_POLLOUT(wsi); 150d4afb5ceSopenharmony_ci switch (n) { 151d4afb5ceSopenharmony_ci case LWS_HP_RET_BAIL_OK: 152d4afb5ceSopenharmony_ci goto bail_ok; 153d4afb5ceSopenharmony_ci case LWS_HP_RET_BAIL_DIE: 154d4afb5ceSopenharmony_ci goto bail_die; 155d4afb5ceSopenharmony_ci case LWS_HP_RET_DROP_POLLOUT: 156d4afb5ceSopenharmony_ci case LWS_HP_RET_USER_SERVICE: 157d4afb5ceSopenharmony_ci break; 158d4afb5ceSopenharmony_ci default: 159d4afb5ceSopenharmony_ci assert(0); 160d4afb5ceSopenharmony_ci } 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci /* one shot */ 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci if (pollfd) { 165d4afb5ceSopenharmony_ci int eff = vwsi->leave_pollout_active; 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci if (!eff) { 168d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { 169d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "failed at set pollfd"); 170d4afb5ceSopenharmony_ci goto bail_die; 171d4afb5ceSopenharmony_ci } 172d4afb5ceSopenharmony_ci } 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci vwsi->handling_pollout = 0; 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci /* cannot get leave_pollout_active set after the above */ 177d4afb5ceSopenharmony_ci if (!eff && wsi->leave_pollout_active) { 178d4afb5ceSopenharmony_ci /* 179d4afb5ceSopenharmony_ci * got set inbetween sampling eff and clearing 180d4afb5ceSopenharmony_ci * handling_pollout, force POLLOUT on 181d4afb5ceSopenharmony_ci */ 182d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "leave_pollout_active"); 183d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { 184d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "failed at set pollfd"); 185d4afb5ceSopenharmony_ci goto bail_die; 186d4afb5ceSopenharmony_ci } 187d4afb5ceSopenharmony_ci } 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci vwsi->leave_pollout_active = 0; 190d4afb5ceSopenharmony_ci } 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci if (lwsi_role_client(wsi) && !wsi->hdr_parsing_completed && 193d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS && 194d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_ISSUE_HTTP_BODY) 195d4afb5ceSopenharmony_ci goto bail_ok; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (n == LWS_HP_RET_DROP_POLLOUT) 198d4afb5ceSopenharmony_ci goto bail_ok; 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 202d4afb5ceSopenharmony_ciuser_service_go_again: 203d4afb5ceSopenharmony_ci#endif 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_perform_user_POLLOUT)) { 206d4afb5ceSopenharmony_ci if (lws_rops_func_fidx(wsi->role_ops, 207d4afb5ceSopenharmony_ci LWS_ROPS_perform_user_POLLOUT). 208d4afb5ceSopenharmony_ci perform_user_POLLOUT(wsi) == -1) 209d4afb5ceSopenharmony_ci goto bail_die; 210d4afb5ceSopenharmony_ci else 211d4afb5ceSopenharmony_ci goto bail_ok; 212d4afb5ceSopenharmony_ci } 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "non mux: wsistate 0x%lx, ops %s", 215d4afb5ceSopenharmony_ci (unsigned long)wsi->wsistate, wsi->role_ops->name); 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci vwsi = (volatile struct lws *)wsi; 218d4afb5ceSopenharmony_ci vwsi->leave_pollout_active = 0; 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci n = lws_callback_as_writeable(wsi); 221d4afb5ceSopenharmony_ci vwsi->handling_pollout = 0; 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (vwsi->leave_pollout_active) 224d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) 225d4afb5ceSopenharmony_ci goto bail_die; 226d4afb5ceSopenharmony_ci 227d4afb5ceSopenharmony_ci return n; 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci /* 230d4afb5ceSopenharmony_ci * since these don't disable the POLLOUT, they are always doing the 231d4afb5ceSopenharmony_ci * right thing for leave_pollout_active whether it was set or not. 232d4afb5ceSopenharmony_ci */ 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_cibail_ok: 235d4afb5ceSopenharmony_ci vwsi->handling_pollout = 0; 236d4afb5ceSopenharmony_ci vwsi->leave_pollout_active = 0; 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci return 0; 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_cibail_die: 241d4afb5ceSopenharmony_ci vwsi->handling_pollout = 0; 242d4afb5ceSopenharmony_ci vwsi->leave_pollout_active = 0; 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci return -1; 245d4afb5ceSopenharmony_ci} 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ciint 248d4afb5ceSopenharmony_cilws_rxflow_cache(struct lws *wsi, unsigned char *buf, size_t n, size_t len) 249d4afb5ceSopenharmony_ci{ 250d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 251d4afb5ceSopenharmony_ci uint8_t *buffered; 252d4afb5ceSopenharmony_ci size_t blen; 253d4afb5ceSopenharmony_ci int ret = LWSRXFC_CACHED, m; 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci /* his RX is flowcontrolled, don't send remaining now */ 256d4afb5ceSopenharmony_ci blen = lws_buflist_next_segment_len(&wsi->buflist, &buffered); 257d4afb5ceSopenharmony_ci if (blen) { 258d4afb5ceSopenharmony_ci if (buf >= buffered && buf + len <= buffered + blen && 259d4afb5ceSopenharmony_ci blen != (size_t)len) { 260d4afb5ceSopenharmony_ci /* 261d4afb5ceSopenharmony_ci * rxflow while we were spilling prev rxflow 262d4afb5ceSopenharmony_ci * 263d4afb5ceSopenharmony_ci * len indicates how much was unused, then... so trim 264d4afb5ceSopenharmony_ci * the head buflist to match that situation 265d4afb5ceSopenharmony_ci */ 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci lws_buflist_use_segment(&wsi->buflist, blen - len); 268d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "trim existing rxflow %d -> %d", 269d4afb5ceSopenharmony_ci (int)blen, (int)len); 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci return LWSRXFC_TRIMMED; 272d4afb5ceSopenharmony_ci } 273d4afb5ceSopenharmony_ci ret = LWSRXFC_ADDITIONAL; 274d4afb5ceSopenharmony_ci } 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci /* a new rxflow, buffer it and warn caller */ 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "rxflow append %d", (int)(len - n)); 279d4afb5ceSopenharmony_ci m = lws_buflist_append_segment(&wsi->buflist, buf + n, len - n); 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci if (m < 0) 282d4afb5ceSopenharmony_ci return LWSRXFC_ERROR; 283d4afb5ceSopenharmony_ci if (m) { 284d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "added to rxflow list");; 285d4afb5ceSopenharmony_ci if (lws_dll2_is_detached(&wsi->dll_buflist)) 286d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner); 287d4afb5ceSopenharmony_ci } 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci return ret; 290d4afb5ceSopenharmony_ci} 291d4afb5ceSopenharmony_ci 292d4afb5ceSopenharmony_ci/* this is used by the platform service code to stop us waiting for network 293d4afb5ceSopenharmony_ci * activity in poll() when we have something that already needs service 294d4afb5ceSopenharmony_ci */ 295d4afb5ceSopenharmony_ci 296d4afb5ceSopenharmony_ciint 297d4afb5ceSopenharmony_cilws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi) 298d4afb5ceSopenharmony_ci{ 299d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci if (!context) 302d4afb5ceSopenharmony_ci return 1; 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci if (!context->protocol_init_done) 305d4afb5ceSopenharmony_ci if (lws_protocol_init(context)) 306d4afb5ceSopenharmony_ci return 1; 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_SMD) 309d4afb5ceSopenharmony_ci if (!tsi && lws_smd_message_pending(context)) { 310d4afb5ceSopenharmony_ci lws_smd_msg_distribute(context); 311d4afb5ceSopenharmony_ci if (lws_smd_message_pending(context)) 312d4afb5ceSopenharmony_ci return 0; 313d4afb5ceSopenharmony_ci } 314d4afb5ceSopenharmony_ci#endif 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci pt = &context->pt[tsi]; 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci if (pt->evlib_pt) { 319d4afb5ceSopenharmony_ci lws_usec_t u; 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); /* -------------- pt { */ 322d4afb5ceSopenharmony_ci 323d4afb5ceSopenharmony_ci u = __lws_sul_service_ripe(pt->pt_sul_owner, 324d4afb5ceSopenharmony_ci LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); 325d4afb5ceSopenharmony_ci /* 326d4afb5ceSopenharmony_ci * We will come back with 0 if nothing to do at the moment, or 327d4afb5ceSopenharmony_ci * the number of us until something to do 328d4afb5ceSopenharmony_ci */ 329d4afb5ceSopenharmony_ci if (u && u < (lws_usec_t)timeout_ms * (lws_usec_t)1000) 330d4afb5ceSopenharmony_ci timeout_ms = (int)(u / 1000); 331d4afb5ceSopenharmony_ci 332d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 333d4afb5ceSopenharmony_ci } 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci /* 336d4afb5ceSopenharmony_ci * Figure out if we really want to wait in poll()... we only need to 337d4afb5ceSopenharmony_ci * wait if really nothing already to do and we have to wait for 338d4afb5ceSopenharmony_ci * something from network 339d4afb5ceSopenharmony_ci */ 340d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS) 341d4afb5ceSopenharmony_ci /* 1) if we know we are draining rx ext, do not wait in poll */ 342d4afb5ceSopenharmony_ci if (pt->ws.rx_draining_ext_list) 343d4afb5ceSopenharmony_ci return 0; 344d4afb5ceSopenharmony_ci#endif 345d4afb5ceSopenharmony_ci 346d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 347d4afb5ceSopenharmony_ci /* 2) if we know we have non-network pending data, 348d4afb5ceSopenharmony_ci * do not wait in poll */ 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci if (pt->context->tls_ops && 351d4afb5ceSopenharmony_ci pt->context->tls_ops->fake_POLLIN_for_buffered && 352d4afb5ceSopenharmony_ci pt->context->tls_ops->fake_POLLIN_for_buffered(pt)) 353d4afb5ceSopenharmony_ci return 0; 354d4afb5ceSopenharmony_ci#endif 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci /* 357d4afb5ceSopenharmony_ci * 4) If there is any wsi with rxflow buffered and in a state to process 358d4afb5ceSopenharmony_ci * it, we should not wait in poll 359d4afb5ceSopenharmony_ci */ 360d4afb5ceSopenharmony_ci 361d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, pt->dll_buflist_owner.head) { 362d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, dll_buflist); 363d4afb5ceSopenharmony_ci 364d4afb5ceSopenharmony_ci if (!lws_is_flowcontrolled(wsi) && 365d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_DEFERRING_ACTION) 366d4afb5ceSopenharmony_ci return 0; 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ci /* 369d4afb5ceSopenharmony_ci * 5) If any guys with http compression to spill, we shouldn't wait in 370d4afb5ceSopenharmony_ci * poll but hurry along and service them 371d4afb5ceSopenharmony_ci */ 372d4afb5ceSopenharmony_ci 373d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci return timeout_ms; 376d4afb5ceSopenharmony_ci} 377d4afb5ceSopenharmony_ci 378d4afb5ceSopenharmony_ci/* 379d4afb5ceSopenharmony_ci * POLLIN said there is something... we must read it, and either use it; or 380d4afb5ceSopenharmony_ci * if other material already in the buflist append it and return the buflist 381d4afb5ceSopenharmony_ci * head material. 382d4afb5ceSopenharmony_ci */ 383d4afb5ceSopenharmony_ciint 384d4afb5ceSopenharmony_cilws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi, 385d4afb5ceSopenharmony_ci struct lws_tokens *ebuf, char fr, const char *hint) 386d4afb5ceSopenharmony_ci{ 387d4afb5ceSopenharmony_ci int n, e, bns; 388d4afb5ceSopenharmony_ci uint8_t *ep, *b; 389d4afb5ceSopenharmony_ci 390d4afb5ceSopenharmony_ci // lwsl_debug("%s: %s: %s: prior %d\n", __func__, lws_wsi_tag(wsi), hint, prior); 391d4afb5ceSopenharmony_ci // lws_buflist_describe(&wsi->buflist, wsi, __func__); 392d4afb5ceSopenharmony_ci 393d4afb5ceSopenharmony_ci (void)hint; 394d4afb5ceSopenharmony_ci if (!ebuf->token) 395d4afb5ceSopenharmony_ci ebuf->token = pt->serv_buf + LWS_PRE; 396d4afb5ceSopenharmony_ci if (!ebuf->len || 397d4afb5ceSopenharmony_ci (unsigned int)ebuf->len > wsi->a.context->pt_serv_buf_size - LWS_PRE) 398d4afb5ceSopenharmony_ci ebuf->len = (int)(wsi->a.context->pt_serv_buf_size - LWS_PRE); 399d4afb5ceSopenharmony_ci 400d4afb5ceSopenharmony_ci e = ebuf->len; 401d4afb5ceSopenharmony_ci ep = ebuf->token; 402d4afb5ceSopenharmony_ci 403d4afb5ceSopenharmony_ci /* h2 or muxed stream... must force the read due to HOL blocking */ 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ci if (wsi->mux_substream) 406d4afb5ceSopenharmony_ci fr = 1; 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci /* there's something on the buflist? */ 409d4afb5ceSopenharmony_ci 410d4afb5ceSopenharmony_ci bns = (int)lws_buflist_next_segment_len(&wsi->buflist, &ebuf->token); 411d4afb5ceSopenharmony_ci b = ebuf->token; 412d4afb5ceSopenharmony_ci 413d4afb5ceSopenharmony_ci if (!fr && bns) 414d4afb5ceSopenharmony_ci goto buflist_material; 415d4afb5ceSopenharmony_ci 416d4afb5ceSopenharmony_ci /* we're going to read something */ 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci ebuf->token = ep; 419d4afb5ceSopenharmony_ci ebuf->len = n = lws_ssl_capable_read(wsi, ep, (size_t)e); 420d4afb5ceSopenharmony_ci 421d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "%s: ssl_capable_read %d", hint, ebuf->len); 422d4afb5ceSopenharmony_ci 423d4afb5ceSopenharmony_ci if (!bns && /* only acknowledge error when we handled buflist content */ 424d4afb5ceSopenharmony_ci n == LWS_SSL_CAPABLE_ERROR) { 425d4afb5ceSopenharmony_ci lwsl_debug("%s: SSL_CAPABLE_ERROR\n", __func__); 426d4afb5ceSopenharmony_ci return -1; 427d4afb5ceSopenharmony_ci } 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci if (n <= 0 && bns) 430d4afb5ceSopenharmony_ci /* 431d4afb5ceSopenharmony_ci * There wasn't anything to read yet, but there's something 432d4afb5ceSopenharmony_ci * on the buflist to give him 433d4afb5ceSopenharmony_ci */ 434d4afb5ceSopenharmony_ci goto buflist_material; 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci /* we read something */ 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci if (fr && bns) { 439d4afb5ceSopenharmony_ci /* 440d4afb5ceSopenharmony_ci * Stash what we read, since there's earlier buflist material 441d4afb5ceSopenharmony_ci */ 442d4afb5ceSopenharmony_ci 443d4afb5ceSopenharmony_ci n = lws_buflist_append_segment(&wsi->buflist, ebuf->token, (size_t)ebuf->len); 444d4afb5ceSopenharmony_ci if (n < 0) 445d4afb5ceSopenharmony_ci return -1; 446d4afb5ceSopenharmony_ci if (n && lws_dll2_is_detached(&wsi->dll_buflist)) 447d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->dll_buflist, 448d4afb5ceSopenharmony_ci &pt->dll_buflist_owner); 449d4afb5ceSopenharmony_ci 450d4afb5ceSopenharmony_ci goto buflist_material; 451d4afb5ceSopenharmony_ci } 452d4afb5ceSopenharmony_ci 453d4afb5ceSopenharmony_ci /* 454d4afb5ceSopenharmony_ci * directly return what we read 455d4afb5ceSopenharmony_ci */ 456d4afb5ceSopenharmony_ci 457d4afb5ceSopenharmony_ci return 0; 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_cibuflist_material: 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ci ebuf->token = b; 462d4afb5ceSopenharmony_ci if (e < bns) 463d4afb5ceSopenharmony_ci /* restrict to e, if more than e available */ 464d4afb5ceSopenharmony_ci ebuf->len = e; 465d4afb5ceSopenharmony_ci else 466d4afb5ceSopenharmony_ci ebuf->len = bns; 467d4afb5ceSopenharmony_ci 468d4afb5ceSopenharmony_ci return 1; /* from buflist */ 469d4afb5ceSopenharmony_ci} 470d4afb5ceSopenharmony_ci 471d4afb5ceSopenharmony_ciint 472d4afb5ceSopenharmony_cilws_buflist_aware_finished_consuming(struct lws *wsi, struct lws_tokens *ebuf, 473d4afb5ceSopenharmony_ci int used, int buffered, const char *hint) 474d4afb5ceSopenharmony_ci{ 475d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 476d4afb5ceSopenharmony_ci int m; 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci /* it's in the buflist; we didn't use any */ 479d4afb5ceSopenharmony_ci 480d4afb5ceSopenharmony_ci if (!used && buffered) 481d4afb5ceSopenharmony_ci return 0; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci if (used && buffered) { 484d4afb5ceSopenharmony_ci if (wsi->buflist) { 485d4afb5ceSopenharmony_ci m = (int)lws_buflist_use_segment(&wsi->buflist, 486d4afb5ceSopenharmony_ci (size_t)used); 487d4afb5ceSopenharmony_ci if (m) 488d4afb5ceSopenharmony_ci return 0; 489d4afb5ceSopenharmony_ci } 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "removed from dll_buflist"); 492d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->dll_buflist); 493d4afb5ceSopenharmony_ci 494d4afb5ceSopenharmony_ci return 0; 495d4afb5ceSopenharmony_ci } 496d4afb5ceSopenharmony_ci 497d4afb5ceSopenharmony_ci /* any remainder goes on the buflist */ 498d4afb5ceSopenharmony_ci 499d4afb5ceSopenharmony_ci if (used < ebuf->len && ebuf->len >= 0 && used >= 0) { 500d4afb5ceSopenharmony_ci m = lws_buflist_append_segment(&wsi->buflist, 501d4afb5ceSopenharmony_ci ebuf->token + used, 502d4afb5ceSopenharmony_ci (unsigned int)(ebuf->len - used)); 503d4afb5ceSopenharmony_ci if (m < 0) 504d4afb5ceSopenharmony_ci return 1; /* OOM */ 505d4afb5ceSopenharmony_ci if (m) { 506d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "added to rxflow list"); 507d4afb5ceSopenharmony_ci if (lws_dll2_is_detached(&wsi->dll_buflist)) 508d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->dll_buflist, 509d4afb5ceSopenharmony_ci &pt->dll_buflist_owner); 510d4afb5ceSopenharmony_ci } 511d4afb5ceSopenharmony_ci } 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci return 0; 514d4afb5ceSopenharmony_ci} 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_civoid 517d4afb5ceSopenharmony_cilws_service_do_ripe_rxflow(struct lws_context_per_thread *pt) 518d4afb5ceSopenharmony_ci{ 519d4afb5ceSopenharmony_ci struct lws_pollfd pfd; 520d4afb5ceSopenharmony_ci 521d4afb5ceSopenharmony_ci if (!pt->dll_buflist_owner.head) 522d4afb5ceSopenharmony_ci return; 523d4afb5ceSopenharmony_ci 524d4afb5ceSopenharmony_ci /* 525d4afb5ceSopenharmony_ci * service all guys with pending rxflow that reached a state they can 526d4afb5ceSopenharmony_ci * accept the pending data 527d4afb5ceSopenharmony_ci */ 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 530d4afb5ceSopenharmony_ci 531d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, 532d4afb5ceSopenharmony_ci pt->dll_buflist_owner.head) { 533d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, dll_buflist); 534d4afb5ceSopenharmony_ci 535d4afb5ceSopenharmony_ci pfd.events = LWS_POLLIN; 536d4afb5ceSopenharmony_ci pfd.revents = LWS_POLLIN; 537d4afb5ceSopenharmony_ci pfd.fd = -1; 538d4afb5ceSopenharmony_ci 539d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "rxflow processing: fc=%d, 0x%lx", 540d4afb5ceSopenharmony_ci lws_is_flowcontrolled(wsi), 541d4afb5ceSopenharmony_ci (unsigned long)wsi->wsistate); 542d4afb5ceSopenharmony_ci 543d4afb5ceSopenharmony_ci if (!lws_is_flowcontrolled(wsi) && 544d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_DEFERRING_ACTION) { 545d4afb5ceSopenharmony_ci pt->inside_lws_service = 1; 546d4afb5ceSopenharmony_ci 547d4afb5ceSopenharmony_ci if (lws_rops_func_fidx(wsi->role_ops, 548d4afb5ceSopenharmony_ci LWS_ROPS_handle_POLLIN). 549d4afb5ceSopenharmony_ci handle_POLLIN(pt, wsi, &pfd) == 550d4afb5ceSopenharmony_ci LWS_HPI_RET_PLEASE_CLOSE_ME) 551d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 552d4afb5ceSopenharmony_ci "close_and_handled"); 553d4afb5ceSopenharmony_ci pt->inside_lws_service = 0; 554d4afb5ceSopenharmony_ci } 555d4afb5ceSopenharmony_ci 556d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(d, d1); 557d4afb5ceSopenharmony_ci 558d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 559d4afb5ceSopenharmony_ci} 560d4afb5ceSopenharmony_ci 561d4afb5ceSopenharmony_ci/* 562d4afb5ceSopenharmony_ci * guys that need POLLIN service again without waiting for network action 563d4afb5ceSopenharmony_ci * can force POLLIN here if not flowcontrolled, so they will get service. 564d4afb5ceSopenharmony_ci * 565d4afb5ceSopenharmony_ci * Return nonzero if anybody got their POLLIN faked 566d4afb5ceSopenharmony_ci */ 567d4afb5ceSopenharmony_ciint 568d4afb5ceSopenharmony_cilws_service_flag_pending(struct lws_context *context, int tsi) 569d4afb5ceSopenharmony_ci{ 570d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 571d4afb5ceSopenharmony_ci int forced = 0; 572d4afb5ceSopenharmony_ci 573d4afb5ceSopenharmony_ci if (!context) 574d4afb5ceSopenharmony_ci return 1; 575d4afb5ceSopenharmony_ci 576d4afb5ceSopenharmony_ci pt = &context->pt[tsi]; 577d4afb5ceSopenharmony_ci 578d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 579d4afb5ceSopenharmony_ci 580d4afb5ceSopenharmony_ci /* 581d4afb5ceSopenharmony_ci * 1) If there is any wsi with a buflist and in a state to process 582d4afb5ceSopenharmony_ci * it, we should not wait in poll 583d4afb5ceSopenharmony_ci */ 584d4afb5ceSopenharmony_ci 585d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, pt->dll_buflist_owner.head) { 586d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, dll_buflist); 587d4afb5ceSopenharmony_ci 588d4afb5ceSopenharmony_ci if (!lws_is_flowcontrolled(wsi) && 589d4afb5ceSopenharmony_ci lwsi_state(wsi) != LRS_DEFERRING_ACTION) { 590d4afb5ceSopenharmony_ci forced = 1; 591d4afb5ceSopenharmony_ci break; 592d4afb5ceSopenharmony_ci } 593d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 594d4afb5ceSopenharmony_ci 595d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 596d4afb5ceSopenharmony_ci forced |= lws_rops_func_fidx(&role_ops_ws, 597d4afb5ceSopenharmony_ci LWS_ROPS_service_flag_pending). 598d4afb5ceSopenharmony_ci service_flag_pending(context, tsi); 599d4afb5ceSopenharmony_ci#endif 600d4afb5ceSopenharmony_ci 601d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 602d4afb5ceSopenharmony_ci /* 603d4afb5ceSopenharmony_ci * 2) For all guys with buffered SSL read data already saved up, if they 604d4afb5ceSopenharmony_ci * are not flowcontrolled, fake their POLLIN status so they'll get 605d4afb5ceSopenharmony_ci * service to use up the buffered incoming data, even though their 606d4afb5ceSopenharmony_ci * network socket may have nothing 607d4afb5ceSopenharmony_ci */ 608d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, 609d4afb5ceSopenharmony_ci lws_dll2_get_head(&pt->tls.dll_pending_tls_owner)) { 610d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(p, struct lws, 611d4afb5ceSopenharmony_ci tls.dll_pending_tls); 612d4afb5ceSopenharmony_ci 613d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table >= 0) { 614d4afb5ceSopenharmony_ci 615d4afb5ceSopenharmony_ci pt->fds[wsi->position_in_fds_table].revents = (short)( 616d4afb5ceSopenharmony_ci pt->fds[wsi->position_in_fds_table].revents | 617d4afb5ceSopenharmony_ci (pt->fds[wsi->position_in_fds_table].events & 618d4afb5ceSopenharmony_ci LWS_POLLIN)); 619d4afb5ceSopenharmony_ci if (pt->fds[wsi->position_in_fds_table].revents & 620d4afb5ceSopenharmony_ci LWS_POLLIN) 621d4afb5ceSopenharmony_ci /* 622d4afb5ceSopenharmony_ci * We're not going to remove the wsi from the 623d4afb5ceSopenharmony_ci * pending tls list. The processing will have 624d4afb5ceSopenharmony_ci * to do it if he exhausts the pending tls. 625d4afb5ceSopenharmony_ci */ 626d4afb5ceSopenharmony_ci forced = 1; 627d4afb5ceSopenharmony_ci } 628d4afb5ceSopenharmony_ci 629d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(p, p1); 630d4afb5ceSopenharmony_ci#endif 631d4afb5ceSopenharmony_ci 632d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 633d4afb5ceSopenharmony_ci 634d4afb5ceSopenharmony_ci return forced; 635d4afb5ceSopenharmony_ci} 636d4afb5ceSopenharmony_ci 637d4afb5ceSopenharmony_ciint 638d4afb5ceSopenharmony_cilws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, 639d4afb5ceSopenharmony_ci int tsi) 640d4afb5ceSopenharmony_ci{ 641d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 642d4afb5ceSopenharmony_ci struct lws *wsi; 643d4afb5ceSopenharmony_ci char cow = 0; 644d4afb5ceSopenharmony_ci 645d4afb5ceSopenharmony_ci if (!context || context->service_no_longer_possible) 646d4afb5ceSopenharmony_ci return -1; 647d4afb5ceSopenharmony_ci 648d4afb5ceSopenharmony_ci pt = &context->pt[tsi]; 649d4afb5ceSopenharmony_ci 650d4afb5ceSopenharmony_ci if (pt->event_loop_pt_unused) 651d4afb5ceSopenharmony_ci return -1; 652d4afb5ceSopenharmony_ci 653d4afb5ceSopenharmony_ci if (!pollfd) { 654d4afb5ceSopenharmony_ci /* 655d4afb5ceSopenharmony_ci * calling with NULL pollfd for periodic background processing 656d4afb5ceSopenharmony_ci * is no longer needed and is now illegal. 657d4afb5ceSopenharmony_ci */ 658d4afb5ceSopenharmony_ci assert(pollfd); 659d4afb5ceSopenharmony_ci return -1; 660d4afb5ceSopenharmony_ci } 661d4afb5ceSopenharmony_ci assert(lws_socket_is_valid(pollfd->fd)); 662d4afb5ceSopenharmony_ci 663d4afb5ceSopenharmony_ci /* no, here to service a socket descriptor */ 664d4afb5ceSopenharmony_ci wsi = wsi_from_fd(context, pollfd->fd); 665d4afb5ceSopenharmony_ci if (!wsi) 666d4afb5ceSopenharmony_ci /* not lws connection ... leave revents alone and return */ 667d4afb5ceSopenharmony_ci return 0; 668d4afb5ceSopenharmony_ci 669d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 670d4afb5ceSopenharmony_ci if (wsi->undergoing_init_from_other_pt) 671d4afb5ceSopenharmony_ci /* 672d4afb5ceSopenharmony_ci * Temporary situation that other service thread is initializing 673d4afb5ceSopenharmony_ci * this wsi right now for use on our service thread. 674d4afb5ceSopenharmony_ci */ 675d4afb5ceSopenharmony_ci return 0; 676d4afb5ceSopenharmony_ci#endif 677d4afb5ceSopenharmony_ci 678d4afb5ceSopenharmony_ci /* 679d4afb5ceSopenharmony_ci * so that caller can tell we handled, past here we need to 680d4afb5ceSopenharmony_ci * zero down pollfd->revents after handling 681d4afb5ceSopenharmony_ci */ 682d4afb5ceSopenharmony_ci 683d4afb5ceSopenharmony_ci /* 684d4afb5ceSopenharmony_ci * Whatever the situation with buffered rx packets, or explicitly read- 685d4afb5ceSopenharmony_ci * and-buffered rx going to be handled before we want to acknowledge the 686d4afb5ceSopenharmony_ci * socket is gone, any sign of HUP always immediately means no more tx 687d4afb5ceSopenharmony_ci * is possible. 688d4afb5ceSopenharmony_ci */ 689d4afb5ceSopenharmony_ci 690d4afb5ceSopenharmony_ci if ((pollfd->revents & LWS_POLLHUP) == LWS_POLLHUP) { 691d4afb5ceSopenharmony_ci wsi->socket_is_permanently_unusable = 1; 692d4afb5ceSopenharmony_ci 693d4afb5ceSopenharmony_ci if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) { 694d4afb5ceSopenharmony_ci 695d4afb5ceSopenharmony_ci /* ... there are no pending rx packets waiting... */ 696d4afb5ceSopenharmony_ci 697d4afb5ceSopenharmony_ci if (!lws_buflist_total_len(&wsi->buflist)) { 698d4afb5ceSopenharmony_ci 699d4afb5ceSopenharmony_ci /* 700d4afb5ceSopenharmony_ci * ... nothing stashed in the buflist either, 701d4afb5ceSopenharmony_ci * so acknowledge the wsi is done 702d4afb5ceSopenharmony_ci */ 703d4afb5ceSopenharmony_ci 704d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "Session Socket %d dead", 705d4afb5ceSopenharmony_ci pollfd->fd); 706d4afb5ceSopenharmony_ci 707d4afb5ceSopenharmony_ci goto close_and_handled; 708d4afb5ceSopenharmony_ci } 709d4afb5ceSopenharmony_ci 710d4afb5ceSopenharmony_ci /* 711d4afb5ceSopenharmony_ci * ... in fact we have some unread rx buffered in the 712d4afb5ceSopenharmony_ci * input buflist. Hold off the closing a bit... 713d4afb5ceSopenharmony_ci */ 714d4afb5ceSopenharmony_ci 715d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 3); 716d4afb5ceSopenharmony_ci } 717d4afb5ceSopenharmony_ci } 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci#ifdef _WIN32 720d4afb5ceSopenharmony_ci if (pollfd->revents & LWS_POLLOUT) 721d4afb5ceSopenharmony_ci wsi->sock_send_blocking = FALSE; 722d4afb5ceSopenharmony_ci#endif 723d4afb5ceSopenharmony_ci 724d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 725d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_SHUTDOWN && 726d4afb5ceSopenharmony_ci lws_is_ssl(wsi) && wsi->tls.ssl) { 727d4afb5ceSopenharmony_ci switch (__lws_tls_shutdown(wsi)) { 728d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_DONE: 729d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_ERROR: 730d4afb5ceSopenharmony_ci goto close_and_handled; 731d4afb5ceSopenharmony_ci 732d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE_READ: 733d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE: 734d4afb5ceSopenharmony_ci case LWS_SSL_CAPABLE_MORE_SERVICE: 735d4afb5ceSopenharmony_ci goto handled; 736d4afb5ceSopenharmony_ci } 737d4afb5ceSopenharmony_ci } 738d4afb5ceSopenharmony_ci#endif 739d4afb5ceSopenharmony_ci 740d4afb5ceSopenharmony_ci if ((pollfd->revents & LWS_POLLOUT) == LWS_POLLOUT && 741d4afb5ceSopenharmony_ci wsi->tls_read_wanted_write) { 742d4afb5ceSopenharmony_ci /* 743d4afb5ceSopenharmony_ci * If this wsi has a pending WANT_WRITE from SSL_read(), it has 744d4afb5ceSopenharmony_ci * asked for a callback on writeable so it can retry the read. 745d4afb5ceSopenharmony_ci * 746d4afb5ceSopenharmony_ci * Let's consume the POLLOUT by turning it into a POLLIIN, and 747d4afb5ceSopenharmony_ci * setting a flag to request a new writeable 748d4afb5ceSopenharmony_ci */ 749d4afb5ceSopenharmony_ci wsi->tls_read_wanted_write = 0; 750d4afb5ceSopenharmony_ci pollfd->revents &= ~(LWS_POLLOUT); 751d4afb5ceSopenharmony_ci pollfd->revents |= LWS_POLLIN; 752d4afb5ceSopenharmony_ci cow = 1; 753d4afb5ceSopenharmony_ci } 754d4afb5ceSopenharmony_ci 755d4afb5ceSopenharmony_ci wsi->could_have_pending = 0; /* clear back-to-back write detection */ 756d4afb5ceSopenharmony_ci pt->inside_lws_service = 1; 757d4afb5ceSopenharmony_ci 758d4afb5ceSopenharmony_ci /* okay, what we came here to do... */ 759d4afb5ceSopenharmony_ci 760d4afb5ceSopenharmony_ci /* if we got here, we should have wire protocol ops set on the wsi */ 761d4afb5ceSopenharmony_ci assert(wsi->role_ops); 762d4afb5ceSopenharmony_ci 763d4afb5ceSopenharmony_ci // lwsl_notice("%s: %s: wsistate 0x%x\n", __func__, wsi->role_ops->name, 764d4afb5ceSopenharmony_ci // wsi->wsistate); 765d4afb5ceSopenharmony_ci 766d4afb5ceSopenharmony_ci switch (lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_handle_POLLIN). 767d4afb5ceSopenharmony_ci handle_POLLIN(pt, wsi, pollfd)) { 768d4afb5ceSopenharmony_ci case LWS_HPI_RET_WSI_ALREADY_DIED: 769d4afb5ceSopenharmony_ci pt->inside_lws_service = 0; 770d4afb5ceSopenharmony_ci return 1; 771d4afb5ceSopenharmony_ci case LWS_HPI_RET_HANDLED: 772d4afb5ceSopenharmony_ci break; 773d4afb5ceSopenharmony_ci case LWS_HPI_RET_PLEASE_CLOSE_ME: 774d4afb5ceSopenharmony_ci //lwsl_notice("%s: %s pollin says please close me\n", __func__, 775d4afb5ceSopenharmony_ci // wsi->role_ops->name); 776d4afb5ceSopenharmony_ciclose_and_handled: 777d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "Close and handled"); 778d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 779d4afb5ceSopenharmony_ci "close_and_handled"); 780d4afb5ceSopenharmony_ci#if defined(_DEBUG) && defined(LWS_WITH_LIBUV) 781d4afb5ceSopenharmony_ci /* 782d4afb5ceSopenharmony_ci * confirm close has no problem being called again while 783d4afb5ceSopenharmony_ci * it waits for libuv service to complete the first async 784d4afb5ceSopenharmony_ci * close 785d4afb5ceSopenharmony_ci */ 786d4afb5ceSopenharmony_ci if (!strcmp(context->event_loop_ops->name, "libuv")) 787d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 788d4afb5ceSopenharmony_ci "close_and_handled uv repeat test"); 789d4afb5ceSopenharmony_ci#endif 790d4afb5ceSopenharmony_ci /* 791d4afb5ceSopenharmony_ci * pollfd may point to something else after the close 792d4afb5ceSopenharmony_ci * due to pollfd swapping scheme on delete on some platforms 793d4afb5ceSopenharmony_ci * we can't clear revents now because it'd be the wrong guy's 794d4afb5ceSopenharmony_ci * revents 795d4afb5ceSopenharmony_ci */ 796d4afb5ceSopenharmony_ci pt->inside_lws_service = 0; 797d4afb5ceSopenharmony_ci return 1; 798d4afb5ceSopenharmony_ci default: 799d4afb5ceSopenharmony_ci assert(0); 800d4afb5ceSopenharmony_ci } 801d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 802d4afb5ceSopenharmony_cihandled: 803d4afb5ceSopenharmony_ci#endif 804d4afb5ceSopenharmony_ci pollfd->revents = 0; 805d4afb5ceSopenharmony_ci if (cow) 806d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 807d4afb5ceSopenharmony_ci pt->inside_lws_service = 0; 808d4afb5ceSopenharmony_ci 809d4afb5ceSopenharmony_ci return 0; 810d4afb5ceSopenharmony_ci} 811d4afb5ceSopenharmony_ci 812d4afb5ceSopenharmony_ciint 813d4afb5ceSopenharmony_cilws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd) 814d4afb5ceSopenharmony_ci{ 815d4afb5ceSopenharmony_ci return lws_service_fd_tsi(context, pollfd, 0); 816d4afb5ceSopenharmony_ci} 817d4afb5ceSopenharmony_ci 818d4afb5ceSopenharmony_ciint 819d4afb5ceSopenharmony_cilws_service(struct lws_context *context, int timeout_ms) 820d4afb5ceSopenharmony_ci{ 821d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 822d4afb5ceSopenharmony_ci int n; 823d4afb5ceSopenharmony_ci 824d4afb5ceSopenharmony_ci if (!context) 825d4afb5ceSopenharmony_ci return 1; 826d4afb5ceSopenharmony_ci 827d4afb5ceSopenharmony_ci pt = &context->pt[0]; 828d4afb5ceSopenharmony_ci pt->inside_service = 1; 829d4afb5ceSopenharmony_ci 830d4afb5ceSopenharmony_ci if (context->event_loop_ops->run_pt) { 831d4afb5ceSopenharmony_ci /* we are configured for an event loop */ 832d4afb5ceSopenharmony_ci context->event_loop_ops->run_pt(context, 0); 833d4afb5ceSopenharmony_ci 834d4afb5ceSopenharmony_ci pt->inside_service = 0; 835d4afb5ceSopenharmony_ci 836d4afb5ceSopenharmony_ci return 1; 837d4afb5ceSopenharmony_ci } 838d4afb5ceSopenharmony_ci n = lws_plat_service(context, timeout_ms); 839d4afb5ceSopenharmony_ci 840d4afb5ceSopenharmony_ci if (n != -1) 841d4afb5ceSopenharmony_ci pt->inside_service = 0; 842d4afb5ceSopenharmony_ci 843d4afb5ceSopenharmony_ci return n; 844d4afb5ceSopenharmony_ci} 845d4afb5ceSopenharmony_ci 846d4afb5ceSopenharmony_ciint 847d4afb5ceSopenharmony_cilws_service_tsi(struct lws_context *context, int timeout_ms, int tsi) 848d4afb5ceSopenharmony_ci{ 849d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 850d4afb5ceSopenharmony_ci int n; 851d4afb5ceSopenharmony_ci 852d4afb5ceSopenharmony_ci if (!context) 853d4afb5ceSopenharmony_ci return 1; 854d4afb5ceSopenharmony_ci 855d4afb5ceSopenharmony_ci pt = &context->pt[tsi]; 856d4afb5ceSopenharmony_ci pt->inside_service = 1; 857d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 858d4afb5ceSopenharmony_ci pt->self = pthread_self(); 859d4afb5ceSopenharmony_ci#endif 860d4afb5ceSopenharmony_ci 861d4afb5ceSopenharmony_ci if (context->event_loop_ops->run_pt) { 862d4afb5ceSopenharmony_ci /* we are configured for an event loop */ 863d4afb5ceSopenharmony_ci context->event_loop_ops->run_pt(context, tsi); 864d4afb5ceSopenharmony_ci 865d4afb5ceSopenharmony_ci pt->inside_service = 0; 866d4afb5ceSopenharmony_ci 867d4afb5ceSopenharmony_ci return 1; 868d4afb5ceSopenharmony_ci } 869d4afb5ceSopenharmony_ci 870d4afb5ceSopenharmony_ci n = _lws_plat_service_tsi(context, timeout_ms, tsi); 871d4afb5ceSopenharmony_ci 872d4afb5ceSopenharmony_ci pt->inside_service = 0; 873d4afb5ceSopenharmony_ci 874d4afb5ceSopenharmony_ci return n; 875d4afb5ceSopenharmony_ci} 876