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 32APR_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 185struct 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 197static 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 226static 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 294static 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 339static 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 440static 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 449apr_pollset_provider_t *apr_pollset_provider_select = &impl; 450