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