1238106Sdes/* 2238106Sdes * mini_event.c - implementation of part of libevent api, portably. 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes * 35238106Sdes */ 36238106Sdes 37238106Sdes/** 38238106Sdes * \file 39238106Sdes * fake libevent implementation. Less broad in functionality, and only 40238106Sdes * supports select(2). 41238106Sdes */ 42238106Sdes 43238106Sdes#include "config.h" 44238106Sdes#ifdef HAVE_TIME_H 45238106Sdes#include <time.h> 46238106Sdes#endif 47238106Sdes#include <sys/time.h> 48238106Sdes 49238106Sdes#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 50238106Sdes#include <signal.h> 51238106Sdes#include "util/mini_event.h" 52238106Sdes#include "util/fptr_wlist.h" 53238106Sdes 54238106Sdes/** compare events in tree, based on timevalue, ptr for uniqueness */ 55238106Sdesint mini_ev_cmp(const void* a, const void* b) 56238106Sdes{ 57238106Sdes const struct event *e = (const struct event*)a; 58238106Sdes const struct event *f = (const struct event*)b; 59238106Sdes if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) 60238106Sdes return -1; 61238106Sdes if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) 62238106Sdes return 1; 63238106Sdes if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) 64238106Sdes return -1; 65238106Sdes if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) 66238106Sdes return 1; 67238106Sdes if(e < f) 68238106Sdes return -1; 69238106Sdes if(e > f) 70238106Sdes return 1; 71238106Sdes return 0; 72238106Sdes} 73238106Sdes 74238106Sdes/** set time */ 75238106Sdesstatic int 76238106Sdessettime(struct event_base* base) 77238106Sdes{ 78238106Sdes if(gettimeofday(base->time_tv, NULL) < 0) { 79238106Sdes return -1; 80238106Sdes } 81238106Sdes#ifndef S_SPLINT_S 82269257Sdes *base->time_secs = (time_t)base->time_tv->tv_sec; 83238106Sdes#endif 84238106Sdes return 0; 85238106Sdes} 86238106Sdes 87238106Sdes/** create event base */ 88269257Sdesvoid *event_init(time_t* time_secs, struct timeval* time_tv) 89238106Sdes{ 90238106Sdes struct event_base* base = (struct event_base*)malloc( 91238106Sdes sizeof(struct event_base)); 92238106Sdes if(!base) 93238106Sdes return NULL; 94238106Sdes memset(base, 0, sizeof(*base)); 95238106Sdes base->time_secs = time_secs; 96238106Sdes base->time_tv = time_tv; 97238106Sdes if(settime(base) < 0) { 98238106Sdes event_base_free(base); 99238106Sdes return NULL; 100238106Sdes } 101238106Sdes base->times = rbtree_create(mini_ev_cmp); 102238106Sdes if(!base->times) { 103238106Sdes event_base_free(base); 104238106Sdes return NULL; 105238106Sdes } 106238106Sdes base->capfd = MAX_FDS; 107238106Sdes#ifdef FD_SETSIZE 108238106Sdes if((int)FD_SETSIZE < base->capfd) 109238106Sdes base->capfd = (int)FD_SETSIZE; 110238106Sdes#endif 111238106Sdes base->fds = (struct event**)calloc((size_t)base->capfd, 112238106Sdes sizeof(struct event*)); 113238106Sdes if(!base->fds) { 114238106Sdes event_base_free(base); 115238106Sdes return NULL; 116238106Sdes } 117238106Sdes base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); 118238106Sdes if(!base->signals) { 119238106Sdes event_base_free(base); 120238106Sdes return NULL; 121238106Sdes } 122238106Sdes#ifndef S_SPLINT_S 123238106Sdes FD_ZERO(&base->reads); 124238106Sdes FD_ZERO(&base->writes); 125238106Sdes#endif 126238106Sdes return base; 127238106Sdes} 128238106Sdes 129238106Sdes/** get version */ 130238106Sdesconst char *event_get_version(void) 131238106Sdes{ 132238106Sdes return "mini-event-"PACKAGE_VERSION; 133238106Sdes} 134238106Sdes 135238106Sdes/** get polling method, select */ 136238106Sdesconst char *event_get_method(void) 137238106Sdes{ 138238106Sdes return "select"; 139238106Sdes} 140238106Sdes 141238106Sdes/** call timeouts handlers, and return how long to wait for next one or -1 */ 142238106Sdesstatic void handle_timeouts(struct event_base* base, struct timeval* now, 143238106Sdes struct timeval* wait) 144238106Sdes{ 145238106Sdes struct event* p; 146238106Sdes#ifndef S_SPLINT_S 147238106Sdes wait->tv_sec = (time_t)-1; 148238106Sdes#endif 149238106Sdes 150238106Sdes while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) 151238106Sdes !=RBTREE_NULL) { 152238106Sdes#ifndef S_SPLINT_S 153238106Sdes if(p->ev_timeout.tv_sec > now->tv_sec || 154238106Sdes (p->ev_timeout.tv_sec==now->tv_sec && 155238106Sdes p->ev_timeout.tv_usec > now->tv_usec)) { 156238106Sdes /* there is a next larger timeout. wait for it */ 157238106Sdes wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; 158238106Sdes if(now->tv_usec > p->ev_timeout.tv_usec) { 159238106Sdes wait->tv_sec--; 160238106Sdes wait->tv_usec = 1000000 - (now->tv_usec - 161238106Sdes p->ev_timeout.tv_usec); 162238106Sdes } else { 163238106Sdes wait->tv_usec = p->ev_timeout.tv_usec 164238106Sdes - now->tv_usec; 165238106Sdes } 166238106Sdes return; 167238106Sdes } 168238106Sdes#endif 169238106Sdes /* event times out, remove it */ 170238106Sdes (void)rbtree_delete(base->times, p); 171238106Sdes p->ev_events &= ~EV_TIMEOUT; 172238106Sdes fptr_ok(fptr_whitelist_event(p->ev_callback)); 173238106Sdes (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); 174238106Sdes } 175238106Sdes} 176238106Sdes 177238106Sdes/** call select and callbacks for that */ 178238106Sdesstatic int handle_select(struct event_base* base, struct timeval* wait) 179238106Sdes{ 180238106Sdes fd_set r, w; 181238106Sdes int ret, i; 182238106Sdes 183238106Sdes#ifndef S_SPLINT_S 184238106Sdes if(wait->tv_sec==(time_t)-1) 185238106Sdes wait = NULL; 186238106Sdes#endif 187238106Sdes memmove(&r, &base->reads, sizeof(fd_set)); 188238106Sdes memmove(&w, &base->writes, sizeof(fd_set)); 189238106Sdes memmove(&base->ready, &base->content, sizeof(fd_set)); 190238106Sdes 191238106Sdes if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { 192238106Sdes ret = errno; 193238106Sdes if(settime(base) < 0) 194238106Sdes return -1; 195238106Sdes errno = ret; 196238106Sdes if(ret == EAGAIN || ret == EINTR) 197238106Sdes return 0; 198238106Sdes return -1; 199238106Sdes } 200238106Sdes if(settime(base) < 0) 201238106Sdes return -1; 202238106Sdes 203238106Sdes for(i=0; i<base->maxfd+1; i++) { 204238106Sdes short bits = 0; 205238106Sdes if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { 206238106Sdes continue; 207238106Sdes } 208238106Sdes if(FD_ISSET(i, &r)) { 209238106Sdes bits |= EV_READ; 210238106Sdes ret--; 211238106Sdes } 212238106Sdes if(FD_ISSET(i, &w)) { 213238106Sdes bits |= EV_WRITE; 214238106Sdes ret--; 215238106Sdes } 216238106Sdes bits &= base->fds[i]->ev_events; 217238106Sdes if(bits) { 218238106Sdes fptr_ok(fptr_whitelist_event( 219238106Sdes base->fds[i]->ev_callback)); 220238106Sdes (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, 221238106Sdes bits, base->fds[i]->ev_arg); 222238106Sdes if(ret==0) 223238106Sdes break; 224238106Sdes } 225238106Sdes } 226238106Sdes return 0; 227238106Sdes} 228238106Sdes 229238106Sdes/** run select in a loop */ 230238106Sdesint event_base_dispatch(struct event_base* base) 231238106Sdes{ 232238106Sdes struct timeval wait; 233238106Sdes if(settime(base) < 0) 234238106Sdes return -1; 235238106Sdes while(!base->need_to_exit) 236238106Sdes { 237238106Sdes /* see if timeouts need handling */ 238238106Sdes handle_timeouts(base, base->time_tv, &wait); 239238106Sdes if(base->need_to_exit) 240238106Sdes return 0; 241238106Sdes /* do select */ 242238106Sdes if(handle_select(base, &wait) < 0) { 243238106Sdes if(base->need_to_exit) 244238106Sdes return 0; 245238106Sdes return -1; 246238106Sdes } 247238106Sdes } 248238106Sdes return 0; 249238106Sdes} 250238106Sdes 251238106Sdes/** exit that loop */ 252238106Sdesint event_base_loopexit(struct event_base* base, 253238106Sdes struct timeval* ATTR_UNUSED(tv)) 254238106Sdes{ 255238106Sdes base->need_to_exit = 1; 256238106Sdes return 0; 257238106Sdes} 258238106Sdes 259238106Sdes/* free event base, free events yourself */ 260238106Sdesvoid event_base_free(struct event_base* base) 261238106Sdes{ 262238106Sdes if(!base) 263238106Sdes return; 264238106Sdes if(base->times) 265238106Sdes free(base->times); 266238106Sdes if(base->fds) 267238106Sdes free(base->fds); 268238106Sdes if(base->signals) 269238106Sdes free(base->signals); 270238106Sdes free(base); 271238106Sdes} 272238106Sdes 273238106Sdes/** set content of event */ 274238106Sdesvoid event_set(struct event* ev, int fd, short bits, 275238106Sdes void (*cb)(int, short, void *), void* arg) 276238106Sdes{ 277238106Sdes ev->node.key = ev; 278238106Sdes ev->ev_fd = fd; 279238106Sdes ev->ev_events = bits; 280238106Sdes ev->ev_callback = cb; 281238106Sdes fptr_ok(fptr_whitelist_event(ev->ev_callback)); 282238106Sdes ev->ev_arg = arg; 283238106Sdes ev->added = 0; 284238106Sdes} 285238106Sdes 286238106Sdes/* add event to a base */ 287238106Sdesint event_base_set(struct event_base* base, struct event* ev) 288238106Sdes{ 289238106Sdes ev->ev_base = base; 290238106Sdes ev->added = 0; 291238106Sdes return 0; 292238106Sdes} 293238106Sdes 294238106Sdes/* add event to make it active, you may not change it with event_set anymore */ 295238106Sdesint event_add(struct event* ev, struct timeval* tv) 296238106Sdes{ 297238106Sdes if(ev->added) 298238106Sdes event_del(ev); 299238106Sdes if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 300238106Sdes return -1; 301238106Sdes if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 302238106Sdes ev->ev_base->fds[ev->ev_fd] = ev; 303238106Sdes if(ev->ev_events&EV_READ) { 304238106Sdes FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 305238106Sdes } 306238106Sdes if(ev->ev_events&EV_WRITE) { 307238106Sdes FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 308238106Sdes } 309238106Sdes FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); 310238106Sdes FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 311238106Sdes if(ev->ev_fd > ev->ev_base->maxfd) 312238106Sdes ev->ev_base->maxfd = ev->ev_fd; 313238106Sdes } 314238106Sdes if(tv && (ev->ev_events&EV_TIMEOUT)) { 315238106Sdes#ifndef S_SPLINT_S 316238106Sdes struct timeval *now = ev->ev_base->time_tv; 317238106Sdes ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 318238106Sdes ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 319238106Sdes while(ev->ev_timeout.tv_usec > 1000000) { 320238106Sdes ev->ev_timeout.tv_usec -= 1000000; 321238106Sdes ev->ev_timeout.tv_sec++; 322238106Sdes } 323238106Sdes#endif 324238106Sdes (void)rbtree_insert(ev->ev_base->times, &ev->node); 325238106Sdes } 326238106Sdes ev->added = 1; 327238106Sdes return 0; 328238106Sdes} 329238106Sdes 330238106Sdes/* remove event, you may change it again */ 331238106Sdesint event_del(struct event* ev) 332238106Sdes{ 333238106Sdes if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 334238106Sdes return -1; 335238106Sdes if((ev->ev_events&EV_TIMEOUT)) 336238106Sdes (void)rbtree_delete(ev->ev_base->times, &ev->node); 337238106Sdes if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 338238106Sdes ev->ev_base->fds[ev->ev_fd] = NULL; 339238106Sdes FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 340238106Sdes FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 341238106Sdes FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 342238106Sdes FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); 343238106Sdes } 344238106Sdes ev->added = 0; 345238106Sdes return 0; 346238106Sdes} 347238106Sdes 348238106Sdes/** which base gets to handle signals */ 349238106Sdesstatic struct event_base* signal_base = NULL; 350238106Sdes/** signal handler */ 351238106Sdesstatic RETSIGTYPE sigh(int sig) 352238106Sdes{ 353238106Sdes struct event* ev; 354238106Sdes if(!signal_base || sig < 0 || sig >= MAX_SIG) 355238106Sdes return; 356238106Sdes ev = signal_base->signals[sig]; 357238106Sdes if(!ev) 358238106Sdes return; 359238106Sdes fptr_ok(fptr_whitelist_event(ev->ev_callback)); 360238106Sdes (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 361238106Sdes} 362238106Sdes 363238106Sdes/** install signal handler */ 364238106Sdesint signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) 365238106Sdes{ 366238106Sdes if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 367238106Sdes return -1; 368238106Sdes signal_base = ev->ev_base; 369238106Sdes ev->ev_base->signals[ev->ev_fd] = ev; 370238106Sdes ev->added = 1; 371238106Sdes if(signal(ev->ev_fd, sigh) == SIG_ERR) { 372238106Sdes return -1; 373238106Sdes } 374238106Sdes return 0; 375238106Sdes} 376238106Sdes 377238106Sdes/** remove signal handler */ 378238106Sdesint signal_del(struct event* ev) 379238106Sdes{ 380238106Sdes if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 381238106Sdes return -1; 382238106Sdes ev->ev_base->signals[ev->ev_fd] = NULL; 383238106Sdes ev->added = 0; 384238106Sdes return 0; 385238106Sdes} 386238106Sdes 387238106Sdes#else /* USE_MINI_EVENT */ 388238106Sdes#ifndef USE_WINSOCK 389238106Sdesint mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 390238106Sdes{ 391238106Sdes return 0; 392238106Sdes} 393238106Sdes#endif /* not USE_WINSOCK */ 394238106Sdes#endif /* USE_MINI_EVENT */ 395