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#include "apr.h"
18251875Speter#include "apr_poll.h"
19251875Speter#include "apr_time.h"
20251875Speter#include "apr_portable.h"
21251875Speter#include "apr_arch_file_io.h"
22251875Speter#include "apr_arch_networkio.h"
23251875Speter#include "apr_arch_misc.h"
24251875Speter#include "apr_arch_poll_private.h"
25251875Speter
26251875Speter#if defined(HAVE_POLL)
27251875Speter
28251875Speter#ifdef HAVE_ALLOCA_H
29251875Speter#include <alloca.h>
30251875Speter#endif
31251875Speter
32251875Speterstatic apr_int16_t get_event(apr_int16_t event)
33251875Speter{
34251875Speter    apr_int16_t rv = 0;
35251875Speter
36251875Speter    if (event & APR_POLLIN)
37251875Speter        rv |= POLLIN;
38251875Speter    if (event & APR_POLLPRI)
39251875Speter        rv |= POLLPRI;
40251875Speter    if (event & APR_POLLOUT)
41251875Speter        rv |= POLLOUT;
42251875Speter    /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */
43251875Speter
44251875Speter    return rv;
45251875Speter}
46251875Speter
47251875Speterstatic apr_int16_t get_revent(apr_int16_t event)
48251875Speter{
49251875Speter    apr_int16_t rv = 0;
50251875Speter
51251875Speter    if (event & POLLIN)
52251875Speter        rv |= APR_POLLIN;
53251875Speter    if (event & POLLPRI)
54251875Speter        rv |= APR_POLLPRI;
55251875Speter    if (event & POLLOUT)
56251875Speter        rv |= APR_POLLOUT;
57251875Speter    if (event & POLLERR)
58251875Speter        rv |= APR_POLLERR;
59251875Speter    if (event & POLLHUP)
60251875Speter        rv |= APR_POLLHUP;
61251875Speter    if (event & POLLNVAL)
62251875Speter        rv |= APR_POLLNVAL;
63251875Speter
64251875Speter    return rv;
65251875Speter}
66251875Speter
67251875Speter#ifdef POLL_USES_POLL
68251875Speter
69251875Speter#define SMALL_POLLSET_LIMIT  8
70251875Speter
71251875SpeterAPR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num,
72251875Speter                                   apr_int32_t *nsds,
73251875Speter                                   apr_interval_time_t timeout)
74251875Speter{
75251875Speter    int i, num_to_poll;
76251875Speter#ifdef HAVE_VLA
77251875Speter    /* XXX: I trust that this is a segv when insufficient stack exists? */
78251875Speter    struct pollfd pollset[num];
79251875Speter#elif defined(HAVE_ALLOCA)
80251875Speter    struct pollfd *pollset = alloca(sizeof(struct pollfd) * num);
81251875Speter    if (!pollset)
82251875Speter        return APR_ENOMEM;
83251875Speter#else
84251875Speter    struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT];
85251875Speter    struct pollfd *pollset;
86251875Speter
87251875Speter    if (num <= SMALL_POLLSET_LIMIT) {
88251875Speter        pollset = tmp_pollset;
89251875Speter    }
90251875Speter    else {
91251875Speter        /* This does require O(n) to copy the descriptors to the internal
92251875Speter         * mapping.
93251875Speter         */
94251875Speter        pollset = malloc(sizeof(struct pollfd) * num);
95251875Speter        /* The other option is adding an apr_pool_abort() fn to invoke
96251875Speter         * the pool's out of memory handler
97251875Speter         */
98251875Speter        if (!pollset)
99251875Speter            return APR_ENOMEM;
100251875Speter    }
101251875Speter#endif
102251875Speter    for (i = 0; i < num; i++) {
103251875Speter        if (aprset[i].desc_type == APR_POLL_SOCKET) {
104251875Speter            pollset[i].fd = aprset[i].desc.s->socketdes;
105251875Speter        }
106251875Speter        else if (aprset[i].desc_type == APR_POLL_FILE) {
107251875Speter            pollset[i].fd = aprset[i].desc.f->filedes;
108251875Speter        }
109251875Speter        else {
110251875Speter            break;
111251875Speter        }
112251875Speter        pollset[i].events = get_event(aprset[i].reqevents);
113251875Speter    }
114251875Speter    num_to_poll = i;
115251875Speter
116251875Speter    if (timeout > 0) {
117251875Speter        timeout /= 1000; /* convert microseconds to milliseconds */
118251875Speter    }
119251875Speter
120251875Speter    i = poll(pollset, num_to_poll, timeout);
121251875Speter    (*nsds) = i;
122251875Speter
123251875Speter    if (i > 0) { /* poll() sets revents only if an event was signalled;
124251875Speter                  * we don't promise to set rtnevents unless an event
125251875Speter                  * was signalled
126251875Speter                  */
127251875Speter        for (i = 0; i < num; i++) {
128251875Speter            aprset[i].rtnevents = get_revent(pollset[i].revents);
129251875Speter        }
130251875Speter    }
131251875Speter
132251875Speter#if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA)
133251875Speter    if (num > SMALL_POLLSET_LIMIT) {
134251875Speter        free(pollset);
135251875Speter    }
136251875Speter#endif
137251875Speter
138251875Speter    if ((*nsds) < 0) {
139251875Speter        return apr_get_netos_error();
140251875Speter    }
141251875Speter    if ((*nsds) == 0) {
142251875Speter        return APR_TIMEUP;
143251875Speter    }
144251875Speter    return APR_SUCCESS;
145251875Speter}
146251875Speter
147251875Speter
148251875Speter#endif /* POLL_USES_POLL */
149251875Speter
150251875Speterstruct apr_pollset_private_t
151251875Speter{
152251875Speter    struct pollfd *pollset;
153251875Speter    apr_pollfd_t *query_set;
154251875Speter    apr_pollfd_t *result_set;
155251875Speter};
156251875Speter
157251875Speterstatic apr_status_t impl_pollset_create(apr_pollset_t *pollset,
158251875Speter                                        apr_uint32_t size,
159251875Speter                                        apr_pool_t *p,
160251875Speter                                        apr_uint32_t flags)
161251875Speter{
162251875Speter    if (flags & APR_POLLSET_THREADSAFE) {
163251875Speter        return APR_ENOTIMPL;
164251875Speter    }
165251875Speter#ifdef WIN32
166251875Speter    if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) {
167251875Speter        return APR_ENOTIMPL;
168251875Speter    }
169251875Speter#endif
170251875Speter    pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
171251875Speter    pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd));
172251875Speter    pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
173251875Speter    pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
174251875Speter
175251875Speter    return APR_SUCCESS;
176251875Speter}
177251875Speter
178251875Speterstatic apr_status_t impl_pollset_add(apr_pollset_t *pollset,
179251875Speter                                     const apr_pollfd_t *descriptor)
180251875Speter{
181251875Speter    if (pollset->nelts == pollset->nalloc) {
182251875Speter        return APR_ENOMEM;
183251875Speter    }
184251875Speter
185251875Speter    pollset->p->query_set[pollset->nelts] = *descriptor;
186251875Speter
187251875Speter    if (descriptor->desc_type == APR_POLL_SOCKET) {
188251875Speter        pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
189251875Speter    }
190251875Speter    else {
191251875Speter#if APR_FILES_AS_SOCKETS
192251875Speter        pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes;
193251875Speter#else
194251875Speter        if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
195251875Speter            descriptor->desc.f == pollset->wakeup_pipe[0])
196251875Speter            pollset->p->pollset[pollset->nelts].fd = (SOCKET)descriptor->desc.f->filedes;
197251875Speter        else
198251875Speter            return APR_EBADF;
199251875Speter#endif
200251875Speter    }
201251875Speter    pollset->p->pollset[pollset->nelts].events =
202251875Speter        get_event(descriptor->reqevents);
203251875Speter    pollset->nelts++;
204251875Speter
205251875Speter    return APR_SUCCESS;
206251875Speter}
207251875Speter
208251875Speterstatic apr_status_t impl_pollset_remove(apr_pollset_t *pollset,
209251875Speter                                        const apr_pollfd_t *descriptor)
210251875Speter{
211251875Speter    apr_uint32_t i;
212251875Speter
213251875Speter    for (i = 0; i < pollset->nelts; i++) {
214251875Speter        if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
215251875Speter            /* Found an instance of the fd: remove this and any other copies */
216251875Speter            apr_uint32_t dst = i;
217251875Speter            apr_uint32_t old_nelts = pollset->nelts;
218251875Speter            pollset->nelts--;
219251875Speter            for (i++; i < old_nelts; i++) {
220251875Speter                if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
221251875Speter                    pollset->nelts--;
222251875Speter                }
223251875Speter                else {
224251875Speter                    pollset->p->pollset[dst] = pollset->p->pollset[i];
225251875Speter                    pollset->p->query_set[dst] = pollset->p->query_set[i];
226251875Speter                    dst++;
227251875Speter                }
228251875Speter            }
229251875Speter            return APR_SUCCESS;
230251875Speter        }
231251875Speter    }
232251875Speter
233251875Speter    return APR_NOTFOUND;
234251875Speter}
235251875Speter
236251875Speterstatic apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
237251875Speter                                      apr_interval_time_t timeout,
238251875Speter                                      apr_int32_t *num,
239251875Speter                                      const apr_pollfd_t **descriptors)
240251875Speter{
241251875Speter    int ret;
242251875Speter    apr_status_t rv = APR_SUCCESS;
243251875Speter
244251875Speter#ifdef WIN32
245251875Speter    /* WSAPoll() requires at least one socket. */
246251875Speter    if (pollset->nelts == 0) {
247251875Speter        *num = 0;
248289166Speter        if (timeout > 0) {
249289166Speter            apr_sleep(timeout);
250251875Speter            return APR_TIMEUP;
251251875Speter        }
252251875Speter        return APR_SUCCESS;
253251875Speter    }
254289166Speter    if (timeout > 0) {
255289166Speter        timeout /= 1000;
256289166Speter    }
257251875Speter    ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout);
258251875Speter#else
259289166Speter    if (timeout > 0) {
260289166Speter        timeout /= 1000;
261289166Speter    }
262251875Speter    ret = poll(pollset->p->pollset, pollset->nelts, timeout);
263251875Speter#endif
264251875Speter    (*num) = ret;
265251875Speter    if (ret < 0) {
266251875Speter        return apr_get_netos_error();
267251875Speter    }
268251875Speter    else if (ret == 0) {
269251875Speter        return APR_TIMEUP;
270251875Speter    }
271251875Speter    else {
272251875Speter        apr_uint32_t i, j;
273251875Speter
274251875Speter        for (i = 0, j = 0; i < pollset->nelts; i++) {
275251875Speter            if (pollset->p->pollset[i].revents != 0) {
276251875Speter                /* Check if the polled descriptor is our
277251875Speter                 * wakeup pipe. In that case do not put it result set.
278251875Speter                 */
279251875Speter                if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
280251875Speter                    pollset->p->query_set[i].desc_type == APR_POLL_FILE &&
281251875Speter                    pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
282251875Speter                        apr_pollset_drain_wakeup_pipe(pollset);
283251875Speter                        rv = APR_EINTR;
284251875Speter                }
285251875Speter                else {
286251875Speter                    pollset->p->result_set[j] = pollset->p->query_set[i];
287251875Speter                    pollset->p->result_set[j].rtnevents =
288251875Speter                        get_revent(pollset->p->pollset[i].revents);
289251875Speter                    j++;
290251875Speter                }
291251875Speter            }
292251875Speter        }
293251875Speter        if (((*num) = j) > 0)
294251875Speter            rv = APR_SUCCESS;
295251875Speter    }
296251875Speter    if (descriptors && (*num))
297251875Speter        *descriptors = pollset->p->result_set;
298251875Speter    return rv;
299251875Speter}
300251875Speter
301251875Speterstatic apr_pollset_provider_t impl = {
302251875Speter    impl_pollset_create,
303251875Speter    impl_pollset_add,
304251875Speter    impl_pollset_remove,
305251875Speter    impl_pollset_poll,
306251875Speter    NULL,
307251875Speter    "poll"
308251875Speter};
309251875Speter
310251875Speterapr_pollset_provider_t *apr_pollset_provider_poll = &impl;
311251875Speter
312251875Speter/* Poll method pollcb.
313251875Speter * This is probably usable only for WIN32 having WSAPoll
314251875Speter */
315251875Speterstatic apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb,
316251875Speter                                       apr_uint32_t size,
317251875Speter                                       apr_pool_t *p,
318251875Speter                                       apr_uint32_t flags)
319251875Speter{
320251875Speter#if APR_HAS_THREADS
321251875Speter    return APR_ENOTIMPL;
322251875Speter#else
323251875Speter    pollcb->fd = -1;
324251875Speter#ifdef WIN32
325251875Speter    if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) {
326251875Speter        return APR_ENOTIMPL;
327251875Speter    }
328251875Speter#endif
329251875Speter
330251875Speter    pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd));
331251875Speter    pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *));
332251875Speter
333251875Speter    return APR_SUCCESS;
334251875Speter#endif
335251875Speter}
336251875Speter
337251875Speterstatic apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb,
338251875Speter                                    apr_pollfd_t *descriptor)
339251875Speter{
340251875Speter    if (pollcb->nelts == pollcb->nalloc) {
341251875Speter        return APR_ENOMEM;
342251875Speter    }
343251875Speter
344251875Speter    if (descriptor->desc_type == APR_POLL_SOCKET) {
345251875Speter        pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes;
346251875Speter    }
347251875Speter    else {
348251875Speter#if APR_FILES_AS_SOCKETS
349251875Speter        pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes;
350251875Speter#else
351251875Speter        return APR_EBADF;
352251875Speter#endif
353251875Speter    }
354251875Speter
355251875Speter    pollcb->pollset.ps[pollcb->nelts].events =
356251875Speter        get_event(descriptor->reqevents);
357251875Speter    pollcb->copyset[pollcb->nelts] = descriptor;
358251875Speter    pollcb->nelts++;
359251875Speter
360251875Speter    return APR_SUCCESS;
361251875Speter}
362251875Speter
363251875Speterstatic apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb,
364251875Speter                                       apr_pollfd_t *descriptor)
365251875Speter{
366251875Speter    apr_uint32_t i;
367251875Speter
368251875Speter    for (i = 0; i < pollcb->nelts; i++) {
369251875Speter        if (descriptor->desc.s == pollcb->copyset[i]->desc.s) {
370251875Speter            /* Found an instance of the fd: remove this and any other copies */
371251875Speter            apr_uint32_t dst = i;
372251875Speter            apr_uint32_t old_nelts = pollcb->nelts;
373251875Speter            pollcb->nelts--;
374251875Speter            for (i++; i < old_nelts; i++) {
375251875Speter                if (descriptor->desc.s == pollcb->copyset[i]->desc.s) {
376251875Speter                    pollcb->nelts--;
377251875Speter                }
378251875Speter                else {
379251875Speter                    pollcb->pollset.ps[dst] = pollcb->pollset.ps[i];
380251875Speter                    pollcb->copyset[dst] = pollcb->copyset[i];
381251875Speter                    dst++;
382251875Speter                }
383251875Speter            }
384251875Speter            return APR_SUCCESS;
385251875Speter        }
386251875Speter    }
387251875Speter
388251875Speter    return APR_NOTFOUND;
389251875Speter}
390251875Speter
391251875Speterstatic apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb,
392251875Speter                                     apr_interval_time_t timeout,
393251875Speter                                     apr_pollcb_cb_t func,
394251875Speter                                     void *baton)
395251875Speter{
396251875Speter    int ret;
397251875Speter    apr_status_t rv = APR_SUCCESS;
398251875Speter    apr_uint32_t i;
399251875Speter
400289166Speter#ifdef WIN32
401289166Speter    /* WSAPoll() requires at least one socket. */
402289166Speter    if (pollcb->nelts == 0) {
403289166Speter        if (timeout > 0) {
404289166Speter            apr_sleep(timeout);
405289166Speter            return APR_TIMEUP;
406289166Speter        }
407289166Speter        return APR_SUCCESS;
408289166Speter    }
409251875Speter    if (timeout > 0) {
410251875Speter        timeout /= 1000;
411251875Speter    }
412251875Speter    ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout);
413251875Speter#else
414289166Speter    if (timeout > 0) {
415289166Speter        timeout /= 1000;
416289166Speter    }
417251875Speter    ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout);
418251875Speter#endif
419251875Speter    if (ret < 0) {
420251875Speter        return apr_get_netos_error();
421251875Speter    }
422251875Speter    else if (ret == 0) {
423251875Speter        return APR_TIMEUP;
424251875Speter    }
425251875Speter    else {
426251875Speter        for (i = 0; i < pollcb->nelts; i++) {
427251875Speter            if (pollcb->pollset.ps[i].revents != 0) {
428251875Speter                apr_pollfd_t *pollfd = pollcb->copyset[i];
429251875Speter                pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents);
430251875Speter                rv = func(baton, pollfd);
431251875Speter                if (rv) {
432251875Speter                    return rv;
433251875Speter                }
434251875Speter            }
435251875Speter        }
436251875Speter    }
437251875Speter    return rv;
438251875Speter}
439251875Speter
440251875Speterstatic apr_pollcb_provider_t impl_cb = {
441251875Speter    impl_pollcb_create,
442251875Speter    impl_pollcb_add,
443251875Speter    impl_pollcb_remove,
444251875Speter    impl_pollcb_poll,
445251875Speter    "poll"
446251875Speter};
447251875Speter
448251875Speterapr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb;
449251875Speter
450251875Speter#endif /* HAVE_POLL */
451