Coverage Report

Created: 2026-09-06 06:08

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