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
30 struct lws *
wsi_from_fd(const struct lws_context * context,int fd)31 wsi_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)
53 int
sanity_assert_no_wsi_traces(const struct lws_context * context,struct lws * wsi)54 sanity_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
80 int
sanity_assert_no_sockfd_traces(const struct lws_context * context,lws_sockfd_type sfd)81 sanity_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
123 int
insert_wsi(const struct lws_context * context,struct lws * wsi)124 insert_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
170 void
delete_from_fd(const struct lws_context * context,int fd)171 delete_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
211 void
delete_from_fdwsi(const struct lws_context * context,struct lws * wsi)212 delete_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
235 void
lws_plat_insert_socket_into_fds(struct lws_context * context,struct lws * wsi)236 lws_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
246 void
lws_plat_delete_socket_from_fds(struct lws_context * context,struct lws * wsi,int m)247 lws_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
259 int
lws_plat_change_pollfd(struct lws_context * context,struct lws * wsi,struct lws_pollfd * pfd)260 lws_plat_change_pollfd(struct lws_context *context,
261 struct lws *wsi, struct lws_pollfd *pfd)
262 {
263 return 0;
264 }
265