1 /* 2 * util/ub_event.c - directly call libevent (compatability) functions 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 * \file 38 * 39 * This file contains and implementation for the indirection layer for pluggable 40 * events that transparently passes it either directly to libevent, or calls 41 * the libevent compatibility layer functions. 42 */ 43 #include "config.h" 44 #include <sys/time.h> 45 #include "util/ub_event.h" 46 #include "util/log.h" 47 #include "util/netevent.h" 48 #include "util/tube.h" 49 50 /* We define libevent structures here to hide the libevent stuff. */ 51 52 #ifdef USE_MINI_EVENT 53 # ifdef USE_WINSOCK 54 # include "util/winsock_event.h" 55 # else 56 # include "util/mini_event.h" 57 # endif /* USE_WINSOCK */ 58 #else /* USE_MINI_EVENT */ 59 /* we use libevent */ 60 # ifdef HAVE_EVENT_H 61 # include <event.h> 62 # else 63 # include "event2/event.h" 64 # include "event2/event_struct.h" 65 # include "event2/event_compat.h" 66 # endif 67 #endif /* USE_MINI_EVENT */ 68 69 #if UB_EV_TIMEOUT != EV_TIMEOUT || UB_EV_READ != EV_READ || \ 70 UB_EV_WRITE != EV_WRITE || UB_EV_SIGNAL != EV_SIGNAL || \ 71 UB_EV_PERSIST != EV_PERSIST 72 /* Only necessary for libev */ 73 # define NATIVE_BITS(b) ( \ 74 (((b) & UB_EV_TIMEOUT) ? EV_TIMEOUT : 0) \ 75 | (((b) & UB_EV_READ ) ? EV_READ : 0) \ 76 | (((b) & UB_EV_WRITE ) ? EV_WRITE : 0) \ 77 | (((b) & UB_EV_SIGNAL ) ? EV_SIGNAL : 0) \ 78 | (((b) & UB_EV_PERSIST) ? EV_PERSIST : 0)) 79 80 # define UB_EV_BITS(b) ( \ 81 (((b) & EV_TIMEOUT) ? UB_EV_TIMEOUT : 0) \ 82 | (((b) & EV_READ ) ? UB_EV_READ : 0) \ 83 | (((b) & EV_WRITE ) ? UB_EV_WRITE : 0) \ 84 | (((b) & EV_SIGNAL ) ? UB_EV_SIGNAL : 0) \ 85 | (((b) & EV_PERSIST) ? UB_EV_PERSIST : 0)) 86 87 # define UB_EV_BITS_CB(C) void my_ ## C (int fd, short bits, void *arg) \ 88 { (C)(fd, UB_EV_BITS(bits), arg); } 89 90 UB_EV_BITS_CB(comm_point_udp_callback); 91 UB_EV_BITS_CB(comm_point_udp_ancil_callback) 92 UB_EV_BITS_CB(comm_point_tcp_accept_callback) 93 UB_EV_BITS_CB(comm_point_tcp_handle_callback) 94 UB_EV_BITS_CB(comm_timer_callback) 95 UB_EV_BITS_CB(comm_signal_callback) 96 UB_EV_BITS_CB(comm_point_local_handle_callback) 97 UB_EV_BITS_CB(comm_point_raw_handle_callback) 98 UB_EV_BITS_CB(tube_handle_signal) 99 UB_EV_BITS_CB(comm_base_handle_slow_accept) 100 101 static void (*NATIVE_BITS_CB(void (*cb)(int, short, void*)))(int, short, void*) 102 { 103 if(cb == comm_point_udp_callback) 104 return my_comm_point_udp_callback; 105 else if(cb == comm_point_udp_ancil_callback) 106 return my_comm_point_udp_ancil_callback; 107 else if(cb == comm_point_tcp_accept_callback) 108 return my_comm_point_tcp_accept_callback; 109 else if(cb == comm_point_tcp_handle_callback) 110 return my_comm_point_tcp_handle_callback; 111 else if(cb == comm_timer_callback) 112 return my_comm_timer_callback; 113 else if(cb == comm_signal_callback) 114 return my_comm_signal_callback; 115 else if(cb == comm_point_local_handle_callback) 116 return my_comm_point_local_handle_callback; 117 else if(cb == comm_point_raw_handle_callback) 118 return my_comm_point_raw_handle_callback; 119 else if(cb == tube_handle_signal) 120 return my_tube_handle_signal; 121 else if(cb == comm_base_handle_slow_accept) 122 return my_comm_base_handle_slow_accept; 123 else 124 return NULL; 125 } 126 #else 127 # define NATIVE_BITS(b) (b) 128 # define NATIVE_BITS_CB(c) (c) 129 #endif 130 131 #ifndef EVFLAG_AUTO 132 #define EVFLAG_AUTO 0 133 #endif 134 135 #define AS_EVENT_BASE(x) \ 136 (((union {struct ub_event_base* a; struct event_base* b;})x).b) 137 #define AS_UB_EVENT_BASE(x) \ 138 (((union {struct event_base* a; struct ub_event_base* b;})x).b) 139 #define AS_EVENT(x) \ 140 (((union {struct ub_event* a; struct event* b;})x).b) 141 #define AS_UB_EVENT(x) \ 142 (((union {struct event* a; struct ub_event* b;})x).b) 143 144 const char* ub_event_get_version() 145 { 146 return event_get_version(); 147 } 148 149 #if (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && defined(EVBACKEND_SELECT) 150 static const char* ub_ev_backend2str(int b) 151 { 152 switch(b) { 153 case EVBACKEND_SELECT: return "select"; 154 case EVBACKEND_POLL: return "poll"; 155 case EVBACKEND_EPOLL: return "epoll"; 156 case EVBACKEND_KQUEUE: return "kqueue"; 157 case EVBACKEND_DEVPOLL: return "devpoll"; 158 case EVBACKEND_PORT: return "evport"; 159 } 160 return "unknown"; 161 } 162 #endif 163 164 void 165 ub_get_event_sys(struct ub_event_base* base, const char** n, const char** s, 166 const char** m) 167 { 168 #ifdef USE_WINSOCK 169 (void)base; 170 *n = "event"; 171 *s = "winsock"; 172 *m = "WSAWaitForMultipleEvents"; 173 #elif defined(USE_MINI_EVENT) 174 (void)base; 175 *n = "mini-event"; 176 *s = "internal"; 177 *m = "select"; 178 #else 179 struct event_base* b = AS_EVENT_BASE(base); 180 *s = event_get_version(); 181 # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 182 *n = "libev"; 183 if (!b) 184 b = (struct event_base*)ev_default_loop(EVFLAG_AUTO); 185 # ifdef EVBACKEND_SELECT 186 *m = ub_ev_backend2str(ev_backend((struct ev_loop*)b)); 187 # else 188 *m = "not obtainable"; 189 # endif 190 # elif defined(HAVE_EVENT_BASE_GET_METHOD) 191 *n = "libevent"; 192 if (!b) 193 b = event_base_new(); 194 *m = event_base_get_method(b); 195 # else 196 *n = "unknown"; 197 *m = "not obtainable"; 198 (void)b; 199 # endif 200 # ifdef HAVE_EVENT_BASE_FREE 201 if (b && b != AS_EVENT_BASE(base)) 202 event_base_free(b); 203 # endif 204 #endif 205 } 206 207 struct ub_event_base* 208 ub_default_event_base(int sigs, time_t* time_secs, struct timeval* time_tv) 209 { 210 void* base; 211 212 (void)base; 213 #ifdef USE_MINI_EVENT 214 (void)sigs; 215 /* use mini event time-sharing feature */ 216 base = event_init(time_secs, time_tv); 217 #else 218 (void)time_secs; 219 (void)time_tv; 220 # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 221 /* libev */ 222 if(sigs) 223 base = ev_default_loop(EVFLAG_AUTO); 224 else 225 base = ev_loop_new(EVFLAG_AUTO); 226 # else 227 (void)sigs; 228 # ifdef HAVE_EVENT_BASE_NEW 229 base = event_base_new(); 230 # else 231 base = event_init(); 232 # endif 233 # endif 234 #endif 235 return (struct ub_event_base*)base; 236 } 237 238 struct ub_event_base * 239 ub_libevent_event_base(struct event_base* libevent_base) 240 { 241 #ifdef USE_MINI_EVENT 242 (void)libevent_base; 243 return NULL; 244 #else 245 return AS_UB_EVENT_BASE(libevent_base); 246 #endif 247 } 248 249 struct event_base * 250 ub_libevent_get_event_base(struct ub_event_base* base) 251 { 252 #ifdef USE_MINI_EVENT 253 (void)base; 254 return NULL; 255 #else 256 return AS_EVENT_BASE(base); 257 #endif 258 } 259 260 void 261 ub_event_base_free(struct ub_event_base* base) 262 { 263 #ifdef USE_MINI_EVENT 264 event_base_free(AS_EVENT_BASE(base)); 265 #elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE) 266 /* only libevent 1.2+ has it, but in 1.2 it is broken - 267 assertion fails on signal handling ev that is not deleted 268 in libevent 1.3c (event_base_once appears) this is fixed. */ 269 event_base_free(AS_EVENT_BASE(base)); 270 #else 271 (void)base; 272 #endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */ 273 } 274 275 int 276 ub_event_base_dispatch(struct ub_event_base* base) 277 { 278 return event_base_dispatch(AS_EVENT_BASE(base)); 279 } 280 281 int 282 ub_event_base_loopexit(struct ub_event_base* base) 283 { 284 return event_base_loopexit(AS_EVENT_BASE(base), NULL); 285 } 286 287 struct ub_event* 288 ub_event_new(struct ub_event_base* base, int fd, short bits, 289 void (*cb)(int, short, void*), void* arg) 290 { 291 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 292 293 if (!ev) 294 return NULL; 295 296 event_set(ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg); 297 if (event_base_set(AS_EVENT_BASE(base), ev) != 0) { 298 free(ev); 299 return NULL; 300 } 301 return AS_UB_EVENT(ev); 302 } 303 304 struct ub_event* 305 ub_signal_new(struct ub_event_base* base, int fd, 306 void (*cb)(int, short, void*), void* arg) 307 { 308 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 309 310 if (!ev) 311 return NULL; 312 313 signal_set(ev, fd, NATIVE_BITS_CB(cb), arg); 314 if (event_base_set(AS_EVENT_BASE(base), ev) != 0) { 315 free(ev); 316 return NULL; 317 } 318 return AS_UB_EVENT(ev); 319 } 320 321 struct ub_event* 322 ub_winsock_register_wsaevent(struct ub_event_base* base, void* wsaevent, 323 void (*cb)(int, short, void*), void* arg) 324 { 325 #if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 326 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 327 328 if (!ev) 329 return NULL; 330 331 if (winsock_register_wsaevent(AS_EVENT_BASE(base), ev, wsaevent, cb, 332 arg)) 333 return AS_UB_EVENT(ev); 334 free(ev); 335 return NULL; 336 #else 337 (void)base; 338 (void)wsaevent; 339 (void)cb; 340 (void)arg; 341 return NULL; 342 #endif 343 } 344 345 void 346 ub_event_add_bits(struct ub_event* ev, short bits) 347 { 348 AS_EVENT(ev)->ev_events |= NATIVE_BITS(bits); 349 } 350 351 void 352 ub_event_del_bits(struct ub_event* ev, short bits) 353 { 354 AS_EVENT(ev)->ev_events &= ~NATIVE_BITS(bits); 355 } 356 357 void 358 ub_event_set_fd(struct ub_event* ev, int fd) 359 { 360 AS_EVENT(ev)->ev_fd = fd; 361 } 362 363 void 364 ub_event_free(struct ub_event* ev) 365 { 366 if (ev) 367 free(AS_EVENT(ev)); 368 } 369 370 int 371 ub_event_add(struct ub_event* ev, struct timeval* tv) 372 { 373 return event_add(AS_EVENT(ev), tv); 374 } 375 376 int 377 ub_event_del(struct ub_event* ev) 378 { 379 return event_del(AS_EVENT(ev)); 380 } 381 382 int 383 ub_timer_add(struct ub_event* ev, struct ub_event_base* base, 384 void (*cb)(int, short, void*), void* arg, struct timeval* tv) 385 { 386 event_set(AS_EVENT(ev), -1, EV_TIMEOUT, NATIVE_BITS_CB(cb), arg); 387 if (event_base_set(AS_EVENT_BASE(base), AS_EVENT(ev)) != 0) 388 return -1; 389 return evtimer_add(AS_EVENT(ev), tv); 390 } 391 392 int 393 ub_timer_del(struct ub_event* ev) 394 { 395 return evtimer_del(AS_EVENT(ev)); 396 } 397 398 int 399 ub_signal_add(struct ub_event* ev, struct timeval* tv) 400 { 401 return signal_add(AS_EVENT(ev), tv); 402 } 403 404 int 405 ub_signal_del(struct ub_event* ev) 406 { 407 return signal_del(AS_EVENT(ev)); 408 } 409 410 void 411 ub_winsock_unregister_wsaevent(struct ub_event* ev) 412 { 413 #if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 414 winsock_unregister_wsaevent(AS_EVENT(ev)); 415 free(AS_EVENT(ev)); 416 #else 417 (void)ev; 418 #endif 419 } 420 421 void 422 ub_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits) 423 { 424 #if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 425 winsock_tcp_wouldblock(AS_EVENT(ev), NATIVE_BITS(eventbits)); 426 #else 427 (void)ev; 428 (void)eventbits; 429 #endif 430 } 431 432 void ub_comm_base_now(struct comm_base* cb) 433 { 434 #ifdef USE_MINI_EVENT 435 /** minievent updates the time when it blocks. */ 436 (void)cb; /* nothing to do */ 437 #else /* !USE_MINI_EVENT */ 438 /** fillup the time values in the event base */ 439 time_t *tt; 440 struct timeval *tv; 441 comm_base_timept(cb, &tt, &tv); 442 if(gettimeofday(tv, NULL) < 0) { 443 log_err("gettimeofday: %s", strerror(errno)); 444 } 445 *tt = tv->tv_sec; 446 #endif /* USE_MINI_EVENT */ 447 } 448 449