Fix a compilation warning on compat_libevent.c on some versions of windows libevent
[tor.git] / src / common / compat_libevent.c
blob56ba3235b5201883b756ba04862183e5a879cd1d
1 /* Copyright (c) 2009-2010, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
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.
11 **/
13 #include "orconfig.h"
14 #include "compat.h"
15 #include "compat_libevent.h"
17 #include "util.h"
18 #include "log.h"
20 #ifdef HAVE_EVENT2_EVENT_H
21 #include <event2/event.h>
22 #else
23 #include <event.h>
24 #endif
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
30 byte is unused.
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. */
55 static void
56 libevent_logging_callback(int severity, const char *msg)
58 char buf[1024];
59 size_t n;
60 if (suppress_msg && strstr(msg, suppress_msg))
61 return;
62 n = strlcpy(buf, msg, sizeof(buf));
63 if (n && n < sizeof(buf) && buf[n-1] == '\n') {
64 buf[n-1] = '\0';
66 switch (severity) {
67 case _EVENT_LOG_DEBUG:
68 log(LOG_DEBUG, LD_NET, "Message from libevent: %s", buf);
69 break;
70 case _EVENT_LOG_MSG:
71 log(LOG_INFO, LD_NET, "Message from libevent: %s", buf);
72 break;
73 case _EVENT_LOG_WARN:
74 log(LOG_WARN, LD_GENERAL, "Warning from libevent: %s", buf);
75 break;
76 case _EVENT_LOG_ERR:
77 log(LOG_ERR, LD_GENERAL, "Error from libevent: %s", buf);
78 break;
79 default:
80 log(LOG_WARN, LD_GENERAL, "Message [%d] from libevent: %s",
81 severity, buf);
82 break;
85 /** Set hook to intercept log messages from libevent. */
86 void
87 configure_libevent_logging(void)
89 event_set_log_callback(libevent_logging_callback);
91 /** Ignore any libevent log message that contains <b>msg</b>. */
92 void
93 suppress_libevent_log_msg(const char *msg)
95 suppress_msg = msg;
97 #else
98 void
99 configure_libevent_logging(void)
102 void
103 suppress_libevent_log_msg(const char *msg)
105 (void)msg;
107 #endif
109 #ifndef HAVE_EVENT2_EVENT_H
110 /** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */
111 struct event *
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);
117 if (! base)
118 base = tor_libevent_get_base();
119 event_base_set(base, e);
120 return e;
122 /** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */
123 struct event *
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. */
130 struct event *
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. */
137 void
138 tor_event_free(struct event *ev)
140 event_del(ev);
141 tor_free(ev);
143 #endif
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). */
151 #ifdef __APPLE__
152 #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
153 #define MACOSX_KQUEUE_IS_BROKEN \
154 (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
155 #else
156 #define MACOSX_KQUEUE_IS_BROKEN 0
157 #endif
158 #endif
160 /** Initialize the Libevent library and set up the event base. */
161 void
162 tor_libevent_initialize(void)
164 tor_assert(the_event_base == NULL);
166 #ifdef __APPLE__
167 if (MACOSX_KQUEUE_IS_BROKEN ||
168 tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
169 setenv("EVENT_NOKQUEUE","1",1);
171 #endif
173 #ifdef HAVE_EVENT2_EVENT_H
174 the_event_base = event_base_new();
175 #else
176 the_event_base = event_init();
177 #endif
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());
185 #else
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.");
191 #endif
194 /** Return the current Libevent event base that we're set up to use. */
195 struct event_base *
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);
210 #endif
212 /** Return the name of the Libevent backend we're using. */
213 const char *
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();
220 #else
221 return "<unknown>";
222 #endif
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 */
228 static le_version_t
229 tor_decode_libevent_version(const char *v)
231 unsigned major, minor, patchlevel;
232 char c, extra;
233 int fields;
235 /* Try the new preferred "1.4.11-stable" format. */
236 fields = sscanf(v, "%u.%u.%u%c", &major, &minor, &patchlevel, &c);
237 if (fields == 3 ||
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);
250 return LE_OTHER;
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.*/
257 static int
258 le_versions_compatibility(le_version_t v)
260 if (v == LE_OTHER)
261 return 0;
262 if (v < V_OLD(1,0,'c'))
263 return 1;
264 else if (v < V(1,4,0))
265 return 2;
266 else if (v < V(1,4,99))
267 return 3;
268 else if (v < V(2,0,1))
269 return 4;
270 else /* Everything 2.0 and later should be compatible. */
271 return 5;
274 /** Return the version number of the currently running version of Libevent.
275 See le_version_t for info on the format.
277 static le_version_t
278 tor_get_libevent_version(const char **v_out)
280 const char *v;
281 le_version_t r;
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);
288 #else
289 v = "pre-1.0c";
290 r = LE_OLD;
291 #endif
292 if (v_out)
293 *v_out = v;
294 return r;
297 /** Return a string representation of the version of the currently running
298 * version of Libevent. */
299 const char *
300 tor_libevent_get_version_str(void)
302 #ifdef HAVE_EVENT_GET_VERSION
303 return event_get_version();
304 #else
305 return "pre-1.0c";
306 #endif
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.
313 void
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'))
338 buggy = 1;
339 } else if (!strcmp(m, "epoll")) {
340 if (version < V(1,1,0))
341 iffy = 1;
342 } else if (!strcmp(m, "poll")) {
343 if (version < V_OLD(1,0,'e'))
344 buggy = 1;
345 if (version < V(1,1,0))
346 slow = 1;
347 } else if (!strcmp(m, "select")) {
348 if (version < V(1,1,0))
349 slow = 1;
350 } else if (!strcmp(m, "win32")) {
351 if (version < V_OLD(1,1,'b'))
352 buggy = 1;
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')) {
359 thread_unsafe = 1;
360 sad_os = "BSD variants";
362 #elif defined(__APPLE__) || defined(__darwin__)
363 if (server && version < V_OLD(1,3,'b')) {
364 thread_unsafe = 1;
365 sad_os = "Mac OS X";
367 #endif
369 if (thread_unsafe) {
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);
373 badness = "BROKEN";
374 } else if (buggy) {
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);
378 badness = "BROKEN";
379 } else if (iffy) {
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);
383 badness = "BUGGY";
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.",
388 v,m);
389 badness = "SLOW";
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
399 #endif
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
403 * user. */
404 void
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())) {
416 le_version_t v1, v2;
417 int compat1 = -1, compat2 = -1;
418 int verybad;
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());
430 if (verybad)
431 log_warn(LD_GENERAL, "This will almost certainly make Tor crash.");
432 else
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());
451 #else
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());
463 #endif
465 #elif defined(HEADER_VERSION)
466 #warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
467 #else
468 /* Your libevent is ancient. */
469 #endif