Back to index

tor  0.2.3.18-rc
compat_libevent.c
Go to the documentation of this file.
00001 /* Copyright (c) 2009-2012, The Tor Project, Inc. */
00002 /* See LICENSE for licensing information */
00003 
00012 #include "orconfig.h"
00013 #include "compat.h"
00014 #include "compat_libevent.h"
00015 
00016 #include "util.h"
00017 #include "torlog.h"
00018 
00019 #ifdef HAVE_EVENT2_EVENT_H
00020 #include <event2/event.h>
00021 #include <event2/thread.h>
00022 #ifdef USE_BUFFEREVENTS
00023 #include <event2/bufferevent.h>
00024 #endif
00025 #else
00026 #include <event.h>
00027 #endif
00028 
00040 typedef uint32_t le_version_t;
00041 
00044 #define V(major, minor, patch) \
00045   (((major) << 24) | ((minor) << 16) | ((patch) << 8))
00046 #define V_OLD(major, minor, patch) \
00047   V((major), (minor), (patch)-'a'+1)
00048 
00052 #define LE_OLD V(0,0,0)
00053 
00055 #define LE_OTHER V(0,0,99)
00056 
00057 static le_version_t tor_get_libevent_version(const char **v_out);
00058 
00059 #if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN)
00060 
00061 static const char *suppress_msg = NULL;
00064 static void
00065 libevent_logging_callback(int severity, const char *msg)
00066 {
00067   char buf[1024];
00068   size_t n;
00069   if (suppress_msg && strstr(msg, suppress_msg))
00070     return;
00071   n = strlcpy(buf, msg, sizeof(buf));
00072   if (n && n < sizeof(buf) && buf[n-1] == '\n') {
00073     buf[n-1] = '\0';
00074   }
00075   switch (severity) {
00076     case _EVENT_LOG_DEBUG:
00077       log(LOG_DEBUG, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
00078       break;
00079     case _EVENT_LOG_MSG:
00080       log(LOG_INFO, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
00081       break;
00082     case _EVENT_LOG_WARN:
00083       log(LOG_WARN, LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
00084       break;
00085     case _EVENT_LOG_ERR:
00086       log(LOG_ERR, LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
00087       break;
00088     default:
00089       log(LOG_WARN, LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
00090           severity, buf);
00091       break;
00092   }
00093 }
00095 void
00096 configure_libevent_logging(void)
00097 {
00098   event_set_log_callback(libevent_logging_callback);
00099 }
00101 void
00102 suppress_libevent_log_msg(const char *msg)
00103 {
00104   suppress_msg = msg;
00105 }
00106 #else
00107 void
00108 configure_libevent_logging(void)
00109 {
00110 }
00111 void
00112 suppress_libevent_log_msg(const char *msg)
00113 {
00114   (void)msg;
00115 }
00116 #endif
00117 
00118 #ifndef HAVE_EVENT2_EVENT_H
00119 
00120 struct event *
00121 tor_event_new(struct event_base *base, int sock, short what,
00122               void (*cb)(int, short, void *), void *arg)
00123 {
00124   struct event *e = tor_malloc_zero(sizeof(struct event));
00125   event_set(e, sock, what, cb, arg);
00126   if (! base)
00127     base = tor_libevent_get_base();
00128   event_base_set(base, e);
00129   return e;
00130 }
00132 struct event *
00133 tor_evtimer_new(struct event_base *base,
00134                 void (*cb)(int, short, void *), void *arg)
00135 {
00136   return tor_event_new(base, -1, 0, cb, arg);
00137 }
00139 struct event *
00140 tor_evsignal_new(struct event_base * base, int sig,
00141                  void (*cb)(int, short, void *), void *arg)
00142 {
00143   return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
00144 }
00146 void
00147 tor_event_free(struct event *ev)
00148 {
00149   event_del(ev);
00150   tor_free(ev);
00151 }
00152 #endif
00153 
00155 struct event_base *the_event_base = NULL;
00156 
00157 /* This is what passes for version detection on OSX.  We set
00158  * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
00159  * 10.4.0 (aka 1040). */
00160 #ifdef __APPLE__
00161 #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
00162 #define MACOSX_KQUEUE_IS_BROKEN \
00163   (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
00164 #else
00165 #define MACOSX_KQUEUE_IS_BROKEN 0
00166 #endif
00167 #endif
00168 
00169 #ifdef USE_BUFFEREVENTS
00170 static int using_iocp_bufferevents = 0;
00171 static void tor_libevent_set_tick_timeout(int msec_per_tick);
00172 
00173 int
00174 tor_libevent_using_iocp_bufferevents(void)
00175 {
00176   return using_iocp_bufferevents;
00177 }
00178 #endif
00179 
00181 void
00182 tor_libevent_initialize(tor_libevent_cfg *torcfg)
00183 {
00184   tor_assert(the_event_base == NULL);
00185   /* some paths below don't use torcfg, so avoid unused variable warnings */
00186   (void)torcfg;
00187 
00188 #ifdef __APPLE__
00189   if (MACOSX_KQUEUE_IS_BROKEN ||
00190       tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
00191     setenv("EVENT_NOKQUEUE","1",1);
00192   }
00193 #endif
00194 
00195 #ifdef HAVE_EVENT2_EVENT_H
00196   {
00197     int attempts = 0;
00198     int using_threads;
00199     struct event_config *cfg;
00200 
00201   retry:
00202     ++attempts;
00203     using_threads = 0;
00204     cfg = event_config_new();
00205     tor_assert(cfg);
00206 
00207 #if defined(_WIN32) && defined(USE_BUFFEREVENTS)
00208     if (! torcfg->disable_iocp) {
00209       evthread_use_windows_threads();
00210       event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
00211       using_iocp_bufferevents = 1;
00212       using_threads = 1;
00213     } else {
00214       using_iocp_bufferevents = 0;
00215     }
00216 #endif
00217 
00218     if (!using_threads) {
00219       /* Telling Libevent not to try to turn locking on can avoid a needless
00220        * socketpair() attempt. */
00221       event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
00222     }
00223 
00224 #if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
00225     if (torcfg->num_cpus > 0)
00226       event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
00227 #endif
00228 
00229 #if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
00230     /* We can enable changelist support with epoll, since we don't give
00231      * Libevent any dup'd fds.  This lets us avoid some syscalls. */
00232     event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
00233 #endif
00234 
00235     the_event_base = event_base_new_with_config(cfg);
00236 
00237     event_config_free(cfg);
00238 
00239     if (using_threads && the_event_base == NULL && attempts < 2) {
00240       /* This could be a socketpair() failure, which can happen sometimes on
00241        * windows boxes with obnoxious firewall rules.  Downgrade and try
00242        * again. */
00243 #if defined(_WIN32) && defined(USE_BUFFEREVENTS)
00244       if (torcfg->disable_iocp == 0) {
00245         log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again "
00246                  "with IOCP disabled.");
00247       } else
00248 #endif
00249       {
00250           log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again.");
00251       }
00252 
00253       torcfg->disable_iocp = 1;
00254       goto retry;
00255     }
00256   }
00257 #else
00258   the_event_base = event_init();
00259 #endif
00260 
00261   if (!the_event_base) {
00262     log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
00263     exit(1);
00264   }
00265 
00266 #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
00267   /* Making this a NOTICE for now so we can link bugs to a libevent versions
00268    * or methods better. */
00269   log(LOG_NOTICE, LD_GENERAL,
00270       "Initialized libevent version %s using method %s. Good.",
00271       event_get_version(), tor_libevent_get_method());
00272 #else
00273   log(LOG_NOTICE, LD_GENERAL,
00274       "Initialized old libevent (version 1.0b or earlier).");
00275   log(LOG_WARN, LD_GENERAL,
00276       "You have a *VERY* old version of libevent.  It is likely to be buggy; "
00277       "please build Tor with a more recent version.");
00278 #endif
00279 
00280 #ifdef USE_BUFFEREVENTS
00281   tor_libevent_set_tick_timeout(torcfg->msec_per_tick);
00282 #endif
00283 }
00284 
00286 struct event_base *
00287 tor_libevent_get_base(void)
00288 {
00289   return the_event_base;
00290 }
00291 
00292 #ifndef HAVE_EVENT_BASE_LOOPEXIT
00293 
00295 int
00296 tor_event_base_loopexit(struct event_base *base, struct timeval *tv)
00297 {
00298   tor_assert(base == the_event_base);
00299   return event_loopexit(tv);
00300 }
00301 #endif
00302 
00304 const char *
00305 tor_libevent_get_method(void)
00306 {
00307 #ifdef HAVE_EVENT2_EVENT_H
00308   return event_base_get_method(the_event_base);
00309 #elif defined(HAVE_EVENT_GET_METHOD)
00310   return event_get_method();
00311 #else
00312   return "<unknown>";
00313 #endif
00314 }
00315 
00319 static le_version_t
00320 tor_decode_libevent_version(const char *v)
00321 {
00322   unsigned major, minor, patchlevel;
00323   char c, e, extra;
00324   int fields;
00325 
00326   /* Try the new preferred "1.4.11-stable" format.
00327    * Also accept "1.4.14b-stable". */
00328   fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e);
00329   if (fields == 3 ||
00330       ((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) ||
00331       (fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) {
00332     return V(major,minor,patchlevel);
00333   }
00334 
00335   /* Try the old "1.3e" format. */
00336   fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
00337   if (fields == 3 && TOR_ISALPHA(c)) {
00338     return V_OLD(major, minor, c);
00339   } else if (fields == 2) {
00340     return V(major, minor, 0);
00341   }
00342 
00343   return LE_OTHER;
00344 }
00345 
00350 static int
00351 le_versions_compatibility(le_version_t v)
00352 {
00353   if (v == LE_OTHER)
00354     return 0;
00355   if (v < V_OLD(1,0,'c'))
00356     return 1;
00357   else if (v < V(1,4,0))
00358     return 2;
00359   else if (v < V(1,4,99))
00360     return 3;
00361   else if (v < V(2,0,1))
00362     return 4;
00363   else /* Everything 2.0 and later should be compatible. */
00364     return 5;
00365 }
00366 
00370 static le_version_t
00371 tor_get_libevent_version(const char **v_out)
00372 {
00373   const char *v;
00374   le_version_t r;
00375 #if defined(HAVE_EVENT_GET_VERSION_NUMBER)
00376   v = event_get_version();
00377   r = event_get_version_number();
00378 #elif defined (HAVE_EVENT_GET_VERSION)
00379   v = event_get_version();
00380   r = tor_decode_libevent_version(v);
00381 #else
00382   v = "pre-1.0c";
00383   r = LE_OLD;
00384 #endif
00385   if (v_out)
00386     *v_out = v;
00387   return r;
00388 }
00389 
00392 const char *
00393 tor_libevent_get_version_str(void)
00394 {
00395 #ifdef HAVE_EVENT_GET_VERSION
00396   return event_get_version();
00397 #else
00398   return "pre-1.0c";
00399 #endif
00400 }
00401 
00406 void
00407 tor_check_libevent_version(const char *m, int server,
00408                            const char **badness_out)
00409 {
00410   int buggy = 0, iffy = 0, slow = 0, thread_unsafe = 0;
00411   le_version_t version;
00412   const char *v = NULL;
00413   const char *badness = NULL;
00414   const char *sad_os = "";
00415 
00416   version = tor_get_libevent_version(&v);
00417 
00418   /* It would be better to disable known-buggy methods rather than warning
00419    * about them.  But the problem is that with older versions of Libevent,
00420    * it's not trivial to get them to change their methods once they're
00421    * initialized... and with newer versions of Libevent, they aren't actually
00422    * broken.  But we should revisit this if we ever find a post-1.4 version
00423    * of Libevent where we need to disable a given method. */
00424   if (!strcmp(m, "kqueue")) {
00425     if (version < V_OLD(1,1,'b'))
00426       buggy = 1;
00427   } else if (!strcmp(m, "epoll")) {
00428     if (version < V(1,1,0))
00429       iffy = 1;
00430   } else if (!strcmp(m, "poll")) {
00431     if (version < V_OLD(1,0,'e'))
00432       buggy = 1;
00433     if (version < V(1,1,0))
00434       slow = 1;
00435   } else if (!strcmp(m, "select")) {
00436     if (version < V(1,1,0))
00437       slow = 1;
00438   } else if (!strcmp(m, "win32")) {
00439     if (version < V_OLD(1,1,'b'))
00440       buggy = 1;
00441   }
00442 
00443   /* Libevent versions before 1.3b do very badly on operating systems with
00444    * user-space threading implementations. */
00445 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
00446   if (server && version < V_OLD(1,3,'b')) {
00447     thread_unsafe = 1;
00448     sad_os = "BSD variants";
00449   }
00450 #elif defined(__APPLE__) || defined(__darwin__)
00451   if (server && version < V_OLD(1,3,'b')) {
00452     thread_unsafe = 1;
00453     sad_os = "Mac OS X";
00454   }
00455 #endif
00456 
00457   if (thread_unsafe) {
00458     log(LOG_WARN, LD_GENERAL,
00459         "Libevent version %s often crashes when running a Tor server with %s. "
00460         "Please use the latest version of libevent (1.3b or later)",v,sad_os);
00461     badness = "BROKEN";
00462   } else if (buggy) {
00463     log(LOG_WARN, LD_GENERAL,
00464         "There are serious bugs in using %s with libevent %s. "
00465         "Please use the latest version of libevent.", m, v);
00466     badness = "BROKEN";
00467   } else if (iffy) {
00468     log(LOG_WARN, LD_GENERAL,
00469         "There are minor bugs in using %s with libevent %s. "
00470         "You may want to use the latest version of libevent.", m, v);
00471     badness = "BUGGY";
00472   } else if (slow && server) {
00473     log(LOG_WARN, LD_GENERAL,
00474         "libevent %s can be very slow with %s. "
00475         "When running a server, please use the latest version of libevent.",
00476         v,m);
00477     badness = "SLOW";
00478   }
00479 
00480   *badness_out = badness;
00481 }
00482 
00483 #if defined(LIBEVENT_VERSION)
00484 #define HEADER_VERSION LIBEVENT_VERSION
00485 #elif defined(_EVENT_VERSION)
00486 #define HEADER_VERSION _EVENT_VERSION
00487 #endif
00488 
00492 void
00493 tor_check_libevent_header_compatibility(void)
00494 {
00495   (void) le_versions_compatibility;
00496   (void) tor_decode_libevent_version;
00497 
00498   /* In libevent versions before 2.0, it's hard to keep binary compatibility
00499    * between upgrades, and unpleasant to detect when the version we compiled
00500    * against is unlike the version we have linked against. Here's how. */
00501 #if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
00502   /* We have a header-file version and a function-call version. Easy. */
00503   if (strcmp(HEADER_VERSION, event_get_version())) {
00504     le_version_t v1, v2;
00505     int compat1 = -1, compat2 = -1;
00506     int verybad;
00507     v1 = tor_decode_libevent_version(HEADER_VERSION);
00508     v2 = tor_decode_libevent_version(event_get_version());
00509     compat1 = le_versions_compatibility(v1);
00510     compat2 = le_versions_compatibility(v2);
00511 
00512     verybad = compat1 != compat2;
00513 
00514     log(verybad ? LOG_WARN : LOG_NOTICE,
00515         LD_GENERAL, "We were compiled with headers from version %s "
00516         "of Libevent, but we're using a Libevent library that says it's "
00517         "version %s.", HEADER_VERSION, event_get_version());
00518     if (verybad)
00519       log_warn(LD_GENERAL, "This will almost certainly make Tor crash.");
00520     else
00521       log_info(LD_GENERAL, "I think these versions are binary-compatible.");
00522   }
00523 #elif defined(HAVE_EVENT_GET_VERSION)
00524   /* event_get_version but no _EVENT_VERSION.  We might be in 1.4.0-beta or
00525      earlier, where that's normal.  To see whether we were compiled with an
00526      earlier version, let's see whether the struct event defines MIN_HEAP_IDX.
00527   */
00528 #ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
00529   /* The header files are 1.4.0-beta or later. If the version is not
00530    * 1.4.0-beta, we are incompatible. */
00531   {
00532     if (strcmp(event_get_version(), "1.4.0-beta")) {
00533       log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
00534                "Libevent 1.4.0-beta header files, whereas you have linked "
00535                "against Libevent %s.  This will probably make Tor crash.",
00536                event_get_version());
00537     }
00538   }
00539 #else
00540   /* Our headers are 1.3e or earlier. If the library version is not 1.4.x or
00541      later, we're probably fine. */
00542   {
00543     const char *v = event_get_version();
00544     if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') {
00545       log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
00546                "Libevent header file from 1.3e or earlier, whereas you have "
00547                "linked against Libevent %s.  This will probably make Tor "
00548                "crash.", event_get_version());
00549     }
00550   }
00551 #endif
00552 
00553 #elif defined(HEADER_VERSION)
00554 #warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
00555 #else
00556   /* Your libevent is ancient. */
00557 #endif
00558 }
00559 
00560 /*
00561   If possible, we're going to try to use Libevent's periodic timer support,
00562   since it does a pretty good job of making sure that periodic events get
00563   called exactly M seconds apart, rather than starting each one exactly M
00564   seconds after the time that the last one was run.
00565  */
00566 #ifdef HAVE_EVENT2_EVENT_H
00567 #define HAVE_PERIODIC
00568 #define PERIODIC_FLAGS EV_PERSIST
00569 #else
00570 #define PERIODIC_FLAGS 0
00571 #endif
00572 
00574 struct periodic_timer_t {
00576   struct event *ev;
00578   void (*cb)(struct periodic_timer_t *, void *);
00580   void *data;
00581 #ifndef HAVE_PERIODIC
00582 
00584   struct timeval tv;
00585 #endif
00586 };
00587 
00589 static void
00590 periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
00591 {
00592   periodic_timer_t *timer = arg;
00593   (void) what;
00594   (void) fd;
00595 #ifndef HAVE_PERIODIC
00596 
00597   event_add(timer->ev, &timer->tv);
00598 #endif
00599   timer->cb(timer, timer->data);
00600 }
00601 
00605 periodic_timer_t *
00606 periodic_timer_new(struct event_base *base,
00607                    const struct timeval *tv,
00608                    void (*cb)(periodic_timer_t *timer, void *data),
00609                    void *data)
00610 {
00611   periodic_timer_t *timer;
00612   tor_assert(base);
00613   tor_assert(tv);
00614   tor_assert(cb);
00615   timer = tor_malloc_zero(sizeof(periodic_timer_t));
00616   if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS,
00617                                   periodic_timer_cb, timer))) {
00618     tor_free(timer);
00619     return NULL;
00620   }
00621   timer->cb = cb;
00622   timer->data = data;
00623 #ifndef HAVE_PERIODIC
00624   memcpy(&timer->tv, tv, sizeof(struct timeval));
00625 #endif
00626   event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/
00627   return timer;
00628 }
00629 
00631 void
00632 periodic_timer_free(periodic_timer_t *timer)
00633 {
00634   if (!timer)
00635     return;
00636   tor_event_free(timer->ev);
00637   tor_free(timer);
00638 }
00639 
00640 #ifdef USE_BUFFEREVENTS
00641 static const struct timeval *one_tick = NULL;
00647 const struct timeval *
00648 tor_libevent_get_one_tick_timeout(void)
00649 {
00650   tor_assert(one_tick);
00651   return one_tick;
00652 }
00653 
00656 static void
00657 tor_libevent_set_tick_timeout(int msec_per_tick)
00658 {
00659   struct event_base *base = tor_libevent_get_base();
00660   struct timeval tv;
00661 
00662   tor_assert(! one_tick);
00663   tv.tv_sec = msec_per_tick / 1000;
00664   tv.tv_usec = (msec_per_tick % 1000) * 1000;
00665   one_tick = event_base_init_common_timeout(base, &tv);
00666 }
00667 
00668 static struct bufferevent *
00669 tor_get_root_bufferevent(struct bufferevent *bev)
00670 {
00671   struct bufferevent *u;
00672   while ((u = bufferevent_get_underlying(bev)) != NULL)
00673     bev = u;
00674   return bev;
00675 }
00676 
00677 int
00678 tor_set_bufferevent_rate_limit(struct bufferevent *bev,
00679                                struct ev_token_bucket_cfg *cfg)
00680 {
00681   return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg);
00682 }
00683 
00684 int
00685 tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
00686                                         struct bufferevent_rate_limit_group *g)
00687 {
00688   return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g);
00689 }
00690 #endif
00691 
00692 #if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1)
00693 void
00694 tor_gettimeofday_cached(struct timeval *tv)
00695 {
00696   event_base_gettimeofday_cached(the_event_base, tv);
00697 }
00698 void
00699 tor_gettimeofday_cache_clear(void)
00700 {
00701   event_base_update_cache_time(the_event_base);
00702 }
00703 #else
00704 
00706 static struct timeval cached_time_hires = {0, 0};
00707 
00709 void
00710 tor_gettimeofday_cached(struct timeval *tv)
00711 {
00712   if (cached_time_hires.tv_sec == 0) {
00713     tor_gettimeofday(&cached_time_hires);
00714   }
00715   *tv = cached_time_hires;
00716 }
00717 
00720 void
00721 tor_gettimeofday_cache_clear(void)
00722 {
00723   cached_time_hires.tv_sec = 0;
00724 }
00725 #endif
00726