tor  0.4.3.0-alpha-dev
compat_libevent.c
Go to the documentation of this file.
1 /* Copyright (c) 2009-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
9 #include "orconfig.h"
10 #define COMPAT_LIBEVENT_PRIVATE
12 
14 #include "lib/log/log.h"
15 #include "lib/log/util_bug.h"
17 
18 #include <event2/event.h>
19 #include <event2/thread.h>
20 #include <string.h>
21 
23 static const char *suppress_msg = NULL;
26 STATIC void
27 libevent_logging_callback(int severity, const char *msg)
28 {
29  char buf[1024];
30  size_t n;
31  if (suppress_msg && strstr(msg, suppress_msg))
32  return;
33  n = strlcpy(buf, msg, sizeof(buf));
34  if (n && n < sizeof(buf) && buf[n-1] == '\n') {
35  buf[n-1] = '\0';
36  }
37  switch (severity) {
38  case _EVENT_LOG_DEBUG:
39  log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
40  break;
41  case _EVENT_LOG_MSG:
42  log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
43  break;
44  case _EVENT_LOG_WARN:
45  log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
46  break;
47  case _EVENT_LOG_ERR:
48  log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
49  break;
50  default:
51  log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
52  severity, buf);
53  break;
54  }
55 }
57 void
59 {
60  event_set_log_callback(libevent_logging_callback);
61 }
62 
64 void
65 suppress_libevent_log_msg(const char *msg)
66 {
67  suppress_msg = msg;
68 }
69 
70 /* Wrapper for event_free() that tolerates tor_event_free(NULL) */
71 void
72 tor_event_free_(struct event *ev)
73 {
74  if (ev == NULL)
75  return;
76  event_free(ev);
77 }
78 
80 static struct event_base *the_event_base = NULL;
81 
102 static struct event *rescan_mainloop_ev = NULL;
103 
108 static void
109 rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg)
110 {
111  (void)fd;
112  (void)events;
113  struct event_base *the_base = arg;
114  event_base_loopbreak(the_base);
115 }
116 
119 /* This is what passes for version detection on OSX. We set
120  * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
121  * 10.4.0 (aka 1040). */
122 #ifdef __APPLE__
123 #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
124 #define MACOSX_KQUEUE_IS_BROKEN \
125  (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
126 #else
127 #define MACOSX_KQUEUE_IS_BROKEN 0
128 #endif /* defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) */
129 #endif /* defined(__APPLE__) */
130 
132 void
134 {
135  tor_assert(the_event_base == NULL);
136  /* some paths below don't use torcfg, so avoid unused variable warnings */
137  (void)torcfg;
138 
139  {
140  int attempts = 0;
141  struct event_config *cfg;
142 
143  ++attempts;
144  cfg = event_config_new();
145  tor_assert(cfg);
146 
147  /* Telling Libevent not to try to turn locking on can avoid a needless
148  * socketpair() attempt. */
149  event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
150 
151  if (torcfg->num_cpus > 0)
152  event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
153 
154  /* We can enable changelist support with epoll, since we don't give
155  * Libevent any dup'd fds. This lets us avoid some syscalls. */
156  event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
157 
158  the_event_base = event_base_new_with_config(cfg);
159 
160  event_config_free(cfg);
161  }
162 
163  if (!the_event_base) {
164  /* LCOV_EXCL_START */
165  log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
166  exit(1); // exit ok: libevent is broken.
167  /* LCOV_EXCL_STOP */
168  }
169 
170  rescan_mainloop_ev = event_new(the_event_base, -1, 0,
172  if (!rescan_mainloop_ev) {
173  /* LCOV_EXCL_START */
174  log_err(LD_GENERAL, "Unable to create rescan event: cannot continue.");
175  exit(1); // exit ok: libevent is broken.
176  /* LCOV_EXCL_STOP */
177  }
178 
179  log_info(LD_GENERAL,
180  "Initialized libevent version %s using method %s. Good.",
181  event_get_version(), tor_libevent_get_method());
182 }
183 
185 MOCK_IMPL(struct event_base *,
186 tor_libevent_get_base, (void))
187 {
188  tor_assert(the_event_base != NULL);
189  return the_event_base;
190 }
191 
193 const char *
195 {
196  return event_base_get_method(the_event_base);
197 }
198 
201 const char *
203 {
204  return event_get_version();
205 }
206 
209 const char *
211 {
212  return LIBEVENT_VERSION;
213 }
214 
218  struct event *ev;
220  void (*cb)(struct periodic_timer_t *, void *);
222  void *data;
223 };
224 
226 static void
227 periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
228 {
229  periodic_timer_t *timer = arg;
230  (void) what;
231  (void) fd;
232  timer->cb(timer, timer->data);
233 }
234 
239 periodic_timer_new(struct event_base *base,
240  const struct timeval *tv,
241  void (*cb)(periodic_timer_t *timer, void *data),
242  void *data)
243 {
244  periodic_timer_t *timer;
245  tor_assert(base);
246  tor_assert(tv);
247  tor_assert(cb);
248  timer = tor_malloc_zero(sizeof(periodic_timer_t));
249  if (!(timer->ev = tor_event_new(base, -1, EV_PERSIST,
250  periodic_timer_cb, timer))) {
251  tor_free(timer);
252  return NULL;
253  }
254  timer->cb = cb;
255  timer->data = data;
256  periodic_timer_launch(timer, tv);
257  return timer;
258 }
259 
266 void
268 {
269  tor_assert(timer);
270  if (event_pending(timer->ev, EV_TIMEOUT, NULL))
271  return;
272  event_add(timer->ev, tv);
273 }
274 
282 void
284 {
285  tor_assert(timer);
286  (void) event_del(timer->ev);
287 }
288 
290 void
292 {
293  if (!timer)
294  return;
295  tor_event_free(timer->ev);
296  tor_free(timer);
297 }
298 
311  struct event *ev;
312  void (*cb)(mainloop_event_t *, void *);
313  void *userdata;
314 };
315 
319 static void
320 mainloop_event_cb(evutil_socket_t fd, short what, void *arg)
321 {
322  (void)fd;
323  (void)what;
324  mainloop_event_t *mev = arg;
325  mev->cb(mev, mev->userdata);
326 }
327 
331 static void
332 mainloop_event_postloop_cb(evutil_socket_t fd, short what, void *arg)
333 {
334  (void)fd;
335  (void)what;
336 
337  /* Note that if rescan_mainloop_ev is already activated,
338  * event_active() will do nothing: only the first post-loop event that
339  * happens each time through the event loop will cause it to be
340  * activated.
341  *
342  * Because event_active() puts events on a FIFO queue, every event
343  * that is made active _after_ rescan_mainloop_ev will get its
344  * callback run after rescan_mainloop_cb is called -- that is, on the
345  * next iteration of the loop.
346  */
347  event_active(rescan_mainloop_ev, EV_READ, 1);
348 
349  mainloop_event_t *mev = arg;
350  mev->cb(mev, mev->userdata);
351 }
352 
356 static mainloop_event_t *
358  void (*cb)(mainloop_event_t *, void *),
359  void *userdata)
360 {
361  tor_assert(cb);
362 
363  struct event_base *base = tor_libevent_get_base();
364  mainloop_event_t *mev = tor_malloc_zero(sizeof(mainloop_event_t));
365  mev->ev = tor_event_new(base, -1, 0,
367  mev);
368  tor_assert(mev->ev);
369  mev->cb = cb;
370  mev->userdata = userdata;
371  return mev;
372 }
373 
386 mainloop_event_new(void (*cb)(mainloop_event_t *, void *),
387  void *userdata)
388 {
389  return mainloop_event_new_impl(0, cb, userdata);
390 }
391 
401  void *userdata)
402 {
403  return mainloop_event_new_impl(1, cb, userdata);
404 }
405 
414 void
416 {
417  tor_assert(event);
418  event_active(event->ev, EV_READ, 1);
419 }
420 
432 int
434 {
435  tor_assert(event);
436  if (BUG(tv == NULL)) {
437  // LCOV_EXCL_START
439  return 0;
440  // LCOV_EXCL_STOP
441  }
442  return event_add(event->ev, tv);
443 }
444 
447 void
449 {
450  if (!event)
451  return;
452  (void) event_del(event->ev);
453 }
454 
456 void
458 {
459  if (!event)
460  return;
461  tor_event_free(event->ev);
462  memset(event, 0xb8, sizeof(*event));
463  tor_free(event);
464 }
465 
466 int
467 tor_init_libevent_rng(void)
468 {
469  int rv = 0;
470  char buf[256];
471  if (evutil_secure_rng_init() < 0) {
472  rv = -1;
473  }
474  crypto_rand(buf, 32);
475 #ifdef HAVE_EVUTIL_SECURE_RNG_ADD_BYTES
476  evutil_secure_rng_add_bytes(buf, 32);
477 #endif
478  evutil_secure_rng_get_bytes(buf, sizeof(buf));
479  return rv;
480 }
481 
485 void
487 {
488  tor_event_free(rescan_mainloop_ev);
489  if (the_event_base)
490  event_base_free(the_event_base);
491  the_event_base = NULL;
492 }
493 
502 int
503 tor_libevent_run_event_loop(struct event_base *base, int once)
504 {
505  const int flags = once ? EVLOOP_ONCE : 0;
506  return event_base_loop(base, flags);
507 }
508 
511 void
512 tor_libevent_exit_loop_after_delay(struct event_base *base,
513  const struct timeval *delay)
514 {
515  event_base_loopexit(base, delay);
516 }
517 
520 void
522 {
523  event_base_loopbreak(base);
524 }
525 
526 #if defined(TOR_UNIT_TESTS)
527 
529 void
530 tor_libevent_postfork(void)
531 {
532  int r = event_reinit(tor_libevent_get_base());
533  tor_assert(r == 0);
534 }
535 #endif /* defined(TOR_UNIT_TESTS) */
static void rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg)
Common functions for using (pseudo-)random number generators.
void periodic_timer_disable(periodic_timer_t *timer)
static void mainloop_event_cb(evutil_socket_t fd, short what, void *arg)
static void periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
#define LD_GENERAL
Definition: log.h:60
static const char * suppress_msg
int tor_libevent_run_event_loop(struct event_base *base, int once)
#define tor_free(p)
Definition: malloc.h:52
mainloop_event_t * mainloop_event_postloop_new(void(*cb)(mainloop_event_t *, void *), void *userdata)
void mainloop_event_activate(mainloop_event_t *event)
void(* cb)(struct periodic_timer_t *, void *)
static mainloop_event_t * mainloop_event_new_impl(int postloop, void(*cb)(mainloop_event_t *, void *), void *userdata)
tor_assert(buffer)
void tor_libevent_exit_loop_after_delay(struct event_base *base, const struct timeval *delay)
static struct event_base * the_event_base
void mainloop_event_cancel(mainloop_event_t *event)
#define LD_NOCB
Definition: log.h:142
periodic_timer_t * periodic_timer_new(struct event_base *base, const struct timeval *tv, void(*cb)(periodic_timer_t *timer, void *data), void *data)
const char * tor_libevent_get_version_str(void)
const char * tor_libevent_get_method(void)
void tor_libevent_initialize(tor_libevent_cfg *torcfg)
void tor_libevent_free_all(void)
MOCK_IMPL(struct event_base *, tor_libevent_get_base,(void))
const char * tor_libevent_get_header_version_str(void)
void tor_libevent_exit_loop_after_callback(struct event_base *base)
mainloop_event_t * mainloop_event_new(void(*cb)(mainloop_event_t *, void *), void *userdata)
void suppress_libevent_log_msg(const char *msg)
static struct event * rescan_mainloop_ev
STATIC void libevent_logging_callback(int severity, const char *msg)
Header for compat_string.c.
void mainloop_event_free_(mainloop_event_t *event)
void configure_libevent_logging(void)
void periodic_timer_launch(periodic_timer_t *timer, const struct timeval *tv)
int mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
static void mainloop_event_postloop_cb(evutil_socket_t fd, short what, void *arg)
#define LD_NET
Definition: log.h:64
Headers for log.c.
Header for compat_libevent.c.
Macros to manage assertions, fatal and non-fatal.
void periodic_timer_free_(periodic_timer_t *timer)
struct event * ev