1 /* Copyright (c) 2009-2010, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 * \file compat_libevent.c
6 * \brief Wrappers to handle porting between different versions of libevent.
8 * In an ideal world, we'd just use Libevent 2.0 from now on. But as of June
9 * 2009, Libevent 2.0 is still in alpha, and we will have old versions of
10 * Libevent for the forseeable future.
15 #include "compat_libevent.h"
20 #ifdef HAVE_EVENT2_EVENT_H
21 #include <event2/event.h>
26 /** A number representing a version of Libevent.
28 This is a 4-byte number, with the first three bytes representing the
29 major, minor, and patchlevel respectively of the library. The fourth
32 This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent
33 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the
34 format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a
35 to be equivalent to 1.0.1, and so on.
37 typedef uint32_t le_version_t
;
39 /* Macros: returns the number of a libevent version. */
40 #define V(major, minor, patch) \
41 (((major) << 24) | ((minor) << 16) | ((patch) << 8))
42 #define V_OLD(major, minor, patch) \
43 V((major), (minor), (patch)-'a'+1)
45 #define LE_OLD V(0,0,0)
46 #define LE_OTHER V(0,0,99)
48 static le_version_t
tor_get_libevent_version(const char **v_out
);
50 #ifdef HAVE_EVENT_SET_LOG_CALLBACK
51 /** A string which, if it appears in a libevent log, should be ignored. */
52 static const char *suppress_msg
= NULL
;
53 /** Callback function passed to event_set_log() so we can intercept
54 * log messages from libevent. */
56 libevent_logging_callback(int severity
, const char *msg
)
60 if (suppress_msg
&& strstr(msg
, suppress_msg
))
62 n
= strlcpy(buf
, msg
, sizeof(buf
));
63 if (n
&& n
< sizeof(buf
) && buf
[n
-1] == '\n') {
67 case _EVENT_LOG_DEBUG
:
68 log(LOG_DEBUG
, LD_NET
, "Message from libevent: %s", buf
);
71 log(LOG_INFO
, LD_NET
, "Message from libevent: %s", buf
);
74 log(LOG_WARN
, LD_GENERAL
, "Warning from libevent: %s", buf
);
77 log(LOG_ERR
, LD_GENERAL
, "Error from libevent: %s", buf
);
80 log(LOG_WARN
, LD_GENERAL
, "Message [%d] from libevent: %s",
85 /** Set hook to intercept log messages from libevent. */
87 configure_libevent_logging(void)
89 event_set_log_callback(libevent_logging_callback
);
91 /** Ignore any libevent log message that contains <b>msg</b>. */
93 suppress_libevent_log_msg(const char *msg
)
99 configure_libevent_logging(void)
103 suppress_libevent_log_msg(const char *msg
)
109 #ifndef HAVE_EVENT2_EVENT_H
110 /** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */
112 tor_event_new(struct event_base
*base
, int sock
, short what
,
113 void (*cb
)(int, short, void *), void *arg
)
115 struct event
*e
= tor_malloc_zero(sizeof(struct event
));
116 event_set(e
, sock
, what
, cb
, arg
);
118 base
= tor_libevent_get_base();
119 event_base_set(base
, e
);
122 /** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */
124 tor_evtimer_new(struct event_base
*base
,
125 void (*cb
)(int, short, void *), void *arg
)
127 return tor_event_new(base
, -1, 0, cb
, arg
);
129 /** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */
131 tor_evsignal_new(struct event_base
* base
, int sig
,
132 void (*cb
)(int, short, void *), void *arg
)
134 return tor_event_new(base
, sig
, EV_SIGNAL
|EV_PERSIST
, cb
, arg
);
136 /** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */
138 tor_event_free(struct event
*ev
)
145 /** Global event base for use by the main thread. */
146 struct event_base
*the_event_base
= NULL
;
148 /* This is what passes for version detection on OSX. We set
149 * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
150 * 10.4.0 (aka 1040). */
152 #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
153 #define MACOSX_KQUEUE_IS_BROKEN \
154 (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
156 #define MACOSX_KQUEUE_IS_BROKEN 0
160 /** Initialize the Libevent library and set up the event base. */
162 tor_libevent_initialize(void)
164 tor_assert(the_event_base
== NULL
);
167 if (MACOSX_KQUEUE_IS_BROKEN
||
168 tor_get_libevent_version(NULL
) < V_OLD(1,1,'b')) {
169 setenv("EVENT_NOKQUEUE","1",1);
173 #ifdef HAVE_EVENT2_EVENT_H
174 the_event_base
= event_base_new();
176 the_event_base
= event_init();
179 #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
180 /* Making this a NOTICE for now so we can link bugs to a libevent versions
181 * or methods better. */
182 log(LOG_NOTICE
, LD_GENERAL
,
183 "Initialized libevent version %s using method %s. Good.",
184 event_get_version(), tor_libevent_get_method());
186 log(LOG_NOTICE
, LD_GENERAL
,
187 "Initialized old libevent (version 1.0b or earlier).");
188 log(LOG_WARN
, LD_GENERAL
,
189 "You have a *VERY* old version of libevent. It is likely to be buggy; "
190 "please build Tor with a more recent version.");
194 /** Return the current Libevent event base that we're set up to use. */
196 tor_libevent_get_base(void)
198 return the_event_base
;
201 #ifndef HAVE_EVENT_BASE_LOOPEXIT
202 /* Replacement for event_base_loopexit on some very old versions of Libevent
203 that we are not yet brave enough to deprecate. */
205 tor_event_base_loopexit(struct event_base
*base
, struct timeval
*tv
)
207 tor_assert(base
== the_event_base
);
208 return event_loopexit(tv
);
212 /** Return the name of the Libevent backend we're using. */
214 tor_libevent_get_method(void)
216 #ifdef HAVE_EVENT2_EVENT_H
217 return event_base_get_method(the_event_base
);
218 #elif defined(HAVE_EVENT_GET_METHOD)
219 return event_get_method();
225 /** Return the le_version_t for the current version of libevent. If the
226 * version is very new, return LE_OTHER. If the version is so old that it
227 * doesn't support event_get_version(), return LE_OLD. DOCDOC */
229 tor_decode_libevent_version(const char *v
)
231 unsigned major
, minor
, patchlevel
;
235 /* Try the new preferred "1.4.11-stable" format. */
236 fields
= sscanf(v
, "%u.%u.%u%c", &major
, &minor
, &patchlevel
, &c
);
238 (fields
== 4 && (c
== '-' || c
== '_'))) {
239 return V(major
,minor
,patchlevel
);
242 /* Try the old "1.3e" format. */
243 fields
= sscanf(v
, "%u.%u%c%c", &major
, &minor
, &c
, &extra
);
244 if (fields
== 3 && TOR_ISALPHA(c
)) {
245 return V_OLD(major
, minor
, c
);
246 } else if (fields
== 2) {
247 return V(major
, minor
, 0);
253 /** Return an integer representing the binary interface of a Libevent library.
254 * Two different versions with different numbers are sure not to be binary
255 * compatible. Two different versions with the same numbers have a decent
256 * chance of binary compatibility.*/
258 le_versions_compatibility(le_version_t v
)
262 if (v
< V_OLD(1,0,'c'))
264 else if (v
< V(1,4,0))
266 else if (v
< V(1,4,99))
268 else if (v
< V(2,0,1))
270 else /* Everything 2.0 and later should be compatible. */
274 /** Return the version number of the currently running version of Libevent.
275 See le_version_t for info on the format.
278 tor_get_libevent_version(const char **v_out
)
282 #if defined(HAVE_EVENT_GET_VERSION_NUMBER)
283 v
= event_get_version();
284 r
= event_get_version_number();
285 #elif defined (HAVE_EVENT_GET_VERSION)
286 v
= event_get_version();
287 r
= tor_decode_libevent_version(v
);
297 /** Return a string representation of the version of the currently running
298 * version of Libevent. */
300 tor_libevent_get_version_str(void)
302 #ifdef HAVE_EVENT_GET_VERSION
303 return event_get_version();
310 * Compare the current Libevent method and version to a list of versions
311 * which are known not to work. Warn the user as appropriate.
314 tor_check_libevent_version(const char *m
, int server
,
315 const char **badness_out
)
317 int buggy
= 0, iffy
= 0, slow
= 0, thread_unsafe
= 0;
318 le_version_t version
;
319 const char *v
= NULL
;
320 const char *badness
= NULL
;
321 const char *sad_os
= "";
323 version
= tor_get_libevent_version(&v
);
325 /* XXX Would it be worthwhile disabling the methods that we know
326 * are buggy, rather than just warning about them and then proceeding
327 * to use them? If so, we should probably not wrap this whole thing
328 * in HAVE_EVENT_GET_VERSION and HAVE_EVENT_GET_METHOD. -RD */
329 /* XXXX The problem is that it's not trivial to get libevent to change it's
330 * method once it's initialized, and it's not trivial to tell what method it
331 * will use without initializing it. I guess we could preemptively disable
332 * buggy libevent modes based on the version _before_ initializing it,
333 * though, but then there's no good way (afaict) to warn "I would have used
334 * kqueue, but instead I'm using select." -NM */
335 /* XXXX022 revist the above; it is fixable now. */
336 if (!strcmp(m
, "kqueue")) {
337 if (version
< V_OLD(1,1,'b'))
339 } else if (!strcmp(m
, "epoll")) {
340 if (version
< V(1,1,0))
342 } else if (!strcmp(m
, "poll")) {
343 if (version
< V_OLD(1,0,'e'))
345 if (version
< V(1,1,0))
347 } else if (!strcmp(m
, "select")) {
348 if (version
< V(1,1,0))
350 } else if (!strcmp(m
, "win32")) {
351 if (version
< V_OLD(1,1,'b'))
355 /* Libevent versions before 1.3b do very badly on operating systems with
356 * user-space threading implementations. */
357 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
358 if (server
&& version
< V_OLD(1,3,'b')) {
360 sad_os
= "BSD variants";
362 #elif defined(__APPLE__) || defined(__darwin__)
363 if (server
&& version
< V_OLD(1,3,'b')) {
370 log(LOG_WARN
, LD_GENERAL
,
371 "Libevent version %s often crashes when running a Tor server with %s. "
372 "Please use the latest version of libevent (1.3b or later)",v
,sad_os
);
375 log(LOG_WARN
, LD_GENERAL
,
376 "There are serious bugs in using %s with libevent %s. "
377 "Please use the latest version of libevent.", m
, v
);
380 log(LOG_WARN
, LD_GENERAL
,
381 "There are minor bugs in using %s with libevent %s. "
382 "You may want to use the latest version of libevent.", m
, v
);
384 } else if (slow
&& server
) {
385 log(LOG_WARN
, LD_GENERAL
,
386 "libevent %s can be very slow with %s. "
387 "When running a server, please use the latest version of libevent.",
392 *badness_out
= badness
;
395 #if defined(LIBEVENT_VERSION)
396 #define HEADER_VERSION LIBEVENT_VERSION
397 #elif defined(_EVENT_VERSION)
398 #define HEADER_VERSION _EVENT_VERSION
401 /** See whether the headers we were built against differ from the library we
402 * linked against so much that we're likely to crash. If so, warn the
405 tor_check_libevent_header_compatibility(void)
407 (void) le_versions_compatibility
;
408 (void) tor_decode_libevent_version
;
410 /* In libevent versions before 2.0, it's hard to keep binary compatibility
411 * between upgrades, and unpleasant to detect when the version we compiled
412 * against is unlike the version we have linked against. Here's how. */
413 #if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
414 /* We have a header-file version and a function-call version. Easy. */
415 if (strcmp(HEADER_VERSION
, event_get_version())) {
417 int compat1
= -1, compat2
= -1;
419 v1
= tor_decode_libevent_version(HEADER_VERSION
);
420 v2
= tor_decode_libevent_version(event_get_version());
421 compat1
= le_versions_compatibility(v1
);
422 compat2
= le_versions_compatibility(v2
);
424 verybad
= compat1
!= compat2
;
426 log(verybad
? LOG_WARN
: LOG_NOTICE
,
427 LD_GENERAL
, "We were compiled with headers from version %s "
428 "of Libevent, but we're using a Libevent library that says it's "
429 "version %s.", HEADER_VERSION
, event_get_version());
431 log_warn(LD_GENERAL
, "This will almost certainly make Tor crash.");
433 log_info(LD_GENERAL
, "I think these versions are binary-compatible.");
435 #elif defined(HAVE_EVENT_GET_VERSION)
436 /* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or
437 earlier, where that's normal. To see whether we were compiled with an
438 earlier version, let's see whether the struct event defines MIN_HEAP_IDX.
440 #ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
441 /* The header files are 1.4.0-beta or later. If the version is not
442 * 1.4.0-beta, we are incompatible. */
444 if (strcmp(event_get_version(), "1.4.0-beta")) {
445 log_warn(LD_GENERAL
, "It's a little hard to tell, but you seem to have "
446 "Libevent 1.4.0-beta header files, whereas you have linked "
447 "against Libevent %s. This will probably make Tor crash.",
448 event_get_version());
452 /* Our headers are 1.3e or earlier. If the library version is not 1.4.x or
453 later, we're probably fine. */
455 const char *v
= event_get_version();
456 if ((v
[0] == '1' && v
[2] == '.' && v
[3] > '3') || v
[0] > '1') {
457 log_warn(LD_GENERAL
, "It's a little hard to tell, but you seem to have "
458 "Libevent header file from 1.3e or earlier, whereas you have "
459 "linked against Libevent %s. This will probably make Tor "
460 "crash.", event_get_version());
465 #elif defined(HEADER_VERSION)
466 #warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
468 /* Your libevent is ancient. */
473 If possible, we're going to try to use Libevent's periodic timer support,
474 since it does a pretty good job of making sure that periodic events get
475 called exactly M seconds apart, rather than starting each one exactly M
476 seconds after the time that the last one was run.
478 #ifdef HAVE_EVENT2_EVENT_H
479 #define HAVE_PERIODIC
480 #define PERIODIC_FLAGS EV_PERSIST
482 #define PERIODIC_FLAGS 0
485 /** Represents a timer that's run every N microseconds by Libevent. */
486 struct periodic_timer_t
{
487 /** Underlying event used to implement this periodic event. */
489 /** The callback we'll be invoking whenever the event triggers */
490 void (*cb
)(struct periodic_timer_t
*, void *);
491 /** User-supplied data for the callback */
493 #ifndef HAVE_PERIODIC
494 /** If Libevent doesn't know how to invoke events every N microseconds,
495 * we'll need to remember the timeout interval here. */
500 /** Libevent callback to implement a periodic event. */
502 periodic_timer_cb(evutil_socket_t fd
, short what
, void *arg
)
504 periodic_timer_t
*timer
= arg
;
507 #ifndef HAVE_PERIODIC
508 /** reschedule the event as needed. */
509 event_add(timer
->ev
, &timer
->tv
);
511 timer
->cb(timer
, timer
->data
);
514 /** Create and schedule a new timer that will run every <b>tv</b> in
515 * the event loop of <b>base</b>. When the timer fires, it will
516 * run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */
518 periodic_timer_new(struct event_base
*base
,
519 const struct timeval
*tv
,
520 void (*cb
)(periodic_timer_t
*timer
, void *data
),
523 periodic_timer_t
*timer
;
527 timer
= tor_malloc_zero(sizeof(periodic_timer_t
));
528 if (!(timer
->ev
= tor_event_new(base
, -1, PERIODIC_FLAGS
,
529 periodic_timer_cb
, timer
))) {
535 #ifndef HAVE_PERIODIC
536 memcpy(&timer
->tv
, tv
, sizeof(struct timeval
));
538 event_add(timer
->ev
, (struct timeval
*)tv
); /*drop const for old libevent*/
542 /** Stop and free a periodic timer */
544 periodic_timer_free(periodic_timer_t
*timer
)
548 tor_event_free(timer
->ev
);