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