Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/poll/unix/select.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
#ifdef WIN32
18
/* POSIX defines 1024 for the FD_SETSIZE */
19
#define FD_SETSIZE 1024
20
#endif
21
22
#include "apr.h"
23
#include "apr_poll.h"
24
#include "apr_time.h"
25
#include "apr_portable.h"
26
#include "apr_arch_file_io.h"
27
#include "apr_arch_networkio.h"
28
#include "apr_arch_poll_private.h"
29
30
#ifdef POLL_USES_SELECT
31
32
APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num,
33
                                   apr_int32_t *nsds,
34
                                   apr_interval_time_t timeout)
35
{
36
    fd_set readset, writeset, exceptset;
37
    int rv, i;
38
    int maxfd = -1;
39
    struct timeval tv, *tvptr;
40
#ifdef NETWARE
41
    apr_datatype_e set_type = APR_NO_DESC;
42
#endif
43
44
#ifdef WIN32
45
    /* On Win32, select() must be presented with at least one socket to
46
     * poll on, or select() will return WSAEINVAL.  So, we'll just
47
     * short-circuit and bail now.
48
     */
49
    if (num == 0) {
50
        (*nsds) = 0;
51
        if (timeout > 0) {
52
            apr_sleep(timeout);
53
            return APR_TIMEUP;
54
        }
55
        return APR_SUCCESS;
56
    }
57
#endif
58
59
    if (timeout < 0) {
60
        tvptr = NULL;
61
    }
62
    else {
63
        tv.tv_sec = (long) apr_time_sec(timeout);
64
        tv.tv_usec = (long) apr_time_usec(timeout);
65
        tvptr = &tv;
66
    }
67
68
    FD_ZERO(&readset);
69
    FD_ZERO(&writeset);
70
    FD_ZERO(&exceptset);
71
72
    for (i = 0; i < num; i++) {
73
        apr_os_sock_t fd;
74
75
        aprset[i].rtnevents = 0;
76
77
        if (aprset[i].desc_type == APR_POLL_SOCKET) {
78
#ifdef NETWARE
79
            if (HAS_PIPES(set_type)) {
80
                return APR_EBADF;
81
            }
82
            else {
83
                set_type = APR_POLL_SOCKET;
84
            }
85
#endif
86
            fd = aprset[i].desc.s->socketdes;
87
        }
88
        else if (aprset[i].desc_type == APR_POLL_FILE) {
89
#if !APR_FILES_AS_SOCKETS
90
            return APR_EBADF;
91
#else
92
#ifdef NETWARE
93
            if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
94
                set_type = APR_POLL_FILE;
95
            }
96
            else
97
                return APR_EBADF;
98
#endif /* NETWARE */
99
100
            fd = aprset[i].desc.f->filedes;
101
102
#endif /* APR_FILES_AS_SOCKETS */
103
        }
104
        else {
105
            break;
106
        }
107
#if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
108
        if (fd >= FD_SETSIZE) {
109
            /* XXX invent new error code so application has a clue */
110
            return APR_EBADF;
111
        }
112
#endif
113
        if (aprset[i].reqevents & APR_POLLIN) {
114
            FD_SET(fd, &readset);
115
        }
116
        if (aprset[i].reqevents & APR_POLLOUT) {
117
            FD_SET(fd, &writeset);
118
        }
119
        if (aprset[i].reqevents &
120
            (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
121
            FD_SET(fd, &exceptset);
122
        }
123
        if ((int) fd > maxfd) {
124
            maxfd = (int) fd;
125
        }
126
    }
127
128
#ifdef NETWARE
129
    if (HAS_PIPES(set_type)) {
130
        rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
131
    }
132
    else {
133
#endif
134
135
        rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
136
137
#ifdef NETWARE
138
    }
139
#endif
140
141
    (*nsds) = rv;
142
    if ((*nsds) == 0) {
143
        return APR_TIMEUP;
144
    }
145
    if ((*nsds) < 0) {
146
        return apr_get_netos_error();
147
    }
148
149
    (*nsds) = 0;
150
    for (i = 0; i < num; i++) {
151
        apr_os_sock_t fd;
152
153
        if (aprset[i].desc_type == APR_POLL_SOCKET) {
154
            fd = aprset[i].desc.s->socketdes;
155
        }
156
        else if (aprset[i].desc_type == APR_POLL_FILE) {
157
#if !APR_FILES_AS_SOCKETS
158
            return APR_EBADF;
159
#else
160
            fd = aprset[i].desc.f->filedes;
161
#endif
162
        }
163
        else {
164
            break;
165
        }
166
        if (FD_ISSET(fd, &readset)) {
167
            aprset[i].rtnevents |= APR_POLLIN;
168
        }
169
        if (FD_ISSET(fd, &writeset)) {
170
            aprset[i].rtnevents |= APR_POLLOUT;
171
        }
172
        if (FD_ISSET(fd, &exceptset)) {
173
            aprset[i].rtnevents |= APR_POLLERR;
174
        }
175
        if (aprset[i].rtnevents) {
176
            (*nsds)++;
177
        }
178
    }
179
180
    return APR_SUCCESS;
181
}
182
183
#endif /* POLL_USES_SELECT */
184
185
struct apr_pollset_private_t
186
{
187
    fd_set readset, writeset, exceptset;
188
    int maxfd;
189
    apr_pollfd_t *query_set;
190
    apr_pollfd_t *result_set;
191
#ifdef NETWARE
192
    int set_type;
193
#endif
194
};
195
196
static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
197
                                        apr_uint32_t size,
198
                                        apr_pool_t *p,
199
                                        apr_uint32_t flags)
200
0
{
201
0
    if (flags & APR_POLLSET_THREADSAFE) {
202
0
        pollset->p = NULL;
203
0
        return APR_ENOTIMPL;
204
0
    }
205
0
#ifdef FD_SETSIZE
206
0
    if (size > FD_SETSIZE) {
207
0
        pollset->p = NULL;
208
0
        return APR_EINVAL;
209
0
    }
210
0
#endif
211
0
    pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
212
0
    FD_ZERO(&(pollset->p->readset));
213
0
    FD_ZERO(&(pollset->p->writeset));
214
0
    FD_ZERO(&(pollset->p->exceptset));
215
0
    pollset->p->maxfd = 0;
216
#ifdef NETWARE
217
    pollset->p->set_type = APR_NO_DESC;
218
#endif
219
0
    pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
220
0
    pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
221
222
0
    return APR_SUCCESS;
223
0
}
224
225
static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
226
                                     const apr_pollfd_t *descriptor)
227
0
{
228
0
    apr_os_sock_t fd;
229
230
0
    if (pollset->nelts == pollset->nalloc) {
231
0
        return APR_ENOMEM;
232
0
    }
233
234
0
    pollset->p->query_set[pollset->nelts] = *descriptor;
235
236
0
    if (descriptor->desc_type == APR_POLL_SOCKET) {
237
#ifdef NETWARE
238
        /* NetWare can't handle mixed descriptor types in select() */
239
        if (HAS_PIPES(pollset->p->set_type)) {
240
            return APR_EBADF;
241
        }
242
        else {
243
            pollset->p->set_type = APR_POLL_SOCKET;
244
        }
245
#endif
246
0
        fd = descriptor->desc.s->socketdes;
247
0
    }
248
0
    else {
249
#if !APR_FILES_AS_SOCKETS
250
        return APR_EBADF;
251
#else
252
#ifdef NETWARE
253
        /* NetWare can't handle mixed descriptor types in select() */
254
        if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->p->set_type)) {
255
            pollset->p->set_type = APR_POLL_FILE;
256
            fd = descriptor->desc.f->filedes;
257
        }
258
        else {
259
            return APR_EBADF;
260
        }
261
#else
262
0
        fd = descriptor->desc.f->filedes;
263
0
#endif
264
0
#endif
265
0
    }
266
0
#if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
267
0
    if (fd >= FD_SETSIZE) {
268
        /* XXX invent new error code so application has a clue */
269
0
        return APR_EBADF;
270
0
    }
271
0
#endif
272
0
    if (descriptor->reqevents & APR_POLLIN) {
273
0
        FD_SET(fd, &(pollset->p->readset));
274
0
    }
275
0
    if (descriptor->reqevents & APR_POLLOUT) {
276
0
        FD_SET(fd, &(pollset->p->writeset));
277
0
    }
278
0
    if (descriptor->reqevents &
279
0
        (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
280
0
        FD_SET(fd, &(pollset->p->exceptset));
281
0
    }
282
0
    if ((int) fd > pollset->p->maxfd) {
283
0
        pollset->p->maxfd = (int) fd;
284
0
    }
285
0
    pollset->nelts++;
286
0
    return APR_SUCCESS;
287
0
}
288
289
static apr_status_t impl_pollset_remove(apr_pollset_t * pollset,
290
                                        const apr_pollfd_t * descriptor)
291
0
{
292
0
    apr_uint32_t i;
293
0
    apr_os_sock_t fd;
294
295
0
    if (descriptor->desc_type == APR_POLL_SOCKET) {
296
0
        fd = descriptor->desc.s->socketdes;
297
0
    }
298
0
    else {
299
#if !APR_FILES_AS_SOCKETS
300
        return APR_EBADF;
301
#else
302
0
        fd = descriptor->desc.f->filedes;
303
0
#endif
304
0
    }
305
306
0
    for (i = 0; i < pollset->nelts; i++) {
307
0
        if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
308
            /* Found an instance of the fd: remove this and any other copies */
309
0
            apr_uint32_t dst = i;
310
0
            apr_uint32_t old_nelts = pollset->nelts;
311
0
            pollset->nelts--;
312
0
            for (i++; i < old_nelts; i++) {
313
0
                if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
314
0
                    pollset->nelts--;
315
0
                }
316
0
                else {
317
0
                    pollset->p->query_set[dst] = pollset->p->query_set[i];
318
0
                    dst++;
319
0
                }
320
0
            }
321
0
            FD_CLR(fd, &(pollset->p->readset));
322
0
            FD_CLR(fd, &(pollset->p->writeset));
323
0
            FD_CLR(fd, &(pollset->p->exceptset));
324
0
            if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) {
325
0
                pollset->p->maxfd--;
326
0
            }
327
0
            return APR_SUCCESS;
328
0
        }
329
0
    }
330
331
0
    return APR_NOTFOUND;
332
0
}
333
334
static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
335
                                      apr_interval_time_t timeout,
336
                                      apr_int32_t *num,
337
                                      const apr_pollfd_t **descriptors)
338
0
{
339
0
    int rs;
340
0
    apr_uint32_t i, j;
341
0
    struct timeval tv, *tvptr;
342
0
    fd_set readset, writeset, exceptset;
343
0
    apr_status_t rv = APR_SUCCESS;
344
345
0
    *num = 0;
346
347
#ifdef WIN32
348
    /* On Win32, select() must be presented with at least one socket to
349
     * poll on, or select() will return WSAEINVAL.  So, we'll just
350
     * short-circuit and bail now.
351
     */
352
    if (pollset->nelts == 0) {
353
        if (timeout > 0) {
354
            apr_sleep(timeout);
355
            return APR_TIMEUP;
356
        }
357
        return APR_SUCCESS;
358
    }
359
#endif
360
361
0
    if (timeout < 0) {
362
0
        tvptr = NULL;
363
0
    }
364
0
    else {
365
0
        tv.tv_sec = (long) apr_time_sec(timeout);
366
0
        tv.tv_usec = (long) apr_time_usec(timeout);
367
0
        tvptr = &tv;
368
0
    }
369
370
0
    memcpy(&readset, &(pollset->p->readset), sizeof(fd_set));
371
0
    memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set));
372
0
    memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set));
373
374
#ifdef NETWARE
375
    if (HAS_PIPES(pollset->p->set_type)) {
376
        rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
377
                         tvptr);
378
    }
379
    else
380
#endif
381
0
        rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
382
0
                    tvptr);
383
384
0
    if (rs < 0) {
385
0
        return apr_get_netos_error();
386
0
    }
387
0
    if (rs == 0) {
388
0
        return APR_TIMEUP;
389
0
    }
390
0
    j = 0;
391
0
    for (i = 0; i < pollset->nelts; i++) {
392
0
        apr_os_sock_t fd;
393
394
0
        if (pollset->flags & APR_POLLSET_WAKEABLE) {
395
0
#if WAKEUP_USES_PIPE
396
0
            if (pollset->p->query_set[i].desc_type == APR_POLL_FILE &&
397
0
                pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
398
0
                apr_poll_drain_wakeup_pipe(&pollset->wakeup_set, pollset->wakeup_pipe);
399
0
                rv = APR_EINTR;
400
0
                continue;
401
0
            }
402
#else
403
            if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET &&
404
                pollset->p->query_set[i].desc.s == pollset->wakeup_socket[0]) {
405
                apr_poll_drain_wakeup_socket(&pollset->wakeup_set, pollset->wakeup_socket);
406
                rv = APR_EINTR;
407
                continue;
408
            }
409
#endif
410
0
        }
411
412
0
        if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) {
413
0
            fd = pollset->p->query_set[i].desc.s->socketdes;
414
0
        }
415
0
        else {
416
#if !APR_FILES_AS_SOCKETS
417
            return APR_EBADF;
418
#else
419
0
            fd = pollset->p->query_set[i].desc.f->filedes;
420
0
#endif
421
0
        }
422
0
        if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
423
0
            FD_ISSET(fd, &exceptset)) {
424
0
            pollset->p->result_set[j] = pollset->p->query_set[i];
425
0
            pollset->p->result_set[j].rtnevents = 0;
426
0
            if (FD_ISSET(fd, &readset)) {
427
0
                pollset->p->result_set[j].rtnevents |= APR_POLLIN;
428
0
            }
429
0
            if (FD_ISSET(fd, &writeset)) {
430
0
                pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
431
0
            }
432
0
            if (FD_ISSET(fd, &exceptset)) {
433
0
                pollset->p->result_set[j].rtnevents |= APR_POLLERR;
434
0
            }
435
0
            j++;
436
0
        }
437
0
    }
438
0
    if (((*num) = j) != 0)
439
0
        rv = APR_SUCCESS;
440
441
0
    if (descriptors)
442
0
        *descriptors = pollset->p->result_set;
443
0
    return rv;
444
0
}
445
446
static const apr_pollset_provider_t impl = {
447
    impl_pollset_create,
448
    impl_pollset_add,
449
    impl_pollset_remove,
450
    impl_pollset_poll,
451
    NULL,
452
    "select"
453
};
454
455
const apr_pollset_provider_t *apr_pollset_provider_select = &impl;