Coverage Report

Created: 2023-03-26 06:28

/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 */