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