/src/libwebsockets/lib/plat/unix/unix-fds.c
Line | Count | Source |
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 * |
31 | | wsi_from_fd(const struct lws_context *context, int fd) |
32 | 0 | { |
33 | 0 | struct lws **p, **done; |
34 | |
|
35 | 0 | if (!context->max_fds_unrelated_to_ulimit) |
36 | 0 | return context->lws_lookup[fd - lws_plat_socket_offset()]; |
37 | | |
38 | | /* slow fds handling */ |
39 | | |
40 | 0 | p = context->lws_lookup; |
41 | 0 | done = &p[context->max_fds]; |
42 | |
|
43 | 0 | while (p != done) { |
44 | 0 | if (*p) { |
45 | 0 | if ((*p)->desc.sockfd == fd) |
46 | 0 | return *p; |
47 | 0 | #if defined(LWS_WITH_CLIENT) |
48 | 0 | for (int j = 0; j < (*p)->parallel_count; j++) { |
49 | 0 | if ((*p)->parallel_conns[j].is_valid && (*p)->parallel_conns[j].desc.sockfd == fd) |
50 | 0 | return *p; |
51 | 0 | } |
52 | 0 | #endif |
53 | 0 | } |
54 | 0 | p++; |
55 | 0 | } |
56 | | |
57 | 0 | return NULL; |
58 | 0 | } |
59 | | |
60 | | #if defined(_DEBUG) |
61 | | int |
62 | | sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi) |
63 | 0 | { |
64 | 0 | struct lws **p, **done; |
65 | 0 | int occurrences = 0; |
66 | 0 | int expected = 0; |
67 | |
|
68 | 0 | #if defined(LWS_WITH_CLIENT) |
69 | 0 | if (lws_socket_is_valid(wsi->desc.sockfd)) |
70 | 0 | expected++; |
71 | 0 | for (int i = 0; i < wsi->parallel_count; i++) |
72 | 0 | if (wsi->parallel_conns[i].is_valid) |
73 | 0 | expected++; |
74 | 0 | #endif |
75 | |
|
76 | 0 | if (!context->max_fds_unrelated_to_ulimit) |
77 | | /* can't tell */ |
78 | 0 | return 0; |
79 | | |
80 | | /* slow fds handling */ |
81 | | |
82 | 0 | p = context->lws_lookup; |
83 | 0 | done = &p[context->max_fds]; |
84 | | |
85 | | /* count occurrences of wsi in lookup table */ |
86 | |
|
87 | 0 | while (p != done) { |
88 | 0 | if (*p == wsi) |
89 | 0 | occurrences++; |
90 | 0 | p++; |
91 | 0 | } |
92 | |
|
93 | 0 | if (occurrences <= expected) |
94 | 0 | return 0; |
95 | | |
96 | 0 | assert(0); /* this wsi is still mentioned inside lws too many times */ |
97 | |
|
98 | 0 | return 1; |
99 | 0 | } |
100 | | |
101 | | int |
102 | | sanity_assert_no_sockfd_traces(const struct lws_context *context, |
103 | | lws_sockfd_type sfd) |
104 | 0 | { |
105 | | #if LWS_MAX_SMP > 1 |
106 | | /* |
107 | | * We can't really do this test... another thread can accept and |
108 | | * reuse the closed fd |
109 | | */ |
110 | | return 0; |
111 | | #else |
112 | 0 | struct lws **p, **done; |
113 | |
|
114 | 0 | if (sfd == LWS_SOCK_INVALID || !context->lws_lookup) |
115 | 0 | return 0; |
116 | | |
117 | 0 | if (!context->max_fds_unrelated_to_ulimit && |
118 | 0 | context->lws_lookup[sfd - lws_plat_socket_offset()]) { |
119 | 0 | assert(0); /* the fd is still in use */ |
120 | 0 | return 1; |
121 | 0 | } |
122 | | |
123 | | /* slow fds handling */ |
124 | | |
125 | 0 | p = context->lws_lookup; |
126 | 0 | done = &p[context->max_fds]; |
127 | | |
128 | | /* confirm the sfd not already in use */ |
129 | |
|
130 | 0 | while (p != done) { |
131 | 0 | if (*p && (*p)->desc.sockfd == sfd) { |
132 | 0 | #if defined(LWS_WITH_CLIENT) |
133 | 0 | if ((*p)->parallel_count > 0) { |
134 | 0 | p++; |
135 | 0 | continue; |
136 | 0 | } |
137 | 0 | #endif |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | p++; |
141 | 0 | } |
142 | |
|
143 | 0 | if (p == done) |
144 | 0 | return 0; |
145 | | |
146 | 0 | assert(0); /* this fd is still in the tables */ |
147 | |
|
148 | 0 | return 1; |
149 | 0 | #endif |
150 | 0 | } |
151 | | #endif |
152 | | |
153 | | |
154 | | int |
155 | | insert_wsi(const struct lws_context *context, struct lws *wsi) |
156 | 0 | { |
157 | 0 | struct lws **p, **done; |
158 | |
|
159 | 0 | if (sanity_assert_no_wsi_traces(context, wsi)) |
160 | 0 | return 0; |
161 | | |
162 | 0 | if (!context->max_fds_unrelated_to_ulimit) { |
163 | 0 | assert(context->lws_lookup[wsi->desc.sockfd - |
164 | 0 | lws_plat_socket_offset()] == 0); |
165 | |
|
166 | 0 | context->lws_lookup[wsi->desc.sockfd - \ |
167 | 0 | lws_plat_socket_offset()] = wsi; |
168 | |
|
169 | 0 | return 0; |
170 | 0 | } |
171 | | |
172 | | /* slow fds handling */ |
173 | | |
174 | 0 | p = context->lws_lookup; |
175 | 0 | done = &p[context->max_fds]; |
176 | | |
177 | | /* confirm fd isn't already in use by a wsi */ |
178 | |
|
179 | 0 | if (sanity_assert_no_sockfd_traces(context, wsi->desc.sockfd)) |
180 | 0 | return 0; |
181 | | |
182 | 0 | p = context->lws_lookup; |
183 | | |
184 | | /* find an empty slot */ |
185 | |
|
186 | 0 | while (p != done && *p) |
187 | 0 | p++; |
188 | |
|
189 | 0 | if (p == done) { |
190 | 0 | lwsl_err("%s: reached max fds\n", __func__); |
191 | 0 | return 1; |
192 | 0 | } |
193 | | |
194 | 0 | *p = wsi; |
195 | |
|
196 | 0 | return 0; |
197 | 0 | } |
198 | | |
199 | | |
200 | | |
201 | | void |
202 | | delete_from_fd(const struct lws_context *context, int fd) |
203 | 0 | { |
204 | |
|
205 | 0 | struct lws **p, **done; |
206 | |
|
207 | 0 | if (!context->max_fds_unrelated_to_ulimit) { |
208 | 0 | if (context->lws_lookup) { |
209 | 0 | assert((int)context->max_fds > fd - lws_plat_socket_offset()); |
210 | 0 | context->lws_lookup[fd - lws_plat_socket_offset()] = NULL; |
211 | 0 | } |
212 | |
|
213 | 0 | return; |
214 | 0 | } |
215 | | |
216 | | /* slow fds handling */ |
217 | | |
218 | 0 | p = context->lws_lookup; |
219 | 0 | assert(p); |
220 | |
|
221 | 0 | done = &p[context->max_fds]; |
222 | | |
223 | | /* find the match */ |
224 | |
|
225 | 0 | while (p != done && (!*p || (*p)->desc.sockfd != fd)) |
226 | 0 | p++; |
227 | |
|
228 | 0 | if (p != done) |
229 | 0 | *p = NULL; |
230 | |
|
231 | 0 | #if defined(_DEBUG) |
232 | 0 | p = context->lws_lookup; |
233 | 0 | while (p != done) { |
234 | 0 | if (*p && (*p)->desc.sockfd == fd) { |
235 | 0 | #if defined(LWS_WITH_CLIENT) |
236 | 0 | if ((*p)->parallel_count > 0) { |
237 | 0 | p++; |
238 | 0 | continue; |
239 | 0 | } |
240 | 0 | #endif |
241 | 0 | break; |
242 | 0 | } |
243 | 0 | p++; |
244 | 0 | } |
245 | |
|
246 | 0 | if (p != done) { |
247 | 0 | lwsl_err("%s: fd %d in lws_lookup again at %d\n", __func__, |
248 | 0 | fd, (int)(p - context->lws_lookup)); |
249 | 0 | assert(0); |
250 | 0 | } |
251 | 0 | #endif |
252 | 0 | } |
253 | | |
254 | | void |
255 | | delete_from_fdwsi(const struct lws_context *context, struct lws *wsi) |
256 | 0 | { |
257 | |
|
258 | 0 | struct lws **p, **done; |
259 | |
|
260 | 0 | if (!context->max_fds_unrelated_to_ulimit) |
261 | 0 | return; |
262 | | |
263 | | |
264 | | /* slow fds handling */ |
265 | | |
266 | 0 | p = context->lws_lookup; |
267 | 0 | done = &p[context->max_fds]; |
268 | | |
269 | | /* find the match */ |
270 | |
|
271 | 0 | while (p != done && (!*p || (*p) != wsi)) |
272 | 0 | p++; |
273 | |
|
274 | 0 | if (p != done) |
275 | 0 | *p = NULL; |
276 | 0 | } |
277 | | |
278 | | void |
279 | | lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) |
280 | 0 | { |
281 | 0 | struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; |
282 | |
|
283 | 0 | if (context->event_loop_ops->io || context->event_loop_ops->io_parallel) |
284 | 0 | _lws_event_loop_ops_io(wsi, LWS_EV_START | LWS_EV_READ); |
285 | |
|
286 | 0 | pt->fds[pt->fds_count++].revents = 0; |
287 | 0 | } |
288 | | |
289 | | void |
290 | | lws_plat_delete_socket_from_fds(struct lws_context *context, |
291 | | struct lws *wsi, int m) |
292 | 0 | { |
293 | 0 | struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; |
294 | |
|
295 | 0 | if (context->event_loop_ops->io || context->event_loop_ops->io_parallel) |
296 | 0 | _lws_event_loop_ops_io(wsi, |
297 | 0 | LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); |
298 | |
|
299 | 0 | pt->fds_count--; |
300 | 0 | } |
301 | | |
302 | | int |
303 | | lws_plat_change_pollfd(struct lws_context *context, |
304 | | struct lws *wsi, struct lws_pollfd *pfd) |
305 | 0 | { |
306 | 0 | return 0; |
307 | 0 | } |