/src/httpd/srclib/apr/poll/unix/select.c
Line | Count | Source |
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 | | #ifdef POLL_USES_SELECT |
31 | | |
32 | | APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num, |
33 | | apr_int32_t *nsds, |
34 | | apr_interval_time_t timeout) |
35 | | { |
36 | | fd_set readset, writeset, exceptset; |
37 | | int rv, i; |
38 | | int maxfd = -1; |
39 | | struct timeval tv, *tvptr; |
40 | | |
41 | | #ifdef WIN32 |
42 | | /* On Win32, select() must be presented with at least one socket to |
43 | | * poll on, or select() will return WSAEINVAL. So, we'll just |
44 | | * short-circuit and bail now. |
45 | | */ |
46 | | if (num == 0) { |
47 | | (*nsds) = 0; |
48 | | if (timeout > 0) { |
49 | | apr_sleep(timeout); |
50 | | return APR_TIMEUP; |
51 | | } |
52 | | return APR_SUCCESS; |
53 | | } |
54 | | #endif |
55 | | |
56 | | if (timeout < 0) { |
57 | | tvptr = NULL; |
58 | | } |
59 | | else { |
60 | | tv.tv_sec = (long) apr_time_sec(timeout); |
61 | | tv.tv_usec = (long) apr_time_usec(timeout); |
62 | | tvptr = &tv; |
63 | | } |
64 | | |
65 | | FD_ZERO(&readset); |
66 | | FD_ZERO(&writeset); |
67 | | FD_ZERO(&exceptset); |
68 | | |
69 | | for (i = 0; i < num; i++) { |
70 | | apr_os_sock_t fd; |
71 | | |
72 | | aprset[i].rtnevents = 0; |
73 | | |
74 | | if (aprset[i].desc_type == APR_POLL_SOCKET) { |
75 | | fd = aprset[i].desc.s->socketdes; |
76 | | } |
77 | | else if (aprset[i].desc_type == APR_POLL_FILE) { |
78 | | #if !APR_FILES_AS_SOCKETS |
79 | | return APR_EBADF; |
80 | | #else |
81 | | |
82 | | fd = aprset[i].desc.f->filedes; |
83 | | |
84 | | #endif /* APR_FILES_AS_SOCKETS */ |
85 | | } |
86 | | else { |
87 | | break; |
88 | | } |
89 | | #if !defined(WIN32) /* socket sets handled with array of handles */ |
90 | | if (fd >= FD_SETSIZE) { |
91 | | /* XXX invent new error code so application has a clue */ |
92 | | return APR_EBADF; |
93 | | } |
94 | | #endif |
95 | | if (aprset[i].reqevents & APR_POLLIN) { |
96 | | FD_SET(fd, &readset); |
97 | | } |
98 | | if (aprset[i].reqevents & APR_POLLOUT) { |
99 | | FD_SET(fd, &writeset); |
100 | | } |
101 | | if (aprset[i].reqevents & |
102 | | (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) { |
103 | | FD_SET(fd, &exceptset); |
104 | | } |
105 | | if ((int) fd > maxfd) { |
106 | | maxfd = (int) fd; |
107 | | } |
108 | | } |
109 | | |
110 | | rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr); |
111 | | |
112 | | (*nsds) = rv; |
113 | | if ((*nsds) == 0) { |
114 | | return APR_TIMEUP; |
115 | | } |
116 | | if ((*nsds) < 0) { |
117 | | return apr_get_netos_error(); |
118 | | } |
119 | | |
120 | | (*nsds) = 0; |
121 | | for (i = 0; i < num; i++) { |
122 | | apr_os_sock_t fd; |
123 | | |
124 | | if (aprset[i].desc_type == APR_POLL_SOCKET) { |
125 | | fd = aprset[i].desc.s->socketdes; |
126 | | } |
127 | | else if (aprset[i].desc_type == APR_POLL_FILE) { |
128 | | #if !APR_FILES_AS_SOCKETS |
129 | | return APR_EBADF; |
130 | | #else |
131 | | fd = aprset[i].desc.f->filedes; |
132 | | #endif |
133 | | } |
134 | | else { |
135 | | break; |
136 | | } |
137 | | if (FD_ISSET(fd, &readset)) { |
138 | | aprset[i].rtnevents |= APR_POLLIN; |
139 | | } |
140 | | if (FD_ISSET(fd, &writeset)) { |
141 | | aprset[i].rtnevents |= APR_POLLOUT; |
142 | | } |
143 | | if (FD_ISSET(fd, &exceptset)) { |
144 | | aprset[i].rtnevents |= APR_POLLERR; |
145 | | } |
146 | | if (aprset[i].rtnevents) { |
147 | | (*nsds)++; |
148 | | } |
149 | | } |
150 | | |
151 | | return APR_SUCCESS; |
152 | | } |
153 | | |
154 | | #endif /* POLL_USES_SELECT */ |
155 | | |
156 | | struct apr_pollset_private_t |
157 | | { |
158 | | fd_set readset, writeset, exceptset; |
159 | | int maxfd; |
160 | | apr_pollfd_t *query_set; |
161 | | apr_pollfd_t *result_set; |
162 | | }; |
163 | | |
164 | | static apr_status_t impl_pollset_create(apr_pollset_t *pollset, |
165 | | apr_uint32_t size, |
166 | | apr_pool_t *p, |
167 | | apr_uint32_t flags) |
168 | 0 | { |
169 | 0 | if (flags & APR_POLLSET_THREADSAFE) { |
170 | 0 | pollset->p = NULL; |
171 | 0 | return APR_ENOTIMPL; |
172 | 0 | } |
173 | 0 | #ifdef FD_SETSIZE |
174 | 0 | if (size > FD_SETSIZE) { |
175 | 0 | pollset->p = NULL; |
176 | 0 | return APR_EINVAL; |
177 | 0 | } |
178 | 0 | #endif |
179 | 0 | pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); |
180 | 0 | FD_ZERO(&(pollset->p->readset)); |
181 | 0 | FD_ZERO(&(pollset->p->writeset)); |
182 | 0 | FD_ZERO(&(pollset->p->exceptset)); |
183 | 0 | pollset->p->maxfd = 0; |
184 | 0 | pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); |
185 | 0 | pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); |
186 | |
|
187 | 0 | return APR_SUCCESS; |
188 | 0 | } |
189 | | |
190 | | static apr_status_t impl_pollset_add(apr_pollset_t *pollset, |
191 | | const apr_pollfd_t *descriptor) |
192 | 0 | { |
193 | 0 | apr_os_sock_t fd; |
194 | |
|
195 | 0 | if (pollset->nelts == pollset->nalloc) { |
196 | 0 | return APR_ENOMEM; |
197 | 0 | } |
198 | | |
199 | 0 | pollset->p->query_set[pollset->nelts] = *descriptor; |
200 | |
|
201 | 0 | if (descriptor->desc_type == APR_POLL_SOCKET) { |
202 | 0 | fd = descriptor->desc.s->socketdes; |
203 | 0 | } |
204 | 0 | else { |
205 | | #if !APR_FILES_AS_SOCKETS |
206 | | return APR_EBADF; |
207 | | #else |
208 | 0 | fd = descriptor->desc.f->filedes; |
209 | 0 | #endif |
210 | 0 | } |
211 | 0 | #if !defined(WIN32) /* socket sets handled with array of handles */ |
212 | 0 | if (fd >= FD_SETSIZE) { |
213 | | /* XXX invent new error code so application has a clue */ |
214 | 0 | return APR_EBADF; |
215 | 0 | } |
216 | 0 | #endif |
217 | 0 | if (descriptor->reqevents & APR_POLLIN) { |
218 | 0 | FD_SET(fd, &(pollset->p->readset)); |
219 | 0 | } |
220 | 0 | if (descriptor->reqevents & APR_POLLOUT) { |
221 | 0 | FD_SET(fd, &(pollset->p->writeset)); |
222 | 0 | } |
223 | 0 | if (descriptor->reqevents & |
224 | 0 | (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) { |
225 | 0 | FD_SET(fd, &(pollset->p->exceptset)); |
226 | 0 | } |
227 | 0 | if ((int) fd > pollset->p->maxfd) { |
228 | 0 | pollset->p->maxfd = (int) fd; |
229 | 0 | } |
230 | 0 | pollset->nelts++; |
231 | 0 | return APR_SUCCESS; |
232 | 0 | } |
233 | | |
234 | | static apr_status_t impl_pollset_remove(apr_pollset_t * pollset, |
235 | | const apr_pollfd_t * descriptor) |
236 | 0 | { |
237 | 0 | apr_uint32_t i; |
238 | 0 | apr_os_sock_t fd; |
239 | |
|
240 | 0 | if (descriptor->desc_type == APR_POLL_SOCKET) { |
241 | 0 | fd = descriptor->desc.s->socketdes; |
242 | 0 | } |
243 | 0 | else { |
244 | | #if !APR_FILES_AS_SOCKETS |
245 | | return APR_EBADF; |
246 | | #else |
247 | 0 | fd = descriptor->desc.f->filedes; |
248 | 0 | #endif |
249 | 0 | } |
250 | |
|
251 | 0 | for (i = 0; i < pollset->nelts; i++) { |
252 | 0 | if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { |
253 | | /* Found an instance of the fd: remove this and any other copies */ |
254 | 0 | apr_uint32_t dst = i; |
255 | 0 | apr_uint32_t old_nelts = pollset->nelts; |
256 | 0 | pollset->nelts--; |
257 | 0 | for (i++; i < old_nelts; i++) { |
258 | 0 | if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { |
259 | 0 | pollset->nelts--; |
260 | 0 | } |
261 | 0 | else { |
262 | 0 | pollset->p->query_set[dst] = pollset->p->query_set[i]; |
263 | 0 | dst++; |
264 | 0 | } |
265 | 0 | } |
266 | 0 | FD_CLR(fd, &(pollset->p->readset)); |
267 | 0 | FD_CLR(fd, &(pollset->p->writeset)); |
268 | 0 | FD_CLR(fd, &(pollset->p->exceptset)); |
269 | 0 | if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) { |
270 | 0 | pollset->p->maxfd--; |
271 | 0 | } |
272 | 0 | return APR_SUCCESS; |
273 | 0 | } |
274 | 0 | } |
275 | | |
276 | 0 | return APR_NOTFOUND; |
277 | 0 | } |
278 | | |
279 | | static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, |
280 | | apr_interval_time_t timeout, |
281 | | apr_int32_t *num, |
282 | | const apr_pollfd_t **descriptors) |
283 | 0 | { |
284 | 0 | int rs; |
285 | 0 | apr_uint32_t i, j; |
286 | 0 | struct timeval tv, *tvptr; |
287 | 0 | fd_set readset, writeset, exceptset; |
288 | 0 | apr_status_t rv = APR_SUCCESS; |
289 | |
|
290 | 0 | *num = 0; |
291 | |
|
292 | | #ifdef WIN32 |
293 | | /* On Win32, select() must be presented with at least one socket to |
294 | | * poll on, or select() will return WSAEINVAL. So, we'll just |
295 | | * short-circuit and bail now. |
296 | | */ |
297 | | if (pollset->nelts == 0) { |
298 | | if (timeout > 0) { |
299 | | apr_sleep(timeout); |
300 | | return APR_TIMEUP; |
301 | | } |
302 | | return APR_SUCCESS; |
303 | | } |
304 | | #endif |
305 | |
|
306 | 0 | if (timeout < 0) { |
307 | 0 | tvptr = NULL; |
308 | 0 | } |
309 | 0 | else { |
310 | 0 | tv.tv_sec = (long) apr_time_sec(timeout); |
311 | 0 | tv.tv_usec = (long) apr_time_usec(timeout); |
312 | 0 | tvptr = &tv; |
313 | 0 | } |
314 | |
|
315 | 0 | memcpy(&readset, &(pollset->p->readset), sizeof(fd_set)); |
316 | 0 | memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set)); |
317 | 0 | memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set)); |
318 | |
|
319 | 0 | rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset, |
320 | 0 | tvptr); |
321 | |
|
322 | 0 | if (rs < 0) { |
323 | 0 | return apr_get_netos_error(); |
324 | 0 | } |
325 | 0 | if (rs == 0) { |
326 | 0 | return APR_TIMEUP; |
327 | 0 | } |
328 | 0 | j = 0; |
329 | 0 | for (i = 0; i < pollset->nelts; i++) { |
330 | 0 | apr_os_sock_t fd; |
331 | |
|
332 | 0 | if (pollset->flags & APR_POLLSET_WAKEABLE) { |
333 | 0 | #if WAKEUP_USES_PIPE |
334 | 0 | if (pollset->p->query_set[i].desc_type == APR_POLL_FILE && |
335 | 0 | pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { |
336 | 0 | apr_poll_drain_wakeup_pipe(&pollset->wakeup_set, pollset->wakeup_pipe); |
337 | 0 | rv = APR_EINTR; |
338 | 0 | continue; |
339 | 0 | } |
340 | | #else |
341 | | if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET && |
342 | | pollset->p->query_set[i].desc.s == pollset->wakeup_socket[0]) { |
343 | | apr_poll_drain_wakeup_socket(&pollset->wakeup_set, pollset->wakeup_socket); |
344 | | rv = APR_EINTR; |
345 | | continue; |
346 | | } |
347 | | #endif |
348 | 0 | } |
349 | | |
350 | 0 | if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) { |
351 | 0 | fd = pollset->p->query_set[i].desc.s->socketdes; |
352 | 0 | } |
353 | 0 | else { |
354 | | #if !APR_FILES_AS_SOCKETS |
355 | | return APR_EBADF; |
356 | | #else |
357 | 0 | fd = pollset->p->query_set[i].desc.f->filedes; |
358 | 0 | #endif |
359 | 0 | } |
360 | 0 | if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) || |
361 | 0 | FD_ISSET(fd, &exceptset)) { |
362 | 0 | pollset->p->result_set[j] = pollset->p->query_set[i]; |
363 | 0 | pollset->p->result_set[j].rtnevents = 0; |
364 | 0 | if (FD_ISSET(fd, &readset)) { |
365 | 0 | pollset->p->result_set[j].rtnevents |= APR_POLLIN; |
366 | 0 | } |
367 | 0 | if (FD_ISSET(fd, &writeset)) { |
368 | 0 | pollset->p->result_set[j].rtnevents |= APR_POLLOUT; |
369 | 0 | } |
370 | 0 | if (FD_ISSET(fd, &exceptset)) { |
371 | 0 | pollset->p->result_set[j].rtnevents |= APR_POLLERR; |
372 | 0 | } |
373 | 0 | j++; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | if (((*num) = j) != 0) |
377 | 0 | rv = APR_SUCCESS; |
378 | |
|
379 | 0 | if (descriptors) |
380 | 0 | *descriptors = pollset->p->result_set; |
381 | 0 | return rv; |
382 | 0 | } |
383 | | |
384 | | static const apr_pollset_provider_t impl = { |
385 | | impl_pollset_create, |
386 | | impl_pollset_add, |
387 | | impl_pollset_remove, |
388 | | impl_pollset_poll, |
389 | | NULL, |
390 | | "select" |
391 | | }; |
392 | | |
393 | | const apr_pollset_provider_t *apr_pollset_provider_select = &impl; |