2011-01-03 17:52:09 +01:00
|
|
|
/* Copyright (c) 2009-2011, The Tor Project, Inc. */
|
2009-06-04 07:05:23 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file compat_libevent.c
|
|
|
|
* \brief Wrappers to handle porting between different versions of libevent.
|
|
|
|
*
|
|
|
|
* In an ideal world, we'd just use Libevent 2.0 from now on. But as of June
|
|
|
|
* 2009, Libevent 2.0 is still in alpha, and we will have old versions of
|
|
|
|
* Libevent for the forseeable future.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "orconfig.h"
|
2010-04-19 22:41:25 +02:00
|
|
|
#include "compat.h"
|
2009-06-04 07:05:23 +02:00
|
|
|
#include "compat_libevent.h"
|
|
|
|
|
|
|
|
#include "util.h"
|
2010-07-10 03:52:20 +02:00
|
|
|
#include "torlog.h"
|
2009-06-04 07:05:23 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_EVENT2_EVENT_H
|
|
|
|
#include <event2/event.h>
|
2011-08-17 20:44:16 +02:00
|
|
|
#include <event2/thread.h>
|
2011-08-24 23:09:56 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
#include <event2/bufferevent.h>
|
|
|
|
#endif
|
2009-06-04 07:05:23 +02:00
|
|
|
#else
|
|
|
|
#include <event.h>
|
|
|
|
#endif
|
|
|
|
|
2009-06-04 09:16:26 +02:00
|
|
|
/** A number representing a version of Libevent.
|
|
|
|
|
|
|
|
This is a 4-byte number, with the first three bytes representing the
|
2009-12-18 12:55:05 +01:00
|
|
|
major, minor, and patchlevel respectively of the library. The fourth
|
2009-06-04 09:16:26 +02:00
|
|
|
byte is unused.
|
|
|
|
|
|
|
|
This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent
|
|
|
|
2.0.1 or later. For versions of Libevent before 1.4.0, which followed the
|
|
|
|
format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a
|
|
|
|
to be equivalent to 1.0.1, and so on.
|
|
|
|
*/
|
|
|
|
typedef uint32_t le_version_t;
|
|
|
|
|
2011-03-16 22:05:37 +01:00
|
|
|
/** @{ */
|
|
|
|
/** Macros: returns the number of a libevent version as a le_version_t */
|
2009-06-12 21:09:09 +02:00
|
|
|
#define V(major, minor, patch) \
|
|
|
|
(((major) << 24) | ((minor) << 16) | ((patch) << 8))
|
|
|
|
#define V_OLD(major, minor, patch) \
|
|
|
|
V((major), (minor), (patch)-'a'+1)
|
2011-03-16 22:05:37 +01:00
|
|
|
/** @} */
|
2009-06-12 21:09:09 +02:00
|
|
|
|
2011-03-16 22:05:37 +01:00
|
|
|
/** Represetns a version of libevent so old we can't figure out what version
|
|
|
|
* it is. */
|
2009-06-12 21:09:09 +02:00
|
|
|
#define LE_OLD V(0,0,0)
|
2011-03-16 22:05:37 +01:00
|
|
|
/** Represents a version of libevent so weird we can't figure out what version
|
2011-05-12 09:27:19 +02:00
|
|
|
* it is. */
|
2009-06-12 21:09:09 +02:00
|
|
|
#define LE_OTHER V(0,0,99)
|
|
|
|
|
2009-06-04 09:16:26 +02:00
|
|
|
static le_version_t tor_get_libevent_version(const char **v_out);
|
|
|
|
|
2009-06-04 07:05:23 +02:00
|
|
|
#ifdef HAVE_EVENT_SET_LOG_CALLBACK
|
|
|
|
/** A string which, if it appears in a libevent log, should be ignored. */
|
|
|
|
static const char *suppress_msg = NULL;
|
|
|
|
/** Callback function passed to event_set_log() so we can intercept
|
|
|
|
* log messages from libevent. */
|
|
|
|
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:
|
2010-11-20 04:22:43 +01:00
|
|
|
log(LOG_DEBUG, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
|
2009-06-04 07:05:23 +02:00
|
|
|
break;
|
|
|
|
case _EVENT_LOG_MSG:
|
2010-11-20 04:22:43 +01:00
|
|
|
log(LOG_INFO, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
|
2009-06-04 07:05:23 +02:00
|
|
|
break;
|
|
|
|
case _EVENT_LOG_WARN:
|
2010-11-20 04:22:43 +01:00
|
|
|
log(LOG_WARN, LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
|
2009-06-04 07:05:23 +02:00
|
|
|
break;
|
|
|
|
case _EVENT_LOG_ERR:
|
2010-11-20 04:22:43 +01:00
|
|
|
log(LOG_ERR, LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
|
2009-06-04 07:05:23 +02:00
|
|
|
break;
|
|
|
|
default:
|
2010-11-20 04:22:43 +01:00
|
|
|
log(LOG_WARN, LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
|
2009-06-04 07:05:23 +02:00
|
|
|
severity, buf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** Set hook to intercept log messages from libevent. */
|
|
|
|
void
|
|
|
|
configure_libevent_logging(void)
|
|
|
|
{
|
|
|
|
event_set_log_callback(libevent_logging_callback);
|
|
|
|
}
|
|
|
|
/** Ignore any libevent log message that contains <b>msg</b>. */
|
|
|
|
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
|
|
|
|
/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */
|
|
|
|
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);
|
2009-06-16 17:30:08 +02:00
|
|
|
if (! base)
|
|
|
|
base = tor_libevent_get_base();
|
2009-06-04 07:05:23 +02:00
|
|
|
event_base_set(base, e);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
/** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
/** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */
|
|
|
|
struct event *
|
|
|
|
tor_evsignal_new(struct event_base * base, int sig,
|
|
|
|
void (*cb)(int, short, void *), void *arg)
|
|
|
|
{
|
2009-06-18 16:07:26 +02:00
|
|
|
return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
|
2009-06-04 07:05:23 +02:00
|
|
|
}
|
|
|
|
/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */
|
|
|
|
void
|
|
|
|
tor_event_free(struct event *ev)
|
|
|
|
{
|
|
|
|
event_del(ev);
|
|
|
|
tor_free(ev);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Global event base for use by the main thread. */
|
|
|
|
struct event_base *the_event_base = NULL;
|
|
|
|
|
2009-06-04 09:16:26 +02:00
|
|
|
/* This is what passes for version detection on OSX. We set
|
|
|
|
* MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
|
|
|
|
* 10.4.0 (aka 1040). */
|
|
|
|
#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
|
|
|
|
|
2011-08-18 21:08:49 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
static int using_iocp_bufferevents = 0;
|
2011-09-08 04:00:48 +02:00
|
|
|
static void tor_libevent_set_tick_timeout(int msec_per_tick);
|
2011-08-18 21:08:49 +02:00
|
|
|
|
|
|
|
int
|
|
|
|
tor_libevent_using_iocp_bufferevents(void)
|
|
|
|
{
|
|
|
|
return using_iocp_bufferevents;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-06-04 07:05:23 +02:00
|
|
|
/** Initialize the Libevent library and set up the event base. */
|
|
|
|
void
|
2010-09-28 20:01:45 +02:00
|
|
|
tor_libevent_initialize(tor_libevent_cfg *torcfg)
|
2009-06-04 07:05:23 +02:00
|
|
|
{
|
|
|
|
tor_assert(the_event_base == NULL);
|
2010-09-29 08:50:46 +02:00
|
|
|
/* some paths below don't use torcfg, so avoid unused variable warnings */
|
|
|
|
(void)torcfg;
|
2009-06-04 09:16:26 +02:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
if (MACOSX_KQUEUE_IS_BROKEN ||
|
|
|
|
tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
|
|
|
|
setenv("EVENT_NOKQUEUE","1",1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-06-04 07:05:23 +02:00
|
|
|
#ifdef HAVE_EVENT2_EVENT_H
|
2010-09-28 20:01:45 +02:00
|
|
|
{
|
|
|
|
struct event_config *cfg = event_config_new();
|
2011-11-14 23:53:45 +01:00
|
|
|
tor_assert(cfg);
|
2010-09-28 20:01:45 +02:00
|
|
|
|
|
|
|
#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
|
2011-08-17 20:44:16 +02:00
|
|
|
if (! torcfg->disable_iocp) {
|
|
|
|
evthread_use_windows_threads();
|
2010-09-28 20:01:45 +02:00
|
|
|
event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
|
2011-08-18 21:08:49 +02:00
|
|
|
using_iocp_bufferevents = 1;
|
2011-08-17 20:44:16 +02:00
|
|
|
}
|
2010-09-28 20:01:45 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
|
|
|
|
if (torcfg->num_cpus > 0)
|
|
|
|
event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
|
|
|
|
#endif
|
|
|
|
|
2010-12-16 19:35:09 +01:00
|
|
|
#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
|
|
|
|
/* We can enable changelist support with epoll, since we don't give
|
|
|
|
* Libevent any dup'd fds. This lets us avoid some syscalls. */
|
|
|
|
event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
|
|
|
|
#endif
|
|
|
|
|
2010-09-28 20:01:45 +02:00
|
|
|
the_event_base = event_base_new_with_config(cfg);
|
2010-10-15 23:14:04 +02:00
|
|
|
|
|
|
|
event_config_free(cfg);
|
2010-09-28 20:01:45 +02:00
|
|
|
}
|
2009-06-04 07:05:23 +02:00
|
|
|
#else
|
|
|
|
the_event_base = event_init();
|
|
|
|
#endif
|
2009-06-04 09:16:26 +02:00
|
|
|
|
2011-11-14 23:53:45 +01:00
|
|
|
if (!the_event_base) {
|
|
|
|
log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-06-04 09:16:26 +02:00
|
|
|
|
|
|
|
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
|
|
|
|
/* Making this a NOTICE for now so we can link bugs to a libevent versions
|
|
|
|
* or methods better. */
|
|
|
|
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
|
2011-09-08 04:00:48 +02:00
|
|
|
|
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
tor_libevent_set_tick_timeout(torcfg->msec_per_tick);
|
|
|
|
#endif
|
2009-06-04 07:05:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the current Libevent event base that we're set up to use. */
|
|
|
|
struct event_base *
|
|
|
|
tor_libevent_get_base(void)
|
|
|
|
{
|
|
|
|
return the_event_base;
|
|
|
|
}
|
|
|
|
|
2009-06-04 09:24:53 +02:00
|
|
|
#ifndef HAVE_EVENT_BASE_LOOPEXIT
|
2011-03-16 22:05:37 +01:00
|
|
|
/** Replacement for event_base_loopexit on some very old versions of Libevent
|
|
|
|
* that we are not yet brave enough to deprecate. */
|
2009-06-04 09:24:53 +02:00
|
|
|
int
|
|
|
|
tor_event_base_loopexit(struct event_base *base, struct timeval *tv)
|
|
|
|
{
|
|
|
|
tor_assert(base == the_event_base);
|
|
|
|
return event_loopexit(tv);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-06-04 07:05:23 +02:00
|
|
|
/** Return the name of the Libevent backend we're using. */
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2011-03-16 23:07:55 +01:00
|
|
|
/** Return the le_version_t for the version of libevent specified in the
|
|
|
|
* string <b>v</b>. If the version is very new or uses an unrecognized
|
|
|
|
* version, format, return LE_OTHER. */
|
2009-06-04 09:16:26 +02:00
|
|
|
static le_version_t
|
|
|
|
tor_decode_libevent_version(const char *v)
|
|
|
|
{
|
|
|
|
unsigned major, minor, patchlevel;
|
2010-07-26 06:40:44 +02:00
|
|
|
char c, e, extra;
|
2009-06-04 09:16:26 +02:00
|
|
|
int fields;
|
|
|
|
|
2010-07-26 06:40:44 +02:00
|
|
|
/* Try the new preferred "1.4.11-stable" format.
|
|
|
|
* Also accept "1.4.14b-stable". */
|
2011-07-01 17:26:30 +02:00
|
|
|
fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e);
|
2009-06-04 09:16:26 +02:00
|
|
|
if (fields == 3 ||
|
2010-07-26 06:40:44 +02:00
|
|
|
((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) ||
|
|
|
|
(fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) {
|
2009-06-04 09:16:26 +02:00
|
|
|
return V(major,minor,patchlevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try the old "1.3e" format. */
|
2011-07-01 17:26:30 +02:00
|
|
|
fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
|
2009-06-04 09:16:26 +02:00
|
|
|
if (fields == 3 && TOR_ISALPHA(c)) {
|
|
|
|
return V_OLD(major, minor, c);
|
|
|
|
} else if (fields == 2) {
|
|
|
|
return V(major, minor, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return LE_OTHER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return an integer representing the binary interface of a Libevent library.
|
|
|
|
* Two different versions with different numbers are sure not to be binary
|
|
|
|
* compatible. Two different versions with the same numbers have a decent
|
|
|
|
* chance of binary compatibility.*/
|
|
|
|
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 /* Everything 2.0 and later should be compatible. */
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the version number of the currently running version of Libevent.
|
2011-03-16 23:07:55 +01:00
|
|
|
* See le_version_t for info on the format.
|
2009-06-04 09:16:26 +02:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a string representation of the version of the currently running
|
|
|
|
* version of Libevent. */
|
|
|
|
const char *
|
|
|
|
tor_libevent_get_version_str(void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_EVENT_GET_VERSION
|
|
|
|
return event_get_version();
|
|
|
|
#else
|
|
|
|
return "pre-1.0c";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compare the current Libevent method and version to a list of versions
|
|
|
|
* which are known not to work. Warn the user as appropriate.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
|
2011-03-25 20:32:45 +01:00
|
|
|
/* It would be better to disable known-buggy methods rather than warning
|
|
|
|
* about them. But the problem is that with older versions of Libevent,
|
|
|
|
* it's not trivial to get them to change their methods once they're
|
|
|
|
* initialized... and with newer versions of Libevent, they aren't actually
|
|
|
|
* broken. But we should revisit this if we ever find a post-1.4 version
|
|
|
|
* of Libevent where we need to disable a given method. */
|
2009-06-04 09:16:26 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Libevent versions before 1.3b do very badly on operating systems with
|
|
|
|
* user-space threading implementations. */
|
|
|
|
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
2009-06-12 21:09:09 +02:00
|
|
|
if (server && version < V_OLD(1,3,'b')) {
|
2009-06-04 09:16:26 +02:00
|
|
|
thread_unsafe = 1;
|
|
|
|
sad_os = "BSD variants";
|
|
|
|
}
|
|
|
|
#elif defined(__APPLE__) || defined(__darwin__)
|
2009-06-12 21:09:09 +02:00
|
|
|
if (server && version < V_OLD(1,3,'b')) {
|
2009-06-04 09:16:26 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
/** See whether the headers we were built against differ from the library we
|
|
|
|
* linked against so much that we're likely to crash. If so, warn the
|
|
|
|
* user. */
|
|
|
|
void
|
|
|
|
tor_check_libevent_header_compatibility(void)
|
|
|
|
{
|
|
|
|
(void) le_versions_compatibility;
|
|
|
|
(void) tor_decode_libevent_version;
|
|
|
|
|
|
|
|
/* In libevent versions before 2.0, it's hard to keep binary compatibility
|
|
|
|
* between upgrades, and unpleasant to detect when the version we compiled
|
|
|
|
* against is unlike the version we have linked against. Here's how. */
|
|
|
|
#if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
|
|
|
|
/* We have a header-file version and a function-call version. Easy. */
|
|
|
|
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)
|
|
|
|
/* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or
|
|
|
|
earlier, where that's normal. To see whether we were compiled with an
|
|
|
|
earlier version, let's see whether the struct event defines MIN_HEAP_IDX.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
|
|
|
|
/* The header files are 1.4.0-beta or later. If the version is not
|
|
|
|
* 1.4.0-beta, we are incompatible. */
|
|
|
|
{
|
|
|
|
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
|
|
|
|
/* Our headers are 1.3e or earlier. If the library version is not 1.4.x or
|
|
|
|
later, we're probably fine. */
|
|
|
|
{
|
|
|
|
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
|
|
|
|
/* Your libevent is ancient. */
|
|
|
|
#endif
|
|
|
|
}
|
2009-06-12 21:09:09 +02:00
|
|
|
|
2010-06-25 21:31:46 +02:00
|
|
|
/*
|
|
|
|
If possible, we're going to try to use Libevent's periodic timer support,
|
|
|
|
since it does a pretty good job of making sure that periodic events get
|
|
|
|
called exactly M seconds apart, rather than starting each one exactly M
|
|
|
|
seconds after the time that the last one was run.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_EVENT2_EVENT_H
|
|
|
|
#define HAVE_PERIODIC
|
|
|
|
#define PERIODIC_FLAGS EV_PERSIST
|
|
|
|
#else
|
|
|
|
#define PERIODIC_FLAGS 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Represents a timer that's run every N microseconds by Libevent. */
|
|
|
|
struct periodic_timer_t {
|
|
|
|
/** Underlying event used to implement this periodic event. */
|
|
|
|
struct event *ev;
|
|
|
|
/** The callback we'll be invoking whenever the event triggers */
|
|
|
|
void (*cb)(struct periodic_timer_t *, void *);
|
|
|
|
/** User-supplied data for the callback */
|
|
|
|
void *data;
|
|
|
|
#ifndef HAVE_PERIODIC
|
|
|
|
/** If Libevent doesn't know how to invoke events every N microseconds,
|
|
|
|
* we'll need to remember the timeout interval here. */
|
|
|
|
struct timeval tv;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Libevent callback to implement a periodic event. */
|
|
|
|
static void
|
|
|
|
periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
|
|
|
|
{
|
|
|
|
periodic_timer_t *timer = arg;
|
|
|
|
(void) what;
|
|
|
|
(void) fd;
|
|
|
|
#ifndef HAVE_PERIODIC
|
|
|
|
/** reschedule the event as needed. */
|
|
|
|
event_add(timer->ev, &timer->tv);
|
|
|
|
#endif
|
|
|
|
timer->cb(timer, timer->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Create and schedule a new timer that will run every <b>tv</b> in
|
|
|
|
* the event loop of <b>base</b>. When the timer fires, it will
|
|
|
|
* run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */
|
|
|
|
periodic_timer_t *
|
|
|
|
periodic_timer_new(struct event_base *base,
|
|
|
|
const struct timeval *tv,
|
|
|
|
void (*cb)(periodic_timer_t *timer, void *data),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
periodic_timer_t *timer;
|
|
|
|
tor_assert(base);
|
|
|
|
tor_assert(tv);
|
|
|
|
tor_assert(cb);
|
|
|
|
timer = tor_malloc_zero(sizeof(periodic_timer_t));
|
|
|
|
if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS,
|
|
|
|
periodic_timer_cb, timer))) {
|
|
|
|
tor_free(timer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
timer->cb = cb;
|
|
|
|
timer->data = data;
|
|
|
|
#ifndef HAVE_PERIODIC
|
|
|
|
memcpy(&timer->tv, tv, sizeof(struct timeval));
|
|
|
|
#endif
|
2010-06-25 22:14:21 +02:00
|
|
|
event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/
|
2010-06-25 21:31:46 +02:00
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Stop and free a periodic timer */
|
|
|
|
void
|
|
|
|
periodic_timer_free(periodic_timer_t *timer)
|
|
|
|
{
|
|
|
|
if (!timer)
|
|
|
|
return;
|
|
|
|
tor_event_free(timer->ev);
|
|
|
|
tor_free(timer);
|
|
|
|
}
|
2010-07-25 13:24:31 +02:00
|
|
|
|
2010-02-22 19:59:34 +01:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
static const struct timeval *one_tick = NULL;
|
|
|
|
/**
|
2010-04-04 03:34:42 +02:00
|
|
|
* Return a special timeout to be passed whenever libevent's O(1) timeout
|
|
|
|
* implementation should be used. Only use this when the timer is supposed
|
2011-09-08 04:00:48 +02:00
|
|
|
* to fire after msec_per_tick ticks have elapsed.
|
2010-02-22 19:59:34 +01:00
|
|
|
*/
|
2010-09-27 18:41:41 +02:00
|
|
|
const struct timeval *
|
|
|
|
tor_libevent_get_one_tick_timeout(void)
|
2010-02-22 19:59:34 +01:00
|
|
|
{
|
2011-09-08 04:00:48 +02:00
|
|
|
tor_assert(one_tick);
|
2010-02-22 19:59:34 +01:00
|
|
|
return one_tick;
|
|
|
|
}
|
2011-08-24 23:09:56 +02:00
|
|
|
|
2011-09-08 04:00:48 +02:00
|
|
|
/** Initialize the common timeout that we'll use to refill the buckets every
|
|
|
|
* time a tick elapses. */
|
|
|
|
static void
|
|
|
|
tor_libevent_set_tick_timeout(int msec_per_tick)
|
|
|
|
{
|
|
|
|
struct event_base *base = tor_libevent_get_base();
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
tor_assert(! one_tick);
|
|
|
|
tv.tv_sec = msec_per_tick / 1000;
|
|
|
|
tv.tv_usec = (msec_per_tick % 1000) * 1000;
|
|
|
|
one_tick = event_base_init_common_timeout(base, &tv);
|
|
|
|
}
|
|
|
|
|
2011-08-24 23:09:56 +02:00
|
|
|
static struct bufferevent *
|
|
|
|
tor_get_root_bufferevent(struct bufferevent *bev)
|
|
|
|
{
|
|
|
|
struct bufferevent *u;
|
|
|
|
while ((u = bufferevent_get_underlying(bev)) != NULL)
|
|
|
|
bev = u;
|
|
|
|
return bev;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
tor_set_bufferevent_rate_limit(struct bufferevent *bev,
|
|
|
|
struct ev_token_bucket_cfg *cfg)
|
|
|
|
{
|
|
|
|
return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
|
|
|
|
struct bufferevent_rate_limit_group *g)
|
|
|
|
{
|
|
|
|
return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g);
|
|
|
|
}
|
2010-02-22 19:59:34 +01:00
|
|
|
#endif
|
|
|
|
|