1 /* 2 * mini_event.c - implementation of part of libevent api, portably. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 */ 36 37 /** 38 * \file 39 * fake libevent implementation. Less broad in functionality, and only 40 * supports select(2). 41 */ 42 43 #include "config.h" 44 #ifdef HAVE_TIME_H 45 #include <time.h> 46 #endif 47 #include <sys/time.h> 48 #include "util/mini_event.h" 49 50 #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 51 #include <signal.h> 52 #include "util/fptr_wlist.h" 53 54 /* Enforce a correct include/config.h as I tire of fixin it. */ 55 #error This code should not be active on NetBSD, please use libevent. 56 57 /** compare events in tree, based on timevalue, ptr for uniqueness */ 58 int mini_ev_cmp(const void* a, const void* b) 59 { 60 const struct event *e = (const struct event*)a; 61 const struct event *f = (const struct event*)b; 62 if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) 63 return -1; 64 if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) 65 return 1; 66 if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) 67 return -1; 68 if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) 69 return 1; 70 if(e < f) 71 return -1; 72 if(e > f) 73 return 1; 74 return 0; 75 } 76 77 /** set time */ 78 static int 79 settime(struct event_base* base) 80 { 81 if(gettimeofday(base->time_tv, NULL) < 0) { 82 return -1; 83 } 84 #ifndef S_SPLINT_S 85 *base->time_secs = (time_t)base->time_tv->tv_sec; 86 #endif 87 return 0; 88 } 89 90 /** create event base */ 91 void *event_init(time_t* time_secs, struct timeval* time_tv) 92 { 93 struct event_base* base = (struct event_base*)malloc( 94 sizeof(struct event_base)); 95 if(!base) 96 return NULL; 97 memset(base, 0, sizeof(*base)); 98 base->time_secs = time_secs; 99 base->time_tv = time_tv; 100 if(settime(base) < 0) { 101 event_base_free(base); 102 return NULL; 103 } 104 base->times = rbtree_create(mini_ev_cmp); 105 if(!base->times) { 106 event_base_free(base); 107 return NULL; 108 } 109 base->capfd = MAX_FDS; 110 #ifdef FD_SETSIZE 111 if((int)FD_SETSIZE < base->capfd) 112 base->capfd = (int)FD_SETSIZE; 113 #endif 114 base->fds = (struct event**)calloc((size_t)base->capfd, 115 sizeof(struct event*)); 116 if(!base->fds) { 117 event_base_free(base); 118 return NULL; 119 } 120 base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); 121 if(!base->signals) { 122 event_base_free(base); 123 return NULL; 124 } 125 #ifndef S_SPLINT_S 126 FD_ZERO(&base->reads); 127 FD_ZERO(&base->writes); 128 #endif 129 return base; 130 } 131 132 /** get version */ 133 const char *event_get_version(void) 134 { 135 return "mini-event-"PACKAGE_VERSION; 136 } 137 138 /** get polling method, select */ 139 const char *event_get_method(void) 140 { 141 return "select"; 142 } 143 144 /** call timeouts handlers, and return how long to wait for next one or -1 */ 145 static void handle_timeouts(struct event_base* base, struct timeval* now, 146 struct timeval* wait) 147 { 148 struct event* p; 149 #ifndef S_SPLINT_S 150 wait->tv_sec = (time_t)-1; 151 #endif 152 153 while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) 154 !=RBTREE_NULL) { 155 #ifndef S_SPLINT_S 156 if(p->ev_timeout.tv_sec > now->tv_sec || 157 (p->ev_timeout.tv_sec==now->tv_sec && 158 p->ev_timeout.tv_usec > now->tv_usec)) { 159 /* there is a next larger timeout. wait for it */ 160 wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; 161 if(now->tv_usec > p->ev_timeout.tv_usec) { 162 wait->tv_sec--; 163 wait->tv_usec = 1000000 - (now->tv_usec - 164 p->ev_timeout.tv_usec); 165 } else { 166 wait->tv_usec = p->ev_timeout.tv_usec 167 - now->tv_usec; 168 } 169 return; 170 } 171 #endif 172 /* event times out, remove it */ 173 (void)rbtree_delete(base->times, p); 174 p->ev_events &= ~EV_TIMEOUT; 175 fptr_ok(fptr_whitelist_event(p->ev_callback)); 176 (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); 177 } 178 } 179 180 /** call select and callbacks for that */ 181 static int handle_select(struct event_base* base, struct timeval* wait) 182 { 183 fd_set r, w; 184 int ret, i; 185 186 #ifndef S_SPLINT_S 187 if(wait->tv_sec==(time_t)-1) 188 wait = NULL; 189 #endif 190 memmove(&r, &base->reads, sizeof(fd_set)); 191 memmove(&w, &base->writes, sizeof(fd_set)); 192 memmove(&base->ready, &base->content, sizeof(fd_set)); 193 194 if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { 195 ret = errno; 196 if(settime(base) < 0) 197 return -1; 198 errno = ret; 199 if(ret == EAGAIN || ret == EINTR) 200 return 0; 201 return -1; 202 } 203 if(settime(base) < 0) 204 return -1; 205 206 for(i=0; i<base->maxfd+1; i++) { 207 short bits = 0; 208 if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { 209 continue; 210 } 211 if(FD_ISSET(i, &r)) { 212 bits |= EV_READ; 213 ret--; 214 } 215 if(FD_ISSET(i, &w)) { 216 bits |= EV_WRITE; 217 ret--; 218 } 219 bits &= base->fds[i]->ev_events; 220 if(bits) { 221 fptr_ok(fptr_whitelist_event( 222 base->fds[i]->ev_callback)); 223 (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, 224 bits, base->fds[i]->ev_arg); 225 if(ret==0) 226 break; 227 } 228 } 229 return 0; 230 } 231 232 /** run select in a loop */ 233 int event_base_dispatch(struct event_base* base) 234 { 235 struct timeval wait; 236 if(settime(base) < 0) 237 return -1; 238 while(!base->need_to_exit) 239 { 240 /* see if timeouts need handling */ 241 handle_timeouts(base, base->time_tv, &wait); 242 if(base->need_to_exit) 243 return 0; 244 /* do select */ 245 if(handle_select(base, &wait) < 0) { 246 if(base->need_to_exit) 247 return 0; 248 return -1; 249 } 250 } 251 return 0; 252 } 253 254 /** exit that loop */ 255 int event_base_loopexit(struct event_base* base, 256 struct timeval* ATTR_UNUSED(tv)) 257 { 258 base->need_to_exit = 1; 259 return 0; 260 } 261 262 /* free event base, free events yourself */ 263 void event_base_free(struct event_base* base) 264 { 265 if(!base) 266 return; 267 free(base->times); 268 free(base->fds); 269 free(base->signals); 270 free(base); 271 } 272 273 /** set content of event */ 274 void event_set(struct event* ev, int fd, short bits, 275 void (*cb)(int, short, void *), void* arg) 276 { 277 ev->node.key = ev; 278 ev->ev_fd = fd; 279 ev->ev_events = bits; 280 ev->ev_callback = cb; 281 fptr_ok(fptr_whitelist_event(ev->ev_callback)); 282 ev->ev_arg = arg; 283 ev->added = 0; 284 } 285 286 /* add event to a base */ 287 int event_base_set(struct event_base* base, struct event* ev) 288 { 289 ev->ev_base = base; 290 ev->added = 0; 291 return 0; 292 } 293 294 /* add event to make it active, you may not change it with event_set anymore */ 295 int event_add(struct event* ev, struct timeval* tv) 296 { 297 if(ev->added) 298 event_del(ev); 299 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 300 return -1; 301 if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 302 ev->ev_base->fds[ev->ev_fd] = ev; 303 if(ev->ev_events&EV_READ) { 304 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 305 } 306 if(ev->ev_events&EV_WRITE) { 307 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 308 } 309 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); 310 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 311 if(ev->ev_fd > ev->ev_base->maxfd) 312 ev->ev_base->maxfd = ev->ev_fd; 313 } 314 if(tv && (ev->ev_events&EV_TIMEOUT)) { 315 #ifndef S_SPLINT_S 316 struct timeval *now = ev->ev_base->time_tv; 317 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 318 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 319 while(ev->ev_timeout.tv_usec >= 1000000) { 320 ev->ev_timeout.tv_usec -= 1000000; 321 ev->ev_timeout.tv_sec++; 322 } 323 #endif 324 (void)rbtree_insert(ev->ev_base->times, &ev->node); 325 } 326 ev->added = 1; 327 return 0; 328 } 329 330 /* remove event, you may change it again */ 331 int event_del(struct event* ev) 332 { 333 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 334 return -1; 335 if((ev->ev_events&EV_TIMEOUT)) 336 (void)rbtree_delete(ev->ev_base->times, &ev->node); 337 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 338 ev->ev_base->fds[ev->ev_fd] = NULL; 339 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 340 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 341 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 342 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); 343 if(ev->ev_fd == ev->ev_base->maxfd) { 344 int i = ev->ev_base->maxfd - 1; 345 for (; i > 3; i--) { 346 if (NULL != ev->ev_base->fds[i]) { 347 break; 348 } 349 } 350 ev->ev_base->maxfd = i; 351 } 352 } 353 ev->added = 0; 354 return 0; 355 } 356 357 /** which base gets to handle signals */ 358 static struct event_base* signal_base = NULL; 359 /** signal handler */ 360 static RETSIGTYPE sigh(int sig) 361 { 362 struct event* ev; 363 if(!signal_base || sig < 0 || sig >= MAX_SIG) 364 return; 365 ev = signal_base->signals[sig]; 366 if(!ev) 367 return; 368 fptr_ok(fptr_whitelist_event(ev->ev_callback)); 369 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 370 } 371 372 /** install signal handler */ 373 int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) 374 { 375 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 376 return -1; 377 signal_base = ev->ev_base; 378 ev->ev_base->signals[ev->ev_fd] = ev; 379 ev->added = 1; 380 if(signal(ev->ev_fd, sigh) == SIG_ERR) { 381 return -1; 382 } 383 return 0; 384 } 385 386 /** remove signal handler */ 387 int signal_del(struct event* ev) 388 { 389 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 390 return -1; 391 ev->ev_base->signals[ev->ev_fd] = NULL; 392 ev->added = 0; 393 return 0; 394 } 395 396 #else /* USE_MINI_EVENT */ 397 #ifndef USE_WINSOCK 398 int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 399 { 400 return 0; 401 } 402 #endif /* not USE_WINSOCK */ 403 #endif /* USE_MINI_EVENT */ 404