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#include "apr_arch_inherit.h"
30251875Speter
31251875Speterstatic apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD;
32251875Speter
33251875Speter#if !APR_FILES_AS_SOCKETS
34251875Speter#if defined (WIN32)
35251875Speter
36251875Speter/* Create a dummy wakeup socket pipe for interrupting the poller
37251875Speter */
38251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset)
39251875Speter{
40251875Speter    apr_status_t rv;
41251875Speter
42251875Speter    if ((rv = apr_file_socket_pipe_create(&pollset->wakeup_pipe[0],
43251875Speter                                          &pollset->wakeup_pipe[1],
44251875Speter                                          pollset->pool)) != APR_SUCCESS)
45251875Speter        return rv;
46251875Speter
47251875Speter    pollset->wakeup_pfd.p = pollset->pool;
48251875Speter    pollset->wakeup_pfd.reqevents = APR_POLLIN;
49251875Speter    pollset->wakeup_pfd.desc_type = APR_POLL_FILE;
50251875Speter    pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0];
51251875Speter
52251875Speter    return apr_pollset_add(pollset, &pollset->wakeup_pfd);
53251875Speter}
54251875Speter
55251875Speter#else  /* !WIN32 */
56251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset)
57251875Speter{
58251875Speter    return APR_ENOTIMPL;
59251875Speter}
60251875Speter
61251875Speterstatic apr_status_t apr_file_socket_pipe_close(apr_file_t *file)
62251875Speter{
63251875Speter    return APR_ENOTIMPL;
64251875Speter}
65251875Speter
66251875Speter#endif /* WIN32 */
67251875Speter#else  /* APR_FILES_AS_SOCKETS */
68251875Speter
69251875Speter/* Create a dummy wakeup pipe for interrupting the poller
70251875Speter */
71251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset)
72251875Speter{
73251875Speter    apr_status_t rv;
74251875Speter
75251875Speter    if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0],
76251875Speter                                   &pollset->wakeup_pipe[1],
77251875Speter                                   pollset->pool)) != APR_SUCCESS)
78251875Speter        return rv;
79251875Speter
80251875Speter    pollset->wakeup_pfd.p = pollset->pool;
81251875Speter    pollset->wakeup_pfd.reqevents = APR_POLLIN;
82251875Speter    pollset->wakeup_pfd.desc_type = APR_POLL_FILE;
83251875Speter    pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0];
84251875Speter
85251875Speter    {
86251875Speter        int flags;
87251875Speter
88251875Speter        if ((flags = fcntl(pollset->wakeup_pipe[0]->filedes, F_GETFD)) == -1)
89251875Speter            return errno;
90251875Speter
91251875Speter        flags |= FD_CLOEXEC;
92251875Speter        if (fcntl(pollset->wakeup_pipe[0]->filedes, F_SETFD, flags) == -1)
93251875Speter            return errno;
94251875Speter    }
95251875Speter    {
96251875Speter        int flags;
97251875Speter
98251875Speter        if ((flags = fcntl(pollset->wakeup_pipe[1]->filedes, F_GETFD)) == -1)
99251875Speter            return errno;
100251875Speter
101251875Speter        flags |= FD_CLOEXEC;
102251875Speter        if (fcntl(pollset->wakeup_pipe[1]->filedes, F_SETFD, flags) == -1)
103251875Speter            return errno;
104251875Speter    }
105251875Speter
106251875Speter    return apr_pollset_add(pollset, &pollset->wakeup_pfd);
107251875Speter}
108251875Speter#endif /* !APR_FILES_AS_SOCKETS */
109251875Speter
110251875Speter/* Read and discard what's ever in the wakeup pipe.
111251875Speter */
112251875Spetervoid apr_pollset_drain_wakeup_pipe(apr_pollset_t *pollset)
113251875Speter{
114251875Speter    char rb[512];
115251875Speter    apr_size_t nr = sizeof(rb);
116251875Speter
117251875Speter    while (apr_file_read(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) {
118251875Speter        /* Although we write just one byte to the other end of the pipe
119251875Speter         * during wakeup, multiple threads could call the wakeup.
120251875Speter         * So simply drain out from the input side of the pipe all
121251875Speter         * the data.
122251875Speter         */
123251875Speter        if (nr != sizeof(rb))
124251875Speter            break;
125251875Speter    }
126251875Speter}
127251875Speter
128251875Speterstatic apr_status_t pollset_cleanup(void *p)
129251875Speter{
130251875Speter    apr_pollset_t *pollset = (apr_pollset_t *) p;
131251875Speter    if (pollset->provider->cleanup) {
132251875Speter        (*pollset->provider->cleanup)(pollset);
133251875Speter    }
134251875Speter    if (pollset->flags & APR_POLLSET_WAKEABLE) {
135251875Speter        /* Close both sides of the wakeup pipe */
136251875Speter        if (pollset->wakeup_pipe[0]) {
137251875Speter#if APR_FILES_AS_SOCKETS
138251875Speter            apr_file_close(pollset->wakeup_pipe[0]);
139251875Speter#else
140251875Speter            apr_file_socket_pipe_close(pollset->wakeup_pipe[0]);
141251875Speter#endif
142251875Speter            pollset->wakeup_pipe[0] = NULL;
143251875Speter        }
144251875Speter        if (pollset->wakeup_pipe[1]) {
145251875Speter#if APR_FILES_AS_SOCKETS
146251875Speter            apr_file_close(pollset->wakeup_pipe[1]);
147251875Speter#else
148251875Speter            apr_file_socket_pipe_close(pollset->wakeup_pipe[1]);
149251875Speter#endif
150251875Speter            pollset->wakeup_pipe[1] = NULL;
151251875Speter        }
152251875Speter    }
153251875Speter
154251875Speter    return APR_SUCCESS;
155251875Speter}
156251875Speter
157251875Speter#if defined(HAVE_KQUEUE)
158251875Speterextern apr_pollset_provider_t *apr_pollset_provider_kqueue;
159251875Speter#endif
160251875Speter#if defined(HAVE_PORT_CREATE)
161251875Speterextern apr_pollset_provider_t *apr_pollset_provider_port;
162251875Speter#endif
163251875Speter#if defined(HAVE_EPOLL)
164251875Speterextern apr_pollset_provider_t *apr_pollset_provider_epoll;
165251875Speter#endif
166269847Speter#if defined(HAVE_AIO_MSGQ)
167269847Speterextern apr_pollset_provider_t *apr_pollset_provider_aio_msgq;
168269847Speter#endif
169251875Speter#if defined(HAVE_POLL)
170251875Speterextern apr_pollset_provider_t *apr_pollset_provider_poll;
171251875Speter#endif
172251875Speterextern apr_pollset_provider_t *apr_pollset_provider_select;
173251875Speter
174251875Speterstatic apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method)
175251875Speter{
176251875Speter    apr_pollset_provider_t *provider = NULL;
177251875Speter    switch (method) {
178251875Speter        case APR_POLLSET_KQUEUE:
179251875Speter#if defined(HAVE_KQUEUE)
180251875Speter            provider = apr_pollset_provider_kqueue;
181251875Speter#endif
182251875Speter        break;
183251875Speter        case APR_POLLSET_PORT:
184251875Speter#if defined(HAVE_PORT_CREATE)
185251875Speter            provider = apr_pollset_provider_port;
186251875Speter#endif
187251875Speter        break;
188251875Speter        case APR_POLLSET_EPOLL:
189251875Speter#if defined(HAVE_EPOLL)
190251875Speter            provider = apr_pollset_provider_epoll;
191251875Speter#endif
192251875Speter        break;
193269847Speter        case APR_POLLSET_AIO_MSGQ:
194269847Speter#if defined(HAVE_AIO_MSGQ)
195269847Speter            provider = apr_pollset_provider_aio_msgq;
196269847Speter#endif
197269847Speter        break;
198251875Speter        case APR_POLLSET_POLL:
199251875Speter#if defined(HAVE_POLL)
200251875Speter            provider = apr_pollset_provider_poll;
201251875Speter#endif
202251875Speter        break;
203251875Speter        case APR_POLLSET_SELECT:
204251875Speter            provider = apr_pollset_provider_select;
205251875Speter        break;
206251875Speter        case APR_POLLSET_DEFAULT:
207251875Speter        break;
208251875Speter    }
209251875Speter    return provider;
210251875Speter}
211251875Speter
212251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset,
213251875Speter                                                apr_uint32_t size,
214251875Speter                                                apr_pool_t *p,
215251875Speter                                                apr_uint32_t flags,
216251875Speter                                                apr_pollset_method_e method)
217251875Speter{
218251875Speter    apr_status_t rv;
219251875Speter    apr_pollset_t *pollset;
220251875Speter    apr_pollset_provider_t *provider = NULL;
221251875Speter
222251875Speter    *ret_pollset = NULL;
223251875Speter
224251875Speter #ifdef WIN32
225251875Speter    /* Favor WSAPoll if supported.
226251875Speter     * This will work only if ws2_32.dll has WSAPoll funtion.
227251875Speter     * In other cases it will fall back to select() method unless
228251875Speter     * the APR_POLLSET_NODEFAULT is added to the flags.
229251875Speter     */
230251875Speter    if (method == APR_POLLSET_DEFAULT) {
231251875Speter        method = APR_POLLSET_POLL;
232251875Speter    }
233251875Speter #endif
234251875Speter
235251875Speter    if (method == APR_POLLSET_DEFAULT)
236251875Speter        method = pollset_default_method;
237251875Speter    while (provider == NULL) {
238251875Speter        provider = pollset_provider(method);
239251875Speter        if (!provider) {
240251875Speter            if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT)
241251875Speter                return APR_ENOTIMPL;
242251875Speter            if (method == pollset_default_method)
243251875Speter                return APR_ENOTIMPL;
244251875Speter            method = pollset_default_method;
245251875Speter        }
246251875Speter    }
247251875Speter    if (flags & APR_POLLSET_WAKEABLE) {
248251875Speter        /* Add room for wakeup descriptor */
249251875Speter        size++;
250251875Speter    }
251251875Speter
252251875Speter    pollset = apr_palloc(p, sizeof(*pollset));
253251875Speter    pollset->nelts = 0;
254251875Speter    pollset->nalloc = size;
255251875Speter    pollset->pool = p;
256251875Speter    pollset->flags = flags;
257251875Speter    pollset->provider = provider;
258251875Speter
259251875Speter    rv = (*provider->create)(pollset, size, p, flags);
260251875Speter    if (rv == APR_ENOTIMPL) {
261251875Speter        if (method == pollset_default_method) {
262251875Speter            return rv;
263251875Speter        }
264251875Speter        provider = pollset_provider(pollset_default_method);
265251875Speter        if (!provider) {
266251875Speter            return APR_ENOTIMPL;
267251875Speter        }
268251875Speter        rv = (*provider->create)(pollset, size, p, flags);
269251875Speter        if (rv != APR_SUCCESS) {
270251875Speter            return rv;
271251875Speter        }
272251875Speter        pollset->provider = provider;
273251875Speter    }
274251875Speter    else if (rv != APR_SUCCESS) {
275251875Speter        return rv;
276251875Speter    }
277251875Speter    if (flags & APR_POLLSET_WAKEABLE) {
278251875Speter        /* Create wakeup pipe */
279251875Speter        if ((rv = create_wakeup_pipe(pollset)) != APR_SUCCESS) {
280251875Speter            return rv;
281251875Speter        }
282251875Speter    }
283251875Speter    if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup)
284251875Speter        apr_pool_cleanup_register(p, pollset, pollset_cleanup,
285251875Speter                                  apr_pool_cleanup_null);
286251875Speter
287251875Speter    *ret_pollset = pollset;
288251875Speter    return APR_SUCCESS;
289251875Speter}
290251875Speter
291251875SpeterAPR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset)
292251875Speter{
293251875Speter    return pollset->provider->name;
294251875Speter}
295251875Speter
296251875SpeterAPR_DECLARE(const char *) apr_poll_method_defname()
297251875Speter{
298251875Speter    apr_pollset_provider_t *provider = NULL;
299251875Speter
300251875Speter    provider = pollset_provider(pollset_default_method);
301251875Speter    if (provider)
302251875Speter        return provider->name;
303251875Speter    else
304251875Speter        return "unknown";
305251875Speter}
306251875Speter
307251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
308251875Speter                                             apr_uint32_t size,
309251875Speter                                             apr_pool_t *p,
310251875Speter                                             apr_uint32_t flags)
311251875Speter{
312251875Speter    apr_pollset_method_e method = APR_POLLSET_DEFAULT;
313251875Speter    return apr_pollset_create_ex(pollset, size, p, flags, method);
314251875Speter}
315251875Speter
316251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset)
317251875Speter{
318251875Speter    if (pollset->flags & APR_POLLSET_WAKEABLE ||
319251875Speter        pollset->provider->cleanup)
320251875Speter        return apr_pool_cleanup_run(pollset->pool, pollset,
321251875Speter                                    pollset_cleanup);
322251875Speter    else
323251875Speter        return APR_SUCCESS;
324251875Speter}
325251875Speter
326251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset)
327251875Speter{
328251875Speter    if (pollset->flags & APR_POLLSET_WAKEABLE)
329251875Speter        return apr_file_putc(1, pollset->wakeup_pipe[1]);
330251875Speter    else
331251875Speter        return APR_EINIT;
332251875Speter}
333251875Speter
334251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
335251875Speter                                          const apr_pollfd_t *descriptor)
336251875Speter{
337251875Speter    return (*pollset->provider->add)(pollset, descriptor);
338251875Speter}
339251875Speter
340251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
341251875Speter                                             const apr_pollfd_t *descriptor)
342251875Speter{
343251875Speter    return (*pollset->provider->remove)(pollset, descriptor);
344251875Speter}
345251875Speter
346251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
347251875Speter                                           apr_interval_time_t timeout,
348251875Speter                                           apr_int32_t *num,
349251875Speter                                           const apr_pollfd_t **descriptors)
350251875Speter{
351251875Speter    return (*pollset->provider->poll)(pollset, timeout, num, descriptors);
352251875Speter}
353