/src/httpd/srclib/apr/poll/unix/poll.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include "apr.h" |
18 | | #include "apr_poll.h" |
19 | | #include "apr_time.h" |
20 | | #include "apr_portable.h" |
21 | | #include "apr_arch_file_io.h" |
22 | | #include "apr_arch_networkio.h" |
23 | | #include "apr_arch_misc.h" |
24 | | #include "apr_arch_poll_private.h" |
25 | | |
26 | | #if defined(HAVE_POLL) |
27 | | |
28 | | #ifdef HAVE_ALLOCA_H |
29 | | #include <alloca.h> |
30 | | #endif |
31 | | |
32 | | static apr_int16_t get_event(apr_int16_t event) |
33 | 0 | { |
34 | 0 | apr_int16_t rv = 0; |
35 | |
|
36 | 0 | if (event & APR_POLLIN) |
37 | 0 | rv |= POLLIN; |
38 | 0 | if (event & APR_POLLPRI) |
39 | 0 | rv |= POLLPRI; |
40 | 0 | if (event & APR_POLLOUT) |
41 | 0 | rv |= POLLOUT; |
42 | | /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */ |
43 | |
|
44 | 0 | return rv; |
45 | 0 | } |
46 | | |
47 | | static apr_int16_t get_revent(apr_int16_t event) |
48 | 0 | { |
49 | 0 | apr_int16_t rv = 0; |
50 | |
|
51 | 0 | if (event & POLLIN) |
52 | 0 | rv |= APR_POLLIN; |
53 | 0 | if (event & POLLPRI) |
54 | 0 | rv |= APR_POLLPRI; |
55 | 0 | if (event & POLLOUT) |
56 | 0 | rv |= APR_POLLOUT; |
57 | 0 | if (event & POLLERR) |
58 | 0 | rv |= APR_POLLERR; |
59 | 0 | if (event & POLLHUP) |
60 | 0 | rv |= APR_POLLHUP; |
61 | 0 | if (event & POLLNVAL) |
62 | 0 | rv |= APR_POLLNVAL; |
63 | |
|
64 | 0 | return rv; |
65 | 0 | } |
66 | | |
67 | | #ifdef POLL_USES_POLL |
68 | | |
69 | | #define SMALL_POLLSET_LIMIT 8 |
70 | | |
71 | | APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num, |
72 | | apr_int32_t *nsds, |
73 | | apr_interval_time_t timeout) |
74 | 0 | { |
75 | 0 | int i, num_to_poll; |
76 | 0 | #ifdef HAVE_VLA |
77 | | /* XXX: I trust that this is a segv when insufficient stack exists? */ |
78 | 0 | struct pollfd pollset[num + 1]; /* +1 since allocating 0 is undefined behaviour */ |
79 | | #elif defined(HAVE_ALLOCA) |
80 | | struct pollfd *pollset = alloca(sizeof(struct pollfd) * num); |
81 | | if (!pollset) |
82 | | return APR_ENOMEM; |
83 | | #else |
84 | | struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT]; |
85 | | struct pollfd *pollset; |
86 | | |
87 | | if (num <= SMALL_POLLSET_LIMIT) { |
88 | | pollset = tmp_pollset; |
89 | | } |
90 | | else { |
91 | | /* This does require O(n) to copy the descriptors to the internal |
92 | | * mapping. |
93 | | */ |
94 | | pollset = malloc(sizeof(struct pollfd) * num); |
95 | | /* The other option is adding an apr_pool_abort() fn to invoke |
96 | | * the pool's out of memory handler |
97 | | */ |
98 | | if (!pollset) |
99 | | return APR_ENOMEM; |
100 | | } |
101 | | #endif |
102 | 0 | for (i = 0; i < num; i++) { |
103 | 0 | if (aprset[i].desc_type == APR_POLL_SOCKET) { |
104 | 0 | pollset[i].fd = aprset[i].desc.s->socketdes; |
105 | 0 | } |
106 | 0 | else if (aprset[i].desc_type == APR_POLL_FILE) { |
107 | 0 | pollset[i].fd = aprset[i].desc.f->filedes; |
108 | 0 | } |
109 | 0 | else { |
110 | 0 | break; |
111 | 0 | } |
112 | 0 | pollset[i].events = get_event(aprset[i].reqevents); |
113 | 0 | } |
114 | 0 | num_to_poll = i; |
115 | |
|
116 | 0 | if (timeout > 0) { |
117 | | /* convert microseconds to milliseconds (round up) */ |
118 | 0 | timeout = (timeout + 999) / 1000; |
119 | 0 | } |
120 | |
|
121 | 0 | i = poll(pollset, num_to_poll, timeout); |
122 | 0 | (*nsds) = i; |
123 | |
|
124 | 0 | if (i > 0) { /* poll() sets revents only if an event was signalled; |
125 | | * we don't promise to set rtnevents unless an event |
126 | | * was signalled |
127 | | */ |
128 | 0 | for (i = 0; i < num; i++) { |
129 | 0 | aprset[i].rtnevents = get_revent(pollset[i].revents); |
130 | 0 | } |
131 | 0 | } |
132 | |
|
133 | | #if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA) |
134 | | if (num > SMALL_POLLSET_LIMIT) { |
135 | | free(pollset); |
136 | | } |
137 | | #endif |
138 | |
|
139 | 0 | if ((*nsds) < 0) { |
140 | 0 | return apr_get_netos_error(); |
141 | 0 | } |
142 | 0 | if ((*nsds) == 0) { |
143 | 0 | return APR_TIMEUP; |
144 | 0 | } |
145 | 0 | return APR_SUCCESS; |
146 | 0 | } |
147 | | |
148 | | |
149 | | #endif /* POLL_USES_POLL */ |
150 | | |
151 | | struct apr_pollset_private_t |
152 | | { |
153 | | struct pollfd *pollset; |
154 | | apr_pollfd_t *query_set; |
155 | | apr_pollfd_t *result_set; |
156 | | }; |
157 | | |
158 | | static apr_status_t impl_pollset_create(apr_pollset_t *pollset, |
159 | | apr_uint32_t size, |
160 | | apr_pool_t *p, |
161 | | apr_uint32_t flags) |
162 | 0 | { |
163 | 0 | if (flags & APR_POLLSET_THREADSAFE) { |
164 | 0 | return APR_ENOTIMPL; |
165 | 0 | } |
166 | | |
167 | 0 | pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); |
168 | 0 | pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd)); |
169 | 0 | pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); |
170 | 0 | pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); |
171 | |
|
172 | 0 | return APR_SUCCESS; |
173 | 0 | } |
174 | | |
175 | | static apr_status_t impl_pollset_add(apr_pollset_t *pollset, |
176 | | const apr_pollfd_t *descriptor) |
177 | 0 | { |
178 | 0 | if (pollset->nelts == pollset->nalloc) { |
179 | 0 | return APR_ENOMEM; |
180 | 0 | } |
181 | | |
182 | 0 | pollset->p->query_set[pollset->nelts] = *descriptor; |
183 | |
|
184 | 0 | if (descriptor->desc_type == APR_POLL_SOCKET) { |
185 | 0 | pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes; |
186 | 0 | } |
187 | 0 | else { |
188 | 0 | #if APR_FILES_AS_SOCKETS |
189 | 0 | pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes; |
190 | | #else |
191 | | return APR_EBADF; |
192 | | #endif |
193 | 0 | } |
194 | 0 | pollset->p->pollset[pollset->nelts].events = |
195 | 0 | get_event(descriptor->reqevents); |
196 | 0 | pollset->nelts++; |
197 | |
|
198 | 0 | return APR_SUCCESS; |
199 | 0 | } |
200 | | |
201 | | static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, |
202 | | const apr_pollfd_t *descriptor) |
203 | 0 | { |
204 | 0 | apr_uint32_t i; |
205 | |
|
206 | 0 | for (i = 0; i < pollset->nelts; i++) { |
207 | 0 | if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { |
208 | | /* Found an instance of the fd: remove this and any other copies */ |
209 | 0 | apr_uint32_t dst = i; |
210 | 0 | apr_uint32_t old_nelts = pollset->nelts; |
211 | 0 | pollset->nelts--; |
212 | 0 | for (i++; i < old_nelts; i++) { |
213 | 0 | if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { |
214 | 0 | pollset->nelts--; |
215 | 0 | } |
216 | 0 | else { |
217 | 0 | pollset->p->pollset[dst] = pollset->p->pollset[i]; |
218 | 0 | pollset->p->query_set[dst] = pollset->p->query_set[i]; |
219 | 0 | dst++; |
220 | 0 | } |
221 | 0 | } |
222 | 0 | return APR_SUCCESS; |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | 0 | return APR_NOTFOUND; |
227 | 0 | } |
228 | | |
229 | | static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, |
230 | | apr_interval_time_t timeout, |
231 | | apr_int32_t *num, |
232 | | const apr_pollfd_t **descriptors) |
233 | 0 | { |
234 | 0 | int ret; |
235 | 0 | apr_status_t rv = APR_SUCCESS; |
236 | |
|
237 | 0 | *num = 0; |
238 | |
|
239 | | #ifdef WIN32 |
240 | | /* WSAPoll() requires at least one socket. */ |
241 | | if (pollset->nelts == 0) { |
242 | | if (timeout > 0) { |
243 | | apr_sleep(timeout); |
244 | | return APR_TIMEUP; |
245 | | } |
246 | | return APR_SUCCESS; |
247 | | } |
248 | | #endif |
249 | |
|
250 | 0 | if (timeout > 0) { |
251 | 0 | timeout = (timeout + 999) / 1000; |
252 | 0 | } |
253 | |
|
254 | | #ifdef WIN32 |
255 | | ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout); |
256 | | #else |
257 | 0 | ret = poll(pollset->p->pollset, pollset->nelts, timeout); |
258 | 0 | #endif |
259 | 0 | if (ret < 0) { |
260 | 0 | return apr_get_netos_error(); |
261 | 0 | } |
262 | 0 | else if (ret == 0) { |
263 | 0 | return APR_TIMEUP; |
264 | 0 | } |
265 | 0 | else { |
266 | 0 | apr_uint32_t i, j; |
267 | |
|
268 | 0 | for (i = 0, j = 0; i < pollset->nelts; i++) { |
269 | 0 | if (pollset->p->pollset[i].revents != 0) { |
270 | | /* Check if the polled descriptor is our |
271 | | * wakeup pipe. In that case do not put it result set. |
272 | | */ |
273 | 0 | #if WAKEUP_USES_PIPE |
274 | 0 | if ((pollset->flags & APR_POLLSET_WAKEABLE) && |
275 | 0 | pollset->p->query_set[i].desc_type == APR_POLL_FILE && |
276 | 0 | pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { |
277 | 0 | apr_poll_drain_wakeup_pipe(&pollset->wakeup_set, pollset->wakeup_pipe); |
278 | 0 | rv = APR_EINTR; |
279 | 0 | } |
280 | | #else |
281 | | if ((pollset->flags & APR_POLLSET_WAKEABLE) && |
282 | | pollset->p->query_set[i].desc_type == APR_POLL_SOCKET && |
283 | | pollset->p->query_set[i].desc.s == pollset->wakeup_socket[0]) { |
284 | | apr_poll_drain_wakeup_socket(&pollset->wakeup_set, pollset->wakeup_socket); |
285 | | rv = APR_EINTR; |
286 | | } |
287 | | #endif |
288 | 0 | else { |
289 | 0 | pollset->p->result_set[j] = pollset->p->query_set[i]; |
290 | 0 | pollset->p->result_set[j].rtnevents = |
291 | 0 | get_revent(pollset->p->pollset[i].revents); |
292 | 0 | j++; |
293 | 0 | } |
294 | 0 | } |
295 | 0 | } |
296 | 0 | if ((*num = j)) { /* any event besides wakeup pipe? */ |
297 | 0 | rv = APR_SUCCESS; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | if (descriptors && (*num)) |
301 | 0 | *descriptors = pollset->p->result_set; |
302 | 0 | return rv; |
303 | 0 | } |
304 | | |
305 | | static const apr_pollset_provider_t impl = { |
306 | | impl_pollset_create, |
307 | | impl_pollset_add, |
308 | | impl_pollset_remove, |
309 | | impl_pollset_poll, |
310 | | NULL, |
311 | | "poll" |
312 | | }; |
313 | | |
314 | | const apr_pollset_provider_t *apr_pollset_provider_poll = &impl; |
315 | | |
316 | | /* Poll method pollcb. |
317 | | * This is probably usable only for WIN32 having WSAPoll |
318 | | */ |
319 | | static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, |
320 | | apr_uint32_t size, |
321 | | apr_pool_t *p, |
322 | | apr_uint32_t flags) |
323 | 0 | { |
324 | 0 | #if APR_HAS_THREADS |
325 | 0 | return APR_ENOTIMPL; |
326 | | #else |
327 | | pollcb->fd = -1; |
328 | | |
329 | | pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd)); |
330 | | pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *)); |
331 | | |
332 | | return APR_SUCCESS; |
333 | | #endif |
334 | 0 | } |
335 | | |
336 | | static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, |
337 | | apr_pollfd_t *descriptor) |
338 | 0 | { |
339 | 0 | if (pollcb->nelts == pollcb->nalloc) { |
340 | 0 | return APR_ENOMEM; |
341 | 0 | } |
342 | | |
343 | 0 | if (descriptor->desc_type == APR_POLL_SOCKET) { |
344 | 0 | pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes; |
345 | 0 | } |
346 | 0 | else { |
347 | 0 | #if APR_FILES_AS_SOCKETS |
348 | 0 | pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes; |
349 | | #else |
350 | | return APR_EBADF; |
351 | | #endif |
352 | 0 | } |
353 | |
|
354 | 0 | pollcb->pollset.ps[pollcb->nelts].events = |
355 | 0 | get_event(descriptor->reqevents); |
356 | 0 | pollcb->copyset[pollcb->nelts] = descriptor; |
357 | 0 | pollcb->nelts++; |
358 | |
|
359 | 0 | return APR_SUCCESS; |
360 | 0 | } |
361 | | |
362 | | static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, |
363 | | apr_pollfd_t *descriptor) |
364 | 0 | { |
365 | 0 | apr_uint32_t i; |
366 | |
|
367 | 0 | for (i = 0; i < pollcb->nelts; i++) { |
368 | 0 | if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { |
369 | | /* Found an instance of the fd: remove this and any other copies */ |
370 | 0 | apr_uint32_t dst = i; |
371 | 0 | apr_uint32_t old_nelts = pollcb->nelts; |
372 | 0 | pollcb->nelts--; |
373 | 0 | for (i++; i < old_nelts; i++) { |
374 | 0 | if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { |
375 | 0 | pollcb->nelts--; |
376 | 0 | } |
377 | 0 | else { |
378 | 0 | pollcb->pollset.ps[dst] = pollcb->pollset.ps[i]; |
379 | 0 | pollcb->copyset[dst] = pollcb->copyset[i]; |
380 | 0 | dst++; |
381 | 0 | } |
382 | 0 | } |
383 | 0 | return APR_SUCCESS; |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | 0 | return APR_NOTFOUND; |
388 | 0 | } |
389 | | |
390 | | static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, |
391 | | apr_interval_time_t timeout, |
392 | | apr_pollcb_cb_t func, |
393 | | void *baton) |
394 | 0 | { |
395 | 0 | int ret; |
396 | 0 | apr_status_t rv = APR_SUCCESS; |
397 | 0 | apr_uint32_t i; |
398 | |
|
399 | | #ifdef WIN32 |
400 | | /* WSAPoll() requires at least one socket. */ |
401 | | if (pollcb->nelts == 0) { |
402 | | if (timeout > 0) { |
403 | | apr_sleep(timeout); |
404 | | return APR_TIMEUP; |
405 | | } |
406 | | return APR_SUCCESS; |
407 | | } |
408 | | #endif |
409 | |
|
410 | 0 | if (timeout > 0) { |
411 | 0 | timeout = (timeout + 999) / 1000; |
412 | 0 | } |
413 | |
|
414 | | #ifdef WIN32 |
415 | | ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout); |
416 | | #else |
417 | 0 | ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout); |
418 | 0 | #endif |
419 | 0 | if (ret < 0) { |
420 | 0 | return apr_get_netos_error(); |
421 | 0 | } |
422 | 0 | else if (ret == 0) { |
423 | 0 | return APR_TIMEUP; |
424 | 0 | } |
425 | 0 | else { |
426 | 0 | for (i = 0; i < pollcb->nelts; i++) { |
427 | 0 | if (pollcb->pollset.ps[i].revents != 0) { |
428 | 0 | apr_pollfd_t *pollfd = pollcb->copyset[i]; |
429 | |
|
430 | 0 | #if WAKEUP_USES_PIPE |
431 | 0 | if ((pollcb->flags & APR_POLLSET_WAKEABLE) && |
432 | 0 | pollfd->desc_type == APR_POLL_FILE && |
433 | 0 | pollfd->desc.f == pollcb->wakeup_pipe[0]) { |
434 | 0 | apr_poll_drain_wakeup_pipe(&pollcb->wakeup_set, pollcb->wakeup_pipe); |
435 | 0 | return APR_EINTR; |
436 | 0 | } |
437 | | #else |
438 | | if ((pollcb->flags & APR_POLLSET_WAKEABLE) && |
439 | | pollfd->desc_type == APR_POLL_SOCKET && |
440 | | pollfd->desc.s == pollcb->wakeup_socket[0]) { |
441 | | apr_poll_drain_wakeup_socket(&pollcb->wakeup_set, pollcb->wakeup_socket); |
442 | | return APR_EINTR; |
443 | | } |
444 | | #endif |
445 | 0 | pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents); |
446 | 0 | rv = func(baton, pollfd); |
447 | 0 | if (rv) { |
448 | 0 | return rv; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | } |
452 | 0 | } |
453 | 0 | return rv; |
454 | 0 | } |
455 | | |
456 | | static const apr_pollcb_provider_t impl_cb = { |
457 | | impl_pollcb_create, |
458 | | impl_pollcb_add, |
459 | | impl_pollcb_remove, |
460 | | impl_pollcb_poll, |
461 | | NULL, |
462 | | "poll" |
463 | | }; |
464 | | |
465 | | const apr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb; |
466 | | |
467 | | #endif /* HAVE_POLL */ |