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