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