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_type*)(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 /* base->times is allocated in region and is freed with the region */ 308 if(base->fds) 309 free(base->fds); 310 if(base->signals) 311 free(base->signals); 312 region_destroy(base->region); 313 free(base); 314 } 315 316 /** set content of event */ 317 void 318 event_set(struct event* ev, int fd, short bits, 319 void (*cb)(int, short, void *), void* arg) 320 { 321 ev->node.key = ev; 322 ev->ev_fd = fd; 323 ev->ev_flags = bits; 324 ev->ev_callback = cb; 325 ev->ev_arg = arg; 326 ev->added = 0; 327 } 328 329 /* add event to a base */ 330 int 331 event_base_set(struct event_base* base, struct event* ev) 332 { 333 ev->ev_base = base; 334 ev->added = 0; 335 return 0; 336 } 337 338 /* add event to make it active, you may not change it with event_set anymore */ 339 int 340 event_add(struct event* ev, struct timeval* tv) 341 { 342 if(ev->added) 343 event_del(ev); 344 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 345 return -1; 346 if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 347 ev->ev_base->fds[ev->ev_fd] = ev; 348 if(ev->ev_flags&EV_READ) { 349 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 350 } 351 if(ev->ev_flags&EV_WRITE) { 352 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 353 } 354 FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); 355 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 356 if(ev->ev_fd > ev->ev_base->maxfd) 357 ev->ev_base->maxfd = ev->ev_fd; 358 } 359 if(tv && (ev->ev_flags&EV_TIMEOUT)) { 360 #ifndef S_SPLINT_S 361 struct timeval* now = ev->ev_base->time_tv; 362 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 363 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 364 while(ev->ev_timeout.tv_usec >= 1000000) { 365 ev->ev_timeout.tv_usec -= 1000000; 366 ev->ev_timeout.tv_sec++; 367 } 368 #endif 369 (void)rbtree_insert(ev->ev_base->times, &ev->node); 370 } 371 ev->added = 1; 372 return 0; 373 } 374 375 /* remove event, you may change it again */ 376 int 377 event_del(struct event* ev) 378 { 379 if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) 380 return -1; 381 if((ev->ev_flags&EV_TIMEOUT)) 382 (void)rbtree_delete(ev->ev_base->times, &ev->node); 383 if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 384 ev->ev_base->fds[ev->ev_fd] = NULL; 385 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); 386 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); 387 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); 388 FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); 389 } 390 ev->added = 0; 391 return 0; 392 } 393 394 /** which base gets to handle signals */ 395 static struct event_base* signal_base = NULL; 396 397 /** signal handler */ 398 static RETSIGTYPE 399 sigh(int sig) 400 { 401 struct event* ev; 402 if(!signal_base || sig < 0 || sig >= MAX_SIG) 403 return; 404 ev = signal_base->signals[sig]; 405 if(!ev) 406 return; 407 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 408 } 409 410 /** install signal handler */ 411 int 412 signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) 413 { 414 struct sigaction action; 415 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 416 return -1; 417 signal_base = ev->ev_base; 418 ev->ev_base->signals[ev->ev_fd] = ev; 419 ev->added = 1; 420 action.sa_handler = sigh; 421 sigfillset(&action.sa_mask); 422 action.sa_flags = 0; 423 return sigaction(ev->ev_fd, &action, NULL); 424 } 425 426 /** remove signal handler */ 427 int 428 signal_del(struct event* ev) 429 { 430 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 431 return -1; 432 ev->ev_base->signals[ev->ev_fd] = NULL; 433 ev->added = 0; 434 return 0; 435 } 436 437 #else /* USE_MINI_EVENT */ 438 #ifndef USE_WINSOCK 439 int 440 mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 441 { 442 return 0; 443 } 444 #endif /* not USE_WINSOCK */ 445 #endif /* USE_MINI_EVENT */ 446