1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#ifdef WIN32
18251875Speter/* POSIX defines 1024 for the FD_SETSIZE */
19251875Speter#define FD_SETSIZE 1024
20251875Speter#endif
21251875Speter
22251875Speter#include "apr.h"
23251875Speter#include "apr_poll.h"
24251875Speter#include "apr_time.h"
25251875Speter#include "apr_portable.h"
26251875Speter#include "apr_arch_file_io.h"
27251875Speter#include "apr_arch_networkio.h"
28251875Speter#include "apr_arch_poll_private.h"
29251875Speter
30251875Speter#ifdef POLL_USES_SELECT
31251875Speter
32251875SpeterAPR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num,
33251875Speter                                   apr_int32_t *nsds,
34251875Speter                                   apr_interval_time_t timeout)
35251875Speter{
36251875Speter    fd_set readset, writeset, exceptset;
37251875Speter    int rv, i;
38251875Speter    int maxfd = -1;
39251875Speter    struct timeval tv, *tvptr;
40251875Speter#ifdef NETWARE
41251875Speter    apr_datatype_e set_type = APR_NO_DESC;
42251875Speter#endif
43251875Speter
44251875Speter#ifdef WIN32
45251875Speter    /* On Win32, select() must be presented with at least one socket to
46251875Speter     * poll on, or select() will return WSAEINVAL.  So, we'll just
47251875Speter     * short-circuit and bail now.
48251875Speter     */
49251875Speter    if (num == 0) {
50251875Speter        (*nsds) = 0;
51251875Speter        if (timeout > 0) {
52251875Speter            apr_sleep(timeout);
53251875Speter            return APR_TIMEUP;
54251875Speter        }
55251875Speter        return APR_SUCCESS;
56251875Speter    }
57251875Speter#endif
58251875Speter
59251875Speter    if (timeout < 0) {
60251875Speter        tvptr = NULL;
61251875Speter    }
62251875Speter    else {
63251875Speter        tv.tv_sec = (long) apr_time_sec(timeout);
64251875Speter        tv.tv_usec = (long) apr_time_usec(timeout);
65251875Speter        tvptr = &tv;
66251875Speter    }
67251875Speter
68251875Speter    FD_ZERO(&readset);
69251875Speter    FD_ZERO(&writeset);
70251875Speter    FD_ZERO(&exceptset);
71251875Speter
72251875Speter    for (i = 0; i < num; i++) {
73251875Speter        apr_os_sock_t fd;
74251875Speter
75251875Speter        aprset[i].rtnevents = 0;
76251875Speter
77251875Speter        if (aprset[i].desc_type == APR_POLL_SOCKET) {
78251875Speter#ifdef NETWARE
79251875Speter            if (HAS_PIPES(set_type)) {
80251875Speter                return APR_EBADF;
81251875Speter            }
82251875Speter            else {
83251875Speter                set_type = APR_POLL_SOCKET;
84251875Speter            }
85251875Speter#endif
86251875Speter            fd = aprset[i].desc.s->socketdes;
87251875Speter        }
88251875Speter        else if (aprset[i].desc_type == APR_POLL_FILE) {
89251875Speter#if !APR_FILES_AS_SOCKETS
90251875Speter            return APR_EBADF;
91251875Speter#else
92251875Speter#ifdef NETWARE
93251875Speter            if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
94251875Speter                set_type = APR_POLL_FILE;
95251875Speter            }
96251875Speter            else
97251875Speter                return APR_EBADF;
98251875Speter#endif /* NETWARE */
99251875Speter
100251875Speter            fd = aprset[i].desc.f->filedes;
101251875Speter
102251875Speter#endif /* APR_FILES_AS_SOCKETS */
103251875Speter        }
104251875Speter        else {
105251875Speter            break;
106251875Speter        }
107251875Speter#if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
108251875Speter        if (fd >= FD_SETSIZE) {
109251875Speter            /* XXX invent new error code so application has a clue */
110251875Speter            return APR_EBADF;
111251875Speter        }
112251875Speter#endif
113251875Speter        if (aprset[i].reqevents & APR_POLLIN) {
114251875Speter            FD_SET(fd, &readset);
115251875Speter        }
116251875Speter        if (aprset[i].reqevents & APR_POLLOUT) {
117251875Speter            FD_SET(fd, &writeset);
118251875Speter        }
119251875Speter        if (aprset[i].reqevents &
120251875Speter            (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
121251875Speter            FD_SET(fd, &exceptset);
122251875Speter        }
123251875Speter        if ((int) fd > maxfd) {
124251875Speter            maxfd = (int) fd;
125251875Speter        }
126251875Speter    }
127251875Speter
128251875Speter#ifdef NETWARE
129251875Speter    if (HAS_PIPES(set_type)) {
130251875Speter        rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
131251875Speter    }
132251875Speter    else {
133251875Speter#endif
134251875Speter
135251875Speter        rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
136251875Speter
137251875Speter#ifdef NETWARE
138251875Speter    }
139251875Speter#endif
140251875Speter
141251875Speter    (*nsds) = rv;
142251875Speter    if ((*nsds) == 0) {
143251875Speter        return APR_TIMEUP;
144251875Speter    }
145251875Speter    if ((*nsds) < 0) {
146251875Speter        return apr_get_netos_error();
147251875Speter    }
148251875Speter
149251875Speter    (*nsds) = 0;
150251875Speter    for (i = 0; i < num; i++) {
151251875Speter        apr_os_sock_t fd;
152251875Speter
153251875Speter        if (aprset[i].desc_type == APR_POLL_SOCKET) {
154251875Speter            fd = aprset[i].desc.s->socketdes;
155251875Speter        }
156251875Speter        else if (aprset[i].desc_type == APR_POLL_FILE) {
157251875Speter#if !APR_FILES_AS_SOCKETS
158251875Speter            return APR_EBADF;
159251875Speter#else
160251875Speter            fd = aprset[i].desc.f->filedes;
161251875Speter#endif
162251875Speter        }
163251875Speter        else {
164251875Speter            break;
165251875Speter        }
166251875Speter        if (FD_ISSET(fd, &readset)) {
167251875Speter            aprset[i].rtnevents |= APR_POLLIN;
168251875Speter        }
169251875Speter        if (FD_ISSET(fd, &writeset)) {
170251875Speter            aprset[i].rtnevents |= APR_POLLOUT;
171251875Speter        }
172251875Speter        if (FD_ISSET(fd, &exceptset)) {
173251875Speter            aprset[i].rtnevents |= APR_POLLERR;
174251875Speter        }
175251875Speter        if (aprset[i].rtnevents) {
176251875Speter            (*nsds)++;
177251875Speter        }
178251875Speter    }
179251875Speter
180251875Speter    return APR_SUCCESS;
181251875Speter}
182251875Speter
183251875Speter#endif /* POLL_USES_SELECT */
184251875Speter
185251875Speterstruct apr_pollset_private_t
186251875Speter{
187251875Speter    fd_set readset, writeset, exceptset;
188251875Speter    int maxfd;
189251875Speter    apr_pollfd_t *query_set;
190251875Speter    apr_pollfd_t *result_set;
191251875Speter    apr_uint32_t flags;
192251875Speter#ifdef NETWARE
193251875Speter    int set_type;
194251875Speter#endif
195251875Speter};
196251875Speter
197251875Speterstatic apr_status_t impl_pollset_create(apr_pollset_t *pollset,
198251875Speter                                        apr_uint32_t size,
199251875Speter                                        apr_pool_t *p,
200251875Speter                                        apr_uint32_t flags)
201251875Speter{
202251875Speter    if (flags & APR_POLLSET_THREADSAFE) {
203251875Speter        pollset->p = NULL;
204251875Speter        return APR_ENOTIMPL;
205251875Speter    }
206251875Speter#ifdef FD_SETSIZE
207251875Speter    if (size > FD_SETSIZE) {
208251875Speter        pollset->p = NULL;
209251875Speter        return APR_EINVAL;
210251875Speter    }
211251875Speter#endif
212251875Speter    pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
213251875Speter    FD_ZERO(&(pollset->p->readset));
214251875Speter    FD_ZERO(&(pollset->p->writeset));
215251875Speter    FD_ZERO(&(pollset->p->exceptset));
216251875Speter    pollset->p->maxfd = 0;
217251875Speter#ifdef NETWARE
218251875Speter    pollset->p->set_type = APR_NO_DESC;
219251875Speter#endif
220251875Speter    pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
221251875Speter    pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
222251875Speter
223251875Speter    return APR_SUCCESS;
224251875Speter}
225251875Speter
226251875Speterstatic apr_status_t impl_pollset_add(apr_pollset_t *pollset,
227251875Speter                                     const apr_pollfd_t *descriptor)
228251875Speter{
229251875Speter    apr_os_sock_t fd;
230251875Speter
231251875Speter    if (pollset->nelts == pollset->nalloc) {
232251875Speter        return APR_ENOMEM;
233251875Speter    }
234251875Speter
235251875Speter    pollset->p->query_set[pollset->nelts] = *descriptor;
236251875Speter
237251875Speter    if (descriptor->desc_type == APR_POLL_SOCKET) {
238251875Speter#ifdef NETWARE
239251875Speter        /* NetWare can't handle mixed descriptor types in select() */
240251875Speter        if (HAS_PIPES(pollset->p->set_type)) {
241251875Speter            return APR_EBADF;
242251875Speter        }
243251875Speter        else {
244251875Speter            pollset->p->set_type = APR_POLL_SOCKET;
245251875Speter        }
246251875Speter#endif
247251875Speter        fd = descriptor->desc.s->socketdes;
248251875Speter    }
249251875Speter    else {
250251875Speter#if !APR_FILES_AS_SOCKETS
251251875Speter        if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
252251875Speter            descriptor->desc.f == pollset->wakeup_pipe[0])
253251875Speter            fd = (apr_os_sock_t)descriptor->desc.f->filedes;
254251875Speter        else
255251875Speter            return APR_EBADF;
256251875Speter#else
257251875Speter#ifdef NETWARE
258251875Speter        /* NetWare can't handle mixed descriptor types in select() */
259251875Speter        if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->p->set_type)) {
260251875Speter            pollset->p->set_type = APR_POLL_FILE;
261251875Speter            fd = descriptor->desc.f->filedes;
262251875Speter        }
263251875Speter        else {
264251875Speter            return APR_EBADF;
265251875Speter        }
266251875Speter#else
267251875Speter        fd = descriptor->desc.f->filedes;
268251875Speter#endif
269251875Speter#endif
270251875Speter    }
271251875Speter#if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
272251875Speter    if (fd >= FD_SETSIZE) {
273251875Speter        /* XXX invent new error code so application has a clue */
274251875Speter        return APR_EBADF;
275251875Speter    }
276251875Speter#endif
277251875Speter    if (descriptor->reqevents & APR_POLLIN) {
278251875Speter        FD_SET(fd, &(pollset->p->readset));
279251875Speter    }
280251875Speter    if (descriptor->reqevents & APR_POLLOUT) {
281251875Speter        FD_SET(fd, &(pollset->p->writeset));
282251875Speter    }
283251875Speter    if (descriptor->reqevents &
284251875Speter        (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
285251875Speter        FD_SET(fd, &(pollset->p->exceptset));
286251875Speter    }
287251875Speter    if ((int) fd > pollset->p->maxfd) {
288251875Speter        pollset->p->maxfd = (int) fd;
289251875Speter    }
290251875Speter    pollset->nelts++;
291251875Speter    return APR_SUCCESS;
292251875Speter}
293251875Speter
294251875Speterstatic apr_status_t impl_pollset_remove(apr_pollset_t * pollset,
295251875Speter                                        const apr_pollfd_t * descriptor)
296251875Speter{
297251875Speter    apr_uint32_t i;
298251875Speter    apr_os_sock_t fd;
299251875Speter
300251875Speter    if (descriptor->desc_type == APR_POLL_SOCKET) {
301251875Speter        fd = descriptor->desc.s->socketdes;
302251875Speter    }
303251875Speter    else {
304251875Speter#if !APR_FILES_AS_SOCKETS
305251875Speter        return APR_EBADF;
306251875Speter#else
307251875Speter        fd = descriptor->desc.f->filedes;
308251875Speter#endif
309251875Speter    }
310251875Speter
311251875Speter    for (i = 0; i < pollset->nelts; i++) {
312251875Speter        if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
313251875Speter            /* Found an instance of the fd: remove this and any other copies */
314251875Speter            apr_uint32_t dst = i;
315251875Speter            apr_uint32_t old_nelts = pollset->nelts;
316251875Speter            pollset->nelts--;
317251875Speter            for (i++; i < old_nelts; i++) {
318251875Speter                if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
319251875Speter                    pollset->nelts--;
320251875Speter                }
321251875Speter                else {
322251875Speter                    pollset->p->query_set[dst] = pollset->p->query_set[i];
323251875Speter                    dst++;
324251875Speter                }
325251875Speter            }
326251875Speter            FD_CLR(fd, &(pollset->p->readset));
327251875Speter            FD_CLR(fd, &(pollset->p->writeset));
328251875Speter            FD_CLR(fd, &(pollset->p->exceptset));
329251875Speter            if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) {
330251875Speter                pollset->p->maxfd--;
331251875Speter            }
332251875Speter            return APR_SUCCESS;
333251875Speter        }
334251875Speter    }
335251875Speter
336251875Speter    return APR_NOTFOUND;
337251875Speter}
338251875Speter
339251875Speterstatic apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
340251875Speter                                      apr_interval_time_t timeout,
341251875Speter                                      apr_int32_t *num,
342251875Speter                                      const apr_pollfd_t **descriptors)
343251875Speter{
344251875Speter    int rs;
345251875Speter    apr_uint32_t i, j;
346251875Speter    struct timeval tv, *tvptr;
347251875Speter    fd_set readset, writeset, exceptset;
348251875Speter    apr_status_t rv = APR_SUCCESS;
349251875Speter
350251875Speter#ifdef WIN32
351251875Speter    /* On Win32, select() must be presented with at least one socket to
352251875Speter     * poll on, or select() will return WSAEINVAL.  So, we'll just
353251875Speter     * short-circuit and bail now.
354251875Speter     */
355251875Speter    if (pollset->nelts == 0) {
356251875Speter        (*num) = 0;
357251875Speter        if (timeout > 0) {
358251875Speter            apr_sleep(timeout);
359251875Speter            return APR_TIMEUP;
360251875Speter        }
361251875Speter        return APR_SUCCESS;
362251875Speter    }
363251875Speter#endif
364251875Speter
365251875Speter    if (timeout < 0) {
366251875Speter        tvptr = NULL;
367251875Speter    }
368251875Speter    else {
369251875Speter        tv.tv_sec = (long) apr_time_sec(timeout);
370251875Speter        tv.tv_usec = (long) apr_time_usec(timeout);
371251875Speter        tvptr = &tv;
372251875Speter    }
373251875Speter
374251875Speter    memcpy(&readset, &(pollset->p->readset), sizeof(fd_set));
375251875Speter    memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set));
376251875Speter    memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set));
377251875Speter
378251875Speter#ifdef NETWARE
379251875Speter    if (HAS_PIPES(pollset->p->set_type)) {
380251875Speter        rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
381251875Speter                         tvptr);
382251875Speter    }
383251875Speter    else
384251875Speter#endif
385251875Speter        rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
386251875Speter                    tvptr);
387251875Speter
388251875Speter    (*num) = rs;
389251875Speter    if (rs < 0) {
390251875Speter        return apr_get_netos_error();
391251875Speter    }
392251875Speter    if (rs == 0) {
393251875Speter        return APR_TIMEUP;
394251875Speter    }
395251875Speter    j = 0;
396251875Speter    for (i = 0; i < pollset->nelts; i++) {
397251875Speter        apr_os_sock_t fd;
398251875Speter        if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) {
399251875Speter            fd = pollset->p->query_set[i].desc.s->socketdes;
400251875Speter        }
401251875Speter        else {
402251875Speter            if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
403251875Speter                pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
404251875Speter                apr_pollset_drain_wakeup_pipe(pollset);
405251875Speter                rv = APR_EINTR;
406251875Speter                continue;
407251875Speter            }
408251875Speter            else {
409251875Speter#if !APR_FILES_AS_SOCKETS
410251875Speter                return APR_EBADF;
411251875Speter#else
412251875Speter                fd = pollset->p->query_set[i].desc.f->filedes;
413251875Speter#endif
414251875Speter            }
415251875Speter        }
416251875Speter        if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
417251875Speter            FD_ISSET(fd, &exceptset)) {
418251875Speter            pollset->p->result_set[j] = pollset->p->query_set[i];
419251875Speter            pollset->p->result_set[j].rtnevents = 0;
420251875Speter            if (FD_ISSET(fd, &readset)) {
421251875Speter                pollset->p->result_set[j].rtnevents |= APR_POLLIN;
422251875Speter            }
423251875Speter            if (FD_ISSET(fd, &writeset)) {
424251875Speter                pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
425251875Speter            }
426251875Speter            if (FD_ISSET(fd, &exceptset)) {
427251875Speter                pollset->p->result_set[j].rtnevents |= APR_POLLERR;
428251875Speter            }
429251875Speter            j++;
430251875Speter        }
431251875Speter    }
432251875Speter    if (((*num) = j) != 0)
433251875Speter        rv = APR_SUCCESS;
434251875Speter
435251875Speter    if (descriptors)
436251875Speter        *descriptors = pollset->p->result_set;
437251875Speter    return rv;
438251875Speter}
439251875Speter
440251875Speterstatic apr_pollset_provider_t impl = {
441251875Speter    impl_pollset_create,
442251875Speter    impl_pollset_add,
443251875Speter    impl_pollset_remove,
444251875Speter    impl_pollset_poll,
445251875Speter    NULL,
446251875Speter    "select"
447251875Speter};
448251875Speter
449251875Speterapr_pollset_provider_t *apr_pollset_provider_select = &impl;
450