1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr.h" 18251875Speter#include "apr_poll.h" 19251875Speter#include "apr_time.h" 20251875Speter#include "apr_portable.h" 21251875Speter#include "apr_arch_file_io.h" 22251875Speter#include "apr_arch_networkio.h" 23251875Speter#include "apr_arch_misc.h" 24251875Speter#include "apr_arch_poll_private.h" 25251875Speter 26251875Speter#if defined(HAVE_POLL) 27251875Speter 28251875Speter#ifdef HAVE_ALLOCA_H 29251875Speter#include <alloca.h> 30251875Speter#endif 31251875Speter 32251875Speterstatic apr_int16_t get_event(apr_int16_t event) 33251875Speter{ 34251875Speter apr_int16_t rv = 0; 35251875Speter 36251875Speter if (event & APR_POLLIN) 37251875Speter rv |= POLLIN; 38251875Speter if (event & APR_POLLPRI) 39251875Speter rv |= POLLPRI; 40251875Speter if (event & APR_POLLOUT) 41251875Speter rv |= POLLOUT; 42251875Speter /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */ 43251875Speter 44251875Speter return rv; 45251875Speter} 46251875Speter 47251875Speterstatic apr_int16_t get_revent(apr_int16_t event) 48251875Speter{ 49251875Speter apr_int16_t rv = 0; 50251875Speter 51251875Speter if (event & POLLIN) 52251875Speter rv |= APR_POLLIN; 53251875Speter if (event & POLLPRI) 54251875Speter rv |= APR_POLLPRI; 55251875Speter if (event & POLLOUT) 56251875Speter rv |= APR_POLLOUT; 57251875Speter if (event & POLLERR) 58251875Speter rv |= APR_POLLERR; 59251875Speter if (event & POLLHUP) 60251875Speter rv |= APR_POLLHUP; 61251875Speter if (event & POLLNVAL) 62251875Speter rv |= APR_POLLNVAL; 63251875Speter 64251875Speter return rv; 65251875Speter} 66251875Speter 67251875Speter#ifdef POLL_USES_POLL 68251875Speter 69251875Speter#define SMALL_POLLSET_LIMIT 8 70251875Speter 71251875SpeterAPR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num, 72251875Speter apr_int32_t *nsds, 73251875Speter apr_interval_time_t timeout) 74251875Speter{ 75251875Speter int i, num_to_poll; 76251875Speter#ifdef HAVE_VLA 77251875Speter /* XXX: I trust that this is a segv when insufficient stack exists? */ 78251875Speter struct pollfd pollset[num]; 79251875Speter#elif defined(HAVE_ALLOCA) 80251875Speter struct pollfd *pollset = alloca(sizeof(struct pollfd) * num); 81251875Speter if (!pollset) 82251875Speter return APR_ENOMEM; 83251875Speter#else 84251875Speter struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT]; 85251875Speter struct pollfd *pollset; 86251875Speter 87251875Speter if (num <= SMALL_POLLSET_LIMIT) { 88251875Speter pollset = tmp_pollset; 89251875Speter } 90251875Speter else { 91251875Speter /* This does require O(n) to copy the descriptors to the internal 92251875Speter * mapping. 93251875Speter */ 94251875Speter pollset = malloc(sizeof(struct pollfd) * num); 95251875Speter /* The other option is adding an apr_pool_abort() fn to invoke 96251875Speter * the pool's out of memory handler 97251875Speter */ 98251875Speter if (!pollset) 99251875Speter return APR_ENOMEM; 100251875Speter } 101251875Speter#endif 102251875Speter for (i = 0; i < num; i++) { 103251875Speter if (aprset[i].desc_type == APR_POLL_SOCKET) { 104251875Speter pollset[i].fd = aprset[i].desc.s->socketdes; 105251875Speter } 106251875Speter else if (aprset[i].desc_type == APR_POLL_FILE) { 107251875Speter pollset[i].fd = aprset[i].desc.f->filedes; 108251875Speter } 109251875Speter else { 110251875Speter break; 111251875Speter } 112251875Speter pollset[i].events = get_event(aprset[i].reqevents); 113251875Speter } 114251875Speter num_to_poll = i; 115251875Speter 116251875Speter if (timeout > 0) { 117251875Speter timeout /= 1000; /* convert microseconds to milliseconds */ 118251875Speter } 119251875Speter 120251875Speter i = poll(pollset, num_to_poll, timeout); 121251875Speter (*nsds) = i; 122251875Speter 123251875Speter if (i > 0) { /* poll() sets revents only if an event was signalled; 124251875Speter * we don't promise to set rtnevents unless an event 125251875Speter * was signalled 126251875Speter */ 127251875Speter for (i = 0; i < num; i++) { 128251875Speter aprset[i].rtnevents = get_revent(pollset[i].revents); 129251875Speter } 130251875Speter } 131251875Speter 132251875Speter#if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA) 133251875Speter if (num > SMALL_POLLSET_LIMIT) { 134251875Speter free(pollset); 135251875Speter } 136251875Speter#endif 137251875Speter 138251875Speter if ((*nsds) < 0) { 139251875Speter return apr_get_netos_error(); 140251875Speter } 141251875Speter if ((*nsds) == 0) { 142251875Speter return APR_TIMEUP; 143251875Speter } 144251875Speter return APR_SUCCESS; 145251875Speter} 146251875Speter 147251875Speter 148251875Speter#endif /* POLL_USES_POLL */ 149251875Speter 150251875Speterstruct apr_pollset_private_t 151251875Speter{ 152251875Speter struct pollfd *pollset; 153251875Speter apr_pollfd_t *query_set; 154251875Speter apr_pollfd_t *result_set; 155251875Speter}; 156251875Speter 157251875Speterstatic apr_status_t impl_pollset_create(apr_pollset_t *pollset, 158251875Speter apr_uint32_t size, 159251875Speter apr_pool_t *p, 160251875Speter apr_uint32_t flags) 161251875Speter{ 162251875Speter if (flags & APR_POLLSET_THREADSAFE) { 163251875Speter return APR_ENOTIMPL; 164251875Speter } 165251875Speter#ifdef WIN32 166251875Speter if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { 167251875Speter return APR_ENOTIMPL; 168251875Speter } 169251875Speter#endif 170251875Speter pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); 171251875Speter pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd)); 172251875Speter pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); 173251875Speter pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); 174251875Speter 175251875Speter return APR_SUCCESS; 176251875Speter} 177251875Speter 178251875Speterstatic apr_status_t impl_pollset_add(apr_pollset_t *pollset, 179251875Speter const apr_pollfd_t *descriptor) 180251875Speter{ 181251875Speter if (pollset->nelts == pollset->nalloc) { 182251875Speter return APR_ENOMEM; 183251875Speter } 184251875Speter 185251875Speter pollset->p->query_set[pollset->nelts] = *descriptor; 186251875Speter 187251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 188251875Speter pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes; 189251875Speter } 190251875Speter else { 191251875Speter#if APR_FILES_AS_SOCKETS 192251875Speter pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes; 193251875Speter#else 194251875Speter if ((pollset->flags & APR_POLLSET_WAKEABLE) && 195251875Speter descriptor->desc.f == pollset->wakeup_pipe[0]) 196251875Speter pollset->p->pollset[pollset->nelts].fd = (SOCKET)descriptor->desc.f->filedes; 197251875Speter else 198251875Speter return APR_EBADF; 199251875Speter#endif 200251875Speter } 201251875Speter pollset->p->pollset[pollset->nelts].events = 202251875Speter get_event(descriptor->reqevents); 203251875Speter pollset->nelts++; 204251875Speter 205251875Speter return APR_SUCCESS; 206251875Speter} 207251875Speter 208251875Speterstatic apr_status_t impl_pollset_remove(apr_pollset_t *pollset, 209251875Speter const apr_pollfd_t *descriptor) 210251875Speter{ 211251875Speter apr_uint32_t i; 212251875Speter 213251875Speter for (i = 0; i < pollset->nelts; i++) { 214251875Speter if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { 215251875Speter /* Found an instance of the fd: remove this and any other copies */ 216251875Speter apr_uint32_t dst = i; 217251875Speter apr_uint32_t old_nelts = pollset->nelts; 218251875Speter pollset->nelts--; 219251875Speter for (i++; i < old_nelts; i++) { 220251875Speter if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { 221251875Speter pollset->nelts--; 222251875Speter } 223251875Speter else { 224251875Speter pollset->p->pollset[dst] = pollset->p->pollset[i]; 225251875Speter pollset->p->query_set[dst] = pollset->p->query_set[i]; 226251875Speter dst++; 227251875Speter } 228251875Speter } 229251875Speter return APR_SUCCESS; 230251875Speter } 231251875Speter } 232251875Speter 233251875Speter return APR_NOTFOUND; 234251875Speter} 235251875Speter 236251875Speterstatic apr_status_t impl_pollset_poll(apr_pollset_t *pollset, 237251875Speter apr_interval_time_t timeout, 238251875Speter apr_int32_t *num, 239251875Speter const apr_pollfd_t **descriptors) 240251875Speter{ 241251875Speter int ret; 242251875Speter apr_status_t rv = APR_SUCCESS; 243251875Speter 244251875Speter#ifdef WIN32 245251875Speter /* WSAPoll() requires at least one socket. */ 246251875Speter if (pollset->nelts == 0) { 247251875Speter *num = 0; 248289166Speter if (timeout > 0) { 249289166Speter apr_sleep(timeout); 250251875Speter return APR_TIMEUP; 251251875Speter } 252251875Speter return APR_SUCCESS; 253251875Speter } 254289166Speter if (timeout > 0) { 255289166Speter timeout /= 1000; 256289166Speter } 257251875Speter ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout); 258251875Speter#else 259289166Speter if (timeout > 0) { 260289166Speter timeout /= 1000; 261289166Speter } 262251875Speter ret = poll(pollset->p->pollset, pollset->nelts, timeout); 263251875Speter#endif 264251875Speter (*num) = ret; 265251875Speter if (ret < 0) { 266251875Speter return apr_get_netos_error(); 267251875Speter } 268251875Speter else if (ret == 0) { 269251875Speter return APR_TIMEUP; 270251875Speter } 271251875Speter else { 272251875Speter apr_uint32_t i, j; 273251875Speter 274251875Speter for (i = 0, j = 0; i < pollset->nelts; i++) { 275251875Speter if (pollset->p->pollset[i].revents != 0) { 276251875Speter /* Check if the polled descriptor is our 277251875Speter * wakeup pipe. In that case do not put it result set. 278251875Speter */ 279251875Speter if ((pollset->flags & APR_POLLSET_WAKEABLE) && 280251875Speter pollset->p->query_set[i].desc_type == APR_POLL_FILE && 281251875Speter pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { 282251875Speter apr_pollset_drain_wakeup_pipe(pollset); 283251875Speter rv = APR_EINTR; 284251875Speter } 285251875Speter else { 286251875Speter pollset->p->result_set[j] = pollset->p->query_set[i]; 287251875Speter pollset->p->result_set[j].rtnevents = 288251875Speter get_revent(pollset->p->pollset[i].revents); 289251875Speter j++; 290251875Speter } 291251875Speter } 292251875Speter } 293251875Speter if (((*num) = j) > 0) 294251875Speter rv = APR_SUCCESS; 295251875Speter } 296251875Speter if (descriptors && (*num)) 297251875Speter *descriptors = pollset->p->result_set; 298251875Speter return rv; 299251875Speter} 300251875Speter 301251875Speterstatic apr_pollset_provider_t impl = { 302251875Speter impl_pollset_create, 303251875Speter impl_pollset_add, 304251875Speter impl_pollset_remove, 305251875Speter impl_pollset_poll, 306251875Speter NULL, 307251875Speter "poll" 308251875Speter}; 309251875Speter 310251875Speterapr_pollset_provider_t *apr_pollset_provider_poll = &impl; 311251875Speter 312251875Speter/* Poll method pollcb. 313251875Speter * This is probably usable only for WIN32 having WSAPoll 314251875Speter */ 315251875Speterstatic apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 316251875Speter apr_uint32_t size, 317251875Speter apr_pool_t *p, 318251875Speter apr_uint32_t flags) 319251875Speter{ 320251875Speter#if APR_HAS_THREADS 321251875Speter return APR_ENOTIMPL; 322251875Speter#else 323251875Speter pollcb->fd = -1; 324251875Speter#ifdef WIN32 325251875Speter if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { 326251875Speter return APR_ENOTIMPL; 327251875Speter } 328251875Speter#endif 329251875Speter 330251875Speter pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd)); 331251875Speter pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *)); 332251875Speter 333251875Speter return APR_SUCCESS; 334251875Speter#endif 335251875Speter} 336251875Speter 337251875Speterstatic apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 338251875Speter apr_pollfd_t *descriptor) 339251875Speter{ 340251875Speter if (pollcb->nelts == pollcb->nalloc) { 341251875Speter return APR_ENOMEM; 342251875Speter } 343251875Speter 344251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 345251875Speter pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes; 346251875Speter } 347251875Speter else { 348251875Speter#if APR_FILES_AS_SOCKETS 349251875Speter pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes; 350251875Speter#else 351251875Speter return APR_EBADF; 352251875Speter#endif 353251875Speter } 354251875Speter 355251875Speter pollcb->pollset.ps[pollcb->nelts].events = 356251875Speter get_event(descriptor->reqevents); 357251875Speter pollcb->copyset[pollcb->nelts] = descriptor; 358251875Speter pollcb->nelts++; 359251875Speter 360251875Speter return APR_SUCCESS; 361251875Speter} 362251875Speter 363251875Speterstatic apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 364251875Speter apr_pollfd_t *descriptor) 365251875Speter{ 366251875Speter apr_uint32_t i; 367251875Speter 368251875Speter for (i = 0; i < pollcb->nelts; i++) { 369251875Speter if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 370251875Speter /* Found an instance of the fd: remove this and any other copies */ 371251875Speter apr_uint32_t dst = i; 372251875Speter apr_uint32_t old_nelts = pollcb->nelts; 373251875Speter pollcb->nelts--; 374251875Speter for (i++; i < old_nelts; i++) { 375251875Speter if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 376251875Speter pollcb->nelts--; 377251875Speter } 378251875Speter else { 379251875Speter pollcb->pollset.ps[dst] = pollcb->pollset.ps[i]; 380251875Speter pollcb->copyset[dst] = pollcb->copyset[i]; 381251875Speter dst++; 382251875Speter } 383251875Speter } 384251875Speter return APR_SUCCESS; 385251875Speter } 386251875Speter } 387251875Speter 388251875Speter return APR_NOTFOUND; 389251875Speter} 390251875Speter 391251875Speterstatic apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 392251875Speter apr_interval_time_t timeout, 393251875Speter apr_pollcb_cb_t func, 394251875Speter void *baton) 395251875Speter{ 396251875Speter int ret; 397251875Speter apr_status_t rv = APR_SUCCESS; 398251875Speter apr_uint32_t i; 399251875Speter 400289166Speter#ifdef WIN32 401289166Speter /* WSAPoll() requires at least one socket. */ 402289166Speter if (pollcb->nelts == 0) { 403289166Speter if (timeout > 0) { 404289166Speter apr_sleep(timeout); 405289166Speter return APR_TIMEUP; 406289166Speter } 407289166Speter return APR_SUCCESS; 408289166Speter } 409251875Speter if (timeout > 0) { 410251875Speter timeout /= 1000; 411251875Speter } 412251875Speter ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout); 413251875Speter#else 414289166Speter if (timeout > 0) { 415289166Speter timeout /= 1000; 416289166Speter } 417251875Speter ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout); 418251875Speter#endif 419251875Speter if (ret < 0) { 420251875Speter return apr_get_netos_error(); 421251875Speter } 422251875Speter else if (ret == 0) { 423251875Speter return APR_TIMEUP; 424251875Speter } 425251875Speter else { 426251875Speter for (i = 0; i < pollcb->nelts; i++) { 427251875Speter if (pollcb->pollset.ps[i].revents != 0) { 428251875Speter apr_pollfd_t *pollfd = pollcb->copyset[i]; 429251875Speter pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents); 430251875Speter rv = func(baton, pollfd); 431251875Speter if (rv) { 432251875Speter return rv; 433251875Speter } 434251875Speter } 435251875Speter } 436251875Speter } 437251875Speter return rv; 438251875Speter} 439251875Speter 440251875Speterstatic apr_pollcb_provider_t impl_cb = { 441251875Speter impl_pollcb_create, 442251875Speter impl_pollcb_add, 443251875Speter impl_pollcb_remove, 444251875Speter impl_pollcb_poll, 445251875Speter "poll" 446251875Speter}; 447251875Speter 448251875Speterapr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb; 449251875Speter 450251875Speter#endif /* HAVE_POLL */ 451