|  | @@ -23,6 +23,21 @@
 | 
	
		
			
				|  |  |  #include <event.h>
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** A number representing a version of Libevent.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    This is a 4-byte number, with the first three bytes representing the
 | 
	
		
			
				|  |  | +    major, minor, and patchlevel respectively of the the library.  The fourth
 | 
	
		
			
				|  |  | +    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;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static le_version_t tor_get_libevent_version(const char **v_out);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #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;
 | 
	
	
		
			
				|  | @@ -119,16 +134,51 @@ tor_event_free(struct event *ev)
 | 
	
		
			
				|  |  |  /** Global event base for use by the main thread. */
 | 
	
		
			
				|  |  |  struct event_base *the_event_base = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 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
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Initialize the Libevent library and set up the event base. */
 | 
	
		
			
				|  |  |  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)
 | 
	
		
			
				|  |  | +  /* 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
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Return the current Libevent event base that we're set up to use. */
 | 
	
	
		
			
				|  | @@ -151,3 +201,258 @@ tor_libevent_get_method(void)
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Macros: returns the number of a libevent version. */
 | 
	
		
			
				|  |  | +#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)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** Return the le_version_t for the current version of libevent.  If the
 | 
	
		
			
				|  |  | + * version is very new, return LE_OTHER.  If the version is so old that it
 | 
	
		
			
				|  |  | + * doesn't support event_get_version(), return LE_OLD. DOCDOC */
 | 
	
		
			
				|  |  | +static le_version_t
 | 
	
		
			
				|  |  | +tor_decode_libevent_version(const char *v)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  unsigned major, minor, patchlevel;
 | 
	
		
			
				|  |  | +  char c, extra;
 | 
	
		
			
				|  |  | +  int fields;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* Try the new preferred "1.4.11-stable" format. */
 | 
	
		
			
				|  |  | +  fields = sscanf(v, "%u.%u.%u%c", &major, &minor, &patchlevel, &c);
 | 
	
		
			
				|  |  | +  if (fields == 3 ||
 | 
	
		
			
				|  |  | +      (fields == 4 && (c == '-' || c == '_'))) {
 | 
	
		
			
				|  |  | +    return V(major,minor,patchlevel);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* Try the old "1.3e" format. */
 | 
	
		
			
				|  |  | +  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;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 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.
 | 
	
		
			
				|  |  | +    See le_version_t for info on the format.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +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);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* XXX Would it be worthwhile disabling the methods that we know
 | 
	
		
			
				|  |  | +   * are buggy, rather than just warning about them and then proceeding
 | 
	
		
			
				|  |  | +   * to use them? If so, we should probably not wrap this whole thing
 | 
	
		
			
				|  |  | +   * in HAVE_EVENT_GET_VERSION and HAVE_EVENT_GET_METHOD. -RD */
 | 
	
		
			
				|  |  | +  /* XXXX The problem is that it's not trivial to get libevent to change it's
 | 
	
		
			
				|  |  | +   * method once it's initialized, and it's not trivial to tell what method it
 | 
	
		
			
				|  |  | +   * will use without initializing it.  I guess we could preemptively disable
 | 
	
		
			
				|  |  | +   * buggy libevent modes based on the version _before_ initializing it,
 | 
	
		
			
				|  |  | +   * though, but then there's no good way (afaict) to warn "I would have used
 | 
	
		
			
				|  |  | +   * kqueue, but instead I'm using select." -NM */
 | 
	
		
			
				|  |  | +  /* XXXX022 revist the above; it is fixable now. */
 | 
	
		
			
				|  |  | +  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__)
 | 
	
		
			
				|  |  | +  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
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 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
 | 
	
		
			
				|  |  | +}
 |