ub_event.c revision 307729
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 90UB_EV_BITS_CB(comm_point_udp_callback); 91UB_EV_BITS_CB(comm_point_udp_ancil_callback) 92UB_EV_BITS_CB(comm_point_tcp_accept_callback) 93UB_EV_BITS_CB(comm_point_tcp_handle_callback) 94UB_EV_BITS_CB(comm_timer_callback) 95UB_EV_BITS_CB(comm_signal_callback) 96UB_EV_BITS_CB(comm_point_local_handle_callback) 97UB_EV_BITS_CB(comm_point_raw_handle_callback) 98UB_EV_BITS_CB(tube_handle_signal) 99UB_EV_BITS_CB(comm_base_handle_slow_accept) 100 101static 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) ((struct event_base*)x) 136#define AS_UB_EVENT_BASE(x) ((struct ub_event_base*)x) 137#define AS_EVENT(x) ((struct event*)x) 138#define AS_UB_EVENT(x) ((struct ub_event*)x) 139 140const char* ub_event_get_version(void) 141{ 142 return event_get_version(); 143} 144 145#if (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && defined(EVBACKEND_SELECT) 146static const char* ub_ev_backend2str(int b) 147{ 148 switch(b) { 149 case EVBACKEND_SELECT: return "select"; 150 case EVBACKEND_POLL: return "poll"; 151 case EVBACKEND_EPOLL: return "epoll"; 152 case EVBACKEND_KQUEUE: return "kqueue"; 153 case EVBACKEND_DEVPOLL: return "devpoll"; 154 case EVBACKEND_PORT: return "evport"; 155 } 156 return "unknown"; 157} 158#endif 159 160void 161ub_get_event_sys(struct ub_event_base* base, const char** n, const char** s, 162 const char** m) 163{ 164#ifdef USE_WINSOCK 165 (void)base; 166 *n = "event"; 167 *s = "winsock"; 168 *m = "WSAWaitForMultipleEvents"; 169#elif defined(USE_MINI_EVENT) 170 (void)base; 171 *n = "mini-event"; 172 *s = "internal"; 173 *m = "select"; 174#else 175 struct event_base* b = AS_EVENT_BASE(base); 176 *s = event_get_version(); 177# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 178 *n = "libev"; 179 if (!b) 180 b = (struct event_base*)ev_default_loop(EVFLAG_AUTO); 181# ifdef EVBACKEND_SELECT 182 *m = ub_ev_backend2str(ev_backend((struct ev_loop*)b)); 183# else 184 *m = "not obtainable"; 185# endif 186# elif defined(HAVE_EVENT_BASE_GET_METHOD) 187 *n = "libevent"; 188 if (!b) 189 b = event_base_new(); 190 *m = event_base_get_method(b); 191# else 192 *n = "unknown"; 193 *m = "not obtainable"; 194 (void)b; 195# endif 196# ifdef HAVE_EVENT_BASE_FREE 197 if (b && b != AS_EVENT_BASE(base)) 198 event_base_free(b); 199# endif 200#endif 201} 202 203struct ub_event_base* 204ub_default_event_base(int sigs, time_t* time_secs, struct timeval* time_tv) 205{ 206 void* base; 207 208 (void)base; 209#ifdef USE_MINI_EVENT 210 (void)sigs; 211 /* use mini event time-sharing feature */ 212 base = event_init(time_secs, time_tv); 213#else 214 (void)time_secs; 215 (void)time_tv; 216# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 217 /* libev */ 218 if(sigs) 219 base = ev_default_loop(EVFLAG_AUTO); 220 else 221 base = ev_loop_new(EVFLAG_AUTO); 222# else 223 (void)sigs; 224# ifdef HAVE_EVENT_BASE_NEW 225 base = event_base_new(); 226# else 227 base = event_init(); 228# endif 229# endif 230#endif 231 return (struct ub_event_base*)base; 232} 233 234struct ub_event_base * 235ub_libevent_event_base(struct event_base* libevent_base) 236{ 237#ifdef USE_MINI_EVENT 238 (void)libevent_base; 239 return NULL; 240#else 241 return AS_UB_EVENT_BASE(libevent_base); 242#endif 243} 244 245struct event_base * 246ub_libevent_get_event_base(struct ub_event_base* base) 247{ 248#ifdef USE_MINI_EVENT 249 (void)base; 250 return NULL; 251#else 252 return AS_EVENT_BASE(base); 253#endif 254} 255 256void 257ub_event_base_free(struct ub_event_base* base) 258{ 259#ifdef USE_MINI_EVENT 260 event_base_free(AS_EVENT_BASE(base)); 261#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE) 262 /* only libevent 1.2+ has it, but in 1.2 it is broken - 263 assertion fails on signal handling ev that is not deleted 264 in libevent 1.3c (event_base_once appears) this is fixed. */ 265 event_base_free(AS_EVENT_BASE(base)); 266#else 267 (void)base; 268#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */ 269} 270 271int 272ub_event_base_dispatch(struct ub_event_base* base) 273{ 274 return event_base_dispatch(AS_EVENT_BASE(base)); 275} 276 277int 278ub_event_base_loopexit(struct ub_event_base* base) 279{ 280 return event_base_loopexit(AS_EVENT_BASE(base), NULL); 281} 282 283struct ub_event* 284ub_event_new(struct ub_event_base* base, int fd, short bits, 285 void (*cb)(int, short, void*), void* arg) 286{ 287 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 288 289 if (!ev) 290 return NULL; 291 292 event_set(ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg); 293 if (event_base_set(AS_EVENT_BASE(base), ev) != 0) { 294 free(ev); 295 return NULL; 296 } 297 return AS_UB_EVENT(ev); 298} 299 300struct ub_event* 301ub_signal_new(struct ub_event_base* base, int fd, 302 void (*cb)(int, short, void*), void* arg) 303{ 304 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 305 306 if (!ev) 307 return NULL; 308 309 signal_set(ev, fd, NATIVE_BITS_CB(cb), arg); 310 if (event_base_set(AS_EVENT_BASE(base), ev) != 0) { 311 free(ev); 312 return NULL; 313 } 314 return AS_UB_EVENT(ev); 315} 316 317struct ub_event* 318ub_winsock_register_wsaevent(struct ub_event_base* base, void* wsaevent, 319 void (*cb)(int, short, void*), void* arg) 320{ 321#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 322 struct event *ev = (struct event*)calloc(1, sizeof(struct event)); 323 324 if (!ev) 325 return NULL; 326 327 if (winsock_register_wsaevent(AS_EVENT_BASE(base), ev, wsaevent, cb, 328 arg)) 329 return AS_UB_EVENT(ev); 330 free(ev); 331 return NULL; 332#else 333 (void)base; 334 (void)wsaevent; 335 (void)cb; 336 (void)arg; 337 return NULL; 338#endif 339} 340 341void 342ub_event_add_bits(struct ub_event* ev, short bits) 343{ 344 AS_EVENT(ev)->ev_events |= NATIVE_BITS(bits); 345} 346 347void 348ub_event_del_bits(struct ub_event* ev, short bits) 349{ 350 AS_EVENT(ev)->ev_events &= ~NATIVE_BITS(bits); 351} 352 353void 354ub_event_set_fd(struct ub_event* ev, int fd) 355{ 356 AS_EVENT(ev)->ev_fd = fd; 357} 358 359void 360ub_event_free(struct ub_event* ev) 361{ 362 if (ev) 363 free(AS_EVENT(ev)); 364} 365 366int 367ub_event_add(struct ub_event* ev, struct timeval* tv) 368{ 369 return event_add(AS_EVENT(ev), tv); 370} 371 372int 373ub_event_del(struct ub_event* ev) 374{ 375 return event_del(AS_EVENT(ev)); 376} 377 378int 379ub_timer_add(struct ub_event* ev, struct ub_event_base* base, 380 void (*cb)(int, short, void*), void* arg, struct timeval* tv) 381{ 382 event_set(AS_EVENT(ev), -1, EV_TIMEOUT, NATIVE_BITS_CB(cb), arg); 383 if (event_base_set(AS_EVENT_BASE(base), AS_EVENT(ev)) != 0) 384 return -1; 385 return evtimer_add(AS_EVENT(ev), tv); 386} 387 388int 389ub_timer_del(struct ub_event* ev) 390{ 391 return evtimer_del(AS_EVENT(ev)); 392} 393 394int 395ub_signal_add(struct ub_event* ev, struct timeval* tv) 396{ 397 return signal_add(AS_EVENT(ev), tv); 398} 399 400int 401ub_signal_del(struct ub_event* ev) 402{ 403 return signal_del(AS_EVENT(ev)); 404} 405 406void 407ub_winsock_unregister_wsaevent(struct ub_event* ev) 408{ 409#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 410 winsock_unregister_wsaevent(AS_EVENT(ev)); 411 free(AS_EVENT(ev)); 412#else 413 (void)ev; 414#endif 415} 416 417void 418ub_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits) 419{ 420#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK) 421 winsock_tcp_wouldblock(AS_EVENT(ev), NATIVE_BITS(eventbits)); 422#else 423 (void)ev; 424 (void)eventbits; 425#endif 426} 427 428void ub_comm_base_now(struct comm_base* cb) 429{ 430 #ifdef USE_MINI_EVENT 431/** minievent updates the time when it blocks. */ 432 (void)cb; /* nothing to do */ 433#else /* !USE_MINI_EVENT */ 434/** fillup the time values in the event base */ 435 time_t *tt; 436 struct timeval *tv; 437 comm_base_timept(cb, &tt, &tv); 438 if(gettimeofday(tv, NULL) < 0) { 439 log_err("gettimeofday: %s", strerror(errno)); 440 } 441 *tt = tv->tv_sec; 442#endif /* USE_MINI_EVENT */ 443} 444 445