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 <string.h> 48 #include <errno.h> 49 #include <sys/time.h> 50 51 #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 52 #ifdef HAVE_WINSOCK2_H 53 #define FD_SET_T (u_int) 54 #else 55 #define FD_SET_T 56 #endif 57 58 #include <signal.h> 59 #include "mini_event.h" 60 #include "util.h" 61 62 /** compare events in tree, based on timevalue, ptr for uniqueness */ 63 int 64 mini_ev_cmp(const void* a, const void* b) 65 { 66 const struct event* e = (const struct event*)a; 67 const struct event* f = (const struct event*)b; 68 if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) 69 return -1; 70 if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) 71 return 1; 72 if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) 73 return -1; 74 if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) 75 return 1; 76 if(e < f) 77 return -1; 78 if(e > f) 79 return 1; 80 return 0; 81 } 82 83 /** set time */ 84 static int 85 settime(struct event_base* base) 86 { 87 if(gettimeofday(base->time_tv, NULL) < 0) { 88 return -1; 89 } 90 #ifndef S_SPLINT_S 91 *base->time_secs = (time_t)base->time_tv->tv_sec; 92 #endif 93 return 0; 94 } 95 96 /** create event base */ 97 void * 98 event_init(time_t* time_secs, struct timeval* time_tv) 99 { 100 struct event_base* base = (struct event_base*)malloc( 101 sizeof(struct event_base)); 102 if(!base) 103 return NULL; 104 memset(base, 0, sizeof(*base)); 105 base->region = region_create(xalloc, free); 106 if(!base->region) { 107 free(base); 108 return NULL; 109 } 110 base->time_secs = time_secs; 111 base->time_tv = time_tv; 112 if(settime(base) < 0) { 113 event_base_free(base); 114 return NULL; 115 } 116 base->times = rbtree_create(base->region, mini_ev_cmp); 117 if(!base->times) { 118 event_base_free(base); 119 return NULL; 120 } 121 base->capfd = MAX_FDS; 122 #ifdef FD_SETSIZE 123 if((int)FD_SETSIZE < base->capfd) 124 base->capfd = (int)FD_SETSIZE; 125 #endif 126 base->fds = (struct event**)calloc((size_t)base->capfd, 127 sizeof(struct event*)); 128 if(!base->fds) { 129 event_base_free(base); 130 return NULL; 131 } 132 base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); 133 if(!base->signals) { 134 event_base_free(base); 135 return NULL; 136 } 137 #ifndef S_SPLINT_S 138 FD_ZERO(&base->reads); 139 FD_ZERO(&base->writes); 140 #endif 141 return base; 142 } 143 144 /** get version */ 145 const char * 146 event_get_version(void) 147 { 148 return "mini-event-"PACKAGE_VERSION; 149 } 150 151 /** get polling method, select */ 152 const char * 153 event_get_method(void) 154 { 155 return "select"; 156 } 157 158 /** call timeouts handlers, and return how long to wait for next one or -1 */ 159 static int 160 handle_timeouts(struct event_base* base, struct timeval* now, 161 struct timeval* wait) 162 { 163 struct event* p; 164 int tofired = 0; 165 #ifndef S_SPLINT_S 166 wait->tv_sec = (time_t)-1; 167 #endif 168 169 while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) 170 !=RBTREE_NULL) { 171 #ifndef S_SPLINT_S 172 if(p->ev_timeout.tv_sec > now->tv_sec || 173 (p->ev_timeout.tv_sec==now->tv_sec && 174 p->ev_timeout.tv_usec > now->tv_usec)) { 175 /* there is a next larger timeout. wait for it */ 176 wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; 177 if(now->tv_usec > p->ev_timeout.tv_usec) { 178 wait->tv_sec--; 179 wait->tv_usec = 1000000 - (now->tv_usec - 180 p->ev_timeout.tv_usec); 181 } else { 182 wait->tv_usec = p->ev_timeout.tv_usec 183 - now->tv_usec; 184 } 185 return tofired; 186 } 187 #endif 188 /* event times out, remove it */ 189 tofired = 1; 190 (void)rbtree_delete(base->times, p); 191 p->ev_flags &= ~EV_TIMEOUT; 192 (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); 193 } 194 return tofired; 195 } 196 197 /** call select and callbacks for that */ 198 static int 199 handle_select(struct event_base* base, struct timeval* wait) 200 { 201 fd_set r, w; 202 int ret, i; 203 204 #ifndef S_SPLINT_S 205 if(wait->tv_sec==(time_t)-1) 206 wait = NULL; 207 #endif 208 memmove(&r, &base->reads, sizeof(fd_set)); 209 memmove(&w, &base->writes, sizeof(fd_set)); 210 memmove(&base->ready, &base->content, sizeof(fd_set)); 211 212 if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { 213 ret = errno; 214 if(settime(base) < 0) 215 return -1; 216 errno = ret; 217 if(ret == EAGAIN || ret == EINTR) 218 return 0; 219 return -1; 220 } 221 if(settime(base) < 0) 222 return -1; 223 224 for(i=0; i<base->maxfd+1; i++) { 225 short bits = 0; 226 if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { 227 continue; 228 } 229 if(FD_ISSET(i, &r)) { 230 bits |= EV_READ; 231 ret--; 232 } 233 if(FD_ISSET(i, &w)) { 234 bits |= EV_WRITE; 235 ret--; 236 } 237 bits &= base->fds[i]->ev_flags; 238 if(bits) { 239 (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, 240 bits, base->fds[i]->ev_arg); 241 if(ret==0) 242 break; 243 } 244 } 245 return 0; 246 } 247 248 /** run select once */ 249 int 250 event_base_loop(struct event_base* base, int flags) 251 { 252 struct timeval wait; 253 if(!(flags & EVLOOP_ONCE)) 254 return event_base_dispatch(base); 255 /* see if timeouts need handling */ 256 if(handle_timeouts(base, base->time_tv, &wait)) 257 return 0; /* there were timeouts, end of loop */ 258 if(base->need_to_exit) 259 return 0; 260 /* do select */ 261 if(handle_select(base, &wait) < 0) { 262 if(base->need_to_exit) 263 return 0; 264 return -1; 265 } 266 return 0; 267 } 268 269 /** run select in a loop */ 270 int 271 event_base_dispatch(struct event_base* base) 272 { 273 struct timeval wait; 274 if(settime(base) < 0) 275 return -1; 276 while(!base->need_to_exit) 277 { 278 /* see if timeouts need handling */ 279 (void)handle_timeouts(base, base->time_tv, &wait); 280 if(base->need_to_exit) 281 return 0; 282 /* do select */ 283 if(handle_select(base, &wait) < 0) { 284 if(base->need_to_exit) 285 return 0; 286 return -1; 287 } 288 } 289 return 0; 290 } 291 292 /** exit that loop */ 293 int 294 event_base_loopexit(struct event_base* base, 295 struct timeval* ATTR_UNUSED(tv)) 296 { 297 base->need_to_exit = 1; 298 return 0; 299 } 300 301 /* free event base, free events yourself */ 302 void 303 event_base_free(struct event_base* base) 304 { 305 if(!base) 306 return; 307 if(base->times) 308 free(base->times); 309 if(base->fds) 310 free(base->fds); 311 if(base->signals) 312 free(base->signals); 313 region_destroy(base->region); 314 free(base); 315 } 316 317 /** set content of event */ 318 void 319 event_set(struct event* ev, int fd, short bits, 320 void (*cb)(int, short, void *), void* arg) 321 { 322 ev->node.key = ev; 323 ev->ev_fd = fd; 324 ev->ev_flags = bits; 325 ev->ev_callback = cb; 326 ev->ev_arg = arg; 327 ev->added = 0; 328 } 329 330 /* add event to a base */ 331 int 332 event_base_set(struct event_base* base, struct event* ev) 333 { 334 ev->ev_base = base; 335 ev->added = 0; 336 return 0; 337 } 338 339 /* add event to make it active, you may not change it with event_set anymore */ 340 int 341 event_add(struct event* ev, struct timeval* tv) 342 { 343 if(ev->added) 344 event_del(ev); 345 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 346 return -1; 347 if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 348 ev->ev_base->fds[ev->ev_fd] = ev; 349 if(ev->ev_flags&EV_READ) { 350 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 351 } 352 if(ev->ev_flags&EV_WRITE) { 353 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 354 } 355 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); 356 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 357 if(ev->ev_fd > ev->ev_base->maxfd) 358 ev->ev_base->maxfd = ev->ev_fd; 359 } 360 if(tv && (ev->ev_flags&EV_TIMEOUT)) { 361 #ifndef S_SPLINT_S 362 struct timeval* now = ev->ev_base->time_tv; 363 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 364 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 365 while(ev->ev_timeout.tv_usec > 1000000) { 366 ev->ev_timeout.tv_usec -= 1000000; 367 ev->ev_timeout.tv_sec++; 368 } 369 #endif 370 (void)rbtree_insert(ev->ev_base->times, &ev->node); 371 } 372 ev->added = 1; 373 return 0; 374 } 375 376 /* remove event, you may change it again */ 377 int 378 event_del(struct event* ev) 379 { 380 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 381 return -1; 382 if((ev->ev_flags&EV_TIMEOUT)) 383 (void)rbtree_delete(ev->ev_base->times, &ev->node); 384 if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 385 ev->ev_base->fds[ev->ev_fd] = NULL; 386 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 387 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 388 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 389 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); 390 } 391 ev->added = 0; 392 return 0; 393 } 394 395 /** which base gets to handle signals */ 396 static struct event_base* signal_base = NULL; 397 398 /** signal handler */ 399 static RETSIGTYPE 400 sigh(int sig) 401 { 402 struct event* ev; 403 if(!signal_base || sig < 0 || sig >= MAX_SIG) 404 return; 405 ev = signal_base->signals[sig]; 406 if(!ev) 407 return; 408 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 409 } 410 411 /** install signal handler */ 412 int 413 signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) 414 { 415 struct sigaction action; 416 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 417 return -1; 418 signal_base = ev->ev_base; 419 ev->ev_base->signals[ev->ev_fd] = ev; 420 ev->added = 1; 421 action.sa_handler = sigh; 422 sigfillset(&action.sa_mask); 423 action.sa_flags = 0; 424 return sigaction(ev->ev_fd, &action, NULL); 425 } 426 427 /** remove signal handler */ 428 int 429 signal_del(struct event* ev) 430 { 431 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 432 return -1; 433 ev->ev_base->signals[ev->ev_fd] = NULL; 434 ev->added = 0; 435 return 0; 436 } 437 438 #else /* USE_MINI_EVENT */ 439 #ifndef USE_WINSOCK 440 int 441 mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 442 { 443 return 0; 444 } 445 #endif /* not USE_WINSOCK */ 446 #endif /* USE_MINI_EVENT */ 447