[tor-commits] [tor/master] Merge remote branch 'origin/maint-0.2.2'

nickm at torproject.org nickm at torproject.org
Tue Feb 22 18:03:44 UTC 2011


commit 46b07462ae636eae1e241d5596b3a1d80c82d7ef
Merge: 933ffd5 9d5873c
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Feb 22 13:02:42 2011 -0500

    Merge remote branch 'origin/maint-0.2.2'

 changes/log_domains |   12 +++++++
 doc/tor.1.txt       |   28 +++++++++++++++
 src/common/log.c    |   92 ++++++++++++++++++++++++++++++++++++++++++--------
 src/common/torlog.h |    1 +
 src/or/config.c     |    7 +++-
 src/or/or.h         |    3 ++
 6 files changed, 127 insertions(+), 16 deletions(-)

diff --combined doc/tor.1.txt
index 7ba5302,033f0a2..19454a7
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@@ -323,6 -323,34 +323,34 @@@ Other options can be specified either o
      Messages are sent to all the logs that match their severity
      level.
  
+ **Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **file** __FILENAME__ +
+ 
+ **Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **stderr**|**stdout**|**syslog** ::
+     As above, but select messages by range of log severity __and__ by a
+     set of "logging domains".  Each logging domain corresponds to an area of
+     functionality inside Tor.  You can specify any number of severity ranges
+     for a single log statement, each of them prefixed by a comma-separated
+     list of logging domains.  You can prefix a domain with ~ to indicate
+     negation, and use * to indicate "all domains".  If you specify a severity
+     range without a list of domains, it matches all domains. +
+  +
+     This is an advanced feature which is most useful for debugging one or two
+     of Tor's subsystems at a time. +
+  +
+     The currently recognized domains are: general, crypto, net, config, fs,
+     protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge,
+     acct, hist, and handshake.  Domain names are case-insensitive. +
+  +
+     For example, "`Log [handshake]debug [~net,~mm]info notice stdout`" sends
+     to stdout: all handshake messages of any severity, all info-and-higher
+     messages from domains other than networking and memory management, and all
+     messages of severity notice or higher.
+ 
+ **LogMessageDomains** **0**|**1**::
+     If 1, Tor includes message domains with each log message.  Every log
+     message currently has at least one domain; most currently have exactly
+     one.  This doesn't affect controller log messages. (Default: 0)
+ 
  **OutboundBindAddress** __IP__::
      Make all outbound connections originate from the IP address specified. This
      is only useful when you have multiple network interfaces, and you want all
@@@ -343,13 -371,6 +371,13 @@@
      on Windows; instead you should use the --service command-line option.
      (Default: 0)
  
 +**LogTimeGranularity** __NUM__::
 +    Set the resolution of timestamps in Tor's logs to NUM milliseconds.
 +    NUM must be positive and either a divisor or a multiple of 1 second.
 +    Note that this option only controls the granularity written by Tor to
 +    a file or console log.  Tor does not (for example) "batch up" log
 +    messages to affect times logged by a controller, times attached to
 +    syslog messages, or the mtime fields on log files.  (Default: 1 second)
  
  **SafeLogging** **0**|**1**|**relay**::
      Tor can scrub potentially sensitive strings from log messages (e.g.
@@@ -404,11 -425,6 +432,11 @@@
      networkstatus. This is an advanced option; you generally shouldn't have
      to mess with it. (Default: not set.)
  
 +**DisableIOCP** **0**|**1**::
 +    If Tor was built to use the Libevent's "bufferevents" networking code
 +    and you're running on Windows, setting this option to 1 will tell Libevent
 +    not to use the Windows IOCP networking API.  (Default: 1)
 +
  CLIENT OPTIONS
  --------------
  
@@@ -483,7 -499,7 +511,7 @@@ The following options are useful only f
      list.
  
  **EntryNodes** __node__,__node__,__...__::
 -    A list of identity fingerprints, nicknames and address
 +    A list of identity fingerprints, nicknames, country codes and address
      patterns of nodes to use for the first hop in normal circuits. These are
      treated only as preferences unless StrictNodes (see below) is also set.
  
@@@ -580,8 -596,7 +608,8 @@@
      constitute a "family" of similar or co-administered servers, so never use
      any two of them in the same circuit. Defining a NodeFamily is only needed
      when a server doesn't list the family itself (with MyFamily). This option
 -    can be used multiple times.
 +    can be used multiple times.  In addition to nodes, you can also list
 +    IP address and ranges and country codes in {curly braces}.
  
  **EnforceDistinctSubnets** **0**|**1**::
      If 1, Tor will not put two servers whose IP addresses are "too close" on
@@@ -884,9 -899,7 +912,9 @@@ is non-zero)
      characters inclusive, and must contain only the characters [a-zA-Z0-9].
  
  **NumCPUs** __num__::
 -    How many processes to use at once for decrypting onionskins. (Default: 1)
 +    How many processes to use at once for decrypting onionskins and other
 +    parallelizable operations.  If this is set to 0, Tor will try to detect
 +    how many CPUs you have, defaulting to 1 if it can't tell.  (Default: 0)
  
  **ORPort** __PORT__::
      Advertise this port to listen for connections from Tor clients and servers.
@@@ -897,18 -910,6 +925,18 @@@
      specified in ORPort. (Default: 0.0.0.0) This directive can be specified
      multiple times to bind to multiple addresses/ports.
  
 +**PortForwarding** **0**|**1**::
 +    Attempt to automatically forward the DirPort and ORPort on a NAT router
 +    connecting this Tor server to the Internet. If set, Tor will try both
 +    NAT-PMP (common on Apple routers) and UPnP (common on routers from other
 +    manufacturers). (Default: 0)
 +
 +**PortForwardingHelper** __filename__|__pathname__::
 +    If PortForwarding is set, use this executable to configure the forwarding.
 +    If set to a filename, the system path will be searched for the executable.
 +    If set to a path, only the specified path will be executed.
 +    (Default: tor-fw-helper)
 +
  **PublishServerDescriptor** **0**|**1**|**v1**|**v2**|**v3**|**bridge**,**...**::
      This option specifies which descriptors Tor will publish when acting as
      a relay. You can
@@@ -928,11 -929,6 +956,11 @@@
      seconds, we exit. If we get a second SIGINT, we exit immedi-
      ately. (Default: 30 seconds)
  
 +**HeartbeatPeriod**  __N__ **minutes**|**hours**|**days**|**weeks**::
 +    Log a heartbeat message every **HeartbeatPeriod** seconds. This is
 +    a log level __info__ message, designed to let you know your Tor
 +    server is still alive and doing useful things. Settings this
 +    to 0 will disable the heartbeat. (Default: 6 hours)
  
  **AccountingMax** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
      Never send more than the specified number of bytes in a given accounting
@@@ -1041,10 -1037,6 +1069,10 @@@
      When this option is enabled, Tor writes statistics on the number of relayed
      bytes and opened stream per exit port to disk every 24 hours. (Default: 0)
  
 +**ConnDirectionStatistics** **0**|**1**::
 +    When this option is enabled, Tor writes statistics on the bidirectional use
 +    of connections to disk every 24 hours. (Default: 0)
 +
  **ExtraInfoStatistics** **0**|**1**::
      When this option is enabled, Tor includes previously gathered statistics in
      its extra-info documents that it uploads to the directory authorities.
diff --combined src/common/log.c
index ba84807,cfa0721..507f162
--- a/src/common/log.c
+++ b/src/common/log.c
@@@ -97,6 -97,9 +97,9 @@@ static int log_mutex_initialized = 0
  
  /** Linked list of logfile_t. */
  static logfile_t *logfiles = NULL;
+ /** Boolean: do we report logging domains? */
+ static int log_domains_are_logged = 0;
+ 
  #ifdef HAVE_SYSLOG_H
  /** The number of open syslog log handlers that we have.  When this reaches 0,
   * we can close our connection to the syslog facility. */
@@@ -126,6 -129,9 +129,9 @@@ int _log_global_min_severity = LOG_NOTI
  static void delete_log(logfile_t *victim);
  static void close_log(logfile_t *victim);
  
+ static char *domain_to_string(log_domain_mask_t domain,
+                              char *buf, size_t buflen);
+ 
  /** Name of the application: used to generate the message we write at the
   * start of each new log. */
  static char *appname = NULL;
@@@ -142,17 -148,6 +148,17 @@@ log_set_application_name(const char *na
    appname = name ? tor_strdup(name) : NULL;
  }
  
 +/** Log time granularity in milliseconds. */
 +static int log_time_granularity = 1;
 +
 +/** Define log time granularity for all logs to be <b>granularity_msec</b>
 + * milliseconds. */
 +void
 +set_log_time_granularity(int granularity_msec)
 +{
 +  log_time_granularity = granularity_msec;
 +}
 +
  /** Helper: Write the standard prefix for log lines to a
   * <b>buf_len</b> character buffer in <b>buf</b>.
   */
@@@ -163,22 -158,14 +169,22 @@@ _log_prefix(char *buf, size_t buf_len, 
    struct timeval now;
    struct tm tm;
    size_t n;
 -  int r;
 +  int r, ms;
  
    tor_gettimeofday(&now);
    t = (time_t)now.tv_sec;
 +  ms = (int)now.tv_usec / 1000;
 +  if (log_time_granularity >= 1000) {
 +    t -= t % (log_time_granularity / 1000);
 +    ms = 0;
 +  } else {
 +    ms -= ((int)now.tv_usec / 1000) % log_time_granularity;
 +  }
  
    n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
 -  r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ",
 -                   (int)now.tv_usec / 1000, sev_to_string(severity));
 +  r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms,
 +                   sev_to_string(severity));
 +
    if (r<0)
      return buf_len-1;
    else
@@@ -236,13 -223,34 +242,34 @@@ format_msg(char *buf, size_t buf_len
    size_t n;
    int r;
    char *end_of_prefix;
+   char *buf_end;
  
-   assert(buf_len >= 2); /* prevent integer underflow */
+   assert(buf_len >= 16); /* prevent integer underflow and general stupidity */
    buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
+   buf_end = buf+buf_len; /* point *after* the last char we can write to */
  
    n = _log_prefix(buf, buf_len, severity);
    end_of_prefix = buf+n;
  
+   if (log_domains_are_logged) {
+     char *cp = buf+n;
+     if (cp == buf_end) goto format_msg_no_room_for_domains;
+     *cp++ = '{';
+     if (cp == buf_end) goto format_msg_no_room_for_domains;
+     cp = domain_to_string(domain, cp, (buf+buf_len-cp));
+     if (cp == buf_end) goto format_msg_no_room_for_domains;
+     *cp++ = '}';
+     if (cp == buf_end) goto format_msg_no_room_for_domains;
+     *cp++ = ' ';
+     if (cp == buf_end) goto format_msg_no_room_for_domains;
+     end_of_prefix = cp;
+     n = cp-buf;
+   format_msg_no_room_for_domains:
+     /* This will leave end_of_prefix and n unchanged, and thus cause
+      * whatever log domain string we had written to be clobbered. */
+     ;
+   }
+ 
    if (funcname && should_log_function_name(domain, severity)) {
      r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname);
      if (r<0)
@@@ -324,6 -332,7 +351,7 @@@ logv(int severity, log_domain_mask_t do
                     &msg_len);
        formatted = 1;
      }
+ 
      if (lf->is_syslog) {
  #ifdef HAVE_SYSLOG_H
        char *m = end_of_prefix;
@@@ -582,8 -591,7 +610,7 @@@ add_stream_log_impl(const log_severity_
   * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
   * not use it after calling this function. */
  void
- add_stream_log(const log_severity_list_t *severity,
-                const char *name, int fd)
+ add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
  {
    LOCK_LOGS();
    add_stream_log_impl(severity, name, fd);
@@@ -602,6 -610,16 +629,16 @@@ init_logging(void
      pending_cb_messages = smartlist_create();
  }
  
+ /** Set whether we report logging domains as a part of our log messages.
+  */
+ void
+ logs_set_domain_logging(int enabled)
+ {
+   LOCK_LOGS();
+   log_domains_are_logged = enabled;
+   UNLOCK_LOGS();
+ }
+ 
  /** Add a log handler to receive messages during startup (before the real
   * logs are initialized).
   */
@@@ -658,7 -676,7 +695,7 @@@ change_callback_log_severity(int loglev
    UNLOCK_LOGS();
  }
  
 -/** If there are any log messages that were genered with LD_NOCB waiting to
 +/** If there are any log messages that were generated with LD_NOCB waiting to
   * be sent to callback-based loggers, send them now. */
  void
  flush_pending_log_callbacks(void)
@@@ -758,7 -776,7 +795,7 @@@ add_file_log(const log_severity_list_t 
    int fd;
    logfile_t *lf;
  
 -  fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
 +  fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
    if (fd<0)
      return -1;
    if (tor_fd_seekend(fd)<0)
@@@ -794,7 -812,6 +831,6 @@@ add_syslog_log(const log_severity_list_
    lf->fd = -1;
    lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
    lf->filename = tor_strdup("<syslog>");
- 
    lf->is_syslog = 1;
  
    LOCK_LOGS();
@@@ -851,18 -868,41 +887,41 @@@ parse_log_domain(const char *domain
    }
    return 0;
  }
- #if 0
- /** Translate a bitmask of log domains to a string, or NULL if the bitmask
-  * is undecodable. */
- static const char *
- domain_to_string(log_domain_mask_t domain)
+ 
+ /** Translate a bitmask of log domains to a string. */
+ static char *
+ domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen)
  {
-   int bit = tor_log2(domain);
-   if ((bit == 0 && domain == 0) || bit >= N_LOGGING_DOMAINS)
-     return NULL;
-   return domain_list[bit];
+   char *cp = buf;
+   char *eos = buf+buflen;
+ 
+   buf[0] = '\0';
+   if (! domain)
+     return buf;
+   while (1) {
+     const char *d;
+     int bit = tor_log2(domain);
+     size_t n;
+     if (bit >= N_LOGGING_DOMAINS) {
+       tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain);
+       return buf+strlen(buf);
+     }
+     d = domain_list[bit];
+     n = strlcpy(cp, d, eos-cp);
+     if (n >= buflen) {
+       tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain);
+       return buf+strlen(buf);
+     }
+     cp += n;
+     domain &= ~(1<<bit);
+ 
+     if (domain == 0 || (eos-cp) < 2)
+       return cp;
+ 
+     memcpy(cp, ",", 2); /*Nul-terminated ,"*/
+     cp++;
+   }
  }
- #endif
  
  /** Parse a log severity pattern in *<b>cfg_ptr</b>.  Advance cfg_ptr after
   * the end of the severityPattern.  Set the value of <b>severity_out</b> to
@@@ -938,7 -978,10 +997,10 @@@ parse_log_severity_config(const char **
        smartlist_free(domains_list);
        if (err)
          return -1;
-       domains &= ~neg_domains;
+       if (domains == 0 && neg_domains)
+         domains = ~neg_domains;
+       else
+         domains &= ~neg_domains;
        cfg = eat_whitespace(closebracket+1);
      } else {
        ++got_an_unqualified_range;
diff --combined src/common/torlog.h
index 4192a88,791e363..add2349
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@@ -92,10 -92,8 +92,10 @@@
  #define LD_HIST     (1u<<18)
  /** OR handshaking */
  #define LD_HANDSHAKE (1u<<19)
 +/** Heartbeat messages */
 +#define LD_HEARTBEAT (1u<<20)
  /** Number of logging domains in the code. */
 -#define N_LOGGING_DOMAINS 20
 +#define N_LOGGING_DOMAINS 21
  
  /** This log message is not safe to send to a callback-based logger
   * immediately.  Used as a flag, not a log domain. */
@@@ -134,6 -132,7 +134,7 @@@ int add_file_log(const log_severity_lis
  int add_syslog_log(const log_severity_list_t *severity);
  #endif
  int add_callback_log(const log_severity_list_t *severity, log_callback cb);
+ void logs_set_domain_logging(int enabled);
  int get_min_log_level(void);
  void switch_logs_debug(void);
  void logs_free_all(void);
@@@ -145,7 -144,6 +146,7 @@@ void change_callback_log_severity(int l
                                    log_callback cb);
  void flush_pending_log_callbacks(void);
  void log_set_application_name(const char *name);
 +void set_log_time_granularity(int granularity_msec);
  
  /* Outputs a message to stdout */
  void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
diff --combined src/or/config.c
index 8bf4842,178ed1e..97a2b32
--- a/src/or/config.c
+++ b/src/or/config.c
@@@ -44,8 -44,6 +44,8 @@@ typedef enum config_type_t 
    CONFIG_TYPE_FILENAME,     /**< A filename: some prefixes get expanded. */
    CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
    CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
 +  CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
 +                              * units */
    CONFIG_TYPE_MEMUNIT,      /**< A number of bytes, with optional units*/
    CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
    CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
@@@ -201,7 -199,6 +201,7 @@@ static config_var_t _option_vars[] = 
    V(ClientOnly,                  BOOL,     "0"),
    V(ConsensusParams,             STRING,   NULL),
    V(ConnLimit,                   UINT,     "1000"),
 +  V(ConnDirectionStatistics,     BOOL,     "0"),
    V(ConstrainedSockets,          BOOL,     "0"),
    V(ConstrainedSockSize,         MEMUNIT,  "8192"),
    V(ContactInfo,                 STRING,   NULL),
@@@ -225,10 -222,9 +225,10 @@@
    OBSOLETE("DirRecordUsageGranularity"),
    OBSOLETE("DirRecordUsageRetainIPs"),
    OBSOLETE("DirRecordUsageSaveInterval"),
 -  V(DirReqStatistics,            BOOL,     "0"),
 +  V(DirReqStatistics,            BOOL,     "1"),
    VAR("DirServer",               LINELIST, DirServers, NULL),
    V(DisableAllSwap,              BOOL,     "0"),
 +  V(DisableIOCP,                 BOOL,     "1"),
    V(DNSPort,                     UINT,     "0"),
    V(DNSListenAddress,            LINELIST, NULL),
    V(DownloadExtraInfo,           BOOL,     "0"),
@@@ -243,7 -239,7 +243,7 @@@
    V(ExitPolicy,                  LINELIST, NULL),
    V(ExitPolicyRejectPrivate,     BOOL,     "1"),
    V(ExitPortStatistics,          BOOL,     "0"),
 -  V(ExtraInfoStatistics,         BOOL,     "0"),
 +  V(ExtraInfoStatistics,         BOOL,     "1"),
  
  #if defined (WINCE)
    V(FallbackNetworkstatusFile,   FILENAME, "fallback-consensus"),
@@@ -267,7 -263,6 +267,7 @@@
  #endif
    OBSOLETE("Group"),
    V(HardwareAccel,               BOOL,     "0"),
 +  V(HeartbeatPeriod,             INTERVAL, "6 hours"),
    V(AccelName,                   STRING,   NULL),
    V(AccelDir,                    FILENAME, NULL),
    V(HashedControlPassword,       LINELIST, NULL),
@@@ -293,10 -288,10 +293,11 @@@
    OBSOLETE("IgnoreVersion"),
    V(KeepalivePeriod,             INTERVAL, "5 minutes"),
    VAR("Log",                     LINELIST, Logs,             NULL),
+   V(LogMessageDomains,           BOOL,     "0"),
    OBSOLETE("LinkPadding"),
    OBSOLETE("LogLevel"),
    OBSOLETE("LogFile"),
 +  V(LogTimeGranularity,          MSEC_INTERVAL, "1 second"),
    V(LongLivedPorts,              CSV,
                           "21,22,706,1863,5050,5190,5222,5223,6667,6697,8300"),
    VAR("MapAddress",              LINELIST, AddressMap,           NULL),
@@@ -313,7 -308,7 +314,7 @@@
    V(WarnUnsafeSocks,              BOOL,     "1"),
    OBSOLETE("NoPublish"),
    VAR("NodeFamily",              LINELIST, NodeFamilies,         NULL),
 -  V(NumCPUs,                     UINT,     "1"),
 +  V(NumCPUs,                     UINT,     "0"),
    V(NumEntryGuards,              UINT,     "3"),
    V(ORListenAddress,             LINELIST, NULL),
    V(ORPort,                      UINT,     "0"),
@@@ -323,8 -318,6 +324,8 @@@
    V(PerConnBWRate,               MEMUNIT,  "0"),
    V(PidFile,                     STRING,   NULL),
    V(TestingTorNetwork,           BOOL,     "0"),
 +  V(PortForwarding,              BOOL,     "0"),
 +  V(PortForwardingHelper,        FILENAME, "tor-fw-helper"),
    V(PreferTunneledDirConns,      BOOL,     "1"),
    V(ProtocolWarnings,            BOOL,     "0"),
    V(PublishServerDescriptor,     CSV,      "1"),
@@@ -393,7 -386,6 +394,7 @@@
    VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
    V(VirtualAddrNetwork,          STRING,   "127.192.0.0/10"),
    V(WarnPlaintextPorts,          CSV,      "23,109,110,143"),
 +  V(_UseFilteringSSLBufferevents, BOOL,    "0"),
    VAR("__ReloadTorrcOnSIGHUP",   BOOL,  ReloadTorrcOnSIGHUP,      "1"),
    VAR("__AllDirActionsPrivate",  BOOL,  AllDirActionsPrivate,     "0"),
    VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
@@@ -566,9 -558,8 +567,9 @@@ static int is_listening_on_low_port(uin
                                      const config_line_t *listen_options);
  
  static uint64_t config_parse_memunit(const char *s, int *ok);
 +static int config_parse_msec_interval(const char *s, int *ok);
  static int config_parse_interval(const char *s, int *ok);
 -static void init_libevent(void);
 +static void init_libevent(const or_options_t *options);
  static int opt_streq(const char *s1, const char *s2);
  
  /** Magic value for or_options_t. */
@@@ -702,11 -693,6 +703,11 @@@ or_options_free(or_options_t *options
      return;
  
    routerset_free(options->_ExcludeExitNodesUnion);
 +  if (options->NodeFamilySets) {
 +    SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *,
 +                      rs, routerset_free(rs));
 +    smartlist_free(options->NodeFamilySets);
 +  }
    config_free(&options_format, options);
  }
  
@@@ -974,7 -960,7 +975,7 @@@ options_act_reversible(or_options_t *ol
      /* Set up libevent.  (We need to do this before we can register the
       * listeners as listeners.) */
      if (running_tor && !libevent_initialized) {
 -      init_libevent();
 +      init_libevent(options);
        libevent_initialized = 1;
      }
  
@@@ -1250,17 -1236,6 +1251,17 @@@ options_act(or_options_t *old_options
    if (accounting_is_enabled(options))
      configure_accounting(time(NULL));
  
 +#ifdef USE_BUFFEREVENTS
 +  /* If we're using the bufferevents implementation and our rate limits
 +   * changed, we need to tell the rate-limiting system about it. */
 +  if (!old_options ||
 +      old_options->BandwidthRate != options->BandwidthRate ||
 +      old_options->BandwidthBurst != options->BandwidthBurst ||
 +      old_options->RelayBandwidthRate != options->RelayBandwidthRate ||
 +      old_options->RelayBandwidthBurst != options->RelayBandwidthBurst)
 +    connection_bucket_init();
 +#endif
 +
    /* parse RefuseUnknownExits tristate */
    if (!strcmp(options->RefuseUnknownExits, "0"))
      options->RefuseUnknownExits_ = 0;
@@@ -1372,52 -1347,44 +1373,52 @@@
      tor_free(actual_fname);
    }
  
 -  if (options->DirReqStatistics && !geoip_is_loaded()) {
 -    /* Check if GeoIP database could be loaded. */
 -    log_warn(LD_CONFIG, "Configured to measure directory request "
 -             "statistics, but no GeoIP database found!");
 -    return -1;
 -  }
 -
 -  if (options->EntryStatistics) {
 -    if (should_record_bridge_info(options)) {
 -      /* Don't allow measuring statistics on entry guards when configured
 -       * as bridge. */
 -      log_warn(LD_CONFIG, "Bridges cannot be configured to measure "
 -               "additional GeoIP statistics as entry guards.");
 -      return -1;
 -    } else if (!geoip_is_loaded()) {
 -      /* Check if GeoIP database could be loaded. */
 -      log_warn(LD_CONFIG, "Configured to measure entry node statistics, "
 -               "but no GeoIP database found!");
 -      return -1;
 -    }
 -  }
 -
    if (options->CellStatistics || options->DirReqStatistics ||
 -      options->EntryStatistics || options->ExitPortStatistics) {
 +      options->EntryStatistics || options->ExitPortStatistics ||
 +      options->ConnDirectionStatistics) {
      time_t now = time(NULL);
 +    int print_notice = 0;
      if ((!old_options || !old_options->CellStatistics) &&
 -        options->CellStatistics)
 +        options->CellStatistics) {
        rep_hist_buffer_stats_init(now);
 +      print_notice = 1;
 +    }
      if ((!old_options || !old_options->DirReqStatistics) &&
 -        options->DirReqStatistics)
 -      geoip_dirreq_stats_init(now);
 +        options->DirReqStatistics) {
 +      if (geoip_is_loaded()) {
 +        geoip_dirreq_stats_init(now);
 +        print_notice = 1;
 +      } else {
 +        options->DirReqStatistics = 0;
 +        log_notice(LD_CONFIG, "Configured to measure directory request "
 +                              "statistics, but no GeoIP database found! "
 +                              "Please specify a GeoIP database using the "
 +                              "GeoIPFile option!");
 +      }
 +    }
      if ((!old_options || !old_options->EntryStatistics) &&
 -        options->EntryStatistics)
 -      geoip_entry_stats_init(now);
 +        options->EntryStatistics && !should_record_bridge_info(options)) {
 +      if (geoip_is_loaded()) {
 +        geoip_entry_stats_init(now);
 +        print_notice = 1;
 +      } else {
 +        options->EntryStatistics = 0;
 +        log_notice(LD_CONFIG, "Configured to measure entry node "
 +                              "statistics, but no GeoIP database found! "
 +                              "Please specify a GeoIP database using the "
 +                              "GeoIPFile option!");
 +      }
 +    }
      if ((!old_options || !old_options->ExitPortStatistics) &&
 -        options->ExitPortStatistics)
 +        options->ExitPortStatistics) {
        rep_hist_exit_stats_init(now);
 -    if (!old_options)
 +      print_notice = 1;
 +    }
 +    if ((!old_options || !old_options->ConnDirectionStatistics) &&
 +        options->ConnDirectionStatistics) {
 +      rep_hist_conn_stats_init(now);
 +    }
 +    if (print_notice)
        log_notice(LD_CONFIG, "Configured to measure statistics. Look for "
                   "the *-stats files that will first be written to the "
                   "data directory in 24 hours from now.");
@@@ -1435,9 -1402,6 +1436,9 @@@
    if (old_options && old_options->ExitPortStatistics &&
        !options->ExitPortStatistics)
      rep_hist_exit_stats_term();
 +  if (old_options && old_options->ConnDirectionStatistics &&
 +      !options->ConnDirectionStatistics)
 +    rep_hist_conn_stats_term();
  
    /* Check if we need to parse and add the EntryNodes config option. */
    if (options->EntryNodes &&
@@@ -1743,18 -1707,6 +1744,18 @@@ config_assign_value(config_format_t *fm
      break;
    }
  
 +  case CONFIG_TYPE_MSEC_INTERVAL: {
 +    i = config_parse_msec_interval(c->value, &ok);
 +    if (!ok) {
 +      tor_asprintf(msg,
 +          "Msec interval '%s %s' is malformed or out of bounds.",
 +          c->key, c->value);
 +      return -1;
 +    }
 +    *(int *)lvalue = i;
 +    break;
 +  }
 +
    case CONFIG_TYPE_MEMUNIT: {
      uint64_t u64 = config_parse_memunit(c->value, &ok);
      if (!ok) {
@@@ -2042,7 -1994,6 +2043,7 @@@ get_assigned_option(config_format_t *fm
        escape_val = 0; /* Can't need escape. */
        break;
      case CONFIG_TYPE_INTERVAL:
 +    case CONFIG_TYPE_MSEC_INTERVAL:
      case CONFIG_TYPE_UINT:
        /* This means every or_options_t uint or bool element
         * needs to be an int. Not, say, a uint16_t or char. */
@@@ -2270,7 -2221,6 +2271,7 @@@ option_clear(config_format_t *fmt, or_o
        *(time_t*)lvalue = 0;
        break;
      case CONFIG_TYPE_INTERVAL:
 +    case CONFIG_TYPE_MSEC_INTERVAL:
      case CONFIG_TYPE_UINT:
      case CONFIG_TYPE_BOOL:
        *(int*)lvalue = 0;
@@@ -2377,7 -2327,7 +2378,7 @@@ resolve_my_address(int warn_severity, o
    int explicit_ip=1;
    int explicit_hostname=1;
    int from_interface=0;
 -  char tmpbuf[INET_NTOA_BUF_LEN];
 +  char *addr_string = NULL;
    const char *address = options->Address;
    int notice_severity = warn_severity <= LOG_NOTICE ?
                            LOG_NOTICE : warn_severity;
@@@ -2419,43 -2369,48 +2420,43 @@@
          return -1;
        }
        from_interface = 1;
 -      in.s_addr = htonl(interface_ip);
 -      tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
 +      addr = interface_ip;
        log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
 -             "local interface. Using that.", tmpbuf);
 +             "local interface. Using that.", fmt_addr32(addr));
        strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
      } else { /* resolved hostname into addr */
 -      in.s_addr = htonl(addr);
 -
        if (!explicit_hostname &&
 -          is_internal_IP(ntohl(in.s_addr), 0)) {
 +          is_internal_IP(addr, 0)) {
          uint32_t interface_ip;
  
 -        tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
          log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
 -               "resolves to a private IP address (%s).  Trying something "
 -               "else.", hostname, tmpbuf);
 +               "resolves to a private IP address (%s). Trying something "
 +               "else.", hostname, fmt_addr32(addr));
  
          if (get_interface_address(warn_severity, &interface_ip)) {
            log_fn(warn_severity, LD_CONFIG,
                   "Could not get local interface IP address. Too bad.");
          } else if (is_internal_IP(interface_ip, 0)) {
 -          struct in_addr in2;
 -          in2.s_addr = htonl(interface_ip);
 -          tor_inet_ntoa(&in2,tmpbuf,sizeof(tmpbuf));
            log_fn(notice_severity, LD_CONFIG,
                   "Interface IP address '%s' is a private address too. "
 -                 "Ignoring.", tmpbuf);
 +                 "Ignoring.", fmt_addr32(interface_ip));
          } else {
            from_interface = 1;
 -          in.s_addr = htonl(interface_ip);
 -          tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
 +          addr = interface_ip;
            log_fn(notice_severity, LD_CONFIG,
                   "Learned IP address '%s' for local interface."
 -                 " Using that.", tmpbuf);
 +                 " Using that.", fmt_addr32(addr));
            strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
          }
        }
      }
 +  } else {
 +    addr = ntohl(in.s_addr); /* set addr so that addr_string is not
 +                              * illformed */
    }
  
 -  tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
 -  if (is_internal_IP(ntohl(in.s_addr), 0)) {
 +  addr_string = tor_dup_ip(addr);
 +  if (is_internal_IP(addr, 0)) {
      /* make sure we're ok with publishing an internal IP */
      if (!options->DirServers && !options->AlternateDirAuthority) {
        /* if they are using the default dirservers, disallow internal IPs
@@@ -2463,8 -2418,7 +2464,8 @@@
        log_fn(warn_severity, LD_CONFIG,
               "Address '%s' resolves to private IP address '%s'. "
               "Tor servers that use the default DirServers must have public "
 -             "IP addresses.", hostname, tmpbuf);
 +             "IP addresses.", hostname, addr_string);
 +      tor_free(addr_string);
        return -1;
      }
      if (!explicit_ip) {
@@@ -2472,20 -2426,19 +2473,20 @@@
         * they're using an internal address. */
        log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
               "IP address '%s'. Please set the Address config option to be "
 -             "the IP address you want to use.", hostname, tmpbuf);
 +             "the IP address you want to use.", hostname, addr_string);
 +      tor_free(addr_string);
        return -1;
      }
    }
  
 -  log_debug(LD_CONFIG, "Resolved Address to '%s'.", tmpbuf);
 -  *addr_out = ntohl(in.s_addr);
 +  log_debug(LD_CONFIG, "Resolved Address to '%s'.", fmt_addr32(addr));
 +  *addr_out = addr;
    if (last_resolved_addr && last_resolved_addr != *addr_out) {
      /* Leave this as a notice, regardless of the requested severity,
       * at least until dynamic IP address support becomes bulletproof. */
      log_notice(LD_NET,
                 "Your IP address seems to have changed to %s. Updating.",
 -               tmpbuf);
 +               addr_string);
      ip_address_changed(0);
    }
    if (last_resolved_addr != *addr_out) {
@@@ -2504,12 -2457,11 +2505,12 @@@
      }
      control_event_server_status(LOG_NOTICE,
                                  "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s %s%s",
 -                                tmpbuf, method, h?"HOSTNAME=":"", h);
 +                                addr_string, method, h?"HOSTNAME=":"", h);
    }
    last_resolved_addr = *addr_out;
    if (hostname_out)
      *hostname_out = tor_strdup(hostname);
 +  tor_free(addr_string);
    return 0;
  }
  
@@@ -2916,10 -2868,6 +2917,10 @@@ compute_publishserverdescriptor(or_opti
   * will generate too many circuits and potentially overload the network. */
  #define MIN_CIRCUIT_STREAM_TIMEOUT 10
  
 +/** Lowest allowable value for HeartbeatPeriod; if this is too low, we might
 + * expose more information than we're comfortable with. */
 +#define MIN_HEARTBEAT_PERIOD (30*60)
 +
  /** Return 0 if every setting in <b>options</b> is reasonable, and a
   * permissible transition from <b>old_options</b>. Else return -1.
   * Should have no side effects, except for normalizing the contents of
@@@ -3120,24 -3068,17 +3121,24 @@@ options_validate(or_options_t *old_opti
      routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeNodes);
    }
  
 +  if (options->NodeFamilies) {
 +    options->NodeFamilySets = smartlist_create();
 +    for (cl = options->NodeFamilies; cl; cl = cl->next) {
 +      routerset_t *rs = routerset_new();
 +      if (routerset_parse(rs, cl->value, cl->key) == 0) {
 +        smartlist_add(options->NodeFamilySets, rs);
 +      } else {
 +        routerset_free(rs);
 +      }
 +    }
 +  }
 +
    if (options->ExcludeNodes && options->StrictNodes) {
      COMPLAIN("You have asked to exclude certain relays from all positions "
               "in your circuits. Expect hidden services and other Tor "
               "features to be broken in unpredictable ways.");
    }
  
 -  if (options->EntryNodes && !routerset_is_list(options->EntryNodes)) {
 -    /* XXXX fix this; see entry_guards_prepend_from_config(). */
 -    REJECT("IPs or countries are not yet supported in EntryNodes.");
 -  }
 -
    if (options->AuthoritativeDir) {
      if (!options->ContactInfo && !options->TestingTorNetwork)
        REJECT("Authoritative directory servers must set ContactInfo");
@@@ -3382,13 -3323,6 +3383,13 @@@
      options->CircuitStreamTimeout = MIN_CIRCUIT_STREAM_TIMEOUT;
    }
  
 +  if (options->HeartbeatPeriod &&
 +      options->HeartbeatPeriod < MIN_HEARTBEAT_PERIOD) {
 +    log_warn(LD_CONFIG, "HeartbeatPeriod option is too short; "
 +             "raising to %d seconds.", MIN_HEARTBEAT_PERIOD);
 +    options->HeartbeatPeriod = MIN_HEARTBEAT_PERIOD;
 +  }
 +
    if (options->KeepalivePeriod < 1)
      REJECT("KeepalivePeriod option must be positive.");
  
@@@ -3607,12 -3541,8 +3608,12 @@@
    if (check_nickname_list(options->MyFamily, "MyFamily", msg))
      return -1;
    for (cl = options->NodeFamilies; cl; cl = cl->next) {
 -    if (check_nickname_list(cl->value, "NodeFamily", msg))
 +    routerset_t *rs = routerset_new();
 +    if (routerset_parse(rs, cl->value, cl->key)) {
 +      routerset_free(rs);
        return -1;
 +    }
 +    routerset_free(rs);
    }
  
    if (validate_addr_policies(options, msg) < 0)
@@@ -3888,7 -3818,8 +3889,8 @@@ options_transition_affects_workers(or_o
        old_options->SafeLogging != new_options->SafeLogging ||
        old_options->ClientOnly != new_options->ClientOnly ||
        public_server_mode(old_options) != public_server_mode(new_options) ||
-       !config_lines_eq(old_options->Logs, new_options->Logs))
+       !config_lines_eq(old_options->Logs, new_options->Logs) ||
+       old_options->LogMessageDomains != new_options->LogMessageDomains)
      return 1;
  
    /* Check whether log options match. */
@@@ -4105,8 -4036,6 +4107,8 @@@ load_torrc_from_disk(int argc, char **a
            "Unable to open configuration file \"%s\".", fname);
        goto err;
      }
 +  } else {
 +    log(LOG_NOTICE, LD_CONFIG, "Read configuration file \"%s\".", fname);
    }
  
    return cf;
@@@ -4395,35 -4324,6 +4397,35 @@@ options_init_logs(or_options_t *options
                 options->RunAsDaemon;
  #endif
  
 +  if (options->LogTimeGranularity <= 0) {
 +    log_warn(LD_CONFIG, "Log time granularity '%d' has to be positive.",
 +             options->LogTimeGranularity);
 +    return -1;
 +  } else if (1000 % options->LogTimeGranularity != 0 &&
 +             options->LogTimeGranularity % 1000 != 0) {
 +    int granularity = options->LogTimeGranularity;
 +    if (granularity < 40) {
 +      do granularity++;
 +      while (1000 % granularity != 0);
 +    } else if (granularity < 1000) {
 +      granularity = 1000 / granularity;
 +      while (1000 % granularity != 0)
 +        granularity--;
 +      granularity = 1000 / granularity;
 +    } else {
 +      granularity = 1000 * ((granularity / 1000) + 1);
 +    }
 +    log_warn(LD_CONFIG, "Log time granularity '%d' has to be either a "
 +                        "divisor or a multiple of 1 second. Changing to "
 +                        "'%d'.",
 +             options->LogTimeGranularity, granularity);
 +    if (!validate_only)
 +      set_log_time_granularity(granularity);
 +  } else {
 +    if (!validate_only)
 +      set_log_time_granularity(options->LogTimeGranularity);
 +  }
 +
    ok = 1;
    elts = smartlist_create();
  
@@@ -4495,6 -4395,9 +4497,9 @@@
    }
    smartlist_free(elts);
  
+   if (ok && !validate_only)
+     logs_set_domain_logging(options->LogMessageDomains);
+ 
    return ok?0:-1;
  }
  
@@@ -4912,26 -4815,6 +4917,26 @@@ static struct unit_table_t time_units[
    { NULL, 0 },
  };
  
 +/** Table to map the names of time units to the number of milliseconds
 + * they contain. */
 +static struct unit_table_t time_msec_units[] = {
 +  { "",         1 },
 +  { "msec",     1 },
 +  { "millisecond", 1 },
 +  { "milliseconds", 1 },
 +  { "second",   1000 },
 +  { "seconds",  1000 },
 +  { "minute",   60*1000 },
 +  { "minutes",  60*1000 },
 +  { "hour",     60*60*1000 },
 +  { "hours",    60*60*1000 },
 +  { "day",      24*60*60*1000 },
 +  { "days",     24*60*60*1000 },
 +  { "week",     7*24*60*60*1000 },
 +  { "weeks",    7*24*60*60*1000 },
 +  { NULL, 0 },
 +};
 +
  /** Parse a string <b>val</b> containing a number, zero or more
   * spaces, and an optional unit string.  If the unit appears in the
   * table <b>u</b>, then multiply the number by the unit multiplier.
@@@ -4995,25 -4878,6 +5000,25 @@@ config_parse_memunit(const char *s, in
    return u;
  }
  
 +/** Parse a string in the format "number unit", where unit is a unit of
 + * time in milliseconds.  On success, set *<b>ok</b> to true and return
 + * the number of milliseconds in the provided interval.  Otherwise, set
 + * *<b>ok</b> to 0 and return -1. */
 +static int
 +config_parse_msec_interval(const char *s, int *ok)
 +{
 +  uint64_t r;
 +  r = config_parse_units(s, time_msec_units, ok);
 +  if (!ok)
 +    return -1;
 +  if (r > INT_MAX) {
 +    log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
 +    *ok = 0;
 +    return -1;
 +  }
 +  return (int)r;
 +}
 +
  /** Parse a string in the format "number unit", where unit is a unit of time.
   * On success, set *<b>ok</b> to true and return the number of seconds in
   * the provided interval.  Otherwise, set *<b>ok</b> to 0 and return -1.
@@@ -5033,29 -4897,13 +5038,29 @@@ config_parse_interval(const char *s, in
    return (int)r;
  }
  
 +/** Return the number of cpus configured in <b>options</b>.  If we are
 + * told to auto-detect the number of cpus, return the auto-detected number. */
 +int
 +get_num_cpus(const or_options_t *options)
 +{
 +  if (options->NumCPUs == 0) {
 +    int n = compute_num_cpus();
 +    return (n >= 1) ? n : 1;
 +  } else {
 +    return options->NumCPUs;
 +  }
 +}
 +
  /**
   * Initialize the libevent library.
   */
  static void
 -init_libevent(void)
 +init_libevent(const or_options_t *options)
  {
    const char *badness=NULL;
 +  tor_libevent_cfg cfg;
 +
 +  tor_assert(options);
  
    configure_libevent_logging();
    /* If the kernel complains that some method (say, epoll) doesn't
@@@ -5065,11 -4913,7 +5070,11 @@@
  
    tor_check_libevent_header_compatibility();
  
 -  tor_libevent_initialize();
 +  memset(&cfg, 0, sizeof(cfg));
 +  cfg.disable_iocp = options->DisableIOCP;
 +  cfg.num_cpus = get_num_cpus(options);
 +
 +  tor_libevent_initialize(&cfg);
  
    suppress_libevent_log_msg(NULL);
  
@@@ -5410,7 -5254,6 +5415,7 @@@ getinfo_helper_config(control_connectio
          case CONFIG_TYPE_FILENAME: type = "Filename"; break;
          case CONFIG_TYPE_UINT: type = "Integer"; break;
          case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break;
 +        case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break;
          case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
          case CONFIG_TYPE_DOUBLE: type = "Float"; break;
          case CONFIG_TYPE_BOOL: type = "Boolean"; break;
diff --combined src/or/or.h
index 90f01e1,2a55668..1617d94
--- a/src/or/or.h
+++ b/src/or/or.h
@@@ -83,13 -83,6 +83,13 @@@
  #define snprintf _snprintf
  #endif
  
 +#ifdef USE_BUFFEREVENTS
 +#include <event2/bufferevent.h>
 +#include <event2/buffer.h>
 +#include <event2/util.h>
 +#endif
 +
 +#include "crypto.h"
  #include "tortls.h"
  #include "../common/torlog.h"
  #include "container.h"
@@@ -391,9 -384,7 +391,9 @@@ typedef enum 
  /** A connection to a hidden service directory server: download a v2 rendezvous
   * descriptor. */
  #define DIR_PURPOSE_FETCH_RENDDESC_V2 18
 -#define _DIR_PURPOSE_MAX 18
 +/** A connection to a directory server: download a microdescriptor. */
 +#define DIR_PURPOSE_FETCH_MICRODESC 19
 +#define _DIR_PURPOSE_MAX 19
  
  /** True iff <b>p</b> is a purpose corresponding to uploading data to a
   * directory server. */
@@@ -814,9 -805,6 +814,9 @@@ typedef enum 
   * Tor 0.1.2.x is obsolete, we can remove this. */
  #define DEFAULT_CLIENT_NICKNAME "client"
  
 +/** Name chosen by routers that don't configure nicknames */
 +#define UNNAMED_ROUTER_NICKNAME "Unnamed"
 +
  /** Number of bytes in a SOCKS4 header. */
  #define SOCKS4_NETWORK_LEN 8
  
@@@ -862,8 -850,8 +862,8 @@@ typedef struct cell_t 
  typedef struct var_cell_t {
    uint8_t command;
    circid_t circ_id;
 -  uint16_t payload_len;
 -  uint8_t payload[1];
 +  uint16_t payload_len; /**< The actual length of <b>payload</b>. */
 +  uint8_t payload[FLEXIBLE_ARRAY_MEMBER];
  } var_cell_t;
  
  /** A cell as packed for writing to the network. */
@@@ -980,7 -968,6 +980,7 @@@ typedef struct connection_t 
    /** Our socket; -1 if this connection is closed, or has no socket. */
    evutil_socket_t s;
    int conn_array_index; /**< Index into the global connection array. */
 +
    struct event *read_event; /**< Libevent event structure. */
    struct event *write_event; /**< Libevent event structure. */
    buf_t *inbuf; /**< Buffer holding data read over this connection. */
@@@ -991,11 -978,6 +991,11 @@@
                                * read? */
    time_t timestamp_lastwritten; /**< When was the last time libevent said we
                                   * could write? */
 +
 +#ifdef USE_BUFFEREVENTS
 +  struct bufferevent *bufev; /**< A Libevent buffered IO structure. */
 +#endif
 +
    time_t timestamp_created; /**< When was this connection_t created? */
  
    /* XXXX_IP6 make this IPv6-capable */
@@@ -1095,16 -1077,10 +1095,16 @@@ typedef struct or_connection_t 
    /* bandwidth* and *_bucket only used by ORs in OPEN state: */
    int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */
    int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */
 +#ifndef USE_BUFFEREVENTS
    int read_bucket; /**< When this hits 0, stop receiving. Every second we
                      * add 'bandwidthrate' to this, capping it at
                      * bandwidthburst. (OPEN ORs only) */
    int write_bucket; /**< When this hits 0, stop writing. Like read_bucket. */
 +#else
 +  /** DOCDOC */
 +  /* XXXX we could share this among all connections. */
 +  struct ev_token_bucket_cfg *bucket_cfg;
 +#endif
    int n_circuits; /**< How many circuits use this connection as p_conn or
                     * n_conn ? */
  
@@@ -1212,13 -1188,8 +1212,13 @@@ typedef struct edge_connection_t 
  typedef struct dir_connection_t {
    connection_t _base;
  
 -  char *requested_resource; /**< Which 'resource' did we ask the directory
 -                             * for? */
 + /** Which 'resource' did we ask the directory for? This is typically the part
 +  * of the URL string that defines, relative to the directory conn purpose,
 +  * what thing we want.  For example, in router descriptor downloads by
 +  * descriptor digest, it contains "d/", then one ore more +-separated
 +  * fingerprints.
 +  **/
 +  char *requested_resource;
    unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */
  
    /* Used only for server sides of some dir connections, to implement
@@@ -1309,51 -1280,6 +1309,51 @@@ static INLINE control_connection_t *TO_
    return DOWNCAST(control_connection_t, c);
  }
  
 +/* Conditional macros to help write code that works whether bufferevents are
 +   disabled or not.
 +
 +   We can't just write:
 +      if (conn->bufev) {
 +        do bufferevent stuff;
 +      } else {
 +        do other stuff;
 +      }
 +   because the bufferevent stuff won't even compile unless we have a fairly
 +   new version of Libevent.  Instead, we say:
 +      IF_HAS_BUFFEREVENT(conn, { do_bufferevent_stuff } );
 +   or:
 +      IF_HAS_BUFFEREVENT(conn, {
 +        do bufferevent stuff;
 +      }) ELSE_IF_NO_BUFFEREVENT {
 +        do non-bufferevent stuff;
 +      }
 +   If we're compiling with bufferevent support, then the macros expand more or
 +   less to:
 +      if (conn->bufev) {
 +        do_bufferevent_stuff;
 +      } else {
 +        do non-bufferevent stuff;
 +      }
 +   and if we aren't using bufferevents, they expand more or less to:
 +      { do non-bufferevent stuff; }
 +*/
 +#ifdef USE_BUFFEREVENTS
 +#define HAS_BUFFEREVENT(c) (((c)->bufev) != NULL)
 +#define IF_HAS_BUFFEREVENT(c, stmt)                \
 +  if ((c)->bufev) do {                             \
 +      stmt ;                                       \
 +  } while (0)
 +#define ELSE_IF_NO_BUFFEREVENT ; else
 +#define IF_HAS_NO_BUFFEREVENT(c)                   \
 +  if (NULL == (c)->bufev)
 +#else
 +#define HAS_BUFFEREVENT(c) (0)
 +#define IF_HAS_BUFFEREVENT(c, stmt) (void)0
 +#define ELSE_IF_NO_BUFFEREVENT ;
 +#define IF_HAS_NO_BUFFEREVENT(c)                \
 +  if (1)
 +#endif
 +
  /** What action type does an address policy indicate: accept or reject? */
  typedef enum {
    ADDR_POLICY_ACCEPT=1,
@@@ -1517,49 -1443,59 +1517,49 @@@ typedef struct 
    char *contact_info; /**< Declared contact info for this router. */
    unsigned int is_hibernating:1; /**< Whether the router claims to be
                                    * hibernating */
 -  unsigned int has_old_dnsworkers:1; /**< Whether the router is using
 -                                      * dnsworker code. */
 -  unsigned int caches_extra_info:1; /**< Whether the router caches and serves
 -                                     * extrainfo documents. */
 -  unsigned int allow_single_hop_exits:1;  /**< Whether the router allows
 -                                     * single hop exits. */
 -
 -  /* local info */
 -  unsigned int is_running:1; /**< As far as we know, is this OR currently
 -                              * running? */
 -  unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR?
 -                               *  (For Authdir: Have we validated this OR?)
 -                               */
 -  unsigned int is_named:1; /**< Do we believe the nickname that this OR gives
 -                            * us? */
 -  unsigned int is_fast:1; /** Do we think this is a fast OR? */
 -  unsigned int is_stable:1; /** Do we think this is a stable OR? */
 -  unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
 -  unsigned int is_exit:1; /**< Do we think this is an OK exit? */
 -  unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
 -                               * or otherwise nasty? */
 -  unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
 -                                    * underpowered, or otherwise useless? */
 +  unsigned int caches_extra_info:1; /**< Whether the router says it caches and
 +                                     * serves extrainfo documents. */
 +  unsigned int allow_single_hop_exits:1;  /**< Whether the router says
 +                                           * it allows single hop exits. */
 +
    unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be
                                        * a hidden service directory. */
 -  unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
 -                             * directory according to the authorities. */
    unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this
                                           * router rejects everything. */
    /** True if, after we have added this router, we should re-launch
     * tests for it. */
    unsigned int needs_retest_if_added:1;
  
 -/** Tor can use this router for general positions in circuits. */
 +/** Tor can use this router for general positions in circuits; we got it
 + * from a directory server as usual, or we're an authority and a server
 + * uploaded it. */
  #define ROUTER_PURPOSE_GENERAL 0
 -/** Tor should avoid using this router for circuit-building. */
 +/** Tor should avoid using this router for circuit-building: we got it
 + * from a crontroller.  If the controller wants to use it, it'll have to
 + * ask for it by identity. */
  #define ROUTER_PURPOSE_CONTROLLER 1
 -/** Tor should use this router only for bridge positions in circuits. */
 +/** Tor should use this router only for bridge positions in circuits: we got
 + * it via a directory request from the bridge itself, or a bridge
 + * authority. x*/
  #define ROUTER_PURPOSE_BRIDGE 2
  /** Tor should not use this router; it was marked in cached-descriptors with
   * a purpose we didn't recognize. */
  #define ROUTER_PURPOSE_UNKNOWN 255
  
 -  uint8_t purpose; /** What positions in a circuit is this router good for? */
 +  /* In what way did we find out about this router?  One of ROUTER_PURPOSE_*.
 +   * Routers of different purposes are kept segregated and used for different
 +   * things; see notes on ROUTER_PURPOSE_* macros above.
 +   */
 +  uint8_t purpose;
  
    /* The below items are used only by authdirservers for
     * reachability testing. */
 +
    /** When was the last time we could reach this OR? */
    time_t last_reachable;
    /** When did we start testing reachability for this OR? */
    time_t testing_since;
 -  /** According to the geoip db what country is this router in? */
 -  country_t country;
 +
  } routerinfo_t;
  
  /** Information needed to keep and cache a signed extra-info document. */
@@@ -1585,9 -1521,8 +1585,9 @@@ typedef struct routerstatus_t 
                                        * has. */
    char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity
                                       * key. */
 -  char descriptor_digest[DIGEST_LEN]; /**< Digest of the router's most recent
 -                                       * descriptor. */
 +  /** Digest of the router's most recent descriptor or microdescriptor.
 +   * If it's a descriptor, we only use the first DIGEST_LEN bytes. */
 +  char descriptor_digest[DIGEST256_LEN];
    uint32_t addr; /**< IPv4 address for this router. */
    uint16_t or_port; /**< OR port for this router. */
    uint16_t dir_port; /**< Directory port for this router. */
@@@ -1595,11 -1530,7 +1595,11 @@@
    unsigned int is_exit:1; /**< True iff this router is a good exit. */
    unsigned int is_stable:1; /**< True iff this router stays up a long time. */
    unsigned int is_fast:1; /**< True iff this router has good bandwidth. */
 -  unsigned int is_running:1; /**< True iff this router is up. */
 +  /** True iff this router is called 'running' in the consensus. We give it
 +   * this funny name so that we don't accidentally use this bit as a view of
 +   * whether we think the router is *currently* running.  If that's what you
 +   * want to know, look at is_running in node_t. */
 +  unsigned int is_flagged_running:1;
    unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */
    unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another
                                * router. */
@@@ -1651,31 -1582,15 +1651,31 @@@
     * from this authority.)  Applies in v2 networkstatus document only.
     */
    unsigned int need_to_mirror:1;
 -  unsigned int name_lookup_warned:1; /**< Have we warned the user for referring
 -                                      * to this (unnamed) router by nickname?
 -                                      */
    time_t last_dir_503_at; /**< When did this router last tell us that it
                             * was too busy to serve directory info? */
    download_status_t dl_status;
  
  } routerstatus_t;
  
 +/** A single entry in a parsed policy summary, describing a range of ports. */
 +typedef struct short_policy_entry_t {
 +  uint16_t min_port, max_port;
 +} short_policy_entry_t;
 +
 +/** A short_poliy_t is the parsed version of a policy summary. */
 +typedef struct short_policy_t {
 +  /** True if the members of 'entries' are port ranges to accept; false if
 +   * they are port ranges to reject */
 +  unsigned int is_accept : 1;
 +  /** The actual number of values in 'entries'. */
 +  unsigned int n_entries : 31;
 +  /** An array of 0 or more short_policy_entry_t values, each describing a
 +   * range of ports that this policy accepts or rejects (depending on the
 +   * value of is_accept).
 +   */
 +  short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER];
 +} short_policy_t;
 +
  /** A microdescriptor is the smallest amount of information needed to build a
   * circuit through a router.  They are generated by the directory authorities,
   * using information from the uploaded routerinfo documents.  They are not
@@@ -1717,83 -1632,15 +1717,83 @@@ typedef struct microdesc_t 
    crypto_pk_env_t *onion_pkey;
    /** As routerinfo_t.family */
    smartlist_t *family;
 -  /** Encoded exit policy summary */
 -  char *exitsummary; /**< exit policy summary -
 -                      * XXX this probably should not stay a string. */
 +  /** Exit policy summary */
 +  short_policy_t *exit_policy;
  } microdesc_t;
  
 +/** A node_t represents a Tor router.
 + *
 + * Specifically, a node_t is a Tor router as we are using it: a router that
 + * we are considering for circuits, connections, and so on.  A node_t is a
 + * thin wrapper around the routerstatus, routerinfo, and microdesc for a
 + * single wrapper, and provides a consistent interface for all of them.
 + *
 + * Also, a node_t has mutable state.  While a routerinfo, a routerstatus,
 + * and a microdesc have[*] only the information read from a router
 + * descriptor, a consensus entry, and a microdescriptor (respectively)...
 + * a node_t has flags based on *our own current opinion* of the node.
 + *
 + * [*] Actually, there is some leftover information in each that is mutable.
 + *  We should try to excise that.
 + */
 +typedef struct node_t {
 +  /* Indexing information */
 +
 +  /** Used to look up the node_t by its identity digest. */
 +  HT_ENTRY(node_t) ht_ent;
 +  /** Position of the node within the list of nodes */
 +  int nodelist_idx;
 +
 +  /** The identity digest of this node_t.  No more than one node_t per
 +   * identity may exist at a time. */
 +  char identity[DIGEST_LEN];
 +
 +  microdesc_t *md;
 +  routerinfo_t *ri;
 +  routerstatus_t *rs;
 +
 +  /* local info: copied from routerstatus, then possibly frobbed based
 +   * on experience.  Authorities set this stuff directly. */
 +
 +  unsigned int is_running:1; /**< As far as we know, is this OR currently
 +                              * running? */
 +  unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR?
 +                               *  (For Authdir: Have we validated this OR?)
 +                               */
 +  unsigned int is_fast:1; /** Do we think this is a fast OR? */
 +  unsigned int is_stable:1; /** Do we think this is a stable OR? */
 +  unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
 +  unsigned int is_exit:1; /**< Do we think this is an OK exit? */
 +  unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
 +                               * or otherwise nasty? */
 +  unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
 +                                    * underpowered, or otherwise useless? */
 +  unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
 +                             * directory according to the authorities. */
 +
 +  /* Local info: warning state. */
 +
 +  unsigned int name_lookup_warned:1; /**< Have we warned the user for referring
 +                                      * to this (unnamed) router by nickname?
 +                                      */
 +
 +  /** Local info: we treat this node as if it rejects everything */
 +  unsigned int rejects_all:1;
 +
 +  /* Local info: derived. */
 +
 +  /** According to the geoip db what country is this router in? */
 +  country_t country;
 +} node_t;
 +
  /** How many times will we try to download a router's descriptor before giving
   * up? */
  #define MAX_ROUTERDESC_DOWNLOAD_FAILURES 8
  
 +/** How many times will we try to download a microdescriptor before giving
 + * up? */
 +#define MAX_MICRODESC_DOWNLOAD_FAILURES 8
 +
  /** Contents of a v2 (non-consensus, non-vote) network status object. */
  typedef struct networkstatus_v2_t {
    /** When did we receive the network-status document? */
@@@ -2269,12 -2116,10 +2269,12 @@@ typedef struct circuit_t 
      * length ONIONSKIN_CHALLENGE_LEN. */
    char *n_conn_onionskin;
  
 -  time_t timestamp_created; /**< When was this circuit created? */
 +  /** When was this circuit created?  We keep this timestamp with a higher
 +   * resolution than most so that the circuit-build-time tracking code can
 +   * get millisecond resolution. */
 +  struct timeval timestamp_created;
    time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
                             * circuit is clean. */
 -  struct timeval highres_created; /**< When exactly was the circuit created? */
  
    uint16_t marked_for_close; /**< Should we close this circuit at the end of
                                * the main loop? (If true, holds the line number
@@@ -2499,8 -2344,10 +2499,11 @@@ typedef struct 
  
    config_line_t *Logs; /**< New-style list of configuration lines
                          * for logs */
 +  int LogTimeGranularity; /**< Log resolution in milliseconds. */
  
+   int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which
+                           * each log message occurs? */
+ 
    char *DebugLogFile; /**< Where to send verbose log messages. */
    char *DataDirectory; /**< OR only: where to store long-term data. */
    char *Nickname; /**< OR only: nickname of this onion router. */
@@@ -2719,9 -2566,6 +2722,9 @@@
                                 * authorizations for hidden services */
    char *ContactInfo; /**< Contact info to be published in the directory. */
  
 +  int HeartbeatPeriod; /**< Log heartbeat messages after this many seconds
 +                        * have passed. */
 +
    char *HTTPProxy; /**< hostname[:port] to use as http proxy, if any. */
    tor_addr_t HTTPProxyAddr; /**< Parsed IPv4 addr for http proxy, if any. */
    uint16_t HTTPProxyPort; /**< Parsed port for http proxy, if any. */
@@@ -2759,8 -2603,7 +2762,8 @@@
  
    char *MyFamily; /**< Declared family for this OR. */
    config_line_t *NodeFamilies; /**< List of config lines for
 -                                       * node families */
 +                                * node families */
 +  smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */
    config_line_t *AuthDirBadDir; /**< Address policy for descriptors to
                                   * mark as bad dir mirrors. */
    config_line_t *AuthDirBadExit; /**< Address policy for descriptors to
@@@ -2865,10 -2708,6 +2868,10 @@@
                         * possible. */
    int PreferTunneledDirConns; /**< If true, avoid dirservers that don't
                                 * support BEGIN_DIR, when possible. */
 +  int PortForwarding; /**< If true, use NAT-PMP or UPnP to automatically
 +                       * forward the DirPort and ORPort on the NAT device */
 +  char *PortForwardingHelper; /** < Filename or full path of the port
 +                                  forwarding helper executable */
    int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames
                                  * with weird characters. */
    /** If true, we try resolving hostnames with weird characters. */
@@@ -2906,9 -2745,6 +2909,9 @@@
    /** If true, the user wants us to collect statistics on port usage. */
    int ExitPortStatistics;
  
 +  /** If true, the user wants us to collect connection statistics. */
 +  int ConnDirectionStatistics;
 +
    /** If true, the user wants us to collect cell statistics. */
    int CellStatistics;
  
@@@ -3005,12 -2841,6 +3008,12 @@@
     */
    double CircuitPriorityHalflife;
  
 +  /** If true, do not enable IOCP on windows with bufferevents, even if
 +   * we think we could. */
 +  int DisableIOCP;
 +  /** For testing only: will go away in 0.2.3.x. */
 +  int _UseFilteringSSLBufferevents;
 +
  } or_options_t;
  
  /** Persistent state for an onion router, as saved to disk. */
@@@ -3119,6 -2949,8 +3122,6 @@@ struct socks_request_t 
                                * every connection. */
  };
  
 -/* all the function prototypes go here */
 -
  /********************************* circuitbuild.c **********************/
  
  /** How many hops does a general-purpose circuit have by default? */
@@@ -3510,7 -3342,7 +3513,7 @@@ typedef enum 
    ADDR_POLICY_PROBABLY_ACCEPTED=1,
    /** Part of the address was unknown, but as far as we can tell, it was
     * rejected. */
 -  ADDR_POLICY_PROBABLY_REJECTED=2
 +  ADDR_POLICY_PROBABLY_REJECTED=2,
  } addr_policy_result_t;
  
  /********************************* rephist.c ***************************/
@@@ -3641,8 -3473,6 +3644,8 @@@ typedef struct trusted_dir_server_t 
   *  fetches to _any_ single directory server.]
   */
  #define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
 +#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4)
 +
  #define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16)
  
  /** Possible ways to weight routers when choosing one randomly.  See
@@@ -3660,8 -3490,7 +3663,8 @@@ typedef enum 
    CRN_NEED_GUARD = 1<<2,
    CRN_ALLOW_INVALID = 1<<3,
    /* XXXX not used, apparently. */
 -  CRN_WEIGHT_AS_EXIT = 1<<5
 +  CRN_WEIGHT_AS_EXIT = 1<<5,
 +  CRN_NEED_DESC = 1<<6
  } router_crn_flags_t;
  
  /** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */



More information about the tor-commits mailing list