123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- #include "orconfig.h"
- #include "compat_libevent.h"
- #include "compat.h"
- #include "util.h"
- #include "log.h"
- #ifdef HAVE_EVENT2_EVENT_H
- #include <event2/event.h>
- #else
- #include <event.h>
- #endif
- typedef uint32_t le_version_t;
- #define V(major, minor, patch) \
- (((major) << 24) | ((minor) << 16) | ((patch) << 8))
- #define V_OLD(major, minor, patch) \
- V((major), (minor), (patch)-'a'+1)
- #define LE_OLD V(0,0,0)
- #define LE_OTHER V(0,0,99)
- static le_version_t tor_get_libevent_version(const char **v_out);
- #ifdef HAVE_EVENT_SET_LOG_CALLBACK
- static const char *suppress_msg = NULL;
- static void
- libevent_logging_callback(int severity, const char *msg)
- {
- char buf[1024];
- size_t n;
- if (suppress_msg && strstr(msg, suppress_msg))
- return;
- n = strlcpy(buf, msg, sizeof(buf));
- if (n && n < sizeof(buf) && buf[n-1] == '\n') {
- buf[n-1] = '\0';
- }
- switch (severity) {
- case _EVENT_LOG_DEBUG:
- log(LOG_DEBUG, LD_NET, "Message from libevent: %s", buf);
- break;
- case _EVENT_LOG_MSG:
- log(LOG_INFO, LD_NET, "Message from libevent: %s", buf);
- break;
- case _EVENT_LOG_WARN:
- log(LOG_WARN, LD_GENERAL, "Warning from libevent: %s", buf);
- break;
- case _EVENT_LOG_ERR:
- log(LOG_ERR, LD_GENERAL, "Error from libevent: %s", buf);
- break;
- default:
- log(LOG_WARN, LD_GENERAL, "Message [%d] from libevent: %s",
- severity, buf);
- break;
- }
- }
- void
- configure_libevent_logging(void)
- {
- event_set_log_callback(libevent_logging_callback);
- }
- void
- suppress_libevent_log_msg(const char *msg)
- {
- suppress_msg = msg;
- }
- #else
- void
- configure_libevent_logging(void)
- {
- }
- void
- suppress_libevent_log_msg(const char *msg)
- {
- (void)msg;
- }
- #endif
- #ifndef HAVE_EVENT2_EVENT_H
- struct event *
- tor_event_new(struct event_base *base, int sock, short what,
- void (*cb)(int, short, void *), void *arg)
- {
- struct event *e = tor_malloc_zero(sizeof(struct event));
- event_set(e, sock, what, cb, arg);
- if (! base)
- base = tor_libevent_get_base();
- event_base_set(base, e);
- return e;
- }
- struct event *
- tor_evtimer_new(struct event_base *base,
- void (*cb)(int, short, void *), void *arg)
- {
- return tor_event_new(base, -1, 0, cb, arg);
- }
- struct event *
- tor_evsignal_new(struct event_base * base, int sig,
- void (*cb)(int, short, void *), void *arg)
- {
- return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
- }
- void
- tor_event_free(struct event *ev)
- {
- event_del(ev);
- tor_free(ev);
- }
- #endif
- struct event_base *the_event_base = NULL;
- #ifdef __APPLE__
- #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
- #define MACOSX_KQUEUE_IS_BROKEN \
- (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
- #else
- #define MACOSX_KQUEUE_IS_BROKEN 0
- #endif
- #endif
- void
- tor_libevent_initialize(void)
- {
- tor_assert(the_event_base == NULL);
- #ifdef __APPLE__
- if (MACOSX_KQUEUE_IS_BROKEN ||
- tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
- setenv("EVENT_NOKQUEUE","1",1);
- }
- #endif
- #ifdef HAVE_EVENT2_EVENT_H
- the_event_base = event_base_new();
- #else
- the_event_base = event_init();
- #endif
- #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
-
- log(LOG_NOTICE, LD_GENERAL,
- "Initialized libevent version %s using method %s. Good.",
- event_get_version(), tor_libevent_get_method());
- #else
- log(LOG_NOTICE, LD_GENERAL,
- "Initialized old libevent (version 1.0b or earlier).");
- log(LOG_WARN, LD_GENERAL,
- "You have a *VERY* old version of libevent. It is likely to be buggy; "
- "please build Tor with a more recent version.");
- #endif
- }
- struct event_base *
- tor_libevent_get_base(void)
- {
- return the_event_base;
- }
- #ifndef HAVE_EVENT_BASE_LOOPEXIT
- int
- tor_event_base_loopexit(struct event_base *base, struct timeval *tv)
- {
- tor_assert(base == the_event_base);
- return event_loopexit(tv);
- }
- #endif
- const char *
- tor_libevent_get_method(void)
- {
- #ifdef HAVE_EVENT2_EVENT_H
- return event_base_get_method(the_event_base);
- #elif defined(HAVE_EVENT_GET_METHOD)
- return event_get_method();
- #else
- return "<unknown>";
- #endif
- }
- static le_version_t
- tor_decode_libevent_version(const char *v)
- {
- unsigned major, minor, patchlevel;
- char c, extra;
- int fields;
-
- fields = sscanf(v, "%u.%u.%u%c", &major, &minor, &patchlevel, &c);
- if (fields == 3 ||
- (fields == 4 && (c == '-' || c == '_'))) {
- return V(major,minor,patchlevel);
- }
-
- fields = sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
- if (fields == 3 && TOR_ISALPHA(c)) {
- return V_OLD(major, minor, c);
- } else if (fields == 2) {
- return V(major, minor, 0);
- }
- return LE_OTHER;
- }
- static int
- le_versions_compatibility(le_version_t v)
- {
- if (v == LE_OTHER)
- return 0;
- if (v < V_OLD(1,0,'c'))
- return 1;
- else if (v < V(1,4,0))
- return 2;
- else if (v < V(1,4,99))
- return 3;
- else if (v < V(2,0,1))
- return 4;
- else
- return 5;
- }
- static le_version_t
- tor_get_libevent_version(const char **v_out)
- {
- const char *v;
- le_version_t r;
- #if defined(HAVE_EVENT_GET_VERSION_NUMBER)
- v = event_get_version();
- r = event_get_version_number();
- #elif defined (HAVE_EVENT_GET_VERSION)
- v = event_get_version();
- r = tor_decode_libevent_version(v);
- #else
- v = "pre-1.0c";
- r = LE_OLD;
- #endif
- if (v_out)
- *v_out = v;
- return r;
- }
- const char *
- tor_libevent_get_version_str(void)
- {
- #ifdef HAVE_EVENT_GET_VERSION
- return event_get_version();
- #else
- return "pre-1.0c";
- #endif
- }
- void
- tor_check_libevent_version(const char *m, int server,
- const char **badness_out)
- {
- int buggy = 0, iffy = 0, slow = 0, thread_unsafe = 0;
- le_version_t version;
- const char *v = NULL;
- const char *badness = NULL;
- const char *sad_os = "";
- version = tor_get_libevent_version(&v);
-
-
-
- if (!strcmp(m, "kqueue")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- } else if (!strcmp(m, "epoll")) {
- if (version < V(1,1,0))
- iffy = 1;
- } else if (!strcmp(m, "poll")) {
- if (version < V_OLD(1,0,'e'))
- buggy = 1;
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "select")) {
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "win32")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- }
-
- #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "BSD variants";
- }
- #elif defined(__APPLE__) || defined(__darwin__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "Mac OS X";
- }
- #endif
- if (thread_unsafe) {
- log(LOG_WARN, LD_GENERAL,
- "Libevent version %s often crashes when running a Tor server with %s. "
- "Please use the latest version of libevent (1.3b or later)",v,sad_os);
- badness = "BROKEN";
- } else if (buggy) {
- log(LOG_WARN, LD_GENERAL,
- "There are serious bugs in using %s with libevent %s. "
- "Please use the latest version of libevent.", m, v);
- badness = "BROKEN";
- } else if (iffy) {
- log(LOG_WARN, LD_GENERAL,
- "There are minor bugs in using %s with libevent %s. "
- "You may want to use the latest version of libevent.", m, v);
- badness = "BUGGY";
- } else if (slow && server) {
- log(LOG_WARN, LD_GENERAL,
- "libevent %s can be very slow with %s. "
- "When running a server, please use the latest version of libevent.",
- v,m);
- badness = "SLOW";
- }
- *badness_out = badness;
- }
- #if defined(LIBEVENT_VERSION)
- #define HEADER_VERSION LIBEVENT_VERSION
- #elif defined(_EVENT_VERSION)
- #define HEADER_VERSION _EVENT_VERSION
- #endif
- void
- tor_check_libevent_header_compatibility(void)
- {
- (void) le_versions_compatibility;
- (void) tor_decode_libevent_version;
-
- #if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
-
- if (strcmp(HEADER_VERSION, event_get_version())) {
- le_version_t v1, v2;
- int compat1 = -1, compat2 = -1;
- int verybad;
- v1 = tor_decode_libevent_version(HEADER_VERSION);
- v2 = tor_decode_libevent_version(event_get_version());
- compat1 = le_versions_compatibility(v1);
- compat2 = le_versions_compatibility(v2);
- verybad = compat1 != compat2;
- log(verybad ? LOG_WARN : LOG_NOTICE,
- LD_GENERAL, "We were compiled with headers from version %s "
- "of Libevent, but we're using a Libevent library that says it's "
- "version %s.", HEADER_VERSION, event_get_version());
- if (verybad)
- log_warn(LD_GENERAL, "This will almost certainly make Tor crash.");
- else
- log_info(LD_GENERAL, "I think these versions are binary-compatible.");
- }
- #elif defined(HAVE_EVENT_GET_VERSION)
-
- #ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
-
- {
- if (strcmp(event_get_version(), "1.4.0-beta")) {
- log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
- "Libevent 1.4.0-beta header files, whereas you have linked "
- "against Libevent %s. This will probably make Tor crash.",
- event_get_version());
- }
- }
- #else
-
- {
- const char *v = event_get_version();
- if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') {
- log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
- "Libevent header file from 1.3e or earlier, whereas you have "
- "linked against Libevent %s. This will probably make Tor "
- "crash.", event_get_version());
- }
- }
- #endif
- #elif defined(HEADER_VERSION)
- #warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
- #else
-
- #endif
- }
|