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 static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD;
31 #if defined(HAVE_KQUEUE)
32 extern const apr_pollcb_provider_t *apr_pollcb_provider_kqueue;
33 #endif
34 #if defined(HAVE_PORT_CREATE)
35 extern const apr_pollcb_provider_t *apr_pollcb_provider_port;
36 #endif
37 #if defined(HAVE_EPOLL)
38 extern const apr_pollcb_provider_t *apr_pollcb_provider_epoll;
39 #endif
40 #if defined(HAVE_POLL)
41 extern const apr_pollcb_provider_t *apr_pollcb_provider_poll;
42 #endif
43 
pollcb_provider(apr_pollset_method_e method)44 static const apr_pollcb_provider_t *pollcb_provider(apr_pollset_method_e method)
45 {
46     const apr_pollcb_provider_t *provider = NULL;
47     switch (method) {
48         case APR_POLLSET_KQUEUE:
49 #if defined(HAVE_KQUEUE)
50             provider = apr_pollcb_provider_kqueue;
51 #endif
52         break;
53         case APR_POLLSET_PORT:
54 #if defined(HAVE_PORT_CREATE)
55             provider = apr_pollcb_provider_port;
56 #endif
57         break;
58         case APR_POLLSET_EPOLL:
59 #if defined(HAVE_EPOLL)
60             provider = apr_pollcb_provider_epoll;
61 #endif
62         break;
63         case APR_POLLSET_POLL:
64 #if defined(HAVE_POLL)
65             provider = apr_pollcb_provider_poll;
66 #endif
67         break;
68         case APR_POLLSET_SELECT:
69         case APR_POLLSET_AIO_MSGQ:
70         case APR_POLLSET_DEFAULT:
71         break;
72     }
73     return provider;
74 }
75 
pollcb_cleanup(void * p)76 static apr_status_t pollcb_cleanup(void *p)
77 {
78     apr_pollcb_t *pollcb = (apr_pollcb_t *) p;
79 
80     if (pollcb->provider->cleanup) {
81         (*pollcb->provider->cleanup)(pollcb);
82     }
83     if (pollcb->flags & APR_POLLSET_WAKEABLE) {
84         apr_poll_close_wakeup_pipe(pollcb->wakeup_pipe);
85     }
86 
87     return APR_SUCCESS;
88 }
89 
apr_pollcb_create_ex(apr_pollcb_t ** ret_pollcb,apr_uint32_t size,apr_pool_t * p,apr_uint32_t flags,apr_pollset_method_e method)90 APR_DECLARE(apr_status_t) apr_pollcb_create_ex(apr_pollcb_t **ret_pollcb,
91                                                apr_uint32_t size,
92                                                apr_pool_t *p,
93                                                apr_uint32_t flags,
94                                                apr_pollset_method_e method)
95 {
96     apr_status_t rv;
97     apr_pollcb_t *pollcb;
98     const apr_pollcb_provider_t *provider = NULL;
99 
100     *ret_pollcb = NULL;
101 
102  #ifdef WIN32
103     /* This will work only if ws2_32.dll has WSAPoll funtion.
104      * We could check the presence of the function here,
105      * but someone might implement other pollcb method in
106      * the future.
107      */
108     if (method == APR_POLLSET_DEFAULT) {
109         method = APR_POLLSET_POLL;
110     }
111  #endif
112 
113     if (method == APR_POLLSET_DEFAULT)
114         method = pollset_default_method;
115     while (provider == NULL) {
116         provider = pollcb_provider(method);
117         if (!provider) {
118             if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT)
119                 return APR_ENOTIMPL;
120             if (method == pollset_default_method)
121                 return APR_ENOTIMPL;
122             method = pollset_default_method;
123         }
124     }
125 
126     if (flags & APR_POLLSET_WAKEABLE) {
127         /* Add room for wakeup descriptor */
128         size++;
129     }
130 
131     pollcb = apr_palloc(p, sizeof(*pollcb));
132     pollcb->nelts = 0;
133     pollcb->nalloc = size;
134     pollcb->flags = flags;
135     pollcb->pool = p;
136     pollcb->provider = provider;
137 
138     rv = (*provider->create)(pollcb, size, p, flags);
139     if (rv == APR_ENOTIMPL) {
140         if (method == pollset_default_method) {
141             return rv;
142         }
143 
144         if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) {
145             return rv;
146         }
147 
148         /* Try with default provider */
149         provider = pollcb_provider(pollset_default_method);
150         if (!provider) {
151             return APR_ENOTIMPL;
152         }
153         rv = (*provider->create)(pollcb, size, p, flags);
154         if (rv != APR_SUCCESS) {
155             return rv;
156         }
157         pollcb->provider = provider;
158     }
159     else if (rv != APR_SUCCESS) {
160         return rv;
161     }
162 
163     if (flags & APR_POLLSET_WAKEABLE) {
164         /* Create wakeup pipe */
165         if ((rv = apr_poll_create_wakeup_pipe(pollcb->pool, &pollcb->wakeup_pfd,
166                                               pollcb->wakeup_pipe))
167                 != APR_SUCCESS) {
168             return rv;
169         }
170 
171         if ((rv = apr_pollcb_add(pollcb, &pollcb->wakeup_pfd)) != APR_SUCCESS) {
172             return rv;
173         }
174     }
175     if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup)
176         apr_pool_cleanup_register(p, pollcb, pollcb_cleanup,
177                                   apr_pool_cleanup_null);
178 
179     *ret_pollcb = pollcb;
180     return APR_SUCCESS;
181 }
182 
apr_pollcb_create(apr_pollcb_t ** pollcb,apr_uint32_t size,apr_pool_t * p,apr_uint32_t flags)183 APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb,
184                                             apr_uint32_t size,
185                                             apr_pool_t *p,
186                                             apr_uint32_t flags)
187 {
188     apr_pollset_method_e method = APR_POLLSET_DEFAULT;
189     return apr_pollcb_create_ex(pollcb, size, p, flags, method);
190 }
191 
apr_pollcb_add(apr_pollcb_t * pollcb,apr_pollfd_t * descriptor)192 APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb,
193                                          apr_pollfd_t *descriptor)
194 {
195     return (*pollcb->provider->add)(pollcb, descriptor);
196 }
197 
apr_pollcb_remove(apr_pollcb_t * pollcb,apr_pollfd_t * descriptor)198 APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb,
199                                             apr_pollfd_t *descriptor)
200 {
201     return (*pollcb->provider->remove)(pollcb, descriptor);
202 }
203 
204 
apr_pollcb_poll(apr_pollcb_t * pollcb,apr_interval_time_t timeout,apr_pollcb_cb_t func,void * baton)205 APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb,
206                                           apr_interval_time_t timeout,
207                                           apr_pollcb_cb_t func,
208                                           void *baton)
209 {
210     return (*pollcb->provider->poll)(pollcb, timeout, func, baton);
211 }
212 
apr_pollcb_wakeup(apr_pollcb_t * pollcb)213 APR_DECLARE(apr_status_t) apr_pollcb_wakeup(apr_pollcb_t *pollcb)
214 {
215     if (pollcb->flags & APR_POLLSET_WAKEABLE)
216         return apr_file_putc(1, pollcb->wakeup_pipe[1]);
217     else
218         return APR_EINIT;
219 }
220 
apr_pollcb_method_name(apr_pollcb_t * pollcb)221 APR_DECLARE(const char *) apr_pollcb_method_name(apr_pollcb_t *pollcb)
222 {
223     return pollcb->provider->name;
224 }
225