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