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#include "apr_arch_inherit.h"
30
31static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD;
32
33static apr_status_t pollset_cleanup(void *p)
34{
35    apr_pollset_t *pollset = (apr_pollset_t *) p;
36    if (pollset->provider->cleanup) {
37        (*pollset->provider->cleanup)(pollset);
38    }
39    if (pollset->flags & APR_POLLSET_WAKEABLE) {
40        apr_poll_close_wakeup_pipe(pollset->wakeup_pipe);
41    }
42
43    return APR_SUCCESS;
44}
45
46#if defined(HAVE_KQUEUE)
47extern const apr_pollset_provider_t *apr_pollset_provider_kqueue;
48#endif
49#if defined(HAVE_PORT_CREATE)
50extern const apr_pollset_provider_t *apr_pollset_provider_port;
51#endif
52#if defined(HAVE_EPOLL)
53extern const apr_pollset_provider_t *apr_pollset_provider_epoll;
54#endif
55#if defined(HAVE_AIO_MSGQ)
56extern const apr_pollset_provider_t *apr_pollset_provider_aio_msgq;
57#endif
58#if defined(HAVE_POLL)
59extern const apr_pollset_provider_t *apr_pollset_provider_poll;
60#endif
61extern const apr_pollset_provider_t *apr_pollset_provider_select;
62
63static const apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method)
64{
65    const apr_pollset_provider_t *provider = NULL;
66    switch (method) {
67        case APR_POLLSET_KQUEUE:
68#if defined(HAVE_KQUEUE)
69            provider = apr_pollset_provider_kqueue;
70#endif
71        break;
72        case APR_POLLSET_PORT:
73#if defined(HAVE_PORT_CREATE)
74            provider = apr_pollset_provider_port;
75#endif
76        break;
77        case APR_POLLSET_EPOLL:
78#if defined(HAVE_EPOLL)
79            provider = apr_pollset_provider_epoll;
80#endif
81        break;
82        case APR_POLLSET_AIO_MSGQ:
83#if defined(HAVE_AIO_MSGQ)
84            provider = apr_pollset_provider_aio_msgq;
85#endif
86        break;
87        case APR_POLLSET_POLL:
88#if defined(HAVE_POLL)
89            provider = apr_pollset_provider_poll;
90#endif
91        break;
92        case APR_POLLSET_SELECT:
93            provider = apr_pollset_provider_select;
94        break;
95        case APR_POLLSET_DEFAULT:
96        break;
97    }
98    return provider;
99}
100
101APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset,
102                                                apr_uint32_t size,
103                                                apr_pool_t *p,
104                                                apr_uint32_t flags,
105                                                apr_pollset_method_e method)
106{
107    apr_status_t rv;
108    apr_pollset_t *pollset;
109    const apr_pollset_provider_t *provider = NULL;
110
111    *ret_pollset = NULL;
112
113 #ifdef WIN32
114    /* Favor WSAPoll if supported.
115     * This will work only if ws2_32.dll has WSAPoll funtion.
116     * In other cases it will fall back to select() method unless
117     * the APR_POLLSET_NODEFAULT is added to the flags.
118     */
119    if (method == APR_POLLSET_DEFAULT) {
120        method = APR_POLLSET_POLL;
121    }
122 #endif
123
124    if (method == APR_POLLSET_DEFAULT)
125        method = pollset_default_method;
126    while (provider == NULL) {
127        provider = pollset_provider(method);
128        if (!provider) {
129            if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT)
130                return APR_ENOTIMPL;
131            if (method == pollset_default_method)
132                return APR_ENOTIMPL;
133            method = pollset_default_method;
134        }
135    }
136    if (flags & APR_POLLSET_WAKEABLE) {
137        /* Add room for wakeup descriptor */
138        size++;
139    }
140
141    pollset = apr_palloc(p, sizeof(*pollset));
142    pollset->nelts = 0;
143    pollset->nalloc = size;
144    pollset->pool = p;
145    pollset->flags = flags;
146    pollset->provider = provider;
147
148    rv = (*provider->create)(pollset, size, p, flags);
149    if (rv == APR_ENOTIMPL) {
150        if (method == pollset_default_method) {
151            return rv;
152        }
153        provider = pollset_provider(pollset_default_method);
154        if (!provider) {
155            return APR_ENOTIMPL;
156        }
157        rv = (*provider->create)(pollset, size, p, flags);
158        if (rv != APR_SUCCESS) {
159            return rv;
160        }
161        pollset->provider = provider;
162    }
163    else if (rv != APR_SUCCESS) {
164        return rv;
165    }
166    if (flags & APR_POLLSET_WAKEABLE) {
167        /* Create wakeup pipe */
168        if ((rv = apr_poll_create_wakeup_pipe(pollset->pool, &pollset->wakeup_pfd,
169                                              pollset->wakeup_pipe))
170                != APR_SUCCESS) {
171            return rv;
172        }
173
174        if ((rv = apr_pollset_add(pollset, &pollset->wakeup_pfd)) != APR_SUCCESS) {
175            return rv;
176        }
177    }
178    if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup)
179        apr_pool_cleanup_register(p, pollset, pollset_cleanup,
180                                  apr_pool_cleanup_null);
181
182    *ret_pollset = pollset;
183    return APR_SUCCESS;
184}
185
186APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset)
187{
188    return pollset->provider->name;
189}
190
191APR_DECLARE(const char *) apr_poll_method_defname()
192{
193    const apr_pollset_provider_t *provider = NULL;
194
195    provider = pollset_provider(pollset_default_method);
196    if (provider)
197        return provider->name;
198    else
199        return "unknown";
200}
201
202APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
203                                             apr_uint32_t size,
204                                             apr_pool_t *p,
205                                             apr_uint32_t flags)
206{
207    apr_pollset_method_e method = APR_POLLSET_DEFAULT;
208    return apr_pollset_create_ex(pollset, size, p, flags, method);
209}
210
211APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset)
212{
213    if (pollset->flags & APR_POLLSET_WAKEABLE ||
214        pollset->provider->cleanup)
215        return apr_pool_cleanup_run(pollset->pool, pollset,
216                                    pollset_cleanup);
217    else
218        return APR_SUCCESS;
219}
220
221APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset)
222{
223    if (pollset->flags & APR_POLLSET_WAKEABLE)
224        return apr_file_putc(1, pollset->wakeup_pipe[1]);
225    else
226        return APR_EINIT;
227}
228
229APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
230                                          const apr_pollfd_t *descriptor)
231{
232    return (*pollset->provider->add)(pollset, descriptor);
233}
234
235APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
236                                             const apr_pollfd_t *descriptor)
237{
238    return (*pollset->provider->remove)(pollset, descriptor);
239}
240
241APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
242                                           apr_interval_time_t timeout,
243                                           apr_int32_t *num,
244                                           const apr_pollfd_t **descriptors)
245{
246    return (*pollset->provider->poll)(pollset, timeout, num, descriptors);
247}
248