compat_libevent.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /* Copyright (c) 2009-2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file compat_libevent.c
  5. * \brief Wrappers and utility functions for Libevent.
  6. */
  7. #include "orconfig.h"
  8. #include "compat.h"
  9. #define COMPAT_LIBEVENT_PRIVATE
  10. #include "compat_libevent.h"
  11. #include "crypto.h"
  12. #include "util.h"
  13. #include "torlog.h"
  14. #include <event2/event.h>
  15. #include <event2/thread.h>
  16. /** A string which, if it appears in a libevent log, should be ignored. */
  17. static const char *suppress_msg = NULL;
  18. /** Callback function passed to event_set_log() so we can intercept
  19. * log messages from libevent. */
  20. STATIC void
  21. libevent_logging_callback(int severity, const char *msg)
  22. {
  23. char buf[1024];
  24. size_t n;
  25. if (suppress_msg && strstr(msg, suppress_msg))
  26. return;
  27. n = strlcpy(buf, msg, sizeof(buf));
  28. if (n && n < sizeof(buf) && buf[n-1] == '\n') {
  29. buf[n-1] = '\0';
  30. }
  31. switch (severity) {
  32. case _EVENT_LOG_DEBUG:
  33. log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
  34. break;
  35. case _EVENT_LOG_MSG:
  36. log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
  37. break;
  38. case _EVENT_LOG_WARN:
  39. log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
  40. break;
  41. case _EVENT_LOG_ERR:
  42. log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
  43. break;
  44. default:
  45. log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
  46. severity, buf);
  47. break;
  48. }
  49. }
  50. /** Set hook to intercept log messages from libevent. */
  51. void
  52. configure_libevent_logging(void)
  53. {
  54. event_set_log_callback(libevent_logging_callback);
  55. }
  56. /** Ignore any libevent log message that contains <b>msg</b>. */
  57. void
  58. suppress_libevent_log_msg(const char *msg)
  59. {
  60. suppress_msg = msg;
  61. }
  62. /* Wrapper for event_free() that tolerates tor_event_free(NULL) */
  63. void
  64. tor_event_free(struct event *ev)
  65. {
  66. if (ev == NULL)
  67. return;
  68. event_free(ev);
  69. }
  70. /** Global event base for use by the main thread. */
  71. static struct event_base *the_event_base = NULL;
  72. /* This is what passes for version detection on OSX. We set
  73. * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
  74. * 10.4.0 (aka 1040). */
  75. #ifdef __APPLE__
  76. #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
  77. #define MACOSX_KQUEUE_IS_BROKEN \
  78. (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
  79. #else
  80. #define MACOSX_KQUEUE_IS_BROKEN 0
  81. #endif
  82. #endif
  83. /** Initialize the Libevent library and set up the event base. */
  84. void
  85. tor_libevent_initialize(tor_libevent_cfg *torcfg)
  86. {
  87. tor_assert(the_event_base == NULL);
  88. /* some paths below don't use torcfg, so avoid unused variable warnings */
  89. (void)torcfg;
  90. {
  91. int attempts = 0;
  92. struct event_config *cfg;
  93. ++attempts;
  94. cfg = event_config_new();
  95. tor_assert(cfg);
  96. /* Telling Libevent not to try to turn locking on can avoid a needless
  97. * socketpair() attempt. */
  98. event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
  99. if (torcfg->num_cpus > 0)
  100. event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
  101. /* We can enable changelist support with epoll, since we don't give
  102. * Libevent any dup'd fds. This lets us avoid some syscalls. */
  103. event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
  104. the_event_base = event_base_new_with_config(cfg);
  105. event_config_free(cfg);
  106. }
  107. if (!the_event_base) {
  108. /* LCOV_EXCL_START */
  109. log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
  110. exit(1);
  111. /* LCOV_EXCL_STOP */
  112. }
  113. log_info(LD_GENERAL,
  114. "Initialized libevent version %s using method %s. Good.",
  115. event_get_version(), tor_libevent_get_method());
  116. }
  117. /** Return the current Libevent event base that we're set up to use. */
  118. MOCK_IMPL(struct event_base *,
  119. tor_libevent_get_base, (void))
  120. {
  121. tor_assert(the_event_base != NULL);
  122. return the_event_base;
  123. }
  124. /** Return the name of the Libevent backend we're using. */
  125. const char *
  126. tor_libevent_get_method(void)
  127. {
  128. return event_base_get_method(the_event_base);
  129. }
  130. /** Return a string representation of the version of the currently running
  131. * version of Libevent. */
  132. const char *
  133. tor_libevent_get_version_str(void)
  134. {
  135. return event_get_version();
  136. }
  137. /** Return a string representation of the version of Libevent that was used
  138. * at compilation time. */
  139. const char *
  140. tor_libevent_get_header_version_str(void)
  141. {
  142. return LIBEVENT_VERSION;
  143. }
  144. /** Represents a timer that's run every N microseconds by Libevent. */
  145. struct periodic_timer_t {
  146. /** Underlying event used to implement this periodic event. */
  147. struct event *ev;
  148. /** The callback we'll be invoking whenever the event triggers */
  149. void (*cb)(struct periodic_timer_t *, void *);
  150. /** User-supplied data for the callback */
  151. void *data;
  152. };
  153. /** Libevent callback to implement a periodic event. */
  154. static void
  155. periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
  156. {
  157. periodic_timer_t *timer = arg;
  158. (void) what;
  159. (void) fd;
  160. timer->cb(timer, timer->data);
  161. }
  162. /** Create and schedule a new timer that will run every <b>tv</b> in
  163. * the event loop of <b>base</b>. When the timer fires, it will
  164. * run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */
  165. periodic_timer_t *
  166. periodic_timer_new(struct event_base *base,
  167. const struct timeval *tv,
  168. void (*cb)(periodic_timer_t *timer, void *data),
  169. void *data)
  170. {
  171. periodic_timer_t *timer;
  172. tor_assert(base);
  173. tor_assert(tv);
  174. tor_assert(cb);
  175. timer = tor_malloc_zero(sizeof(periodic_timer_t));
  176. if (!(timer->ev = tor_event_new(base, -1, EV_PERSIST,
  177. periodic_timer_cb, timer))) {
  178. tor_free(timer);
  179. return NULL;
  180. }
  181. timer->cb = cb;
  182. timer->data = data;
  183. event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/
  184. return timer;
  185. }
  186. /** Stop and free a periodic timer */
  187. void
  188. periodic_timer_free(periodic_timer_t *timer)
  189. {
  190. if (!timer)
  191. return;
  192. tor_event_free(timer->ev);
  193. tor_free(timer);
  194. }
  195. int
  196. tor_init_libevent_rng(void)
  197. {
  198. int rv = 0;
  199. char buf[256];
  200. if (evutil_secure_rng_init() < 0) {
  201. rv = -1;
  202. }
  203. crypto_rand(buf, 32);
  204. #ifdef HAVE_EVUTIL_SECURE_RNG_ADD_BYTES
  205. evutil_secure_rng_add_bytes(buf, 32);
  206. #endif
  207. evutil_secure_rng_get_bytes(buf, sizeof(buf));
  208. return rv;
  209. }
  210. #if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1) \
  211. && !defined(TOR_UNIT_TESTS)
  212. void
  213. tor_gettimeofday_cached(struct timeval *tv)
  214. {
  215. event_base_gettimeofday_cached(the_event_base, tv);
  216. }
  217. void
  218. tor_gettimeofday_cache_clear(void)
  219. {
  220. event_base_update_cache_time(the_event_base);
  221. }
  222. #else
  223. /** Cache the current hi-res time; the cache gets reset when libevent
  224. * calls us. */
  225. static struct timeval cached_time_hires = {0, 0};
  226. /** Return a fairly recent view of the current time. */
  227. void
  228. tor_gettimeofday_cached(struct timeval *tv)
  229. {
  230. if (cached_time_hires.tv_sec == 0) {
  231. tor_gettimeofday(&cached_time_hires);
  232. }
  233. *tv = cached_time_hires;
  234. }
  235. /** Reset the cached view of the current time, so that the next time we try
  236. * to learn it, we will get an up-to-date value. */
  237. void
  238. tor_gettimeofday_cache_clear(void)
  239. {
  240. cached_time_hires.tv_sec = 0;
  241. }
  242. #ifdef TOR_UNIT_TESTS
  243. /** For testing: force-update the cached time to a given value. */
  244. void
  245. tor_gettimeofday_cache_set(const struct timeval *tv)
  246. {
  247. tor_assert(tv);
  248. memcpy(&cached_time_hires, tv, sizeof(*tv));
  249. }
  250. /** For testing: called post-fork to make libevent reinitialize
  251. * kernel structures. */
  252. void
  253. tor_libevent_postfork(void)
  254. {
  255. int r = event_reinit(tor_libevent_get_base());
  256. tor_assert(r == 0);
  257. }
  258. #endif
  259. #endif