1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25#if !defined(_GNU_SOURCE)
26#define _GNU_SOURCE
27#endif
28#include "private-lib-core.h"
29
30struct lws *
31wsi_from_fd(const struct lws_context *context, int fd)
32{
33	struct lws **p, **done;
34
35	if (!context->max_fds_unrelated_to_ulimit)
36		return context->lws_lookup[fd - lws_plat_socket_offset()];
37
38	/* slow fds handling */
39
40	p = context->lws_lookup;
41	done = &p[context->max_fds];
42
43	while (p != done) {
44		if (*p && (*p)->desc.sockfd == fd)
45			return *p;
46		p++;
47	}
48
49	return NULL;
50}
51
52#if defined(_DEBUG)
53int
54sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi)
55{
56	struct lws **p, **done;
57
58	if (!context->max_fds_unrelated_to_ulimit)
59		/* can't tell */
60		return 0;
61
62	/* slow fds handling */
63
64	p = context->lws_lookup;
65	done = &p[context->max_fds];
66
67	/* confirm the wsi doesn't already exist */
68
69	while (p != done && *p != wsi)
70		p++;
71
72	if (p == done)
73		return 0;
74
75	assert(0); /* this wsi is still mentioned inside lws */
76
77	return 1;
78}
79
80int
81sanity_assert_no_sockfd_traces(const struct lws_context *context,
82			       lws_sockfd_type sfd)
83{
84#if LWS_MAX_SMP > 1
85	/*
86	 * We can't really do this test... another thread can accept and
87	 * reuse the closed fd
88	 */
89	return 0;
90#else
91	struct lws **p, **done;
92
93	if (sfd == LWS_SOCK_INVALID || !context->lws_lookup)
94		return 0;
95
96	if (!context->max_fds_unrelated_to_ulimit &&
97	    context->lws_lookup[sfd - lws_plat_socket_offset()]) {
98		assert(0); /* the fd is still in use */
99		return 1;
100	}
101
102	/* slow fds handling */
103
104	p = context->lws_lookup;
105	done = &p[context->max_fds];
106
107	/* confirm the sfd not already in use */
108
109	while (p != done && (!*p || (*p)->desc.sockfd != sfd))
110		p++;
111
112	if (p == done)
113		return 0;
114
115	assert(0); /* this fd is still in the tables */
116
117	return 1;
118#endif
119}
120#endif
121
122
123int
124insert_wsi(const struct lws_context *context, struct lws *wsi)
125{
126	struct lws **p, **done;
127
128	if (sanity_assert_no_wsi_traces(context, wsi))
129		return 0;
130
131	if (!context->max_fds_unrelated_to_ulimit) {
132		assert(context->lws_lookup[wsi->desc.sockfd -
133		                           lws_plat_socket_offset()] == 0);
134
135		context->lws_lookup[wsi->desc.sockfd - \
136				  lws_plat_socket_offset()] = wsi;
137
138		return 0;
139	}
140
141	/* slow fds handling */
142
143	p = context->lws_lookup;
144	done = &p[context->max_fds];
145
146	/* confirm fd isn't already in use by a wsi */
147
148	if (sanity_assert_no_sockfd_traces(context, wsi->desc.sockfd))
149		return 0;
150
151	p = context->lws_lookup;
152
153	/* find an empty slot */
154
155	while (p != done && *p)
156		p++;
157
158	if (p == done) {
159		lwsl_err("%s: reached max fds\n", __func__);
160		return 1;
161	}
162
163	*p = wsi;
164
165	return 0;
166}
167
168
169
170void
171delete_from_fd(const struct lws_context *context, int fd)
172{
173
174	struct lws **p, **done;
175
176	if (!context->max_fds_unrelated_to_ulimit) {
177		if (context->lws_lookup)
178			context->lws_lookup[fd - lws_plat_socket_offset()] = NULL;
179
180		return;
181	}
182
183	/* slow fds handling */
184
185	p = context->lws_lookup;
186	assert(p);
187
188	done = &p[context->max_fds];
189
190	/* find the match */
191
192	while (p != done && (!*p || (*p)->desc.sockfd != fd))
193		p++;
194
195	if (p != done)
196		*p = NULL;
197
198#if defined(_DEBUG)
199	p = context->lws_lookup;
200	while (p != done && (!*p || (*p)->desc.sockfd != fd))
201		p++;
202
203	if (p != done) {
204		lwsl_err("%s: fd %d in lws_lookup again at %d\n", __func__,
205				fd, (int)(p - context->lws_lookup));
206		assert(0);
207	}
208#endif
209}
210
211void
212delete_from_fdwsi(const struct lws_context *context, struct lws *wsi)
213{
214
215	struct lws **p, **done;
216
217	if (!context->max_fds_unrelated_to_ulimit)
218		return;
219
220
221	/* slow fds handling */
222
223	p = context->lws_lookup;
224	done = &p[context->max_fds];
225
226	/* find the match */
227
228	while (p != done && (!*p || (*p) != wsi))
229		p++;
230
231	if (p != done)
232		*p = NULL;
233}
234
235void
236lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
237{
238	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
239
240	if (context->event_loop_ops->io)
241		context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
242
243	pt->fds[pt->fds_count++].revents = 0;
244}
245
246void
247lws_plat_delete_socket_from_fds(struct lws_context *context,
248						struct lws *wsi, int m)
249{
250	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
251
252	if (context->event_loop_ops->io)
253		context->event_loop_ops->io(wsi,
254				LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
255
256	pt->fds_count--;
257}
258
259int
260lws_plat_change_pollfd(struct lws_context *context,
261		      struct lws *wsi, struct lws_pollfd *pfd)
262{
263	return 0;
264}
265