diff options
70 files changed, 2024 insertions, 1066 deletions
diff --git a/autogen.sh b/autogen.sh index 0592f16c2e..efa2251c24 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,7 +1,17 @@ #!/bin/sh if [ -x "`which autoreconf 2>/dev/null`" ] ; then - exec autoreconf -ivf + opt="-if" + + for i in $@; do + case "$i" in + -v) + opt=$opt"v" + ;; + esac + done + + exec autoreconf $opt fi set -e diff --git a/changes/4664 b/changes/4664 new file mode 100644 index 0000000000..eb81da925e --- /dev/null +++ b/changes/4664 @@ -0,0 +1,4 @@ + o Minor features (build): + - Do not report status verbosely from autogen.sh unless the -v flag + is specified. Fixes issue 4664. Patch from Onizuka. + diff --git a/changes/bug5823 b/changes/bug5823 new file mode 100644 index 0000000000..d76b590889 --- /dev/null +++ b/changes/bug5823 @@ -0,0 +1,5 @@ + o Removed featurs: + - Stop exporting estimates of v2 and v3 directory traffic shares + in extrainfo documents. They were unneeded and sometimes inaccurate. + Also stop exporting any v2 directory request statistics. Resolves + ticket 5823. diff --git a/changes/bug7708 b/changes/bug7708 new file mode 100644 index 0000000000..e272adf227 --- /dev/null +++ b/changes/bug7708 @@ -0,0 +1,5 @@ + o Major bugfixes: + - When a TLS write is partially successful but incomplete, remember + that the flushed part has been flushed, and notice that bytes were + actually written. Reported and fixed pseudonymously. Fixes bug + 7708; bugfix on Tor 0.1.0.5-rc. diff --git a/changes/bug7802 b/changes/bug7802 new file mode 100644 index 0000000000..9bc0f36fe1 --- /dev/null +++ b/changes/bug7802 @@ -0,0 +1,11 @@ + o Minor features: + - Path Use Bias: Perform separate accounting for successful circuit use. + Separate statistics on stream attempt versus success rates are kept + for each guard. Configurable thresholds are provided to determine + when to emit log messages or disable use of guards that fail too + many stream attempts. + o Minor bugfixes: + - Remove a source of rounding error during path bias count scaling. + - Don't count cannibalized circuits as used for path bias until we + actually try to use them. + - Fix circuit_package_relay_cell warning message about n_chan==NULL. diff --git a/changes/bug8093 b/changes/bug8093 new file mode 100644 index 0000000000..cbddfd990f --- /dev/null +++ b/changes/bug8093 @@ -0,0 +1,4 @@ + o Minor features: + - Improve the log message when "Bug/attack: unexpected sendme cell + from client" occurs, to help us track bug 8093. + diff --git a/changes/double-0-check b/changes/double-0-check new file mode 100644 index 0000000000..74554cd272 --- /dev/null +++ b/changes/double-0-check @@ -0,0 +1,8 @@ + o Build improvements (bizarre platform detection): + - Try to detect it if we are ever building on a platform where + memset(...,0,...) does not set the value of a double to 0.0. Such + platforms are permitted by the C standard, though in practice + they're pretty rare (since IEEE 754 is nigh-ubiquitous). We don't + currently support them, but it's better to detect them and fail + than to perform erroneously. + diff --git a/changes/feature5956 b/changes/feature5956 new file mode 100644 index 0000000000..2e18810588 --- /dev/null +++ b/changes/feature5956 @@ -0,0 +1,8 @@ + o Major features: + - When deciding whether we have enough descriptors to build circuits, + instead of looking at raw circuit counts, look at which fraction of + (bandwidth-weighted) paths we're able to build. This approach keeps + clients from building circuits if their paths are likely to stand out + statistically. The default fraction of paths needed is taken from the + consensus directory; you can override it with the new + PathsNeededToBuildCircuits option. Fixes issue 5956. diff --git a/changes/rename_log_7599 b/changes/rename_log_7599 new file mode 100644 index 0000000000..38e843f066 --- /dev/null +++ b/changes/rename_log_7599 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Rename Tor's logging function log() to tor_log(), to avoid conflicts + with the natural logarithm function from the system libm. Resolves + ticket 7599. diff --git a/changes/rename_queue_macros b/changes/rename_queue_macros new file mode 100644 index 0000000000..29373ac234 --- /dev/null +++ b/changes/rename_queue_macros @@ -0,0 +1,6 @@ + o Major bugfixes: + - Rename all macros in our local copy of queue.h to begin with TOR_; + this seems the only good way to permanently prevent conflicts + with queue.h on various operating systems. Fixes bug 8107; bugfix on + 0.2.4.6-alpha. + diff --git a/changes/timed_onionqueue b/changes/timed_onionqueue new file mode 100644 index 0000000000..fe54d78ac8 --- /dev/null +++ b/changes/timed_onionqueue @@ -0,0 +1,11 @@ + o Minor features (relay): + - Instead of limiting the number of queued onionskins to a configured, + hard-to-configure number, we limit the size of the queue based on how + many we expect to be able to process in a given amount of time. We + estimate the time it will take to process an onionskin based on average + processing time of previous onionskins. Closes ticket 7291. You'll + never have to configure MaxOnionsPending again. + + - We compute the overhead from passing onionskins back and forth to + cpuworkers, and report it when dumping statistics in response to + SIGUSR1. diff --git a/configure.ac b/configure.ac index f047ab9027..6c4a0792fe 100644 --- a/configure.ac +++ b/configure.ac @@ -1033,6 +1033,30 @@ if test "$tor_cv_null_is_zero" != no; then [Define to 1 iff memset(0) sets pointers to NULL]) fi +AC_CACHE_CHECK([whether memset(0) sets doubles to 0.0], tor_cv_dbl0_is_zero, +[AC_RUN_IFELSE([AC_LANG_SOURCE( +[[#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif +int main () { double d1,d2; d1=0; memset(&d2,0,sizeof(d2)); +return memcmp(&d1,&d2,sizeof(d1))?1:0; }]])], + [tor_cv_dbl0_is_zero=yes], + [tor_cv_dbl0_is_zero=no], + [tor_cv_dbl0_is_zero=cross])]) + +if test "$tor_cv_dbl0_is_zero" = cross ; then + # Cross-compiling; let's hope that the target isn't raving mad. + AC_MSG_NOTICE([Cross-compiling: we'll assume that 0.0 can be represented as a sequence of 0-valued bytes.]) +fi + +if test "$tor_cv_dbl0_is_zero" != no; then + AC_DEFINE([DOUBLE_0_REP_IS_ZERO_BYTES], 1, + [Define to 1 iff memset(0) sets doubles to 0.0]) +fi + # And what happens when we malloc zero? AC_CACHE_CHECK([whether we can malloc(0) safely.], tor_cv_malloc_zero_works, [AC_RUN_IFELSE([AC_LANG_SOURCE( diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 947322161a..a15aecb488 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1250,20 +1250,11 @@ The following options are useful only for clients (that is, if **PathBiasDropGuards** __NUM__ + -**PathBiasScaleThreshold** __NUM__ + - -**PathBiasMultFactor** __NUM__ + - -**PathBiasScaleFactor** __NUM__ + - -**PathBiasUseCloseCounts** __NUM__:: +**PathBiasScaleThreshold** __NUM__:: These options override the default behavior of Tor's (**currently experimental**) path bias detection algorithm. To try to find broken or misbehaving guard nodes, Tor looks for nodes where more than a certain - fraction of circuits through that guard fail to get built. If - PathBiasUseCloseCounts is set to 1 (the default), usage-based accounting is - performed, and circuits that fail to carry streams are also counted as - failures. + + fraction of circuits through that guard fail to get built. + The PathBiasCircThreshold option controls how many circuits we need to build through a guard before we make these checks. The PathBiasNoticeRate, @@ -1273,14 +1264,35 @@ The following options are useful only for clients (that is, if is set to 1, we disable use of that guard. + + When we have seen more than PathBiasScaleThreshold - circuits through a guard, we scale our observations by - PathBiasMultFactor/PathBiasScaleFactor, so that new observations don't get - swamped by old ones. + + circuits through a guard, we scale our observations by 0.5 (governed by + the consensus) so that new observations don't get swamped by old ones. + + By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document. If no defaults are available there, these options default to 150, .70, - .50, .30, 0, 300, 1, and 2 respectively. + .50, .30, 0, and 300 respectively. + +**PathBiasUseThreshold** __NUM__ + + +**PathBiasNoticeUseRate** __NUM__ + + +**PathBiasExtremeUseRate** __NUM__ + + +**PathBiasScaleUseThreshold** __NUM__:: + Similar to the above options, these options override the default behavior + of Tor's (**currently experimental**) path use bias detection algorithm. + + + Where as the path bias parameters govern thresholds for successfully + building circuits, these four path use bias parameters govern thresholds + only for circuit usage. Circuits which receive no stream usage + are not counted by this detection algorithm. A used circuit is considered + successful if it is capable of carrying streams or otherwise receiving + well-formed responses to RELAY cells. + + + By default, or if a negative value is provided for one of these options, + Tor uses reasonable defaults from the networkstatus consensus document. + If no defaults are available there, these options default to 20, .90, + .70, and 100, respectively. **ClientUseIPv6** **0**|**1**:: If this option is set to 1, Tor might connect to entry nodes over @@ -1294,6 +1306,18 @@ The following options are useful only for clients (that is, if things may influence the choice. This option breaks a tie to the favor of IPv6. (Default: 0) +**PathsNeededToBuildCircuits** __NUM__:: + Tor clients don't build circuits for user traffic until they know + about enough of the network so that they could potentially construct + enough of the possible paths through the network. If this option + is set to a fraction between 0.25 and 0.95, Tor won't build circuits + until it has enough descriptors or microdescriptors to construct + that fraction of possible paths. Note that setting this option too low + can make your Tor client less anonymous, and setting it too high can + prevent your Tor client from bootstrapping. If this option is negative, + Tor will use a default value chosen by the directory + authorities. (Default: -1.) + SERVER OPTIONS -------------- @@ -1388,9 +1412,9 @@ is non-zero): If set, and we are an exit node, allow clients to use us for IPv6 traffic. (Default: 0) -**MaxOnionsPending** __NUM__:: - If you have more than this number of onionskins queued for decrypt, reject - new ones. (Default: 100) +**MaxOnionQueueDelay** __NUM__ [**msec**|**second**]:: + If we have more onionskins queued for processing than we can process in + this amount of time, reject new ones. (Default: 1750 msec) **MyFamily** __node__,__node__,__...__:: Declare that this Tor server is controlled or administered by a group or diff --git a/src/common/address.c b/src/common/address.c index 3529b10c1a..6fc9fb3c47 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1270,14 +1270,14 @@ get_interface_addresses_raw(int severity) /* This interface, AFAICT, only supports AF_INET addresses */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { - log(severity, LD_NET, "socket failed: %s", strerror(errno)); + tor_log(severity, LD_NET, "socket failed: %s", strerror(errno)); goto done; } /* Guess how much space we need. */ ifc.ifc_len = sz = 15*1024; ifc.ifc_ifcu.ifcu_req = tor_malloc(sz); if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { - log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); + tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); close(fd); goto done; } diff --git a/src/common/compat.h b/src/common/compat.h index 25293a4ed6..d2944e6f48 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -74,6 +74,10 @@ #error "It seems your platform does not represent NULL as zero. We can't cope." #endif +#ifndef DOUBLE_0_REP_IS_ZERO_BYTES +#error "It seems your platform does not represent 0.0 as zeros. We can't cope." +#endif + #if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 #error "It seems that you encode characters in something other than ASCII." #endif diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c index fc5b0accfe..200a7c65fb 100644 --- a/src/common/compat_libevent.c +++ b/src/common/compat_libevent.c @@ -76,19 +76,19 @@ libevent_logging_callback(int severity, const char *msg) } switch (severity) { case _EVENT_LOG_DEBUG: - log(LOG_DEBUG, LD_NOCB|LD_NET, "Message from libevent: %s", buf); + log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf); break; case _EVENT_LOG_MSG: - log(LOG_INFO, LD_NOCB|LD_NET, "Message from libevent: %s", buf); + log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf); break; case _EVENT_LOG_WARN: - log(LOG_WARN, LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf); + log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf); break; case _EVENT_LOG_ERR: - log(LOG_ERR, LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf); + log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf); break; default: - log(LOG_WARN, LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s", + log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s", severity, buf); break; } @@ -187,13 +187,6 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg) /* some paths below don't use torcfg, so avoid unused variable warnings */ (void)torcfg; -#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 { int attempts = 0; @@ -268,13 +261,13 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg) #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_INFO, LD_GENERAL, + log_info(LD_GENERAL, "Initialized libevent version %s using method %s. Good.", event_get_version(), tor_libevent_get_method()); #else - log(LOG_NOTICE, LD_GENERAL, + log_notice(LD_GENERAL, "Initialized old libevent (version 1.0b or earlier)."); - log(LOG_WARN, LD_GENERAL, + 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 @@ -411,35 +404,9 @@ void tor_check_libevent_version(const char *m, int server, const char **badness_out) { - int thread_unsafe = 0; - const char *v = NULL; - const char *badness = NULL; - const char *sad_os = ""; (void) m; (void) server; - - /* 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"; - } - - *badness_out = badness; + *badness_out = NULL; } #if defined(LIBEVENT_VERSION) @@ -473,7 +440,7 @@ tor_check_libevent_header_compatibility(void) verybad = compat1 != compat2; - log(verybad ? LOG_WARN : LOG_NOTICE, + tor_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()); diff --git a/src/common/crypto.c b/src/common/crypto.c index 7c73f79cff..70bd45299f 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -151,10 +151,11 @@ crypto_log_errors(int severity, const char *doing) if (!lib) lib = "(null)"; if (!func) func = "(null)"; if (doing) { - log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + doing, msg, lib, func); } else { - log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func); + tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", + msg, lib, func); } } } @@ -168,10 +169,10 @@ log_engine(const char *fn, ENGINE *e) const char *name, *id; name = ENGINE_get_name(e); id = ENGINE_get_id(e); - log(LOG_NOTICE, LD_CRYPTO, "Using OpenSSL engine %s [%s] for %s", + log_notice(LD_CRYPTO, "Using OpenSSL engine %s [%s] for %s", name?name:"?", id?id:"?", fn); } else { - log(LOG_INFO, LD_CRYPTO, "Using default implementation for %s", fn); + log_info(LD_CRYPTO, "Using default implementation for %s", fn); } } #endif diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c index 88705427a8..62398f62e6 100644 --- a/src/common/crypto_curve25519.c +++ b/src/common/crypto_curve25519.c @@ -69,7 +69,7 @@ curve25519_secret_key_generate(curve25519_secret_key_t *key_out, return -1; if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) { /* If they asked for extra-strong entropy and we have some, use it as an - * HMAC key to improve not-so-good entopy rather than using it directly, + * HMAC key to improve not-so-good entropy rather than using it directly, * just in case the extra-strong entropy is less amazing than we hoped. */ crypto_hmac_sha256((char *)key_out->secret_key, (const char *)k_tmp, sizeof(k_tmp), diff --git a/src/common/procmon.c b/src/common/procmon.c index efb39e5bb7..0a49689e3a 100644 --- a/src/common/procmon.c +++ b/src/common/procmon.c @@ -321,7 +321,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2, its_dead_jim = its_dead_jim && (errno == ESRCH); #endif - log(its_dead_jim ? LOG_NOTICE : LOG_INFO, + tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO, procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.", procmon->pid, its_dead_jim ? "dead" : "still alive"); diff --git a/src/common/torlog.h b/src/common/torlog.h index 97271fa81e..23ee597a4e 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -153,7 +153,6 @@ void set_log_time_granularity(int granularity_msec); void tor_log(int severity, log_domain_mask_t domain, const char *format, ...) CHECK_PRINTF(3,4); -#define log tor_log /* hack it so we don't conflict with log() as much */ #if defined(__GNUC__) || defined(RUNNING_DOXYGEN) extern int log_global_min_severity_; diff --git a/src/common/tortls.c b/src/common/tortls.c index 6151d3fde4..94cedba24b 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -334,11 +334,11 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, if (!lib) lib = "(null)"; if (!func) func = "(null)"; if (doing) { - log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)", + tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)", doing, addr?" with ":"", addr?addr:"", msg, lib, func, state); } else { - log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)", + tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)", addr?" with ":"", addr?addr:"", msg, lib, func, state); } @@ -427,12 +427,12 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra, if (extra&CATCH_SYSCALL) return TOR_TLS_SYSCALL_; if (r == 0) { - log(severity, LD_NET, "TLS error: unexpected close while %s (%s)", + tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)", doing, SSL_state_string_long(tls->ssl)); tor_error = TOR_TLS_ERROR_IO; } else { int e = tor_socket_errno(tls->socket); - log(severity, LD_NET, + tor_log(severity, LD_NET, "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)", doing, e, tor_socket_strerror(e), SSL_state_string_long(tls->ssl)); @@ -443,7 +443,7 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra, case SSL_ERROR_ZERO_RETURN: if (extra&CATCH_ZERO) return TOR_TLS_ZERORETURN_; - log(severity, LD_NET, "TLS connection closed while %s in state %s", + tor_log(severity, LD_NET, "TLS connection closed while %s in state %s", doing, SSL_state_string_long(tls->ssl)); tls_log_errors(tls, severity, domain, doing); return TOR_TLS_CLOSE; @@ -1224,7 +1224,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2, key_lifetime); if (!cert || !idcert || !authcert) { - log(LOG_WARN, LD_CRYPTO, "Error creating certificate"); + log_warn(LD_CRYPTO, "Error creating certificate"); goto error; } } @@ -2272,7 +2272,7 @@ tor_tls_shutdown(tor_tls_t *tls) */ if (tls->state == TOR_TLS_ST_GOTCLOSE || tls->state == TOR_TLS_ST_SENTCLOSE) { - log(LOG_WARN, LD_NET, + log_warn(LD_NET, "TLS returned \"half-closed\" value while already half-closed"); return TOR_TLS_ERROR_MISC; } @@ -2322,7 +2322,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) struct tm tm; if (problem) - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Certificate %s. Either their clock is set wrong, or your clock " "is wrong.", problem); @@ -2347,7 +2347,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "(certificate lifetime runs from %s through %s. Your time is %s.)", s1,s2,mytime); @@ -2568,7 +2568,7 @@ check_no_tls_errors_(const char *fname, int line) { if (ERR_peek_error() == 0) return; - log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ", + log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ", tor_fix_source_file(fname), line); tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); } diff --git a/src/common/util.c b/src/common/util.c index 49ec75dc4a..7d72a896f9 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -20,7 +20,6 @@ #define UTIL_PRIVATE #include "util.h" #include "torlog.h" -#undef log #include "crypto.h" #include "torint.h" #include "container.h" @@ -323,8 +322,8 @@ tor_log_mallinfo(int severity) * ===== */ /** - * Returns the natural logarithm of d base 2. We define this wrapper here so - * as to make it easier not to conflict with Tor's log() macro. + * Returns the natural logarithm of d base e. We defined this wrapper here so + * to avoid conflicts with old versions of tor_log(), which were named log(). */ double tor_mathlog(double d) diff --git a/src/ext/README b/src/ext/README index cd23f29496..58ba7f699d 100644 --- a/src/ext/README +++ b/src/ext/README @@ -34,7 +34,9 @@ tor_queue.h A copy of sys/queue.h from OpenBSD. We keep our own copy rather than using sys/queue.h, since some platforms don't have a sys/queue.h, and the ones that do have diverged in incompatible - ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) + ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename + the identifiers with a TOR_ prefix to avoid conflicts with + the system headers. curve25519_donna/*.c diff --git a/src/ext/eventdns.c b/src/ext/eventdns.c index b1f586b2fb..5316338dc2 100644 --- a/src/ext/eventdns.c +++ b/src/ext/eventdns.c @@ -534,7 +534,7 @@ nameserver_probe_failed(struct nameserver *const ns) { ns->failed_times++; if (add_timeout_event(ns, (struct timeval *) timeout) < 0) { - log(EVDNS_LOG_WARN, + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", debug_ntop((struct sockaddr *)&ns->address)); /* ???? Do more? */ @@ -550,19 +550,19 @@ nameserver_failed(struct nameserver *const ns, const char *msg) { /* then don't do anything */ if (!ns->state) return; - log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s", + tor_log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s", debug_ntop((struct sockaddr *)&ns->address), msg); global_good_nameservers--; assert(global_good_nameservers >= 0); if (global_good_nameservers == 0) { - log(EVDNS_LOG_WARN, "All nameservers have failed"); + tor_log(EVDNS_LOG_WARN, "All nameservers have failed"); } ns->state = 0; ns->failed_times = 1; if (add_timeout_event(ns, (struct timeval *) &global_nameserver_timeouts[0]) < 0) { - log(EVDNS_LOG_WARN, + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", debug_ntop((struct sockaddr *)&ns->address)); /* ???? Do more? */ @@ -593,7 +593,7 @@ nameserver_failed(struct nameserver *const ns, const char *msg) { static void nameserver_up(struct nameserver *const ns) { if (ns->state) return; - log(EVDNS_LOG_WARN, "Nameserver %s is back up", + tor_log(EVDNS_LOG_WARN, "Nameserver %s is back up", debug_ntop((struct sockaddr *)&ns->address)); del_timeout_event(ns); ns->state = 1; @@ -624,7 +624,7 @@ request_finished(struct evdns_request *const req, struct evdns_request **head) { } } - log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx", + tor_log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx", (unsigned long) req); del_timeout_event(req); @@ -776,7 +776,7 @@ reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply * * confusing." Treat this as a timeout, not a failure. */ /*XXXX refactor the parts of */ - log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; " + tor_log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; " "will allow the request to time out.", debug_ntop((struct sockaddr *)&req->ns->address)); break; @@ -1268,7 +1268,7 @@ nameserver_read(struct nameserver *ns) { } /* XXX Match port too? */ if (!sockaddr_eq(sa, (struct sockaddr*)&ns->address, 0)) { - log(EVDNS_LOG_WARN, + tor_log(EVDNS_LOG_WARN, "Address mismatch on received DNS packet. Address was %s", debug_ntop(sa)); return; @@ -1294,7 +1294,7 @@ server_port_read(struct evdns_server_port *s) { if (r < 0) { int err = last_error(s->socket); if (error_is_eagain(err)) return; - log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.", + tor_log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.", tor_socket_strerror(err), err); return; } @@ -1314,7 +1314,7 @@ server_port_flush(struct evdns_server_port *port) int err = last_error(port->socket); if (error_is_eagain(err)) return; - log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err); + tor_log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err); } if (server_request_free(req)) { /* we released the last reference to req->port. */ @@ -1331,7 +1331,7 @@ server_port_flush(struct evdns_server_port *port) event_set(&port->event, port->socket, EV_READ | EV_PERSIST, server_port_ready_callback, port); if (event_add(&port->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); /* ???? Do more? */ } } @@ -1349,7 +1349,7 @@ nameserver_write_waiting(struct nameserver *ns, char waiting) { event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST, nameserver_ready_callback, ns); if (event_add(&ns->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", debug_ntop((struct sockaddr *)&ns->address)); /* ???? Do more? */ } @@ -1859,7 +1859,7 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err) event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port); if (event_add(&port->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); } } @@ -1995,7 +1995,7 @@ evdns_request_timeout_callback(int fd, short events, void *arg) { (void) fd; (void) events; - log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg); + tor_log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg); req->ns->timedout++; if (req->ns->timedout > global_max_nameserver_timeout) { @@ -2074,11 +2074,11 @@ evdns_request_transmit(struct evdns_request *req) { * and make us retransmit the request anyway. */ default: /* transmitted; we need to check for timeout. */ - log(EVDNS_LOG_DEBUG, + tor_log(EVDNS_LOG_DEBUG, "Setting timeout for request %lx", (unsigned long) req); if (add_timeout_event(req, &global_timeout) < 0) { - log(EVDNS_LOG_WARN, + tor_log(EVDNS_LOG_WARN, "Error from libevent when adding timer for request %lx", (unsigned long) req); /* ???? Do more? */ @@ -2126,7 +2126,7 @@ nameserver_send_probe(struct nameserver *const ns) { addr = mm_malloc(sizeof(struct sockaddr_storage)); memcpy(addr, &ns->address, sizeof(struct sockaddr_storage)); - log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address)); + tor_log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address)); req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, addr); if (!req) { @@ -2282,14 +2282,14 @@ _evdns_nameserver_add_impl(const struct sockaddr *address, if (server) { do { if (sockaddr_eq(address, (struct sockaddr *)&server->address, 1)) { - log(EVDNS_LOG_DEBUG, "Duplicate nameserver."); + tor_log(EVDNS_LOG_DEBUG, "Duplicate nameserver."); return 3; } server = server->next; } while (server != started_at); } if (addrlen > (int)sizeof(ns->address)) { - log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen); + tor_log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen); return 2; } @@ -2315,14 +2315,14 @@ _evdns_nameserver_add_impl(const struct sockaddr *address, !sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) { if (bind(ns->socket, (struct sockaddr *)&global_bind_address, global_bind_addrlen) < 0) { - log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address."); + tor_log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address."); err = 2; goto out2; } } if (connect(ns->socket, address, addrlen) != 0) { - log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver."); + tor_log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver."); err = 2; goto out2; } @@ -2331,12 +2331,12 @@ _evdns_nameserver_add_impl(const struct sockaddr *address, ns->state = 1; event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns); if (event_add(&ns->event, NULL) < 0) { - log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver."); + tor_log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver."); err = 2; goto out2; } - log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address)); + tor_log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address)); /* insert this nameserver into the list of them */ if (!server_head) { @@ -2360,7 +2360,7 @@ out2: out1: CLEAR(ns); mm_free(ns); - log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err); + tor_log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err); return err; } @@ -2393,18 +2393,18 @@ evdns_nameserver_ip_add(const char *ip_as_string) { * ipv4 */ - log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string); + tor_log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string); cp = strchr(ip_as_string, ':'); if (*ip_as_string == '[') { size_t len; if (!(cp = strchr(ip_as_string, ']'))) { - log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]"); + tor_log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]"); return 4; } len = cp-(ip_as_string + 1); if (len > sizeof(buf)-1) { - log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer."); + tor_log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer."); return 4; } memcpy(buf, ip_as_string+1, len); @@ -2422,7 +2422,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) { } else if (cp) { is_ipv6 = 0; if (cp - ip_as_string > (int)sizeof(buf)-1) { - log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer."); + tor_log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer."); return 4; } memcpy(buf, ip_as_string, cp-ip_as_string); @@ -2440,7 +2440,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) { } else { port = strtoint(port_part); if (port <= 0 || port > 65535) { - log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range", + tor_log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range", port_part); return 4; } @@ -2457,7 +2457,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) { sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); if (1 != tor_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr)) { - log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part); + tor_log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part); return 4; } return _evdns_nameserver_add_impl((struct sockaddr*)&sin6, @@ -2471,7 +2471,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) { sin.sin_family = AF_INET; sin.sin_port = htons(port); if (!inet_aton(addr_part, &sin.sin_addr)) { - log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part); + tor_log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part); return 4; } return _evdns_nameserver_add_impl((struct sockaddr*)&sin, @@ -2594,7 +2594,7 @@ request_submit(struct evdns_request *const req) { /* exported function */ int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr) { - log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); + tor_log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); if (flags & DNS_QUERY_NO_SEARCH) { struct evdns_request *const req = request_new(TYPE_A, name, flags, callback, ptr); @@ -2610,7 +2610,7 @@ int evdns_resolve_ipv4(const char *name, int flags, /* exported function */ int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr) { - log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); + tor_log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); if (flags & DNS_QUERY_NO_SEARCH) { struct evdns_request *const req = request_new(TYPE_AAAA, name, flags, callback, ptr); @@ -2634,7 +2634,7 @@ int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_ty (int)(u8)((a>>8 )&0xff), (int)(u8)((a>>16)&0xff), (int)(u8)((a>>24)&0xff)); - log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); + tor_log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); req = request_new(TYPE_PTR, buf, flags, callback, ptr); if (!req) return 1; request_submit(req); @@ -2658,7 +2658,7 @@ int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callb } assert(cp + strlen("ip6.arpa") < buf+sizeof(buf)); memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1); - log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); + tor_log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); req = request_new(TYPE_PTR, buf, flags, callback, ptr); if (!req) return 1; request_submit(req); @@ -2874,7 +2874,7 @@ search_try_next(struct evdns_request *const req) { if (string_num_dots(req->search_origname) < req->search_state->ndots) { /* yep, we need to try it raw */ struct evdns_request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer); - log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname); + tor_log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname); if (newreq) { request_submit(newreq); return 0; @@ -2885,7 +2885,7 @@ search_try_next(struct evdns_request *const req) { new_name = search_make_new(req->search_state, req->search_index, req->search_origname); if (!new_name) return 1; - log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index); + tor_log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index); newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer); mm_free(new_name); if (!newreq) return 1; @@ -2955,7 +2955,7 @@ evdns_set_option(const char *option, const char *val, int flags) const int ndots = strtoint(val); if (ndots == -1) return -1; if (!(flags & DNS_OPTION_SEARCH)) return 0; - log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); + tor_log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); if (!global_search_state) global_search_state = search_state_new(); if (!global_search_state) return -1; global_search_state->ndots = ndots; @@ -2963,20 +2963,20 @@ evdns_set_option(const char *option, const char *val, int flags) const int timeout = strtoint(val); if (timeout == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout); + tor_log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout); global_timeout.tv_sec = timeout; } else if (!strncmp(option, "max-timeouts:", 12)) { const int maxtimeout = strtoint_clipped(val, 1, 255); if (maxtimeout == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", + tor_log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", maxtimeout); global_max_nameserver_timeout = maxtimeout; } else if (!strncmp(option, "max-inflight:", 13)) { const int maxinflight = strtoint_clipped(val, 1, 65000); if (maxinflight == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", + tor_log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", maxinflight); global_max_requests_inflight = maxinflight; } else if (!strncmp(option, "attempts:", 9)) { @@ -2984,12 +2984,12 @@ evdns_set_option(const char *option, const char *val, int flags) if (retries == -1) return -1; if (retries > 255) retries = 255; if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); + tor_log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); global_max_retransmits = retries; } else if (!strncmp(option, "randomize-case:", 15)) { int randcase = strtoint(val); if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase); + tor_log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase); global_randomize_case = randcase; } return 0; @@ -3047,7 +3047,7 @@ evdns_resolv_conf_parse(int flags, const char *const filename) { char *start; int err = 0; - log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); + tor_log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); fd = tor_open_cloexec(filename, O_RDONLY, 0); if (fd < 0) { @@ -3146,13 +3146,13 @@ load_nameservers_with_getnetworkparams(void) GetNetworkParams_fn_t fn; if (!(handle = load_windows_system_library(TEXT("iphlpapi.dll")))) { - log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); + tor_log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); /* right now status = 0, doesn't that mean "good" - mikec */ status = -1; goto done; } if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, TEXT("GetNetworkParams")))) { - log(EVDNS_LOG_WARN, "Could not get address of function."); + tor_log(EVDNS_LOG_WARN, "Could not get address of function."); /* same as above */ status = -1; goto done; @@ -3173,7 +3173,7 @@ load_nameservers_with_getnetworkparams(void) fixed = buf; r = fn(fixed, &size); if (r != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG, "fn() failed."); + tor_log(EVDNS_LOG_DEBUG, "fn() failed."); status = -1; goto done; } @@ -3185,12 +3185,12 @@ load_nameservers_with_getnetworkparams(void) while (ns) { r = evdns_nameserver_ip_add_line(ns->IpAddress.String); if (r) { - log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, " + tor_log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, " "error: %d; status: %d", (ns->IpAddress.String),(int)GetLastError(), r); status = r; } else { - log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String); + tor_log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String); added_any++; } @@ -3198,7 +3198,7 @@ load_nameservers_with_getnetworkparams(void) } if (!added_any) { - log(EVDNS_LOG_DEBUG, "No nameservers added."); + tor_log(EVDNS_LOG_DEBUG, "No nameservers added."); if (status == 0) status = -1; } else { @@ -3254,10 +3254,10 @@ load_nameservers_from_registry(void) #define TRY(k, name) \ if (!found && config_nameserver_from_reg_key(k,TEXT(name)) == 0) { \ - log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ + tor_log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ found = 1; \ } else if (!found) { \ - log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ + tor_log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ #k,#name); \ } @@ -3266,14 +3266,14 @@ load_nameservers_from_registry(void) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &nt_key) != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); + tor_log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); return -1; } r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &interfaces_key); if (r != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); + tor_log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); return -1; } TRY(nt_key, "NameServer"); @@ -3286,7 +3286,7 @@ load_nameservers_from_registry(void) HKEY win_key = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0, KEY_READ, &win_key) != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); + tor_log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); return -1; } TRY(win_key, "NameServer"); @@ -3294,7 +3294,7 @@ load_nameservers_from_registry(void) } if (found == 0) { - log(EVDNS_LOG_WARN,"Didn't find any nameservers."); + tor_log(EVDNS_LOG_WARN,"Didn't find any nameservers."); } return found ? 0 : -1; diff --git a/src/ext/tor_queue.h b/src/ext/tor_queue.h index 595e4a3423..f05e48c18e 100644 --- a/src/ext/tor_queue.h +++ b/src/ext/tor_queue.h @@ -32,8 +32,8 @@ * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ +#ifndef TOR_QUEUE_H_ +#define TOR_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, @@ -83,78 +83,73 @@ */ #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) -#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#define TOR_Q_INVALIDATE_(a) (a) = ((void *)-1) #else -#define _Q_INVALIDATE(a) +#define TOR_Q_INVALIDATE_(a) #endif /* * Singly-linked List definitions. */ -#define SLIST_HEAD(name, type) \ +#define TOR_SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } -#define SLIST_HEAD_INITIALIZER(head) \ +#define TOR_SLIST_HEAD_INITIALIZER(head) \ { NULL } -/* XXXX This macro name conflicts with a typedef in winnt.h, so Tor - * has to redefine it. */ #define TOR_SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } -#ifndef _WIN32 -#define SLIST_ENTRY(type) TOR_SLIST_ENTRY(type) -#endif /* * Singly-linked List access methods. */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST(head); \ - (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ +#define TOR_SLIST_FIRST(head) ((head)->slh_first) +#define TOR_SLIST_END(head) NULL +#define TOR_SLIST_EMPTY(head) (SLIST_FIRST(head) == TOR_SLIST_END(head)) +#define TOR_SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define TOR_SLIST_FOREACH(var, head, field) \ + for((var) = TOR_SLIST_FIRST(head); \ + (var) != TOR_SLIST_END(head); \ + (var) = TOR_SLIST_NEXT(var, field)) + +#define TOR_SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TOR_SLIST_FIRST(head); \ + (var) && ((tvar) = TOR_SLIST_NEXT(var, field), 1); \ (var) = (tvar)) /* * Singly-linked List functions. */ -#define SLIST_INIT(head) { \ - SLIST_FIRST(head) = SLIST_END(head); \ +#define TOR_SLIST_INIT(head) { \ + TOR_SLIST_FIRST(head) = TOR_SLIST_END(head); \ } -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ +#define TOR_SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) -#define SLIST_INSERT_HEAD(head, elm, field) do { \ +#define TOR_SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) -#define SLIST_REMOVE_AFTER(elm, field) do { \ +#define TOR_SLIST_REMOVE_AFTER(elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) -#define SLIST_REMOVE_HEAD(head, field) do { \ +#define TOR_SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) -#define SLIST_REMOVE(head, elm, type, field) do { \ +#define TOR_SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ + TOR_SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ @@ -162,22 +157,22 @@ struct { \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ - _Q_INVALIDATE((elm)->field.sle_next); \ + TOR_Q_INVALIDATE_((elm)->field.sle_next); \ } \ } while (0) /* * List definitions. */ -#define LIST_HEAD(name, type) \ +#define TOR_LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } -#define LIST_HEAD_INITIALIZER(head) \ +#define TOR_LIST_HEAD_INITIALIZER(head) \ { NULL } -#define LIST_ENTRY(type) \ +#define TOR_LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ @@ -186,29 +181,29 @@ struct { \ /* * List access methods */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for((var) = LIST_FIRST(head); \ - (var)!= LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST(head); \ - (var) && ((tvar) = LIST_NEXT(var, field), 1); \ +#define TOR_LIST_FIRST(head) ((head)->lh_first) +#define TOR_LIST_END(head) NULL +#define TOR_LIST_EMPTY(head) (TOR_LIST_FIRST(head) == TOR_LIST_END(head)) +#define TOR_LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define TOR_LIST_FOREACH(var, head, field) \ + for((var) = TOR_LIST_FIRST(head); \ + (var)!= TOR_LIST_END(head); \ + (var) = TOR_LIST_NEXT(var, field)) + +#define TOR_LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TOR_LIST_FIRST(head); \ + (var) && ((tvar) = TOR_LIST_NEXT(var, field), 1); \ (var) = (tvar)) /* * List functions. */ -#define LIST_INIT(head) do { \ - LIST_FIRST(head) = LIST_END(head); \ +#define TOR_LIST_INIT(head) do { \ + TOR_LIST_FIRST(head) = TOR_LIST_END(head); \ } while (0) -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ +#define TOR_LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ @@ -216,52 +211,52 @@ struct { \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ +#define TOR_LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) -#define LIST_INSERT_HEAD(head, elm, field) do { \ +#define TOR_LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) -#define LIST_REMOVE(elm, field) do { \ +#define TOR_LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ + TOR_Q_INVALIDATE_((elm)->field.le_prev); \ + TOR_Q_INVALIDATE_((elm)->field.le_next); \ } while (0) -#define LIST_REPLACE(elm, elm2, field) do { \ +#define TOR_LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ + TOR_Q_INVALIDATE_((elm)->field.le_prev); \ + TOR_Q_INVALIDATE_((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ -#define SIMPLEQ_HEAD(name, type) \ +#define TOR_SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } -#define SIMPLEQ_HEAD_INITIALIZER(head) \ +#define TOR_SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } -#define SIMPLEQ_ENTRY(type) \ +#define TOR_SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } @@ -269,53 +264,53 @@ struct { \ /* * Simple queue access methods. */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SIMPLEQ_FIRST(head); \ - (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ +#define TOR_SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define TOR_SIMPLEQ_END(head) NULL +#define TOR_SIMPLEQ_EMPTY(head) (TOR_SIMPLEQ_FIRST(head) == TOR_SIMPLEQ_END(head)) +#define TOR_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define TOR_SIMPLEQ_FOREACH(var, head, field) \ + for((var) = TOR_SIMPLEQ_FIRST(head); \ + (var) != TOR_SIMPLEQ_END(head); \ + (var) = TOR_SIMPLEQ_NEXT(var, field)) + +#define TOR_SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TOR_SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = TOR_SIMPLEQ_NEXT(var, field), 1); \ (var) = (tvar)) /* * Simple queue functions. */ -#define SIMPLEQ_INIT(head) do { \ +#define TOR_SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ +#define TOR_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ +#define TOR_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ +#define TOR_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ +#define TOR_SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) -#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ +#define TOR_SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ @@ -324,16 +319,16 @@ struct { \ /* * Tail queue definitions. */ -#define TAILQ_HEAD(name, type) \ +#define TOR_TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } -#define TAILQ_HEAD_INITIALIZER(head) \ +#define TOR_TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } -#define TAILQ_ENTRY(type) \ +#define TOR_TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ @@ -342,49 +337,49 @@ struct { \ /* * tail queue access methods */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ +#define TOR_TAILQ_FIRST(head) ((head)->tqh_first) +#define TOR_TAILQ_END(head) NULL +#define TOR_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TOR_TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ -#define TAILQ_PREV(elm, headname, field) \ +#define TOR_TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head) && \ - ((tvar) = TAILQ_NEXT(var, field), 1); \ +#define TOR_TAILQ_EMPTY(head) \ + (TOR_TAILQ_FIRST(head) == TOR_TAILQ_END(head)) + +#define TOR_TAILQ_FOREACH(var, head, field) \ + for((var) = TOR_TAILQ_FIRST(head); \ + (var) != TOR_TAILQ_END(head); \ + (var) = TOR_TAILQ_NEXT(var, field)) + +#define TOR_TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TOR_TAILQ_FIRST(head); \ + (var) != TOR_TAILQ_END(head) && \ + ((tvar) = TOR_TAILQ_NEXT(var, field), 1); \ (var) = (tvar)) -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) +#define TOR_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TOR_TAILQ_LAST(head, headname); \ + (var) != TOR_TAILQ_END(head); \ + (var) = TOR_TAILQ_PREV(var, headname, field)) -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head) && \ - ((tvar) = TAILQ_PREV(var, headname, field), 1); \ +#define TOR_TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TOR_TAILQ_LAST(head, headname); \ + (var) != TOR_TAILQ_END(head) && \ + ((tvar) = TOR_TAILQ_PREV(var, headname, field), 1); \ (var) = (tvar)) /* * Tail queue functions. */ -#define TAILQ_INIT(head) do { \ +#define TOR_TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ +#define TOR_TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ @@ -394,14 +389,14 @@ struct { \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ +#define TOR_TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ +#define TOR_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ @@ -411,25 +406,25 @@ struct { \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ +#define TOR_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) -#define TAILQ_REMOVE(head, elm, field) do { \ +#define TOR_TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ + TOR_Q_INVALIDATE_((elm)->field.tqe_prev); \ + TOR_Q_INVALIDATE_((elm)->field.tqe_next); \ } while (0) -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ +#define TOR_TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ @@ -437,23 +432,23 @@ struct { \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ + TOR_Q_INVALIDATE_((elm)->field.tqe_prev); \ + TOR_Q_INVALIDATE_((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ -#define CIRCLEQ_HEAD(name, type) \ +#define TOR_CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } +#define TOR_CIRCLEQ_HEAD_INITIALIZER(head) \ + { TOR_CIRCLEQ_END(&head), TOR_CIRCLEQ_END(&head) } -#define CIRCLEQ_ENTRY(type) \ +#define TOR_CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ @@ -462,112 +457,112 @@ struct { \ /* * Circular queue access methods */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head) && \ - ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ +#define TOR_CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define TOR_CIRCLEQ_LAST(head) ((head)->cqh_last) +#define TOR_CIRCLEQ_END(head) ((void *)(head)) +#define TOR_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define TOR_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define TOR_CIRCLEQ_EMPTY(head) \ + (TOR_CIRCLEQ_FIRST(head) == TOR_CIRCLEQ_END(head)) + +#define TOR_CIRCLEQ_FOREACH(var, head, field) \ + for((var) = TOR_CIRCLEQ_FIRST(head); \ + (var) != TOR_CIRCLEQ_END(head); \ + (var) = TOR_CIRCLEQ_NEXT(var, field)) + +#define TOR_CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TOR_CIRCLEQ_FIRST(head); \ + (var) != TOR_CIRCLEQ_END(head) && \ + ((tvar) = TOR_CIRCLEQ_NEXT(var, field), 1); \ (var) = (tvar)) -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) +#define TOR_CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = TOR_CIRCLEQ_LAST(head); \ + (var) != TOR_CIRCLEQ_END(head); \ + (var) = TOR_CIRCLEQ_PREV(var, field)) -#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = CIRCLEQ_LAST(head, headname); \ - (var) != CIRCLEQ_END(head) && \ - ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ +#define TOR_CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TOR_CIRCLEQ_LAST(head, headname); \ + (var) != TOR_CIRCLEQ_END(head) && \ + ((tvar) = TOR_CIRCLEQ_PREV(var, headname, field), 1); \ (var) = (tvar)) /* * Circular queue functions. */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ +#define TOR_CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = TOR_CIRCLEQ_END(head); \ + (head)->cqh_last = TOR_CIRCLEQ_END(head); \ } while (0) -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ +#define TOR_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + if ((listelm)->field.cqe_next == TOR_CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ +#define TOR_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + if ((listelm)->field.cqe_prev == TOR_CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ +#define TOR_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (elm)->field.cqe_prev = TOR_CIRCLEQ_END(head); \ + if ((head)->cqh_last == TOR_CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ +#define TOR_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = TOR_CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ + if ((head)->cqh_first == TOR_CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ +#define TOR_CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == TOR_CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + if ((elm)->field.cqe_prev == TOR_CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ + TOR_Q_INVALIDATE_((elm)->field.cqe_prev); \ + TOR_Q_INVALIDATE_((elm)->field.cqe_next); \ } while (0) -#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ +#define TOR_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ - CIRCLEQ_END(head)) \ + TOR_CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ - CIRCLEQ_END(head)) \ + TOR_CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ + TOR_Q_INVALIDATE_((elm)->field.cqe_prev); \ + TOR_Q_INVALIDATE_((elm)->field.cqe_next); \ } while (0) #endif /* !_SYS_QUEUE_H_ */ diff --git a/src/or/buffers.c b/src/or/buffers.c index 7868a45488..e5fac9172d 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -335,11 +335,11 @@ buf_dump_freelist_sizes(int severity) { #ifdef ENABLE_BUF_FREELISTS int i; - log(severity, LD_MM, "====== Buffer freelists:"); + tor_log(severity, LD_MM, "====== Buffer freelists:"); for (i = 0; freelists[i].alloc_size; ++i) { uint64_t total = ((uint64_t)freelists[i].cur_length) * freelists[i].alloc_size; - log(severity, LD_MM, + tor_log(severity, LD_MM, U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]", U64_PRINTF_ARG(total), @@ -348,7 +348,7 @@ buf_dump_freelist_sizes(int severity) U64_PRINTF_ARG(freelists[i].n_free), U64_PRINTF_ARG(freelists[i].n_hit)); } - log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes", + tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes", U64_PRINTF_ARG(n_freelist_miss)); #else (void)severity; diff --git a/src/or/channel.c b/src/or/channel.c index 7781622977..104b018cf4 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -33,7 +33,7 @@ typedef struct cell_queue_entry_s cell_queue_entry_t; struct cell_queue_entry_s { - SIMPLEQ_ENTRY(cell_queue_entry_s) next; + TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next; enum { CELL_QUEUE_FIXED, CELL_QUEUE_VAR, @@ -89,7 +89,7 @@ HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map = typedef struct channel_idmap_entry_s { HT_ENTRY(channel_idmap_entry_s) node; uint8_t digest[DIGEST_LEN]; - LIST_HEAD(channel_list_s, channel_s) channel_list; + TOR_LIST_HEAD(channel_list_s, channel_s) channel_list; } channel_idmap_entry_t; static INLINE unsigned @@ -554,10 +554,10 @@ channel_add_to_digest_map(channel_t *chan) if (! ent) { ent = tor_malloc(sizeof(channel_idmap_entry_t)); memcpy(ent->digest, chan->identity_digest, DIGEST_LEN); - LIST_INIT(&ent->channel_list); + TOR_LIST_INIT(&ent->channel_list); HT_INSERT(channel_idmap, &channel_identity_map, ent); } - LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); + TOR_LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); log_debug(LD_CHANNEL, "Added channel %p (global ID " U64_FORMAT ") " @@ -612,7 +612,7 @@ channel_remove_from_digest_map(channel_t *chan) #endif /* Pull it out of its list, wherever that list is */ - LIST_REMOVE(chan, next_with_same_id); + TOR_LIST_REMOVE(chan, next_with_same_id); memcpy(search.digest, chan->identity_digest, DIGEST_LEN); ent = HT_FIND(channel_idmap, &channel_identity_map, &search); @@ -621,7 +621,7 @@ channel_remove_from_digest_map(channel_t *chan) if (ent) { /* Okay, it's here */ - if (LIST_EMPTY(&ent->channel_list)) { + if (TOR_LIST_EMPTY(&ent->channel_list)) { HT_REMOVE(channel_idmap, &channel_identity_map, ent); tor_free(ent); } @@ -691,7 +691,7 @@ channel_find_by_remote_digest(const char *identity_digest) memcpy(search.digest, identity_digest, DIGEST_LEN); ent = HT_FIND(channel_idmap, &channel_identity_map, &search); if (ent) { - rv = LIST_FIRST(&ent->channel_list); + rv = TOR_LIST_FIRST(&ent->channel_list); } return rv; @@ -709,7 +709,7 @@ channel_next_with_digest(channel_t *chan) { tor_assert(chan); - return LIST_NEXT(chan, next_with_same_id); + return TOR_LIST_NEXT(chan, next_with_same_id); } /** @@ -735,8 +735,8 @@ channel_init(channel_t *chan) chan->next_circ_id = crypto_rand_int(1 << 15); /* Initialize queues. */ - SIMPLEQ_INIT(&chan->incoming_queue); - SIMPLEQ_INIT(&chan->outgoing_queue); + TOR_SIMPLEQ_INIT(&chan->incoming_queue); + TOR_SIMPLEQ_INIT(&chan->outgoing_queue); /* Initialize list entries. */ memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id)); @@ -879,16 +879,16 @@ channel_force_free(channel_t *chan) } /* We might still have a cell queue; kill it */ - SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { + TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { cell_queue_entry_free(cell, 0); } - SIMPLEQ_INIT(&chan->incoming_queue); + TOR_SIMPLEQ_INIT(&chan->incoming_queue); /* Outgoing cell queue is similar, but we can have to free packed cells */ - SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { + TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { cell_queue_entry_free(cell, 0); } - SIMPLEQ_INIT(&chan->outgoing_queue); + TOR_SIMPLEQ_INIT(&chan->outgoing_queue); tor_free(chan); } @@ -1051,7 +1051,7 @@ channel_set_cell_handlers(channel_t *chan, chan->var_cell_handler = var_cell_handler; /* Re-run the queue if we have one and there's any reason to */ - if (! SIMPLEQ_EMPTY(&chan->incoming_queue) && + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue) && try_again && (chan->cell_handler || chan->var_cell_handler)) channel_process_cells(chan); @@ -1686,7 +1686,7 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) } /* Can we send it right out? If so, try */ - if (SIMPLEQ_EMPTY(&chan->outgoing_queue) && + if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) && chan->state == CHANNEL_STATE_OPEN) { /* Pick the right write function for this cell type and save the result */ switch (q->type) { @@ -1728,7 +1728,7 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) * used the stack. */ tmp = cell_queue_entry_dup(q); - SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next); + TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next); /* Try to process the queue? */ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan); } @@ -1914,15 +1914,15 @@ channel_change_state(channel_t *chan, channel_state_t to_state) channel_do_open_actions(chan); /* Check for queued cells to process */ - if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) channel_process_cells(chan); - if (! SIMPLEQ_EMPTY(&chan->outgoing_queue)) + if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) channel_flush_cells(chan); } else if (to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR) { /* Assert that all queues are empty */ - tor_assert(SIMPLEQ_EMPTY(&chan->incoming_queue)); - tor_assert(SIMPLEQ_EMPTY(&chan->outgoing_queue)); + tor_assert(TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)); + tor_assert(TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)); } } @@ -2096,7 +2096,7 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ if (chan->state == CHANNEL_STATE_OPEN) { while ((unlimited || num_cells > flushed) && - NULL != (q = SIMPLEQ_FIRST(&chan->outgoing_queue))) { + NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) { if (1) { /* @@ -2185,7 +2185,7 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, } /* if q got NULLed out, we used it and should remove the queue entry */ - if (!q) SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); + if (!q) TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); /* No cell removed from list, so we can't go on any further */ else break; } @@ -2193,7 +2193,7 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan, } /* Did we drain the queue? */ - if (SIMPLEQ_EMPTY(&chan->outgoing_queue)) { + if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { channel_timestamp_drained(chan); } @@ -2227,7 +2227,7 @@ channel_more_to_flush(channel_t *chan) tor_assert(chan); /* Check if we have any queued */ - if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return 1; /* Check if any circuits would like to queue some */ @@ -2435,13 +2435,13 @@ channel_process_cells(channel_t *chan) if (!(chan->cell_handler || chan->var_cell_handler)) return; /* Nothing we can do if we have no cells */ - if (SIMPLEQ_EMPTY(&chan->incoming_queue)) return; + if (TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return; /* * Process cells until we're done or find one we have no current handler * for. */ - while (NULL != (q = SIMPLEQ_FIRST(&chan->incoming_queue))) { + while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) { tor_assert(q); tor_assert(q->type == CELL_QUEUE_FIXED || q->type == CELL_QUEUE_VAR); @@ -2449,7 +2449,7 @@ channel_process_cells(channel_t *chan) if (q->type == CELL_QUEUE_FIXED && chan->cell_handler) { /* Handle a fixed-length cell */ - SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); + TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.fixed.cell); log_debug(LD_CHANNEL, "Processing incoming cell_t %p for channel %p (global ID " @@ -2461,7 +2461,7 @@ channel_process_cells(channel_t *chan) } else if (q->type == CELL_QUEUE_VAR && chan->var_cell_handler) { /* Handle a variable-length cell */ - SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); + TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.var.var_cell); log_debug(LD_CHANNEL, "Processing incoming var_cell_t %p for channel %p (global ID " @@ -2496,7 +2496,7 @@ channel_queue_cell(channel_t *chan, cell_t *cell) /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->cell_handler)) need_to_queue = 1; - if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; /* Timestamp for receiving */ @@ -2522,7 +2522,7 @@ channel_queue_cell(channel_t *chan, cell_t *cell) "(global ID " U64_FORMAT ")", cell, chan, U64_PRINTF_ARG(chan->global_identifier)); - SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); + TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); @@ -2549,7 +2549,7 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->var_cell_handler)) need_to_queue = 1; - if (! SIMPLEQ_EMPTY(&chan->incoming_queue)) + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; /* Timestamp for receiving */ @@ -2575,7 +2575,7 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) "(global ID " U64_FORMAT ")", var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); - SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); + TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); @@ -2636,10 +2636,10 @@ void channel_dumpstats(int severity) { if (all_channels && smartlist_len(all_channels) > 0) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Dumping statistics about %d channels:", smartlist_len(all_channels)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "%d are active, and %d are done and waiting for cleanup", (active_channels != NULL) ? smartlist_len(active_channels) : 0, @@ -2649,10 +2649,10 @@ channel_dumpstats(int severity) SMARTLIST_FOREACH(all_channels, channel_t *, chan, channel_dump_statistics(chan, severity)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Done spamming about channels now"); } else { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "No channels to dump"); } } @@ -2668,10 +2668,10 @@ void channel_listener_dumpstats(int severity) { if (all_listeners && smartlist_len(all_listeners) > 0) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Dumping statistics about %d channel listeners:", smartlist_len(all_listeners)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "%d are active and %d are done and waiting for cleanup", (active_listeners != NULL) ? smartlist_len(active_listeners) : 0, @@ -2681,10 +2681,10 @@ channel_listener_dumpstats(int severity) SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l, channel_listener_dump_statistics(chan_l, severity)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Done spamming about channel listeners now"); } else { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "No channel listeners to dump"); } } @@ -3115,7 +3115,7 @@ chan_cell_queue_len(const chan_cell_queue_t *queue) { int r = 0; cell_queue_entry_t *cell; - SIMPLEQ_FOREACH(cell, queue, next) + TOR_SIMPLEQ_FOREACH(cell, queue, next) ++r; return r; } @@ -3139,13 +3139,13 @@ channel_dump_statistics(channel_t *chan, int severity) age = (double)(now - chan->timestamp_created); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Channel " U64_FORMAT " (at %p) with transport %s is in state " "%s (%d)", U64_PRINTF_ARG(chan->global_identifier), chan, channel_describe_transport(chan), channel_state_to_string(chan->state), chan->state); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was created at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", @@ -3158,14 +3158,14 @@ channel_dump_statistics(channel_t *chan, int severity) /* Handle digest and nickname */ if (!tor_digest_is_zero(chan->identity_digest)) { if (chan->nickname) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says it is connected " "to an OR with digest %s and nickname %s", U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN), chan->nickname); } else { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says it is connected " "to an OR with digest %s and no known nickname", U64_PRINTF_ARG(chan->global_identifier), @@ -3173,13 +3173,13 @@ channel_dump_statistics(channel_t *chan, int severity) } } else { if (chan->nickname) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know the digest" " of the OR it is connected to, but reports its nickname is %s", U64_PRINTF_ARG(chan->global_identifier), chan->nickname); } else { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know the digest" " or the nickname of the OR it is connected to", U64_PRINTF_ARG(chan->global_identifier)); @@ -3191,7 +3191,7 @@ channel_dump_statistics(channel_t *chan, int severity) if (have_remote_addr) { char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); remote_addr_str = tor_dup_addr(&remote_addr); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says its remote address" " is %s, and gives a canonical description of \"%s\" and an " "actual description of \"%s\"", @@ -3203,7 +3203,7 @@ channel_dump_statistics(channel_t *chan, int severity) tor_free(actual); } else { char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know its remote " "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", @@ -3214,7 +3214,7 @@ channel_dump_statistics(channel_t *chan, int severity) } /* Handle marks */ - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has these marks: %s %s %s " "%s %s %s", U64_PRINTF_ARG(chan->global_identifier), @@ -3233,7 +3233,7 @@ channel_dump_statistics(channel_t *chan, int severity) "incoming" : "outgoing"); /* Describe queues */ - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has %d queued incoming cells" " and %d queued outgoing cells", U64_PRINTF_ARG(chan->global_identifier), @@ -3241,7 +3241,7 @@ channel_dump_statistics(channel_t *chan, int severity) chan_cell_queue_len(&chan->outgoing_queue)); /* Describe circuits */ - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has %d active circuits out of" " %d in total", U64_PRINTF_ARG(chan->global_identifier), @@ -3251,25 +3251,25 @@ channel_dump_statistics(channel_t *chan, int severity) circuitmux_num_circuits(chan->cmux) : 0); /* Describe timestamps */ - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was last used by a " "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_client), U64_PRINTF_ARG(now - chan->timestamp_client)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was last drained at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_drained), U64_PRINTF_ARG(now - chan->timestamp_drained)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " last received a cell " "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_recv), U64_PRINTF_ARG(now - chan->timestamp_recv)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " last trasmitted a cell " "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), @@ -3277,7 +3277,7 @@ channel_dump_statistics(channel_t *chan, int severity) U64_PRINTF_ARG(now - chan->timestamp_xmit)); /* Describe counters and rates */ - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has received " U64_FORMAT " cells and transmitted " U64_FORMAT, U64_PRINTF_ARG(chan->global_identifier), @@ -3288,13 +3288,13 @@ channel_dump_statistics(channel_t *chan, int severity) if (chan->n_cells_recved > 0) { avg = (double)(chan->n_cells_recved) / age; if (avg >= 1.0) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "cells received per second", U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "seconds between received cells", U64_PRINTF_ARG(chan->global_identifier), interval); @@ -3303,13 +3303,13 @@ channel_dump_statistics(channel_t *chan, int severity) if (chan->n_cells_xmitted > 0) { avg = (double)(chan->n_cells_xmitted) / age; if (avg >= 1.0) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "cells transmitted per second", U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "seconds between transmitted cells", U64_PRINTF_ARG(chan->global_identifier), interval); @@ -3337,13 +3337,13 @@ channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) age = (double)(now - chan_l->timestamp_created); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Channel listener " U64_FORMAT " (at %p) with transport %s is in " "state %s (%d)", U64_PRINTF_ARG(chan_l->global_identifier), chan_l, channel_listener_describe_transport(chan_l), channel_listener_state_to_string(chan_l->state), chan_l->state); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " was created at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", @@ -3353,7 +3353,7 @@ channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) U64_PRINTF_ARG(chan_l->timestamp_active), U64_PRINTF_ARG(now - chan_l->timestamp_active)); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " last accepted an incoming " "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and has accepted " U64_FORMAT " channels in total", @@ -3371,13 +3371,13 @@ channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) chan_l->n_accepted > 0) { avg = (double)(chan_l->n_accepted) / age; if (avg >= 1.0) { - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " has averaged %f incoming " "channels per second", U64_PRINTF_ARG(chan_l->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " has averaged %f seconds " "between incoming channels", U64_PRINTF_ARG(chan_l->global_identifier), interval); @@ -3504,7 +3504,7 @@ channel_has_queued_writes(channel_t *chan) tor_assert(chan); tor_assert(chan->has_queued_writes); - if (! SIMPLEQ_EMPTY(&chan->outgoing_queue)) { + if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { has_writes = 1; } else { /* Check with the lower layer */ diff --git a/src/or/channel.h b/src/or/channel.h index 31bd519474..ec79888063 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -19,7 +19,7 @@ typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); struct cell_queue_entry_s; -SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue; +TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue; typedef struct chan_cell_queue chan_cell_queue_t; /* @@ -125,7 +125,7 @@ struct channel_s { * Linked list of channels with the same identity digest, for the * digest->channel map */ - LIST_ENTRY(channel_s) next_with_same_id; + TOR_LIST_ENTRY(channel_s) next_with_same_id; /* List of incoming cells to handle */ chan_cell_queue_t incoming_queue; diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b986243867..5a5a3afea7 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -67,7 +67,10 @@ static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard); static void pathbias_count_build_success(origin_circuit_t *circ); static void pathbias_count_successful_close(origin_circuit_t *circ); static void pathbias_count_collapse(origin_circuit_t *circ); -static void pathbias_count_unusable(origin_circuit_t *circ); +static void pathbias_count_use_failed(origin_circuit_t *circ); +static void pathbias_measure_use_rate(entry_guard_t *guard); +static void pathbias_measure_close_rate(entry_guard_t *guard); +static void pathbias_scale_use_rates(entry_guard_t *guard); /** This function tries to get a channel to the specified endpoint, * and then calls command_setup_channel() to give it the right @@ -821,9 +824,6 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) /* We're done with measurement circuits here. Just close them */ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { - /* If a measurement circ ever gets back to us, consider it - * succeeded for path bias */ - circ->path_state = PATH_STATE_USE_SUCCEEDED; circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); } return 0; @@ -1176,53 +1176,93 @@ pathbias_get_scale_threshold(const or_options_t *options) } /** - * The scale factor is the denominator for our scaling - * of circuit counts for our path bias window. + * Compute the path bias scaling ratio from the consensus + * parameters pb_multfactor/pb_scalefactor. * - * Note that our use of doubles for the path bias state - * file means that powers of 2 work best here. + * Returns a value in (0, 1.0] which we multiply our pathbias + * counts with to scale them down. */ +static double +pathbias_get_scale_ratio(const or_options_t *options) +{ + /* + * The scale factor is the denominator for our scaling + * of circuit counts for our path bias window. + * + * Note that our use of doubles for the path bias state + * file means that powers of 2 work best here. + */ + int denominator = networkstatus_get_param(NULL, "pb_scalefactor", + 2, 2, INT32_MAX); + (void) options; + /** + * The mult factor is the numerator for our scaling + * of circuit counts for our path bias window. It + * allows us to scale by fractions. + */ + return networkstatus_get_param(NULL, "pb_multfactor", + 1, 1, denominator)/((double)denominator); +} + +/** The minimum number of circuit usage attempts before we start + * thinking about warning about path use bias and dropping guards */ static int -pathbias_get_scale_factor(const or_options_t *options) +pathbias_get_min_use(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_MIN_USE 20 + if (options->PathBiasUseThreshold >= 3) + return options->PathBiasUseThreshold; + else + return networkstatus_get_param(NULL, "pb_minuse", + DFLT_PATH_BIAS_MIN_USE, + 3, INT32_MAX); +} + +/** The circuit use success rate below which we issue a notice */ +static double +pathbias_get_notice_use_rate(const or_options_t *options) { -#define DFLT_PATH_BIAS_SCALE_FACTOR 2 - if (options->PathBiasScaleFactor >= 1) - return options->PathBiasScaleFactor; +#define DFLT_PATH_BIAS_NOTICE_USE_PCT 90 + if (options->PathBiasNoticeUseRate >= 0.0) + return options->PathBiasNoticeUseRate; else - return networkstatus_get_param(NULL, "pb_scalefactor", - DFLT_PATH_BIAS_SCALE_FACTOR, 1, INT32_MAX); + return networkstatus_get_param(NULL, "pb_noticeusepct", + DFLT_PATH_BIAS_NOTICE_USE_PCT, + 0, 100)/100.0; } /** - * The mult factor is the numerator for our scaling - * of circuit counts for our path bias window. It - * allows us to scale by fractions. + * The extreme use rate is the rate at which we would drop the guard, + * if pb_dropguard is also set. Otherwise we just warn. */ -static int -pathbias_get_mult_factor(const or_options_t *options) +double +pathbias_get_extreme_use_rate(const or_options_t *options) { -#define DFLT_PATH_BIAS_MULT_FACTOR 1 - if (options->PathBiasMultFactor >= 1) - return options->PathBiasMultFactor; +#define DFLT_PATH_BIAS_EXTREME_USE_PCT 70 + if (options->PathBiasExtremeUseRate >= 0.0) + return options->PathBiasExtremeUseRate; else - return networkstatus_get_param(NULL, "pb_multfactor", - DFLT_PATH_BIAS_MULT_FACTOR, 1, - pathbias_get_scale_factor(options)); + return networkstatus_get_param(NULL, "pb_extremeusepct", + DFLT_PATH_BIAS_EXTREME_USE_PCT, + 0, 100)/100.0; } /** - * If this parameter is set to a true value (default), we use the - * successful_circuits_closed. Otherwise, we use the success_count. + * This is the number of circuits at which we scale our + * use counts by mult_factor/scale_factor. Note, this count is + * not exact, as we only perform the scaling in the event + * of no integer truncation. */ static int -pathbias_use_close_counts(const or_options_t *options) +pathbias_get_scale_use_threshold(const or_options_t *options) { -#define DFLT_PATH_BIAS_USE_CLOSE_COUNTS 1 - if (options->PathBiasUseCloseCounts >= 0) - return options->PathBiasUseCloseCounts; +#define DFLT_PATH_BIAS_SCALE_USE_THRESHOLD 100 + if (options->PathBiasScaleUseThreshold >= 10) + return options->PathBiasScaleUseThreshold; else - return networkstatus_get_param(NULL, "pb_useclosecounts", - DFLT_PATH_BIAS_USE_CLOSE_COUNTS, 0, 1); + return networkstatus_get_param(NULL, "pb_scaleuse", + DFLT_PATH_BIAS_SCALE_USE_THRESHOLD, + 10, INT32_MAX); } /** @@ -1238,10 +1278,14 @@ pathbias_state_to_string(path_state_t state) return "build attempted"; case PATH_STATE_BUILD_SUCCEEDED: return "build succeeded"; + case PATH_STATE_USE_ATTEMPTED: + return "use attempted"; case PATH_STATE_USE_SUCCEEDED: return "use succeeded"; case PATH_STATE_USE_FAILED: return "use failed"; + case PATH_STATE_ALREADY_COUNTED: + return "already counted"; } return "unknown"; @@ -1303,6 +1347,24 @@ pathbias_should_count(origin_circuit_t *circ) circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED || (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) { + + /* Check to see if the shouldcount result has changed due to a + * unexpected purpose change that would affect our results. + * + * The reason we check the path state too here is because for the + * cannibalized versions of these purposes, we count them as successful + * before their purpose change. + */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED + && circ->path_state != PATH_STATE_ALREADY_COUNTED) { + log_info(LD_BUG, + "Circuit %d is now being ignored despite being counted " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; return 0; } @@ -1325,9 +1387,33 @@ pathbias_should_count(origin_circuit_t *circ) } tor_fragile_assert(); } + + /* Check to see if the shouldcount result has changed due to a + * unexpected change that would affect our results */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED) { + log_info(LD_BUG, + "One-hop circuit %d is now being ignored despite being counted " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; return 0; } + /* Check to see if the shouldcount result has changed due to a + * unexpected purpose change that would affect our results */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_IGNORED) { + log_info(LD_BUG, + "Circuit %d is now being counted despite being ignored " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_COUNTED; + return 1; } @@ -1338,7 +1424,7 @@ pathbias_should_count(origin_circuit_t *circ) * Also check for several potential error cases for bug #6475. */ static int -pathbias_count_circ_attempt(origin_circuit_t *circ) +pathbias_count_build_attempt(origin_circuit_t *circ) { #define CIRC_ATTEMPT_NOTICE_INTERVAL (600) static ratelim_t circ_attempt_notice_limit = @@ -1448,6 +1534,7 @@ pathbias_count_build_success(origin_circuit_t *circ) if (circ->path_state == PATH_STATE_BUILD_ATTEMPTED) { circ->path_state = PATH_STATE_BUILD_SUCCEEDED; guard->circ_successes++; + entry_guards_changed(); log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s", guard->circ_successes, guard->circ_attempts, @@ -1505,6 +1592,158 @@ pathbias_count_build_success(origin_circuit_t *circ) } /** + * Record an attempt to use a circuit. Changes the circuit's + * path state and update its guard's usage counter. + * + * Used for path bias usage accounting. + */ +void +pathbias_count_use_attempt(origin_circuit_t *circ) +{ + entry_guard_t *guard; + + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { + log_notice(LD_BUG, + "Used circuit is in strange path state %s. " + "Circuit is a %s currently %s.", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + if (guard) { + pathbias_measure_use_rate(guard); + pathbias_scale_use_rates(guard); + guard->use_attempts++; + entry_guards_changed(); + + log_debug(LD_CIRC, + "Marked circuit %d (%f/%f) as used for guard %s=%s.", + circ->global_identifier, + guard->use_successes, guard->use_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } + + circ->path_state = PATH_STATE_USE_ATTEMPTED; + } else { + /* Harmless but educational log message */ + log_info(LD_CIRC, + "Used circuit %d is already in path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } + + return; +} + +/** + * Check the circuit's path state is appropriate and mark it as + * successfully used. Used for path bias usage accounting. + * + * We don't actually increment the guard's counters until + * pathbias_check_close(), because the circuit can still transition + * back to PATH_STATE_USE_ATTEMPTED if a stream fails later (this + * is done so we can probe the circuit for liveness at close). + */ +void +pathbias_mark_use_success(origin_circuit_t *circ) +{ + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { + log_notice(LD_BUG, + "Used circuit %d is in strange path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + + pathbias_count_use_attempt(circ); + } + + /* We don't do any accounting at the guard until actual circuit close */ + circ->path_state = PATH_STATE_USE_SUCCEEDED; + + return; +} + +/** + * If a stream ever detatches from a circuit in a retriable way, + * we need to mark this circuit as still needing either another + * successful stream, or in need of a probe. + * + * An adversary could let the first stream request succeed (ie the + * resolve), but then tag and timeout the remainder (via cell + * dropping), forcing them on new circuits. + * + * Rolling back the state will cause us to probe such circuits, which + * should lead to probe failures in the event of such tagging due to + * either unrecognized cells coming in while we wait for the probe, + * or the cipher state getting out of sync in the case of dropped cells. + */ +void +pathbias_mark_use_rollback(origin_circuit_t *circ) +{ + if (circ->path_state == PATH_STATE_USE_SUCCEEDED) { + log_info(LD_CIRC, + "Rolling back pathbias use state to 'attempted' for detached " + "circuit %d", circ->global_identifier); + circ->path_state = PATH_STATE_USE_ATTEMPTED; + } +} + +/** + * Actually count a circuit success towards a guard's usage counters + * if the path state is appropriate. + */ +static void +pathbias_count_use_success(origin_circuit_t *circ) +{ + entry_guard_t *guard; + + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state != PATH_STATE_USE_SUCCEEDED) { + log_notice(LD_BUG, + "Successfully used circuit %d is in strange path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } else { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + if (guard) { + guard->use_successes++; + entry_guards_changed(); + + log_debug(LD_CIRC, + "Marked circuit %d (%f/%f) as used successfully for guard " + "%s=%s.", + circ->global_identifier, guard->use_successes, + guard->use_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } + } + + return; +} + +/** * Send a probe down a circuit that the client attempted to use, * but for which the stream timed out/failed. The probe is a * RELAY_BEGIN cell with a 0.a.b.c destination address, which @@ -1554,6 +1793,16 @@ pathbias_send_usable_probe(circuit_t *circ) return -1; } + /* Can't probe if the channel isn't open */ + if (circ->n_chan == NULL || + (circ->n_chan->state != CHANNEL_STATE_OPEN + && circ->n_chan->state != CHANNEL_STATE_MAINT)) { + log_info(LD_CIRC, + "Skipping pathbias probe for circuit %d: Channel is not open.", + ocirc->global_identifier); + return -1; + } + circuit_change_purpose(circ, CIRCUIT_PURPOSE_PATH_BIAS_TESTING); /* Update timestamp for when circuit_expire_building() should kill us */ @@ -1648,7 +1897,7 @@ pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) /* Check nonce */ if (ipv4_host == ocirc->pathbias_probe_nonce) { - ocirc->path_state = PATH_STATE_USE_SUCCEEDED; + pathbias_mark_use_success(ocirc); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); log_info(LD_CIRC, "Got valid path bias probe back for circ %d, stream %d.", @@ -1691,24 +1940,11 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason) return 0; } - if (ocirc->path_state == PATH_STATE_BUILD_SUCCEEDED) { - if (circ->timestamp_dirty) { - if (pathbias_send_usable_probe(circ) == 0) - return -1; - else - pathbias_count_unusable(ocirc); - - /* Any circuit where there were attempted streams but no successful - * streams could be bias */ - log_info(LD_CIRC, - "Circuit %d closed without successful use for reason %d. " - "Circuit purpose %d currently %d,%s. Len %d.", - ocirc->global_identifier, - reason, circ->purpose, ocirc->has_opened, - circuit_state_to_string(circ->state), - ocirc->build_state->desired_path_len); - - } else { + switch (ocirc->path_state) { + /* If the circuit was closed after building, but before use, we need + * to ensure we were the ones who tried to close it (and not a remote + * actor). */ + case PATH_STATE_BUILD_SUCCEEDED: if (reason & END_CIRC_REASON_FLAG_REMOTE) { /* Remote circ close reasons on an unused circuit all could be bias */ log_info(LD_CIRC, @@ -1739,11 +1975,45 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason) } else { pathbias_count_successful_close(ocirc); } - } - } else if (ocirc->path_state == PATH_STATE_USE_SUCCEEDED) { - pathbias_count_successful_close(ocirc); + break; + + /* If we tried to use a circuit but failed, we should probe it to ensure + * it has not been tampered with. */ + case PATH_STATE_USE_ATTEMPTED: + /* XXX: Only probe and/or count failure if the network is live? + * What about clock jumps/suspends? */ + if (pathbias_send_usable_probe(circ) == 0) + return -1; + else + pathbias_count_use_failed(ocirc); + + /* Any circuit where there were attempted streams but no successful + * streams could be bias */ + log_info(LD_CIRC, + "Circuit %d closed without successful use for reason %d. " + "Circuit purpose %d currently %d,%s. Len %d.", + ocirc->global_identifier, + reason, circ->purpose, ocirc->has_opened, + circuit_state_to_string(circ->state), + ocirc->build_state->desired_path_len); + break; + + case PATH_STATE_USE_SUCCEEDED: + pathbias_count_successful_close(ocirc); + pathbias_count_use_success(ocirc); + break; + + case PATH_STATE_USE_FAILED: + pathbias_count_use_failed(ocirc); + break; + + default: + // Other states are uninteresting. No stats to count. + break; } + ocirc->path_state = PATH_STATE_ALREADY_COUNTED; + return 0; } @@ -1792,6 +2062,7 @@ static void pathbias_count_collapse(origin_circuit_t *circ) { entry_guard_t *guard = NULL; + if (!pathbias_should_count(circ)) { return; } @@ -1816,8 +2087,13 @@ pathbias_count_collapse(origin_circuit_t *circ) } } +/** + * Count a known failed circuit (because we could not probe it). + * + * This counter is informational. + */ static void -pathbias_count_unusable(origin_circuit_t *circ) +pathbias_count_use_failed(origin_circuit_t *circ) { entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { @@ -1879,20 +2155,20 @@ pathbias_count_timeout(origin_circuit_t *circ) } /** - * Return the number of circuits counted as successfully closed for - * this guard. - * - * Also add in the currently open circuits to give them the benefit - * of the doubt. + * Helper function to count all of the currently opened circuits + * for a guard that are in a given path state range. The state + * range is inclusive on both ends. */ -double -pathbias_get_closed_count(entry_guard_t *guard) +static int +pathbias_count_circs_in_states(entry_guard_t *guard, + path_state_t from, + path_state_t to) { - circuit_t *circ; + circuit_t *circ = global_circuitlist; int open_circuits = 0; - /* Count currently open circuits. Give them the benefit of the doubt. */ - for (circ = global_circuitlist; circ; circ = circ->next) { + /* Count currently open circuits. Give them the benefit of the doubt */ + for ( ; circ; circ = circ->next) { origin_circuit_t *ocirc = NULL; if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */ circ->marked_for_close) /* already counted */ @@ -1903,63 +2179,193 @@ pathbias_get_closed_count(entry_guard_t *guard) if (!ocirc->cpath || !ocirc->cpath->extend_info) continue; - if (ocirc->path_state >= PATH_STATE_BUILD_SUCCEEDED && + if (ocirc->path_state >= from && + ocirc->path_state <= to && + pathbias_should_count(ocirc) && fast_memeq(guard->identity, - ocirc->cpath->extend_info->identity_digest, - DIGEST_LEN)) { + ocirc->cpath->extend_info->identity_digest, + DIGEST_LEN)) { + log_debug(LD_CIRC, "Found opened circuit %d in path_state %s", + ocirc->global_identifier, + pathbias_state_to_string(ocirc->path_state)); open_circuits++; } } - return guard->successful_circuits_closed + open_circuits; + return open_circuits; } /** - * This function checks the consensus parameters to decide - * if it should return guard->circ_successes or - * guard->successful_circuits_closed. + * Return the number of circuits counted as successfully closed for + * this guard. + * + * Also add in the currently open circuits to give them the benefit + * of the doubt. */ double -pathbias_get_success_count(entry_guard_t *guard) +pathbias_get_close_success_count(entry_guard_t *guard) { - if (pathbias_use_close_counts(get_options())) { - return pathbias_get_closed_count(guard); - } else { - return guard->circ_successes; - } + return guard->successful_circuits_closed + + pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_SUCCEEDED, + PATH_STATE_USE_SUCCEEDED); } -/** Increment the number of times we successfully extended a circuit to - * <b>guard</b>, first checking if the failure rate is high enough that - * we should eliminate the guard. Return -1 if the guard looks no good; - * return 0 if the guard looks fine. +/** + * Return the number of circuits counted as successfully used + * this guard. + * + * Also add in the currently open circuits that we are attempting + * to use to give them the benefit of the doubt. */ -static int -entry_guard_inc_circ_attempt_count(entry_guard_t *guard) +double +pathbias_get_use_success_count(entry_guard_t *guard) +{ + return guard->use_successes + + pathbias_count_circs_in_states(guard, + PATH_STATE_USE_ATTEMPTED, + PATH_STATE_USE_SUCCEEDED); +} + +/** + * Check the path bias use rate against our consensus parameter limits. + * + * Emits a log message if the use success rates are too low. + * + * If pathbias_get_dropguards() is set, we also disable the use of + * very failure prone guards. + */ +static void +pathbias_measure_use_rate(entry_guard_t *guard) { const or_options_t *options = get_options(); - entry_guards_changed(); + if (guard->use_attempts > pathbias_get_min_use(options)) { + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_use_success_count(guard)/guard->use_attempts + < pathbias_get_extreme_use_rate(options)) { + /* Dropping is currently disabled by default. */ + if (pathbias_get_dropguards(options)) { + if (!guard->path_bias_disabled) { + log_warn(LD_CIRC, + "Your Guard %s=%s is failing to carry an extremely large " + "amount of stream on its circuits. " + "To avoid potential route manipluation attacks, Tor has " + "disabled use of this guard. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(circ_times.close_ms/1000)); + guard->path_bias_disabled = 1; + guard->bad_since = approx_time(); + entry_guards_changed(); + return; + } + } else if (!guard->path_bias_extreme) { + guard->path_bias_extreme = 1; + log_warn(LD_CIRC, + "Your Guard %s=%s is failing to carry an extremely large " + "amount of streams on its circuits. " + "This could indicate a route manipulation attack, network " + "overload, bad local network connectivity, or a bug. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(circ_times.close_ms/1000)); + } + } else if (pathbias_get_use_success_count(guard)/guard->use_attempts + < pathbias_get_notice_use_rate(options)) { + if (!guard->path_bias_noticed) { + guard->path_bias_noticed = 1; + log_notice(LD_CIRC, + "Your Guard %s=%s is failing to carry more streams on its " + "circuits than usual. " + "Most likely this means the Tor network is overloaded " + "or your network connection is poor. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(circ_times.close_ms/1000)); + } + } + } +} + +/** + * Check the path bias circuit close status rates against our consensus + * parameter limits. + * + * Emits a log message if the use success rates are too low. + * + * If pathbias_get_dropguards() is set, we also disable the use of + * very failure prone guards. + * + * XXX: This function shares similar log messages and checks to + * pathbias_measure_use_rate(). It may be possible to combine them + * eventually, especially if we can ever remove the need for 3 + * levels of closure warns (if the overall circuit failure rate + * goes down with ntor). + */ +static void +pathbias_measure_close_rate(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); if (guard->circ_attempts > pathbias_get_min_circs(options)) { /* Note: We rely on the < comparison here to allow us to set a 0 * rate and disable the feature entirely. If refactoring, don't * change to <= */ - if (pathbias_get_success_count(guard)/guard->circ_attempts + if (pathbias_get_close_success_count(guard)/guard->circ_attempts < pathbias_get_extreme_rate(options)) { /* Dropping is currently disabled by default. */ if (pathbias_get_dropguards(options)) { if (!guard->path_bias_disabled) { log_warn(LD_CIRC, - "Your Guard %s=%s is failing an extremely large amount of " - "circuits. To avoid potential route manipulation attacks, " - "Tor has disabled use of this guard. " - "Success counts are %ld/%ld. %ld circuits completed, %ld " - "were unusable, %ld collapsed, and %ld timed out. For " - "reference, your timeout cutoff is %ld seconds.", + "Your Guard %s=%s is failing an extremely large " + "amount of circuits. " + "To avoid potential route manipluation attacks, Tor has " + "disabled use of this guard. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), - tor_lround(pathbias_get_closed_count(guard)), + tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), @@ -1967,94 +2373,180 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard) tor_lround(circ_times.close_ms/1000)); guard->path_bias_disabled = 1; guard->bad_since = approx_time(); - return -1; + entry_guards_changed(); + return; } } else if (!guard->path_bias_extreme) { guard->path_bias_extreme = 1; log_warn(LD_CIRC, - "Your Guard %s=%s is failing an extremely large amount of " - "circuits. This could indicate a route manipulation attack, " + "Your Guard %s=%s is failing an extremely large " + "amount of circuits. " + "This could indicate a route manipulation attack, " "extreme network overload, or a bug. " - "Success counts are %ld/%ld. %ld circuits completed, %ld " - "were unusable, %ld collapsed, and %ld timed out. For " - "reference, your timeout cutoff is %ld seconds.", + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), - tor_lround(pathbias_get_closed_count(guard)), + tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } - } else if (pathbias_get_success_count(guard)/((double)guard->circ_attempts) - < pathbias_get_warn_rate(options)) { + } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts + < pathbias_get_warn_rate(options)) { if (!guard->path_bias_warned) { guard->path_bias_warned = 1; log_warn(LD_CIRC, - "Your Guard %s=%s is failing a very large amount of " - "circuits. Most likely this means the Tor network is " + "Your Guard %s=%s is failing a very large " + "amount of circuits. " + "Most likely this means the Tor network is " "overloaded, but it could also mean an attack against " "you or potentially the guard itself. " - "Success counts are %ld/%ld. %ld circuits completed, %ld " - "were unusable, %ld collapsed, and %ld timed out. For " - "reference, your timeout cutoff is %ld seconds.", + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), - tor_lround(pathbias_get_closed_count(guard)), + tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } - } else if (pathbias_get_success_count(guard)/((double)guard->circ_attempts) + } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts < pathbias_get_notice_rate(options)) { if (!guard->path_bias_noticed) { guard->path_bias_noticed = 1; log_notice(LD_CIRC, - "Your Guard %s=%s is failing more circuits than usual. " - "Most likely this means the Tor network is overloaded. " - "Success counts are %ld/%ld. %ld circuits completed, %ld " - "were unusable, %ld collapsed, and %ld timed out. For " - "reference, your timeout cutoff is %ld seconds.", - guard->nickname, hex_str(guard->identity, DIGEST_LEN), - tor_lround(pathbias_get_closed_count(guard)), - tor_lround(guard->circ_attempts), - tor_lround(guard->circ_successes), - tor_lround(guard->unusable_circuits), - tor_lround(guard->collapsed_circuits), - tor_lround(guard->timeouts), - tor_lround(circ_times.close_ms/1000)); + "Your Guard %s=%s is failing more circuits than " + "usual. " + "Most likely this means the Tor network is overloaded. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(circ_times.close_ms/1000)); } } } +} + +/** + * This function scales the path bias use rates if we have + * more data than the scaling threshold. This allows us to + * be more sensitive to recent measurements. + * + * XXX: The attempt count transfer stuff here might be done + * better by keeping separate pending counters that get + * transfered at circuit close. + */ +static void +pathbias_scale_close_rates(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); /* If we get a ton of circuits, just scale everything down */ if (guard->circ_attempts > pathbias_get_scale_threshold(options)) { - const int scale_factor = pathbias_get_scale_factor(options); - const int mult_factor = pathbias_get_mult_factor(options); + double scale_ratio = pathbias_get_scale_ratio(options); + int opened_attempts = pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_ATTEMPTED, PATH_STATE_BUILD_ATTEMPTED); + int opened_built = pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_SUCCEEDED, + PATH_STATE_USE_FAILED); + guard->circ_attempts -= opened_attempts; + guard->circ_successes -= opened_built; + + guard->circ_attempts *= scale_ratio; + guard->circ_successes *= scale_ratio; + guard->timeouts *= scale_ratio; + guard->successful_circuits_closed *= scale_ratio; + guard->collapsed_circuits *= scale_ratio; + guard->unusable_circuits *= scale_ratio; + + guard->circ_attempts += opened_attempts; + guard->circ_successes += opened_built; + + entry_guards_changed(); + log_info(LD_CIRC, - "Scaling pathbias counts to (%f/%f)*(%d/%d) for guard %s=%s", - guard->circ_successes, guard->circ_attempts, - mult_factor, scale_factor, guard->nickname, - hex_str(guard->identity, DIGEST_LEN)); - - guard->circ_attempts *= mult_factor; - guard->circ_successes *= mult_factor; - guard->timeouts *= mult_factor; - guard->successful_circuits_closed *= mult_factor; - guard->collapsed_circuits *= mult_factor; - guard->unusable_circuits *= mult_factor; - - guard->circ_attempts /= scale_factor; - guard->circ_successes /= scale_factor; - guard->timeouts /= scale_factor; - guard->successful_circuits_closed /= scale_factor; - guard->collapsed_circuits /= scale_factor; - guard->unusable_circuits /= scale_factor; + "Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard " + "%s=%s", + guard->circ_successes, guard->successful_circuits_closed, + guard->circ_attempts, opened_built, opened_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } +} + +/** + * This function scales the path bias circuit close rates if we have + * more data than the scaling threshold. This allows us to be more + * sensitive to recent measurements. + * + * XXX: The attempt count transfer stuff here might be done + * better by keeping separate pending counters that get + * transfered at circuit close. + */ +void +pathbias_scale_use_rates(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); + + /* If we get a ton of circuits, just scale everything down */ + if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) { + double scale_ratio = pathbias_get_scale_ratio(options); + int opened_attempts = pathbias_count_circs_in_states(guard, + PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED); + guard->use_attempts -= opened_attempts; + + guard->use_attempts *= scale_ratio; + guard->use_successes *= scale_ratio; + + guard->use_attempts += opened_attempts; + + log_info(LD_CIRC, + "Scaled pathbias use counts to %f/%f (%d open) for guard %s=%s", + guard->use_successes, guard->use_attempts, opened_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + entry_guards_changed(); + } +} + +/** Increment the number of times we successfully extended a circuit to + * 'guard', first checking if the failure rate is high enough that we should + * eliminate the guard. Return -1 if the guard looks no good; return 0 if the + * guard looks fine. */ +static int +entry_guard_inc_circ_attempt_count(entry_guard_t *guard) +{ + entry_guards_changed(); + + pathbias_measure_close_rate(guard); + + if (guard->path_bias_disabled) + return -1; + + pathbias_scale_close_rates(guard); guard->circ_attempts++; + log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); @@ -2078,7 +2570,7 @@ circuit_finish_handshake(origin_circuit_t *circ, crypt_path_t *hop; int rv; - if ((rv = pathbias_count_circ_attempt(circ)) < 0) + if ((rv = pathbias_count_build_attempt(circ)) < 0) return rv; if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) { @@ -2761,9 +3253,7 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit) return -1; } - /* Set timestamp_dirty, so we can check it for path use bias */ - if (!circ->base_.timestamp_dirty) - circ->base_.timestamp_dirty = time(NULL); + // XXX: Should cannibalized circuits be dirty or not? Not easy to say.. return 0; } diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index e6cf802f2b..3ca8d1531d 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -58,10 +58,14 @@ const char *build_state_get_exit_nickname(cpath_build_state_t *state); const node_t *choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state); double pathbias_get_extreme_rate(const or_options_t *options); +double pathbias_get_extreme_use_rate(const or_options_t *options); int pathbias_get_dropguards(const or_options_t *options); void pathbias_count_timeout(origin_circuit_t *circ); int pathbias_check_close(origin_circuit_t *circ, int reason); int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell); +void pathbias_count_use_attempt(origin_circuit_t *circ); +void pathbias_mark_use_success(origin_circuit_t *circ); +void pathbias_mark_use_rollback(origin_circuit_t *circ); #endif diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index b8f71bd342..6987dc42fd 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -783,8 +783,8 @@ circuit_dump_conn_details(int severity, int this_circid, int other_circid) { - log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " - "state %d (%s), born %ld:", + tor_log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d " + "(other side %d), state %d (%s), born %ld:", conn_array_index, type, this_circid, other_circid, circ->state, circuit_state_to_string(circ->state), (long)circ->timestamp_began.tv_sec); @@ -846,8 +846,8 @@ circuit_dump_chan_details(int severity, int this_circid, int other_circid) { - log(severity, LD_CIRC, "Conn %p has %s circuit: circID %d (other side %d), " - "state %d (%s), born %ld:", + tor_log(severity, LD_CIRC, "Conn %p has %s circuit: circID %d " + "(other side %d), state %d (%s), born %ld:", chan, type, this_circid, other_circid, circ->state, circuit_state_to_string(circ->state), (long)circ->timestamp_began.tv_sec); @@ -1343,7 +1343,7 @@ circuit_mark_for_close_(circuit_t *circ, int reason, int line, tor_assert(file); if (circ->marked_for_close) { - log(LOG_WARN,LD_BUG, + log_warn(LD_BUG, "Duplicate call to circuit_mark_for_close at %s:%d" " (first at %s:%d)", file, line, circ->marked_for_close_file, circ->marked_for_close); diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 625083c9b8..73e34d9ed7 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -183,16 +183,6 @@ circuit_build_times_quantile_cutoff(void) return num/100.0; } -/* DOCDOC circuit_build_times_get_bw_scale */ -int -circuit_build_times_get_bw_scale(networkstatus_t *ns) -{ - return networkstatus_get_param(ns, "bwweightscale", - BW_WEIGHT_SCALE, - BW_MIN_WEIGHT_SCALE, - BW_MAX_WEIGHT_SCALE); -} - /** * Retrieve and bounds-check the cbtclosequantile consensus paramter. * diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 83734c9d6d..cfd41be792 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -668,18 +668,6 @@ circuit_expire_building(void) circuit_build_times_set_timeout(&circ_times); } } - - if (TO_ORIGIN_CIRCUIT(victim)->has_opened && - victim->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { - /* For path bias: we want to let these guys live for a while - * so we get a chance to test them. */ - log_info(LD_CIRC, - "Allowing cannibalized circuit %d time to finish building " - "as a pathbias testing circ.", - TO_ORIGIN_CIRCUIT(victim)->global_identifier); - circuit_change_purpose(victim, CIRCUIT_PURPOSE_PATH_BIAS_TESTING); - continue; /* It now should have a longer timeout next time */ - } } /* If this is a hidden service client circuit which is far enough @@ -1090,7 +1078,10 @@ circuit_expire_old_circuits_clientside(void) "purpose %d)", circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty), circ->purpose); - circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + /* Don't do this magic for testing circuits. Their death is governed + * by circuit_expire_building */ + if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) { if (timercmp(&circ->timestamp_began, &cutoff, <)) { if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || @@ -1507,17 +1498,19 @@ circuit_launch_by_extend_info(uint8_t purpose, purpose == CIRCUIT_PURPOSE_C_INTRODUCING) && circ->path_state == PATH_STATE_BUILD_SUCCEEDED) { /* Path bias: Cannibalized rends pre-emptively count as a - * successfully used circ. We don't wait until the extend, - * because the rend point could be malicious. + * successfully built but unused closed circuit. We don't + * wait until the extend (or the close) because the rend + * point could be malicious. * * Same deal goes for client side introductions. Clients * can be manipulated to connect repeatedly to them * (especially web clients). * * If we decide to probe the initial portion of these circs, - * (up to the adversaries final hop), we need to remove this. + * (up to the adversary's final hop), we need to remove this, + * or somehow mark the circuit with a special path state. */ - circ->path_state = PATH_STATE_USE_SUCCEEDED; + /* This must be called before the purpose change */ pathbias_check_close(circ, END_CIRC_REASON_FINISHED); } @@ -2037,6 +2030,8 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, if (!circ->base_.timestamp_dirty) circ->base_.timestamp_dirty = time(NULL); + pathbias_count_use_attempt(circ); + link_apconn_to_circ(conn, circ, cpath); tor_assert(conn->socks_request); if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { @@ -2163,6 +2158,11 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) * feasibility, at this point. */ rendcirc->base_.timestamp_dirty = time(NULL); + + /* We've also attempted to use them. If they fail, we need to + * probe them for path bias */ + pathbias_count_use_attempt(rendcirc); + link_apconn_to_circ(conn, rendcirc, NULL); if (connection_ap_handshake_send_begin(conn) < 0) return 0; /* already marked, let them fade away */ @@ -2214,6 +2214,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) case 0: /* success */ rendcirc->base_.timestamp_dirty = time(NULL); introcirc->base_.timestamp_dirty = time(NULL); + + pathbias_count_use_attempt(introcirc); + pathbias_count_use_attempt(rendcirc); + assert_circuit_ok(TO_CIRCUIT(rendcirc)); assert_circuit_ok(TO_CIRCUIT(introcirc)); return 0; diff --git a/src/or/config.c b/src/or/config.c index ce751122ff..31695baa73 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -297,7 +297,8 @@ static config_var_t option_vars_[] = { V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"), V(MaxCircuitDirtiness, INTERVAL, "10 minutes"), V(MaxClientCircuitsPending, UINT, "32"), - V(MaxOnionsPending, UINT, "100"), + OBSOLETE("MaxOnionsPending"), + V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), OBSOLETE("MonthlyAccountingStart"), V(MyFamily, STRING, NULL), V(NewCircuitPeriod, INTERVAL, "30 seconds"), @@ -321,11 +322,17 @@ static config_var_t option_vars_[] = { V(PathBiasWarnRate, DOUBLE, "-1"), V(PathBiasExtremeRate, DOUBLE, "-1"), V(PathBiasScaleThreshold, INT, "-1"), - V(PathBiasScaleFactor, INT, "-1"), - V(PathBiasMultFactor, INT, "-1"), + OBSOLETE("PathBiasScaleFactor"), + OBSOLETE("PathBiasMultFactor"), V(PathBiasDropGuards, AUTOBOOL, "0"), - V(PathBiasUseCloseCounts, AUTOBOOL, "1"), + OBSOLETE("PathBiasUseCloseCounts"), + V(PathBiasUseThreshold, INT, "-1"), + V(PathBiasNoticeUseRate, DOUBLE, "-1"), + V(PathBiasExtremeUseRate, DOUBLE, "-1"), + V(PathBiasScaleUseThreshold, INT, "-1"), + + V(PathsNeededToBuildCircuits, DOUBLE, "-1"), OBSOLETE("PathlenCoinWeight"), V(PerConnBWBurst, MEMUNIT, "0"), V(PerConnBWRate, MEMUNIT, "0"), @@ -1086,7 +1093,7 @@ options_act_reversible(const or_options_t *old_options, char **msg) mark_logs_temp(); /* Close current logs once new logs are open. */ logs_marked = 1; - if (options_init_logs(options, 0)<0) { /* Configure the log(s) */ + if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */ *msg = tor_strdup("Failed to init Log options. See logs for details."); goto rollback; } @@ -1262,7 +1269,7 @@ options_act(const or_options_t *old_options) return -1; #ifdef NON_ANONYMOUS_MODE_ENABLED - log(LOG_WARN, LD_GENERAL, "This copy of Tor was compiled to run in a " + log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " "non-anonymous mode. It will provide NO ANONYMITY."); #endif @@ -1776,7 +1783,7 @@ config_get_commandlines(int argc, char **argv, config_line_t **result) (*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup(""); (*new)->command = command; (*new)->next = NULL; - log(LOG_DEBUG, LD_CONFIG, "command line: parsed keyword '%s', value '%s'", + log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'", (*new)->key, (*new)->value); new = &((*new)->next); @@ -2224,7 +2231,7 @@ options_validate(or_options_t *old_options, or_options_t *options, int n_ports=0; #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END -#define COMPLAIN(arg) STMT_BEGIN log(LOG_WARN, LD_CONFIG, arg); STMT_END +#define COMPLAIN(arg) STMT_BEGIN log_warn(LD_CONFIG, arg); STMT_END tor_assert(msg); *msg = NULL; @@ -2233,7 +2240,7 @@ options_validate(or_options_t *old_options, or_options_t *options, (!strcmpstart(uname, "Windows 95") || !strcmpstart(uname, "Windows 98") || !strcmpstart(uname, "Windows Me"))) { - log(LOG_WARN, LD_CONFIG, "Tor is running as a server, but you are " + log_warn(LD_CONFIG, "Tor is running as a server, but you are " "running %s; this probably won't work. See " "https://wiki.torproject.org/TheOnionRouter/TorFAQ#ServerOS " "for details.", uname); @@ -2262,7 +2269,7 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (server_mode(options) && !options->ContactInfo) - log(LOG_NOTICE, LD_CONFIG, "Your ContactInfo config option is not set. " + log_notice(LD_CONFIG, "Your ContactInfo config option is not set. " "Please consider setting it, so we can contact you if your server is " "misconfigured or something else goes wrong."); @@ -2274,7 +2281,7 @@ options_validate(or_options_t *old_options, or_options_t *options, config_line_append(&options->Logs, "Log", "warn stdout"); } - if (options_init_logs(options, 1)<0) /* Validate the log(s) */ + if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */ REJECT("Failed to validate Log options. See logs for details."); if (authdir_mode(options)) { @@ -2292,7 +2299,7 @@ options_validate(or_options_t *old_options, or_options_t *options, /* XXXX require that the only port not be DirPort? */ /* XXXX require that at least one port be listened-upon. */ if (n_ports == 0 && !options->RendConfigLines) - log(LOG_WARN, LD_CONFIG, + log_warn(LD_CONFIG, "SocksPort, TransPort, NATDPort, DNSPort, and ORPort are all " "undefined, and there aren't any hidden services configured. " "Tor will still run, but probably won't do anything."); @@ -2399,6 +2406,18 @@ options_validate(or_options_t *old_options, or_options_t *options, return -1; } + if (options->PathsNeededToBuildCircuits >= 0.0) { + if (options->PathsNeededToBuildCircuits < 0.25) { + log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too low. Increasing " + "to 0.25"); + options->PathsNeededToBuildCircuits = 0.25; + } else if (options->PathsNeededToBuildCircuits < 0.95) { + log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too high. Decreasing " + "to 0.95"); + options->PathsNeededToBuildCircuits = 0.95; + } + } + if (options->MaxClientCircuitsPending <= 0 || options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) { tor_asprintf(msg, @@ -2440,7 +2459,7 @@ options_validate(or_options_t *old_options, or_options_t *options, }); new_line->value = smartlist_join_strings(instead,",",0,NULL); /* These have been deprecated since 0.1.1.5-alpha-cvs */ - log(LOG_NOTICE, LD_CONFIG, + log_notice(LD_CONFIG, "Converting FascistFirewall and FirewallPorts " "config options to new format: \"ReachableAddresses %s\"", new_line->value); @@ -2455,7 +2474,7 @@ options_validate(or_options_t *old_options, or_options_t *options, new_line->key = tor_strdup("ReachableDirAddresses"); new_line->value = tor_strdup("*:80"); options->ReachableDirAddresses = new_line; - log(LOG_NOTICE, LD_CONFIG, "Converting FascistFirewall config option " + log_notice(LD_CONFIG, "Converting FascistFirewall config option " "to new format: \"ReachableDirAddresses *:80\""); } if (!options->ReachableORAddresses) { @@ -2463,7 +2482,7 @@ options_validate(or_options_t *old_options, or_options_t *options, new_line->key = tor_strdup("ReachableORAddresses"); new_line->value = tor_strdup("*:443"); options->ReachableORAddresses = new_line; - log(LOG_NOTICE, LD_CONFIG, "Converting FascistFirewall config option " + log_notice(LD_CONFIG, "Converting FascistFirewall config option " "to new format: \"ReachableORAddresses *:443\""); } } @@ -2643,6 +2662,37 @@ options_validate(or_options_t *old_options, or_options_t *options, RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT ); } + if (options->PathBiasNoticeRate > 1.0) { + tor_asprintf(msg, + "PathBiasNoticeRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasWarnRate > 1.0) { + tor_asprintf(msg, + "PathBiasWarnRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasExtremeRate > 1.0) { + tor_asprintf(msg, + "PathBiasExtremeRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasNoticeUseRate > 1.0) { + tor_asprintf(msg, + "PathBiasNoticeUseRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasExtremeUseRate > 1.0) { + tor_asprintf(msg, + "PathBiasExtremeUseRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->MaxCircuitDirtiness < MIN_MAX_CIRCUIT_DIRTINESS) { log_warn(LD_CONFIG, "MaxCircuitDirtiness option is too short; " "raising to %d seconds.", MIN_MAX_CIRCUIT_DIRTINESS); @@ -3417,7 +3467,7 @@ find_torrc_filename(int argc, char **argv, for (i = 1; i < argc; ++i) { if (i < argc-1 && !strcmp(argv[i],fname_opt)) { if (fname) { - log(LOG_WARN, LD_CONFIG, "Duplicate %s options on command line.", + log_warn(LD_CONFIG, "Duplicate %s options on command line.", fname_opt); tor_free(fname); } @@ -3480,7 +3530,7 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file) fname = find_torrc_filename(argc, argv, defaults_file, &using_default_torrc, &ignore_missing_torrc); tor_assert(fname); - log(LOG_DEBUG, LD_CONFIG, "Opening config file \"%s\"", fname); + log_debug(LD_CONFIG, "Opening config file \"%s\"", fname); tor_free(*fname_var); *fname_var = fname; @@ -3490,18 +3540,18 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file) !(cf = read_file_to_str(fname,0,NULL))) { if (using_default_torrc == 1 || ignore_missing_torrc) { if (!defaults_file) - log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, " + log_notice(LD_CONFIG, "Configuration file \"%s\" not present, " "using reasonable defaults.", fname); tor_free(fname); /* sets fname to NULL */ *fname_var = NULL; cf = tor_strdup(""); } else { - log(LOG_WARN, LD_CONFIG, + log_warn(LD_CONFIG, "Unable to open configuration file \"%s\".", fname); goto err; } } else { - log(LOG_NOTICE, LD_CONFIG, "Read configuration file \"%s\".", fname); + log_notice(LD_CONFIG, "Read configuration file \"%s\".", fname); } return cf; @@ -3593,7 +3643,7 @@ options_init_from_torrc(int argc, char **argv) tor_free(cf); tor_free(cf_defaults); if (errmsg) { - log(LOG_WARN,LD_CONFIG,"%s", errmsg); + log_warn(LD_CONFIG,"%s", errmsg); tor_free(errmsg); } return retval < 0 ? -1 : 0; @@ -5377,7 +5427,7 @@ check_server_ports(const smartlist_t *ports, } if (n_low_port && options->AccountingMax) { - log(LOG_WARN, LD_CONFIG, + log_warn(LD_CONFIG, "You have set AccountingMax to use hibernation. You have also " "chosen a low DirPort or OrPort. This combination can make Tor stop " "working when it tries to re-attach the port after a period of " diff --git a/src/or/connection.c b/src/or/connection.c index b3719151f0..0d8242a54e 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -731,7 +731,7 @@ connection_mark_for_close_internal_(connection_t *conn, tor_assert(file); if (conn->marked_for_close) { - log(LOG_WARN,LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d" + log_warn(LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d" " (first at %s:%d)", file, line, conn->marked_for_close_file, conn->marked_for_close); tor_fragile_assert(); @@ -2530,7 +2530,7 @@ connection_bucket_refill_helper(int *bucket, int rate, int burst, *bucket = burst; } } - log(LOG_DEBUG, LD_NET,"%s now %d.", name, *bucket); + log_debug(LD_NET,"%s now %d.", name, *bucket); } } @@ -3276,6 +3276,7 @@ connection_handle_write_impl(connection_t *conn, int force) ssize_t max_to_write; time_t now = approx_time(); size_t n_read = 0, n_written = 0; + int dont_stop_writing = 0; tor_assert(!connection_is_listener(conn)); @@ -3332,6 +3333,7 @@ connection_handle_write_impl(connection_t *conn, int force) if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { or_connection_t *or_conn = TO_OR_CONN(conn); + size_t initial_size; if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { connection_stop_writing(conn); @@ -3355,6 +3357,7 @@ connection_handle_write_impl(connection_t *conn, int force) } /* else open, or closing */ + initial_size = buf_datalen(conn->outbuf); result = flush_buf_tls(or_conn->tls, conn->outbuf, max_to_write, &conn->outbuf_flushlen); @@ -3385,7 +3388,8 @@ connection_handle_write_impl(connection_t *conn, int force) case TOR_TLS_WANTWRITE: log_debug(LD_NET,"wanted write."); /* we're already writing */ - return 0; + dont_stop_writing = 1; + break; case TOR_TLS_WANTREAD: /* Make sure to avoid a loop if the receive buckets are empty. */ log_debug(LD_NET,"wanted read."); @@ -3407,6 +3411,12 @@ connection_handle_write_impl(connection_t *conn, int force) tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written); log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written", result, (long)n_read, (long)n_written); + /* So we notice bytes were written even on error */ + /* XXXX024 This cast is safe since we can never write INT_MAX bytes in a + * single set of TLS operations. But it looks kinda ugly. If we refactor + * the *_buf_tls functions, we should make them return ssize_t or size_t + * or something. */ + result = (int)(initial_size-buf_datalen(conn->outbuf)); } else { CONN_LOG_PROTECT(conn, result = flush_buf(conn->s, conn->outbuf, @@ -3453,7 +3463,8 @@ connection_handle_write_impl(connection_t *conn, int force) } } - if (!connection_wants_to_flush(conn)) { /* it's done flushing */ + if (!connection_wants_to_flush(conn) && + !dont_stop_writing) { /* it's done flushing */ if (connection_finished_flushing(conn) < 0) { /* already marked */ return -1; @@ -3897,7 +3908,7 @@ client_check_address_changed(tor_socket_t sock) } else { /* The interface changed. We're a client, so we need to regenerate our * keys. First, reset the state. */ - log(LOG_NOTICE, LD_NET, "Our IP address has changed. Rotating keys..."); + log_notice(LD_NET, "Our IP address has changed. Rotating keys..."); tor_addr_copy(*last_interface_ip_ptr, &iface_addr); SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr)); smartlist_clear(outgoing_addrs); @@ -3981,8 +3992,9 @@ connection_flushed_some(connection_t *conn) return r; } -/** We just finished flushing bytes from conn-\>outbuf, and there - * are no more bytes remaining. +/** We just finished flushing bytes to the appropriately low network layer, + * and there are no more bytes remaining in conn-\>outbuf, conn-\>bev, or + * conn-\>tls to be flushed. * * This function just passes conn to the connection-specific * connection_*_finished_flushing() function. @@ -4109,14 +4121,14 @@ connection_dump_buffer_mem_stats(int severity) total_alloc += alloc_by_type[i]; } - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated", smartlist_len(conns), U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc)); for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) { if (!n_conns_by_type[i]) continue; - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, " For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated", n_conns_by_type[i], conn_type_to_string(i), U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i])); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 870ded98c9..b4fa3e6fe2 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -37,6 +37,7 @@ #include "router.h" #include "routerlist.h" #include "routerset.h" +#include "circuitbuild.h" #ifdef HAVE_LINUX_TYPES_H #include <linux/types.h> @@ -641,6 +642,10 @@ connection_ap_expire_beginning(void) " '%s.onion'.", seconds_idle, safe_str_client(entry_conn->socks_request->address)); + /* Roll back path bias use state so that we probe the circuit + * if nothing else succeeds on it */ + pathbias_mark_use_rollback(TO_ORIGIN_CIRCUIT(circ)); + connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); } @@ -805,6 +810,10 @@ connection_ap_detach_retriable(entry_connection_t *conn, control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason); ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL); + /* Roll back path bias use state so that we probe the circuit + * if nothing else succeeds on it */ + pathbias_mark_use_rollback(circ); + if (conn->pending_optimistic_data) { generic_buffer_set_to_copy(&conn->sending_optimistic_data, conn->pending_optimistic_data); @@ -2205,8 +2214,10 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), endreason); } else { - TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit)->path_state - = PATH_STATE_USE_SUCCEEDED; + // XXX: Hrmm. It looks like optimistic data can't go through this + // codepath, but someone should probably test it and make sure. + // We don't want to mark optimistically opened streams as successful. + pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit)); } } @@ -2480,7 +2491,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) connection_exit_connect(n_stream); /* For path bias: This circuit was used successfully */ - origin_circ->path_state = PATH_STATE_USE_SUCCEEDED; + pathbias_mark_use_success(origin_circ); tor_free(address); return 0; diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 872decba11..5ec32d6324 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -295,13 +295,13 @@ connection_or_report_broken_states(int severity, int domain) smartlist_sort(items, broken_state_count_compare); - log(severity, domain, "%d connections have failed%s", total, + tor_log(severity, domain, "%d connections have failed%s", total, smartlist_len(items) > MAX_REASONS_TO_REPORT ? ". Top reasons:" : ":"); SMARTLIST_FOREACH_BEGIN(items, const broken_state_count_t *, c) { if (c_sl_idx > MAX_REASONS_TO_REPORT) break; - log(severity, domain, + tor_log(severity, domain, " %d connections died in state %s", (int)c->count, c->state); } SMARTLIST_FOREACH_END(c); diff --git a/src/or/control.c b/src/or/control.c index 54e5c597a1..9ab0dafb7b 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -4663,7 +4663,7 @@ control_event_bootstrap(bootstrap_status_t status, int progress) if (status > bootstrap_percent || (progress && progress > bootstrap_percent)) { bootstrap_status_to_string(status, &tag, &summary); - log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL, + tor_log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL, "Bootstrapped %d%%: %s.", progress ? progress : status, summary); tor_snprintf(buf, sizeof(buf), "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"", diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 465f15516d..b5740f091d 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -98,6 +98,11 @@ typedef struct cpuworker_request_t { /** Task code. Must be one of CPUWORKER_TASK_* */ uint8_t task; + /** Flag: Are we timing this request? */ + unsigned timed : 1; + /** If we're timing this request, when was it sent to the cpuworker? */ + struct timeval started_at; + /** A create cell for the cpuworker to process. */ create_cell_t create_cell; @@ -113,6 +118,17 @@ typedef struct cpuworker_reply_t { /** True iff we got a successful request. */ uint8_t success; + /** Are we timing this request? */ + unsigned int timed : 1; + /** What handshake type was the request? (Used for timing) */ + uint16_t handshake_type; + /** When did we send the request to the cpuworker? */ + struct timeval started_at; + /** Once the cpuworker received the request, how many microseconds did it + * take? (This shouldn't overflow; 4 billion micoseconds is over an hour, + * and we'll never have an onion handshake that takes so long.) */ + uint32_t n_usec; + /** Output of processing a create cell * * @{ @@ -163,6 +179,110 @@ connection_cpu_reached_eof(connection_t *conn) return 0; } +/** Indexed by handshake type: how many onionskins have we processed and + * counted of that type? */ +static uint64_t onionskins_n_processed[MAX_ONION_HANDSHAKE_TYPE+1]; +/** Indexed by handshake type, corresponding to the onionskins counted in + * onionskins_n_processed: how many microseconds have we spent in cpuworkers + * processing that kind of onionskin? */ +static uint64_t onionskins_usec_internal[MAX_ONION_HANDSHAKE_TYPE+1]; +/** Indexed by handshake type, corresponding to onionskins counted in + * onionskins_n_processed: how many microseconds have we spent waiting for + * cpuworkers to give us answers for that kind of onionskin? + */ +static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1]; + +/** If any onionskin takes longer than this, we clip them to this + * time. (microseconds) */ +#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000) + +/** Return true iff we'd like to measure a handshake of type + * <b>onionskin_type</b>. */ +static int +should_time_request(uint16_t onionskin_type) +{ + /* If we've never heard of this type, we shouldn't even be here. */ + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) + return 0; + /* Measure the first N handshakes of each type, to ensure we have a + * sample */ + if (onionskins_n_processed[onionskin_type] < 4096) + return 1; + /** Otherwise, measure with P=1/128. We avoid doing this for every + * handshake, since the measurement itself can take a little time. */ + return tor_weak_random() < (TOR_RAND_MAX/128); +} + +/** Return an estimate of how many microseconds we will need for a single + * cpuworker to to process <b>n_requests</b> onionskins of type + * <b>onionskin_type</b>. */ +uint64_t +estimated_usec_for_onionskins(uint32_t n_requests, uint16_t onionskin_type) +{ + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */ + return 1000 * n_requests; + if (PREDICT_UNLIKELY(onionskins_n_processed[onionskin_type] < 100)) { + /* Until we have 100 data points, just asssume everything takes 1 msec. */ + return 1000 * n_requests; + } else { + /* This can't overflow: we'll never have more than 500000 onionskins + * measured in onionskin_usec_internal, and they won't take anything near + * 1 sec each, and we won't have anything like 1 million queued + * onionskins. But that's 5e5 * 1e6 * 1e6, which is still less than + * UINT64_MAX. */ + return (onionskins_usec_internal[onionskin_type] * n_requests) / + onionskins_n_processed[onionskin_type]; + } +} + +/** Compute the absolute and relative overhead of using the cpuworker + * framework for onionskins of type <b>onionskin_type</b>.*/ +static int +get_overhead_for_onionskins(uint32_t *usec_out, double *frac_out, + uint16_t onionskin_type) +{ + uint64_t overhead; + + *usec_out = 0; + *frac_out = 0.0; + + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */ + return -1; + if (onionskins_n_processed[onionskin_type] == 0 || + onionskins_usec_internal[onionskin_type] == 0 || + onionskins_usec_roundtrip[onionskin_type] == 0) + return -1; + + overhead = onionskins_usec_roundtrip[onionskin_type] - + onionskins_usec_internal[onionskin_type]; + + *usec_out = (uint32_t)(overhead / onionskins_n_processed[onionskin_type]); + *frac_out = U64_TO_DBL(overhead) / onionskins_usec_internal[onionskin_type]; + + return 0; +} + +/** If we've measured overhead for onionskins of type <b>onionskin_type</b>, + * log it. */ +void +cpuworker_log_onionskin_overhead(int severity, int onionskin_type, + const char *onionskin_type_name) +{ + uint32_t overhead; + double relative_overhead; + int r; + + r = get_overhead_for_onionskins(&overhead, &relative_overhead, + onionskin_type); + if (!overhead || r<0) + return; + + log_fn(severity, LD_OR, + "%s onionskins have averaged %u usec overhead (%.2f%%) in " + "cpuworker code ", + onionskin_type_name, (unsigned)overhead, relative_overhead*100); +} + /** Called when we get data from a cpuworker. If the answer is not complete, * wait for a complete answer. If the answer is complete, * process it as appropriate. @@ -190,6 +310,30 @@ connection_cpu_process_inbuf(connection_t *conn) connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn); tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC); + + if (rpl.timed && rpl.success && + rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) { + /* Time how long this request took. The handshake_type check should be + needless, but let's leave it in to be safe. */ + struct timeval tv_end, tv_diff; + int64_t usec_roundtrip; + tor_gettimeofday(&tv_end); + timersub(&tv_end, &rpl.started_at, &tv_diff); + usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec; + if (usec_roundtrip >= 0 && + usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) { + ++onionskins_n_processed[rpl.handshake_type]; + onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec; + onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip; + if (onionskins_n_processed[rpl.handshake_type] >= 500000) { + /* Scale down every 500000 handshakes. On a busy server, that's + * less impressive than it sounds. */ + onionskins_n_processed[rpl.handshake_type] /= 2; + onionskins_usec_internal[rpl.handshake_type] /= 2; + onionskins_usec_roundtrip[rpl.handshake_type] /= 2; + } + } + } /* parse out the circ it was talking about */ tag_unpack(rpl.tag, &chan_id, &circ_id); circ = NULL; @@ -289,7 +433,13 @@ cpuworker_main(void *data) if (req.task == CPUWORKER_TASK_ONION) { const create_cell_t *cc = &req.create_cell; created_cell_t *cell_out = &rpl.created_cell; + struct timeval tv_start, tv_end; int n; + rpl.timed = req.timed; + rpl.started_at = req.started_at; + rpl.handshake_type = cc->handshake_type; + if (req.timed) + tor_gettimeofday(&tv_start); n = onion_skin_server_handshake(cc->handshake_type, cc->onionskin, cc->handshake_len, &onion_keys, @@ -321,6 +471,17 @@ cpuworker_main(void *data) rpl.success = 1; } rpl.magic = CPUWORKER_REPLY_MAGIC; + if (req.timed) { + struct timeval tv_diff; + int64_t usec; + tor_gettimeofday(&tv_end); + timersub(&tv_end, &tv_start, &tv_diff); + usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec; + if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY) + rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY; + else + rpl.n_usec = (uint32_t) usec; + } if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto end; @@ -478,6 +639,7 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker, cpuworker_request_t req; time_t now = approx_time(); static time_t last_culled_cpuworkers = 0; + int should_time; /* Checking for wedged cpuworkers requires a linear search over all * connections, so let's do it only once a minute. @@ -512,16 +674,18 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker, return -1; } + should_time = should_time_request(onionskin->handshake_type); memset(&req, 0, sizeof(req)); req.magic = CPUWORKER_REQUEST_MAGIC; tag_pack(req.tag, circ->p_chan->global_identifier, circ->p_circ_id); + req.timed = should_time; cpuworker->state = CPUWORKER_STATE_BUSY_ONION; /* touch the lastwritten timestamp, since that's how we check to * see how long it's been since we asked the question, and sometimes * we check before the first call to connection_handle_write(). */ - cpuworker->timestamp_lastwritten = time(NULL); + cpuworker->timestamp_lastwritten = now; num_cpuworkers_busy++; req.task = CPUWORKER_TASK_ONION; @@ -529,6 +693,9 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker, tor_free(onionskin); + if (should_time) + tor_gettimeofday(&req.started_at); + connection_write_to_buf((void*)&req, sizeof(req), cpuworker); memwipe(&req, 0, sizeof(req)); } diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h index 18d45153c7..317cef43ba 100644 --- a/src/or/cpuworker.h +++ b/src/or/cpuworker.h @@ -22,5 +22,10 @@ int assign_onionskin_to_cpuworker(connection_t *cpuworker, or_circuit_t *circ, struct create_cell_t *onionskin); +uint64_t estimated_usec_for_onionskins(uint32_t n_requests, + uint16_t onionskin_type); +void cpuworker_log_onionskin_overhead(int severity, int onionskin_type, + const char *onionskin_type_name); + #endif diff --git a/src/or/directory.c b/src/or/directory.c index 692a6d6b2c..c101418446 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1860,7 +1860,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) const char *flavname = conn->requested_resource; if (status_code != 200) { int severity = (status_code == 304) ? LOG_INFO : LOG_WARN; - log(severity, LD_DIR, + tor_log(severity, LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching consensus directory.", status_code, escaped(reason), conn->base_.address, @@ -2800,8 +2800,6 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, /* v2 or v3 network status fetch. */ smartlist_t *dir_fps = smartlist_new(); int is_v3 = !strcmpstart(url, "/tor/status-vote"); - geoip_client_action_t act = - is_v3 ? GEOIP_CLIENT_NETWORKSTATUS : GEOIP_CLIENT_NETWORKSTATUS_V2; const char *request_type = NULL; const char *key = url + strlen("/tor/status/"); long lifetime = NETWORKSTATUS_CACHE_LIFETIME; @@ -2851,7 +2849,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, write_http_status_line(conn, 404, "Consensus not signed by sufficient " "number of requested authorities"); smartlist_free(dir_fps); - geoip_note_ns_response(act, GEOIP_REJECT_NOT_ENOUGH_SIGS); + geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS); tor_free(flavor); goto done; } @@ -2870,7 +2868,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */ write_http_status_line(conn, 503, "Network status object unavailable"); smartlist_free(dir_fps); - geoip_note_ns_response(act, GEOIP_REJECT_UNAVAILABLE); + if (is_v3) + geoip_note_ns_response(GEOIP_REJECT_UNAVAILABLE); goto done; } @@ -2878,13 +2877,15 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, write_http_status_line(conn, 404, "Not found"); SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); smartlist_free(dir_fps); - geoip_note_ns_response(act, GEOIP_REJECT_NOT_FOUND); + if (is_v3) + geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); goto done; } else if (!smartlist_len(dir_fps)) { write_http_status_line(conn, 304, "Not modified"); SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); smartlist_free(dir_fps); - geoip_note_ns_response(act, GEOIP_REJECT_NOT_MODIFIED); + if (is_v3) + geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED); goto done; } @@ -2896,24 +2897,24 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, write_http_status_line(conn, 503, "Directory busy, try again later"); SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp)); smartlist_free(dir_fps); - geoip_note_ns_response(act, GEOIP_REJECT_BUSY); + if (is_v3) + geoip_note_ns_response(GEOIP_REJECT_BUSY); goto done; } - { + if (is_v3) { struct in_addr in; tor_addr_t addr; if (tor_inet_aton((TO_CONN(conn))->address, &in)) { tor_addr_from_ipv4h(&addr, ntohl(in.s_addr)); - geoip_note_client_seen(act, &addr, time(NULL)); - geoip_note_ns_response(act, GEOIP_SUCCESS); + geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, time(NULL)); + geoip_note_ns_response(GEOIP_SUCCESS); /* Note that a request for a network status has started, so that we * can measure the download time later on. */ if (conn->dirreq_id) - geoip_start_dirreq(conn->dirreq_id, dlen, act, - DIRREQ_TUNNELED); + geoip_start_dirreq(conn->dirreq_id, dlen, DIRREQ_TUNNELED); else - geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, act, + geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, DIRREQ_DIRECT); } } diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 8af848ca02..e2cd7cfd26 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2017,7 +2017,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl) median_uint32(bandwidths_excluding_exits, n_active_nonexit); } - log(LOG_INFO, LD_DIRSERV, + log_info(LD_DIRSERV, "Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. " "For Fast: %lu bytes/sec. " "For Guard: WFU %.03f%%, time-known %lu sec, " diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 0731426d97..aee9a6edfe 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -2288,7 +2288,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target, if (sig->good_signature || !old_sig || old_sig->bad_signature) { log_info(LD_DIR, "Adding signature from %s with %s", voter_identity, algorithm); - log(severity, LD_DIR, "Added a signature for %s from %s.", + tor_log(severity, LD_DIR, "Added a signature for %s from %s.", target_voter->nickname, source); ++r; if (old_sig) { diff --git a/src/or/dns.c b/src/or/dns.c index 68309a80df..edcf92e5b3 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -262,7 +262,7 @@ evdns_log_cb(int warn, const char *msg) int severity = warn ? LOG_WARN : LOG_INFO; if (!strcmpstart(msg, "Resolve requested for") && get_options()->SafeLogging) { - log(LOG_INFO, LD_EXIT, "eventdns: Resolve requested."); + log_info(LD_EXIT, "eventdns: Resolve requested."); return; } else if (!strcmpstart(msg, "Search: ")) { return; @@ -291,7 +291,7 @@ evdns_log_cb(int warn, const char *msg) control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN"); all_down = 1; } - log(severity, LD_EXIT, "eventdns: %s", msg); + tor_log(severity, LD_EXIT, "eventdns: %s", msg); } /** Helper: passed to eventdns.c as a callback so it can generate random @@ -835,7 +835,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, return -1; if (address_is_invalid_destination(exitconn->base_.address, 0)) { - log(LOG_PROTOCOL_WARN, LD_EXIT, + tor_log(LOG_PROTOCOL_WARN, LD_EXIT, "Rejecting invalid destination address %s", escaped_safe_str(exitconn->base_.address)); return -1; @@ -1844,7 +1844,7 @@ wildcard_increment_answer(const char *id) if (*ip > 5 && n_wildcard_requests > 10) { if (!dns_wildcard_list) dns_wildcard_list = smartlist_new(); if (!smartlist_contains_string(dns_wildcard_list, id)) { - log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + tor_log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider has given \"%s\" as an answer for %d different " "invalid addresses. Apparently they are hijacking DNS failures. " "I'll try to correct for this by treating future occurrences of " @@ -1876,7 +1876,7 @@ add_wildcarded_test_address(const char *address) smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address)); n = smartlist_len(dns_wildcarded_test_address_list); if (n > n_test_addrs/2) { - log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, + tor_log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk " "address. It has done this with %d test addresses so far. I'm " "going to stop being an exit node for now, since our DNS seems so " @@ -1920,7 +1920,7 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl, } } - log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + tor_log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider gave an answer for \"%s\", which " "is not supposed to exist. Apparently they are hijacking " "DNS failures. Trying to correct for this. We've noticed %d " @@ -2151,8 +2151,8 @@ dump_dns_mem_usage(int severity) /* Print out the count and estimated size of our &cache_root. It undercounts hostnames in cached reverse resolves. */ - log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count); - log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.", + tor_log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count); + tor_log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.", (unsigned)hash_mem); } diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 3e58371643..4ca56cbacf 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1098,6 +1098,40 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) continue; } digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1)); + } else if (!strcasecmp(line->key, "EntryGuardPathUseBias")) { + const or_options_t *options = get_options(); + double use_cnt, success_cnt; + + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardPathUseBias without EntryGuard"); + break; + } + + if (tor_sscanf(line->value, "%lf %lf", + &use_cnt, &success_cnt) != 2) { + log_info(LD_GENERAL, "Malformed path use bias line for node %s", + node->nickname); + continue; + } + + node->use_attempts = use_cnt; + node->use_successes = success_cnt; + + log_info(LD_GENERAL, "Read %f/%f path use bias for node %s", + node->use_successes, node->use_attempts, node->nickname); + + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_use_success_count(node)/node->use_attempts + < pathbias_get_extreme_use_rate(options) && + pathbias_get_dropguards(options)) { + node->path_bias_disabled = 1; + log_info(LD_GENERAL, + "Path use bias is too high (%f/%f); disabling node %s", + node->circ_successes, node->circ_attempts, node->nickname); + } } else if (!strcasecmp(line->key, "EntryGuardPathBias")) { const or_options_t *options = get_options(); double hop_cnt, success_cnt, timeouts, collapsed, successful_closed, @@ -1144,7 +1178,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) /* Note: We rely on the < comparison here to allow us to set a 0 * rate and disable the feature entirely. If refactoring, don't * change to <= */ - if (pathbias_get_success_count(node)/node->circ_attempts + if (pathbias_get_close_success_count(node)/node->circ_attempts < pathbias_get_extreme_rate(options) && pathbias_get_dropguards(options)) { node->path_bias_disabled = 1; @@ -1282,10 +1316,20 @@ entry_guards_update_state(or_state_t *state) * unusable_circuits */ tor_asprintf(&line->value, "%f %f %f %f %f %f", e->circ_attempts, e->circ_successes, - pathbias_get_closed_count(e), e->collapsed_circuits, + pathbias_get_close_success_count(e), + e->collapsed_circuits, e->unusable_circuits, e->timeouts); next = &(line->next); } + if (e->use_attempts > 0) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardPathUseBias"); + + tor_asprintf(&line->value, "%f %f", + e->use_attempts, + pathbias_get_use_success_count(e)); + next = &(line->next); + } } SMARTLIST_FOREACH_END(e); if (!get_options()->AvoidDiskWrites) diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 1e52ba28ea..e6c973c95a 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -61,6 +61,9 @@ typedef struct entry_guard_t { * attempted, but none succeeded. */ double timeouts; /**< Number of 'right-censored' circuit timeouts for this * guard. */ + double use_attempts; /**< Number of circuits we tried to use with streams */ + double use_successes; /**< Number of successfully used circuits using + * this guard as first hop. */ } entry_guard_t; entry_guard_t *entry_guard_get_by_id_digest(const char *digest); @@ -113,8 +116,8 @@ int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, int validate_pluggable_transports_config(void); -double pathbias_get_closed_count(entry_guard_t *gaurd); -double pathbias_get_success_count(entry_guard_t *guard); +double pathbias_get_close_success_count(entry_guard_t *guard); +double pathbias_get_use_success_count(entry_guard_t *guard); #endif diff --git a/src/or/geoip.c b/src/or/geoip.c index f9d036e07e..9ba1e31b8b 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -38,7 +38,6 @@ typedef struct geoip_ipv6_entry_t { /** A per-country record for GeoIP request history. */ typedef struct geoip_country_t { char countrycode[3]; - uint32_t n_v2_ns_requests; uint32_t n_v3_ns_requests; } geoip_country_t; @@ -515,67 +514,6 @@ client_history_clear(void) } } -/** How often do we update our estimate which share of v2 and v3 directory - * requests is sent to us? We could as well trigger updates of shares from - * network status updates, but that means adding a lot of calls into code - * that is independent from geoip stats (and keeping them up-to-date). We - * are perfectly fine with an approximation of 15-minute granularity. */ -#define REQUEST_SHARE_INTERVAL (15 * 60) - -/** When did we last determine which share of v2 and v3 directory requests - * is sent to us? */ -static time_t last_time_determined_shares = 0; - -/** Sum of products of v2 shares times the number of seconds for which we - * consider these shares as valid. */ -static double v2_share_times_seconds; - -/** Sum of products of v3 shares times the number of seconds for which we - * consider these shares as valid. */ -static double v3_share_times_seconds; - -/** Number of seconds we are determining v2 and v3 shares. */ -static int share_seconds; - -/** Try to determine which fraction of v2 and v3 directory requests aimed at - * caches will be sent to us at time <b>now</b> and store that value in - * order to take a mean value later on. */ -static void -geoip_determine_shares(time_t now) -{ - double v2_share = 0.0, v3_share = 0.0; - if (router_get_my_share_of_directory_requests(&v2_share, &v3_share) < 0) - return; - if (last_time_determined_shares) { - v2_share_times_seconds += v2_share * - ((double) (now - last_time_determined_shares)); - v3_share_times_seconds += v3_share * - ((double) (now - last_time_determined_shares)); - share_seconds += (int)(now - last_time_determined_shares); - } - last_time_determined_shares = now; -} - -/** Calculate which fraction of v2 and v3 directory requests aimed at caches - * have been sent to us since the last call of this function up to time - * <b>now</b>. Set *<b>v2_share_out</b> and *<b>v3_share_out</b> to the - * fractions of v2 and v3 protocol shares we expect to have seen. Reset - * counters afterwards. Return 0 on success, -1 on failure (e.g. when zero - * seconds have passed since the last call).*/ -static int -geoip_get_mean_shares(time_t now, double *v2_share_out, - double *v3_share_out) -{ - geoip_determine_shares(now); - if (!share_seconds) - return -1; - *v2_share_out = v2_share_times_seconds / ((double) share_seconds); - *v3_share_out = v3_share_times_seconds / ((double) share_seconds); - v2_share_times_seconds = v3_share_times_seconds = 0.0; - share_seconds = 0; - return 0; -} - /** Note that we've seen a client connect from the IP <b>addr</b> * at time <b>now</b>. Ignored by all but bridges and directories if * configured accordingly. */ @@ -610,22 +548,14 @@ geoip_note_client_seen(geoip_client_action_t action, else ent->last_seen_in_minutes = 0; - if (action == GEOIP_CLIENT_NETWORKSTATUS || - action == GEOIP_CLIENT_NETWORKSTATUS_V2) { + if (action == GEOIP_CLIENT_NETWORKSTATUS) { int country_idx = geoip_get_country_by_addr(addr); if (country_idx < 0) country_idx = 0; /** unresolved requests are stored at index 0. */ if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) { geoip_country_t *country = smartlist_get(geoip_countries, country_idx); - if (action == GEOIP_CLIENT_NETWORKSTATUS) - ++country->n_v3_ns_requests; - else - ++country->n_v2_ns_requests; + ++country->n_v3_ns_requests; } - - /* Periodically determine share of requests that we should see */ - if (last_time_determined_shares + REQUEST_SHARE_INTERVAL < now) - geoip_determine_shares(now); } } @@ -652,36 +582,24 @@ geoip_remove_old_clients(time_t cutoff) &cutoff); } -/** How many responses are we giving to clients requesting v2 network - * statuses? */ -static uint32_t ns_v2_responses[GEOIP_NS_RESPONSE_NUM]; - /** How many responses are we giving to clients requesting v3 network * statuses? */ static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM]; -/** Note that we've rejected a client's request for a v2 or v3 network - * status, encoded in <b>action</b> for reason <b>reason</b> at time - * <b>now</b>. */ +/** Note that we've rejected a client's request for a v3 network status + * for reason <b>reason</b> at time <b>now</b>. */ void -geoip_note_ns_response(geoip_client_action_t action, - geoip_ns_response_t response) +geoip_note_ns_response(geoip_ns_response_t response) { static int arrays_initialized = 0; if (!get_options()->DirReqStatistics) return; if (!arrays_initialized) { - memset(ns_v2_responses, 0, sizeof(ns_v2_responses)); memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); arrays_initialized = 1; } - tor_assert(action == GEOIP_CLIENT_NETWORKSTATUS || - action == GEOIP_CLIENT_NETWORKSTATUS_V2); tor_assert(response < GEOIP_NS_RESPONSE_NUM); - if (action == GEOIP_CLIENT_NETWORKSTATUS) - ns_v3_responses[response]++; - else - ns_v2_responses[response]++; + ns_v3_responses[response]++; } /** Do not mention any country from which fewer than this number of IPs have @@ -736,7 +654,6 @@ typedef struct dirreq_map_entry_t { unsigned int state:3; /**< State of this directory request. */ unsigned int type:1; /**< Is this a direct or a tunneled request? */ unsigned int completed:1; /**< Is this request complete? */ - unsigned int action:2; /**< Is this a v2 or v3 request? */ /** When did we receive the request and started sending the response? */ struct timeval request_time; size_t response_size; /**< What is the size of the response in bytes? */ @@ -805,12 +722,11 @@ dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id) } /** Note that an either direct or tunneled (see <b>type</b>) directory - * request for a network status with unique ID <b>dirreq_id</b> of size - * <b>response_size</b> and action <b>action</b> (either v2 or v3) has - * started. */ + * request for a v3 network status with unique ID <b>dirreq_id</b> of size + * <b>response_size</b> has started. */ void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, - geoip_client_action_t action, dirreq_type_t type) + dirreq_type_t type) { dirreq_map_entry_t *ent; if (!get_options()->DirReqStatistics) @@ -819,7 +735,6 @@ geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, ent->dirreq_id = dirreq_id; tor_gettimeofday(&ent->request_time); ent->response_size = response_size; - ent->action = action; ent->type = type; dirreq_map_put_(ent, type, dirreq_id); } @@ -860,8 +775,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, * times by deciles and quartiles. Return NULL if we have not observed * requests for long enough. */ static char * -geoip_get_dirreq_history(geoip_client_action_t action, - dirreq_type_t type) +geoip_get_dirreq_history(dirreq_type_t type) { char *result = NULL; smartlist_t *dirreq_completed = NULL; @@ -871,13 +785,10 @@ geoip_get_dirreq_history(geoip_client_action_t action, struct timeval now; tor_gettimeofday(&now); - if (action != GEOIP_CLIENT_NETWORKSTATUS && - action != GEOIP_CLIENT_NETWORKSTATUS_V2) - return NULL; dirreq_completed = smartlist_new(); for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) { ent = *ptr; - if (ent->action != action || ent->type != type) { + if (ent->type != type) { next = HT_NEXT(dirreqmap, &dirreq_map, ptr); continue; } else { @@ -1063,18 +974,15 @@ geoip_get_client_history(geoip_client_action_t action, } /** Return a newly allocated string holding the per-country request history - * for <b>action</b> in a format suitable for an extra-info document, or NULL - * on failure. */ + * for v3 network statuses in a format suitable for an extra-info document, + * or NULL on failure. */ char * -geoip_get_request_history(geoip_client_action_t action) +geoip_get_request_history(void) { smartlist_t *entries, *strings; char *result; unsigned granularity = IP_GRANULARITY; - if (action != GEOIP_CLIENT_NETWORKSTATUS && - action != GEOIP_CLIENT_NETWORKSTATUS_V2) - return NULL; if (!geoip_countries) return NULL; @@ -1082,8 +990,7 @@ geoip_get_request_history(geoip_client_action_t action) SMARTLIST_FOREACH_BEGIN(geoip_countries, geoip_country_t *, c) { uint32_t tot = 0; c_hist_t *ent; - tot = (action == GEOIP_CLIENT_NETWORKSTATUS) ? - c->n_v3_ns_requests : c->n_v2_ns_requests; + tot = c->n_v3_ns_requests; if (!tot) continue; ent = tor_malloc_zero(sizeof(c_hist_t)); @@ -1121,14 +1028,13 @@ void geoip_reset_dirreq_stats(time_t now) { SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, { - c->n_v2_ns_requests = c->n_v3_ns_requests = 0; + c->n_v3_ns_requests = 0; }); { clientmap_entry_t **ent, **next, *this; for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) { - if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS || - (*ent)->action == GEOIP_CLIENT_NETWORKSTATUS_V2) { + if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS) { this = *ent; next = HT_NEXT_RMV(clientmap, &client_history, ent); tor_free(this); @@ -1137,10 +1043,6 @@ geoip_reset_dirreq_stats(time_t now) } } } - v2_share_times_seconds = v3_share_times_seconds = 0.0; - last_time_determined_shares = 0; - share_seconds = 0; - memset(ns_v2_responses, 0, sizeof(ns_v2_responses)); memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); { dirreq_map_entry_t **ent, **next, *this; @@ -1168,12 +1070,9 @@ char * geoip_format_dirreq_stats(time_t now) { char t[ISO_TIME_LEN+1]; - double v2_share = 0.0, v3_share = 0.0; int i; - char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string, - *v2_share_string = NULL, *v3_share_string = NULL, - *v3_direct_dl_string, *v2_direct_dl_string, - *v3_tunneled_dl_string, *v2_tunneled_dl_string; + char *v3_ips_string, *v3_reqs_string, *v3_direct_dl_string, + *v3_tunneled_dl_string; char *result; if (!start_of_dirreq_stats_interval) @@ -1182,90 +1081,45 @@ geoip_format_dirreq_stats(time_t now) tor_assert(now >= start_of_dirreq_stats_interval); format_iso_time(t, now); - geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2, &v2_ips_string, - NULL); geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS, &v3_ips_string, NULL); - v2_reqs_string = geoip_get_request_history( - GEOIP_CLIENT_NETWORKSTATUS_V2); - v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS); + v3_reqs_string = geoip_get_request_history(); #define RESPONSE_GRANULARITY 8 for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) { - ns_v2_responses[i] = round_uint32_to_next_multiple_of( - ns_v2_responses[i], RESPONSE_GRANULARITY); ns_v3_responses[i] = round_uint32_to_next_multiple_of( ns_v3_responses[i], RESPONSE_GRANULARITY); } #undef RESPONSE_GRANULARITY - if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) { - tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2f%%\n", - v2_share*100); - tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2f%%\n", - v3_share*100); - } - - v2_direct_dl_string = geoip_get_dirreq_history( - GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT); - v3_direct_dl_string = geoip_get_dirreq_history( - GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT); - - v2_tunneled_dl_string = geoip_get_dirreq_history( - GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED); - v3_tunneled_dl_string = geoip_get_dirreq_history( - GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED); + v3_direct_dl_string = geoip_get_dirreq_history(DIRREQ_DIRECT); + v3_tunneled_dl_string = geoip_get_dirreq_history(DIRREQ_TUNNELED); /* Put everything together into a single string. */ tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n" "dirreq-v3-ips %s\n" - "dirreq-v2-ips %s\n" "dirreq-v3-reqs %s\n" - "dirreq-v2-reqs %s\n" "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u," "not-found=%u,not-modified=%u,busy=%u\n" - "dirreq-v2-resp ok=%u,unavailable=%u," - "not-found=%u,not-modified=%u,busy=%u\n" - "%s" - "%s" "dirreq-v3-direct-dl %s\n" - "dirreq-v2-direct-dl %s\n" - "dirreq-v3-tunneled-dl %s\n" - "dirreq-v2-tunneled-dl %s\n", + "dirreq-v3-tunneled-dl %s\n", t, (unsigned) (now - start_of_dirreq_stats_interval), v3_ips_string ? v3_ips_string : "", - v2_ips_string ? v2_ips_string : "", v3_reqs_string ? v3_reqs_string : "", - v2_reqs_string ? v2_reqs_string : "", ns_v3_responses[GEOIP_SUCCESS], ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS], ns_v3_responses[GEOIP_REJECT_UNAVAILABLE], ns_v3_responses[GEOIP_REJECT_NOT_FOUND], ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED], ns_v3_responses[GEOIP_REJECT_BUSY], - ns_v2_responses[GEOIP_SUCCESS], - ns_v2_responses[GEOIP_REJECT_UNAVAILABLE], - ns_v2_responses[GEOIP_REJECT_NOT_FOUND], - ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED], - ns_v2_responses[GEOIP_REJECT_BUSY], - v2_share_string ? v2_share_string : "", - v3_share_string ? v3_share_string : "", v3_direct_dl_string ? v3_direct_dl_string : "", - v2_direct_dl_string ? v2_direct_dl_string : "", - v3_tunneled_dl_string ? v3_tunneled_dl_string : "", - v2_tunneled_dl_string ? v2_tunneled_dl_string : ""); + v3_tunneled_dl_string ? v3_tunneled_dl_string : ""); /* Free partial strings. */ tor_free(v3_ips_string); - tor_free(v2_ips_string); tor_free(v3_reqs_string); - tor_free(v2_reqs_string); - tor_free(v2_share_string); - tor_free(v3_share_string); tor_free(v3_direct_dl_string); - tor_free(v2_direct_dl_string); tor_free(v3_tunneled_dl_string); - tor_free(v2_tunneled_dl_string); return result; } diff --git a/src/or/geoip.h b/src/or/geoip.h index 60d44a5536..ebefee5f4e 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -30,18 +30,17 @@ void geoip_note_client_seen(geoip_client_action_t action, const tor_addr_t *addr, time_t now); void geoip_remove_old_clients(time_t cutoff); -void geoip_note_ns_response(geoip_client_action_t action, - geoip_ns_response_t response); +void geoip_note_ns_response(geoip_ns_response_t response); int geoip_get_client_history(geoip_client_action_t action, char **country_str, char **ipver_str); -char *geoip_get_request_history(geoip_client_action_t action); +char *geoip_get_request_history(void); int getinfo_helper_geoip(control_connection_t *control_conn, const char *question, char **answer, const char **errmsg); void geoip_free_all(void); void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, - geoip_client_action_t action, dirreq_type_t type); + dirreq_type_t type); void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, dirreq_state_t new_state); diff --git a/src/or/main.c b/src/or/main.c index 1dd207a753..79b0f25778 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -973,7 +973,7 @@ directory_info_has_arrived(time_t now, int from_cache) if (!router_have_minimum_dir_info()) { int quiet = from_cache || directory_too_idle_to_fetch_descriptors(options, now); - log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, + tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "I learned some more directory information, but not enough to " "build a circuit: %s", get_dir_info_status_string()); update_all_descriptor_downloads(now); @@ -1201,7 +1201,7 @@ run_scheduled_events(time_t now) * eventually. */ if (signewnym_is_pending && time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) { - log(LOG_INFO, LD_CONTROL, "Honoring delayed NEWNYM request"); + log_info(LD_CONTROL, "Honoring delayed NEWNYM request"); signewnym_impl(now); } @@ -2083,7 +2083,7 @@ process_signal(uintptr_t sig) time_t now = time(NULL); if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) { signewnym_is_pending = 1; - log(LOG_NOTICE, LD_CONTROL, + log_notice(LD_CONTROL, "Rate limiting NEWNYM request: delaying by %d second(s)", (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); } else { @@ -2115,7 +2115,7 @@ static void dumpmemusage(int severity) { connection_dump_buffer_mem_stats(severity); - log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", + tor_log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num); dump_routerlist_mem_usage(severity); dump_cell_pool_usage(severity); @@ -2133,27 +2133,27 @@ dumpstats(int severity) time_t elapsed; size_t rbuf_cap, wbuf_cap, rbuf_len, wbuf_len; - log(severity, LD_GENERAL, "Dumping stats:"); + tor_log(severity, LD_GENERAL, "Dumping stats:"); SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { int i = conn_sl_idx; - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", i, (int)conn->s, conn->type, conn_type_to_string(conn->type), conn->state, conn_state_to_string(conn->type, conn->state), (int)(now - conn->timestamp_created)); if (!connection_is_listener(conn)) { - log(severity,LD_GENERAL, + tor_log(severity,LD_GENERAL, "Conn %d is to %s:%d.", i, safe_str_client(conn->address), conn->port); - log(severity,LD_GENERAL, + tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)", i, (int)connection_get_inbuf_len(conn), (int)buf_allocation(conn->inbuf), (int)(now - conn->timestamp_lastread)); - log(severity,LD_GENERAL, + tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on outbuf " "(len %d, last written %d secs ago)",i, (int)connection_get_outbuf_len(conn), @@ -2164,7 +2164,7 @@ dumpstats(int severity) if (or_conn->tls) { tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len, &wbuf_cap, &wbuf_len); - log(severity, LD_GENERAL, + tor_log(severity, LD_GENERAL, "Conn %d: %d/%d bytes used on OpenSSL read buffer; " "%d/%d bytes used on write buffer.", i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap); @@ -2178,7 +2178,7 @@ dumpstats(int severity) channel_dumpstats(severity); channel_listener_dumpstats(severity); - log(severity, LD_NET, + tor_log(severity, LD_NET, "Cells processed: "U64_FORMAT" padding\n" " "U64_FORMAT" create\n" " "U64_FORMAT" created\n" @@ -2194,33 +2194,36 @@ dumpstats(int severity) U64_PRINTF_ARG(stats_n_relay_cells_delivered), U64_PRINTF_ARG(stats_n_destroy_cells_processed)); if (stats_n_data_cells_packaged) - log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", + tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); if (stats_n_data_cells_received) - log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", + tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_received) / U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); + cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP"); + cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor"); + if (now - time_of_process_start >= 0) elapsed = now - time_of_process_start; else elapsed = 0; if (elapsed) { - log(severity, LD_NET, + tor_log(severity, LD_NET, "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec reading", U64_PRINTF_ARG(stats_n_bytes_read), (int)elapsed, (int) (stats_n_bytes_read/elapsed)); - log(severity, LD_NET, + tor_log(severity, LD_NET, "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec writing", U64_PRINTF_ARG(stats_n_bytes_written), (int)elapsed, (int) (stats_n_bytes_written/elapsed)); } - log(severity, LD_NET, "--------------- Dumping memory information:"); + tor_log(severity, LD_NET, "--------------- Dumping memory information:"); dumpmemusage(severity); rep_hist_dump_stats(now,severity); @@ -2361,7 +2364,7 @@ tor_init(int argc, char *argv[]) } #ifdef NON_ANONYMOUS_MODE_ENABLED - log(LOG_WARN, LD_GENERAL, "This copy of Tor was compiled to run in a " + log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " "non-anonymous mode. It will provide NO ANONYMITY."); #endif diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 79dd706c47..71ac054f88 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -561,7 +561,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, if (warn >= 0) { SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter, { - log(severity, LD_DIR, "Consensus includes unrecognized authority " + tor_log(severity, LD_DIR, "Consensus includes unrecognized authority " "'%s' at %s:%d (contact %s; identity %s)", voter->nickname, voter->address, (int)voter->dir_port, voter->contact?voter->contact:"n/a", @@ -569,7 +569,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, }); SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter, { - log(severity, LD_DIR, "Looks like we need to download a new " + tor_log(severity, LD_DIR, "Looks like we need to download a new " "certificate from authority '%s' at %s:%d (contact %s; " "identity %s)", voter->nickname, voter->address, (int)voter->dir_port, @@ -578,7 +578,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, }); SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds, { - log(severity, LD_DIR, "Consensus does not include configured " + tor_log(severity, LD_DIR, "Consensus does not include configured " "authority '%s' at %s:%d (identity %s)", ds->nickname, ds->address, (int)ds->dir_port, hex_str(ds->v3_identity_digest, DIGEST_LEN)); @@ -614,7 +614,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, "because we were missing the keys.", n_missing_key); } joined = smartlist_join_strings(sl, " ", 0, NULL); - log(severity, LD_DIR, "%s", joined); + tor_log(severity, LD_DIR, "%s", joined); tor_free(joined); SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); smartlist_free(sl); @@ -2239,6 +2239,21 @@ networkstatus_get_param(const networkstatus_t *ns, const char *param_name, default_val, min_val, max_val); } +/** + * Retrieve the consensus parameter that governs the + * fixed-point precision of our network balancing 'bandwidth-weights' + * (which are themselves integer consensus values). We divide them + * by this value and ensure they never exceed this value. + */ +int +networkstatus_get_weight_scale_param(networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "bwweightscale", + BW_WEIGHT_SCALE, + BW_MIN_WEIGHT_SCALE, + BW_MAX_WEIGHT_SCALE); +} + /** Return the value of a integer bw weight parameter from the networkstatus * <b>ns</b> whose name is <b>weight_name</b>. If <b>ns</b> is NULL, try * loading the latest consensus ourselves. Return <b>default_val</b> if no @@ -2255,7 +2270,7 @@ networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name, if (!ns || !ns->weight_params) return default_val; - max = circuit_build_times_get_bw_scale(ns); + max = networkstatus_get_weight_scale_param(ns); param = get_net_param_from_list(ns->weight_params, weight_name, default_val, -1, BW_MAX_WEIGHT_SCALE); diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index d6d6a036cd..b437c5ec2f 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -112,6 +112,7 @@ int networkstatus_parse_flavor_name(const char *flavname); void document_signature_free(document_signature_t *sig); document_signature_t *document_signature_dup(const document_signature_t *sig); void networkstatus_free_all(void); +int networkstatus_get_weight_scale_param(networkstatus_t *ns); #endif diff --git a/src/or/nodelist.c b/src/or/nodelist.c index e444c73247..9f77dcafed 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -1213,7 +1213,7 @@ static int have_min_dir_info = 0; static int need_to_update_have_min_dir_info = 1; /** String describing what we're missing before we have enough directory * info. */ -static char dir_info_status[128] = ""; +static char dir_info_status[256] = ""; /** Return true iff we have enough networkstatus and router information to * start building circuits. Right now, this means "more than half the @@ -1253,10 +1253,12 @@ get_dir_info_status_string(void) * descriptors for. Store the former in *<b>num_usable</b> and the latter in * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes - * with the Exit flag. + * with the Exit flag. If *descs_out is present, add a node_t for each + * usable descriptor to it. */ static void count_usable_descriptors(int *num_present, int *num_usable, + smartlist_t *descs_out, const networkstatus_t *consensus, const or_options_t *options, time_t now, routerset_t *in_set, int exit_only) @@ -1266,6 +1268,10 @@ count_usable_descriptors(int *num_present, int *num_usable, SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs) { + const node_t *node = node_get_by_id(rs->identity_digest); + if (!node) + continue; /* This would be a bug: every entry in the consensus is + * supposed to have a node. */ if (exit_only && ! rs->is_exit) continue; if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1)) @@ -1282,6 +1288,8 @@ count_usable_descriptors(int *num_present, int *num_usable, /* we have the descriptor listed in the consensus. */ ++*num_present; } + if (descs_out) + smartlist_add(descs_out, (node_t*)node); } } SMARTLIST_FOREACH_END(rs); @@ -1291,6 +1299,66 @@ count_usable_descriptors(int *num_present, int *num_usable, md ? "microdesc" : "desc", exit_only ? " exits" : "s"); } +/** Return an extimate of which fraction of usable paths through the Tor + * network we have available for use. */ +static double +compute_frac_paths_available(const networkstatus_t *consensus, + const or_options_t *options, time_t now, + int *num_present_out, int *num_usable_out, + char **status_out) +{ + smartlist_t *guards = smartlist_new(); + smartlist_t *mid = smartlist_new(); + smartlist_t *exits = smartlist_new(); + smartlist_t *myexits= smartlist_new(); + double f_guard, f_mid, f_exit, f_myexit; + int np, nu; /* Ignored */ + + count_usable_descriptors(num_present_out, num_usable_out, + mid, consensus, options, now, NULL, 0); + if (options->EntryNodes) { + count_usable_descriptors(&np, &nu, guards, consensus, options, now, + options->EntryNodes, 0); + } else { + SMARTLIST_FOREACH(mid, const node_t *, node, { + if (node->is_possible_guard) + smartlist_add(guards, (node_t*)node); + }); + } + + count_usable_descriptors(&np, &nu, exits, consensus, options, now, + NULL, 1); + count_usable_descriptors(&np, &nu, myexits, consensus, options, now, + options->ExitNodes, 1); + + f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); + f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); + f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); + f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); + + smartlist_free(guards); + smartlist_free(mid); + smartlist_free(exits); + smartlist_free(myexits); + + /* This is a tricky point here: we don't want to make it easy for a + * directory to trickle exits to us until it learns which exits we have + * configured, so require that we have a threshold both of total exits + * and usable exits. */ + if (f_myexit < f_exit) + f_exit = f_myexit; + + tor_asprintf(status_out, + "%d%% of guards bw, " + "%d%% of midpoint bw, and " + "%d%% of exit bw", + (int)(f_guard*100), + (int)(f_mid*100), + (int)(f_exit*100)); + + return f_guard * f_mid * f_exit; +} + /** We just fetched a new set of descriptors. Compute how far through * the "loading descriptors" bootstrapping phase we are, so we can inform * the controller of our progress. */ @@ -1306,7 +1374,7 @@ count_loading_descriptors_progress(void) if (!consensus) return 0; /* can't count descriptors if we have no list of them */ - count_usable_descriptors(&num_present, &num_usable, + count_usable_descriptors(&num_present, &num_usable, NULL, consensus, get_options(), now, NULL, 0); if (num_usable == 0) @@ -1319,14 +1387,28 @@ count_loading_descriptors_progress(void) BOOTSTRAP_STATUS_LOADING_DESCRIPTORS)); } +/** Return the fraction of paths needed before we're willing to build + * circuits, as configured in <b>options</b>, or in the consensus <b>ns</b>. */ +static double +get_frac_paths_needed_for_circs(const or_options_t *options, + const networkstatus_t *ns) +{ +#define DFLT_PCT_USABLE_NEEDED 60 + if (options->PathsNeededToBuildCircuits >= 1.0) { + return options->PathsNeededToBuildCircuits; + } else { + return networkstatus_get_param(ns, "min_paths_for_circs_pct", + DFLT_PCT_USABLE_NEEDED, + 25, 95)/100.0; + } +} + /** Change the value of have_min_dir_info, setting it true iff we have enough * network and router information to build circuits. Clear the value of * need_to_update_have_min_dir_info. */ static void update_router_have_minimum_dir_info(void) { - int num_present = 0, num_usable=0; - int num_exit_present = 0, num_exit_usable = 0; time_t now = time(NULL); int res; const or_options_t *options = get_options(); @@ -1355,66 +1437,40 @@ update_router_have_minimum_dir_info(void) using_md = consensus->flavor == FLAV_MICRODESC; - count_usable_descriptors(&num_present, &num_usable, consensus, options, now, - NULL, 0); - count_usable_descriptors(&num_exit_present, &num_exit_usable, - consensus, options, now, options->ExitNodes, 1); - -/* What fraction of desired server descriptors do we need before we will - * build circuits? */ -#define FRAC_USABLE_NEEDED .75 -/* What fraction of desired _exit_ server descriptors do we need before we - * will build circuits? */ -#define FRAC_EXIT_USABLE_NEEDED .5 - - if (num_present < num_usable * FRAC_USABLE_NEEDED) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable %sdescriptors.", - num_present, num_usable, using_md ? "micro" : ""); - res = 0; - control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); - goto done; - } else if (num_present < 2) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "Only %d %sdescriptor%s here and believed reachable!", - num_present, using_md ? "micro" : "", num_present ? "" : "s"); - res = 0; - goto done; - } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable exit node descriptors.", - num_exit_present, num_exit_usable); - res = 0; - control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); - goto done; - } - - /* Check for entry nodes. */ - if (options->EntryNodes) { - count_usable_descriptors(&num_present, &num_usable, consensus, options, - now, options->EntryNodes, 0); + { + char *status = NULL; + int num_present=0, num_usable=0; + double paths = compute_frac_paths_available(consensus, options, now, + &num_present, &num_usable, + &status); - if (!num_usable || !num_present) { + if (paths < get_frac_paths_needed_for_circs(options,consensus)) { tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable entry node %sdescriptors.", - num_present, num_usable, using_md?"micro":""); + "We need more %sdescriptors: we have %d/%d, and " + "can only build %d%% of likely paths. (We have %s.)", + using_md?"micro":"", num_present, num_usable, + (int)(paths*100), status); + /* log_notice(LD_NET, "%s", dir_info_status); */ + tor_free(status); res = 0; + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); goto done; } - } - res = 1; + tor_free(status); + res = 1; + } done: if (res && !have_min_dir_info) { - log(LOG_NOTICE, LD_DIR, + log_notice(LD_DIR, "We now have enough directory information to build circuits."); control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0); } if (!res && have_min_dir_info) { int quiet = directory_too_idle_to_fetch_descriptors(options, now); - log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, + tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "Our directory information is no longer up-to-date " "enough to build circuits: %s", dir_info_status); diff --git a/src/or/onion.c b/src/or/onion.c index 4625346f25..b9f5aa6c7d 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -13,6 +13,7 @@ #include "or.h" #include "circuitlist.h" #include "config.h" +#include "cpuworker.h" #include "onion.h" #include "onion_fast.h" #include "onion_ntor.h" @@ -20,29 +21,71 @@ #include "relay.h" #include "rephist.h" #include "router.h" +#include "tor_queue.h" /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { + TOR_TAILQ_ENTRY(onion_queue_t) next; or_circuit_t *circ; create_cell_t *onionskin; time_t when_added; - struct onion_queue_t *next; } onion_queue_t; /** 5 seconds on the onion queue til we just send back a destroy */ #define ONIONQUEUE_WAIT_CUTOFF 5 -/** First and last elements in the linked list of circuits waiting for CPU - * workers, or NULL if the list is empty. - * @{ */ -static onion_queue_t *ol_list=NULL; -static onion_queue_t *ol_tail=NULL; -/**@}*/ -/** Length of ol_list */ -static int ol_length=0; +/** Queue of circuits waiting for CPU workers, or NULL if the list is empty.*/ +TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list = + TOR_TAILQ_HEAD_INITIALIZER(ol_list); -/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN */ +/** Number of entries of each type currently in ol_list. */ +static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; + +static void onion_queue_entry_remove(onion_queue_t *victim); + +/* XXXX024 Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN. + * + * (By which I think I meant, "make sure that no + * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than + * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN." Also, make sure that we can pass + * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/ + +/** Return true iff we have room to queue another oninoskin of type + * <b>type</b>. */ +static int +have_room_for_onionskin(uint16_t type) +{ + const or_options_t *options = get_options(); + int num_cpus; + uint64_t tap_usec, ntor_usec; + /* If we've got fewer than 50 entries, we always have room for one more. */ + if (ol_entries[ONION_HANDSHAKE_TYPE_TAP] + + ol_entries[ONION_HANDSHAKE_TYPE_NTOR] < 50) + return 1; + num_cpus = get_num_cpus(options); + /* Compute how many microseconds we'd expect to need to clear all + * onionskins in the current queue. */ + tap_usec = estimated_usec_for_onionskins( + ol_entries[ONION_HANDSHAKE_TYPE_TAP], + ONION_HANDSHAKE_TYPE_TAP) / num_cpus; + ntor_usec = estimated_usec_for_onionskins( + ol_entries[ONION_HANDSHAKE_TYPE_NTOR], + ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; + /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue + * this. */ + if ((tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) + return 0; +#ifdef CURVE25519_ENABLED + /* If we support the ntor handshake, then don't let TAP handshakes use + * more than 2/3 of the space on the queue. */ + if (type == ONION_HANDSHAKE_TYPE_TAP && + tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3) + return 0; +#endif + + return 1; +} /** Add <b>circ</b> to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. @@ -58,19 +101,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) tmp->onionskin = onionskin; tmp->when_added = now; - if (!ol_tail) { - tor_assert(!ol_list); - tor_assert(!ol_length); - ol_list = tmp; - ol_tail = tmp; - ol_length++; - return 0; - } - - tor_assert(ol_list); - tor_assert(!ol_tail->next); - - if (ol_length >= get_options()->MaxOnionsPending) { + if (!have_room_for_onionskin(onionskin->handshake_type)) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); @@ -87,13 +118,19 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) return -1; } - ol_length++; - ol_tail->next = tmp; - ol_tail = tmp; - while ((int)(now - ol_list->when_added) >= ONIONQUEUE_WAIT_CUTOFF) { - /* cull elderly requests. */ - circ = ol_list->circ; - onion_pending_remove(ol_list->circ); + ++ol_entries[onionskin->handshake_type]; + circ->onionqueue_entry = tmp; + TOR_TAILQ_INSERT_TAIL(&ol_list, tmp, next); + + /* cull elderly requests. */ + while (1) { + onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); + if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) + break; + + circ = head->circ; + circ->onionqueue_entry = NULL; + onion_queue_entry_remove(head); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); @@ -108,17 +145,21 @@ or_circuit_t * onion_next_task(create_cell_t **onionskin_out) { or_circuit_t *circ; + onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list); - if (!ol_list) + if (!head) return NULL; /* no onions pending, we're done */ - tor_assert(ol_list->circ); - tor_assert(ol_list->circ->p_chan); /* make sure it's still valid */ - tor_assert(ol_length > 0); - circ = ol_list->circ; - *onionskin_out = ol_list->onionskin; - ol_list->onionskin = NULL; /* prevent free. */ - onion_pending_remove(ol_list->circ); + tor_assert(head->circ); + tor_assert(head->circ->p_chan); /* make sure it's still valid */ + circ = head->circ; + if (head->onionskin && + head->onionskin->handshake_type <= MAX_ONION_HANDSHAKE_TYPE) + --ol_entries[head->onionskin->handshake_type]; + *onionskin_out = head->onionskin; + head->onionskin = NULL; /* prevent free. */ + circ->onionqueue_entry = NULL; + onion_queue_entry_remove(head); return circ; } @@ -128,37 +169,29 @@ onion_next_task(create_cell_t **onionskin_out) void onion_pending_remove(or_circuit_t *circ) { - onion_queue_t *tmpo, *victim; - - if (!ol_list) - return; /* nothing here. */ - - /* first check to see if it's the first entry */ - tmpo = ol_list; - if (tmpo->circ == circ) { - /* it's the first one. remove it from the list. */ - ol_list = tmpo->next; - if (!ol_list) - ol_tail = NULL; - ol_length--; - victim = tmpo; - } else { /* we need to hunt through the rest of the list */ - for ( ;tmpo->next && tmpo->next->circ != circ; tmpo=tmpo->next) ; - if (!tmpo->next) { - log_debug(LD_GENERAL, - "circ (p_circ_id %d) not in list, probably at cpuworker.", - circ->p_circ_id); - return; - } - /* now we know tmpo->next->circ == circ */ - victim = tmpo->next; - tmpo->next = victim->next; - if (ol_tail == victim) - ol_tail = tmpo; - ol_length--; - } + onion_queue_t *victim; + + if (!circ) + return; + + victim = circ->onionqueue_entry; + if (victim) + onion_queue_entry_remove(victim); +} + +/** Remove a queue entry <b>victim</b> from the queue, unlinking it from + * its circuit and freeing it and any structures it owns.*/ +static void +onion_queue_entry_remove(onion_queue_t *victim) +{ + TOR_TAILQ_REMOVE(&ol_list, victim, next); + + if (victim->circ) + victim->circ->onionqueue_entry = NULL; - /* now victim points to the element that needs to be removed */ + if (victim->onionskin && + victim->onionskin->handshake_type <= MAX_ONION_HANDSHAKE_TYPE) + --ol_entries[victim->onionskin->handshake_type]; tor_free(victim->onionskin); tor_free(victim); @@ -168,14 +201,11 @@ onion_pending_remove(or_circuit_t *circ) void clear_pending_onions(void) { - while (ol_list) { - onion_queue_t *victim = ol_list; - ol_list = victim->next; - tor_free(victim->onionskin); - tor_free(victim); + onion_queue_t *victim; + while ((victim = TOR_TAILQ_FIRST(&ol_list))) { + onion_queue_entry_remove(victim); } - ol_list = ol_tail = NULL; - ol_length = 0; + memset(ol_entries, 0, sizeof(ol_entries)); } /* ============================================================ */ diff --git a/src/or/or.h b/src/or/or.h index 328e8dfa7f..a0a921a9f4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2584,6 +2584,7 @@ struct ntor_handshake_state_t; #define ONION_HANDSHAKE_TYPE_TAP 0x0000 #define ONION_HANDSHAKE_TYPE_FAST 0x0001 #define ONION_HANDSHAKE_TYPE_NTOR 0x0002 +#define MAX_ONION_HANDSHAKE_TYPE 0x0002 typedef struct { uint16_t tag; union { @@ -2826,8 +2827,18 @@ typedef struct circuit_t { /** * Describes the circuit building process in simplified terms based - * on the path bias accounting state for a circuit. Created to prevent - * overcounting due to unknown cases of circuit reuse. See Bug #6475. + * on the path bias accounting state for a circuit. + * + * NOTE: These state values are enumerated in the order for which we + * expect circuits to transition through them. If you add states, + * you need to preserve this overall ordering. The various pathbias + * state transition and accounting functions (pathbias_mark_* and + * pathbias_count_*) contain ordinal comparisons to enforce proper + * state transitions for corrections. + * + * This state machine and the associated logic was created to prevent + * miscounting due to unknown cases of circuit reuse. See also tickets + * #6475 and #7802. */ typedef enum { /** This circuit is "new". It has not yet completed a first hop @@ -2838,7 +2849,7 @@ typedef enum { PATH_STATE_BUILD_ATTEMPTED = 1, /** This circuit has been completely built */ PATH_STATE_BUILD_SUCCEEDED = 2, - /** Did any SOCKS streams or hidserv introductions actually succeed on + /** Did we try to attach any SOCKS streams or hidserv introductions to * this circuit? * * Note: If we ever implement end-to-end stream timing through test @@ -2846,13 +2857,28 @@ typedef enum { * (or any other automatic streams) because the adversary could * just tag at a later point. */ - PATH_STATE_USE_SUCCEEDED = 3, + PATH_STATE_USE_ATTEMPTED = 3, + /** Did any SOCKS streams or hidserv introductions actually succeed on + * this circuit? + * + * If any streams detatch/fail from this circuit, the code transitions + * the circuit back to PATH_STATE_USE_ATTEMPTED to ensure we probe. See + * pathbias_mark_use_rollback() for that. + */ + PATH_STATE_USE_SUCCEEDED = 4, /** * This is a special state to indicate that we got a corrupted * relay cell on a circuit and we don't intend to probe it. */ - PATH_STATE_USE_FAILED = 4, + PATH_STATE_USE_FAILED = 5, + + /** + * This is a special state to indicate that we already counted + * the circuit. Used to guard against potential state machine + * violations. + */ + PATH_STATE_ALREADY_COUNTED = 6, } path_state_t; /** An origin_circuit_t holds data necessary to build and use a circuit. @@ -2888,10 +2914,25 @@ typedef struct origin_circuit_t { * cannibalized circuits. */ unsigned int has_opened : 1; - /** Kludge to help us prevent the warn in bug #6475 and eventually - * debug why we are not seeing first hops in some cases. */ + /** + * Path bias state machine. Used to ensure integrity of our + * circuit building and usage accounting. See path_state_t + * for more details. + */ ENUM_BF(path_state_t) path_state : 3; + /** + * Tristate variable to guard against pathbias miscounting + * due to circuit purpose transitions changing the decision + * of pathbias_should_count(). This variable is informational + * only. The current results of pathbias_should_count() are + * the official decision for pathbias accounting. + */ + uint8_t pathbias_shouldcount; +#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0 +#define PATHBIAS_SHOULDCOUNT_IGNORED 1 +#define PATHBIAS_SHOULDCOUNT_COUNTED 2 + /** For path probing. Store the temporary probe stream ID * for response comparison */ streamid_t pathbias_probe_id; @@ -2997,9 +3038,10 @@ typedef struct origin_circuit_t { * ISO_STREAM. */ uint64_t associated_isolated_stream_global_id; /**@}*/ - } origin_circuit_t; +struct onion_queue_t; + /** An or_circuit_t holds information needed to implement a circuit at an * OR. */ typedef struct or_circuit_t { @@ -3013,6 +3055,9 @@ typedef struct or_circuit_t { * cells to p_chan. NULL if we have no cells pending, or if we're not * linked to an OR connection. */ struct circuit_t *prev_active_on_p_chan; + /** Pointer to an entry on the onion queue, if this circuit is waiting for a + * chance to give an onionskin to a cpuworker. Used only in onion.c */ + struct onion_queue_t *onionqueue_entry; /** The circuit_id used in the previous (backward) hop of this circuit. */ circid_t p_circ_id; @@ -3496,9 +3541,7 @@ typedef struct { * and try a new circuit if the stream has been * waiting for this many seconds. If zero, use * our default internal timeout schedule. */ - int MaxOnionsPending; /**< How many circuit CREATE requests do we allow - * to wait simultaneously before we start dropping - * them? */ + int MaxOnionQueueDelay; /**<DOCDOC*/ int NewCircuitPeriod; /**< How long do we use a circuit before building * a new one? */ int MaxCircuitDirtiness; /**< Never use circs that were first used more than @@ -3912,9 +3955,16 @@ typedef struct { double PathBiasExtremeRate; int PathBiasDropGuards; int PathBiasScaleThreshold; - int PathBiasScaleFactor; - int PathBiasMultFactor; - int PathBiasUseCloseCounts; + /** @} */ + + /** + * Parameters for path-bias use detection + * @{ + */ + int PathBiasUseThreshold; + double PathBiasNoticeUseRate; + double PathBiasExtremeUseRate; + int PathBiasScaleUseThreshold; /** @} */ int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */ @@ -3923,6 +3973,9 @@ typedef struct { /** Autobool: should we use the ntor handshake if we can? */ int UseNTorHandshake; + + /** Fraction: */ + double PathsNeededToBuildCircuits; } or_options_t; /** Persistent state for an onion router, as saved to disk. */ diff --git a/src/or/policies.c b/src/or/policies.c index f9a03aef2c..9696b8123b 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -881,7 +881,7 @@ exit_policy_remove_redundancies(smartlist_t *dest) char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN]; policy_write_item(p1, sizeof(p1), tmp, 0); policy_write_item(p2, sizeof(p2), ap, 0); - log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s (%d). It is made " + log_debug(LD_CONFIG, "Removing exit policy %s (%d). It is made " "redundant by %s (%d).", p1, j, p2, i); smartlist_del_keeporder(dest, j--); addr_policy_free(tmp); @@ -910,7 +910,7 @@ exit_policy_remove_redundancies(smartlist_t *dest) char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN]; policy_write_item(p1, sizeof(p1), ap, 0); policy_write_item(p2, sizeof(p2), tmp, 0); - log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s. It is already " + log_debug(LD_CONFIG, "Removing exit policy %s. It is already " "covered by %s.", p1, p2); smartlist_del_keeporder(dest, i--); addr_policy_free(ap); diff --git a/src/or/relay.c b/src/or/relay.c index bb3a835442..3ae5b47ba5 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -730,7 +730,7 @@ connection_ap_process_end_not_open( * We rely on recognized+digest being strong enough to make * tags unlikely to allow us to get tagged, yet 'recognized' * reason codes here. */ - circ->path_state = PATH_STATE_USE_SUCCEEDED; + pathbias_mark_use_success(circ); } } @@ -1443,7 +1443,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, /*XXXX024: Downgrade this back to LOG_PROTOCOL_WARN after a while*/ log_fn(LOG_WARN, LD_PROTOCOL, "Bug/attack: unexpected sendme cell from client. " - "Closing circ."); + "Closing circ (window %d).", + circ->package_window); return -END_CIRC_REASON_TORPROTOCOL; } circ->package_window += CIRCWINDOW_INCREMENT; @@ -2023,8 +2024,9 @@ dump_cell_pool_usage(int severity) n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n; ++n_circs; } - log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.", - n_cells, n_circs, total_cells_allocated - n_cells); + tor_log(severity, LD_MM, + "%d cells allocated on %d circuits. %d cells leaked.", + n_cells, n_circs, total_cells_allocated - n_cells); mp_pool_log_status(cell_pool, severity); } diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 32623c3f40..61e3b917e3 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -71,6 +71,9 @@ rend_client_send_establish_rendezvous(origin_circuit_t *circ) * and the rend cookie also means we've used the circ. */ circ->base_.timestamp_dirty = time(NULL); + /* We've attempted to use this circuit. Probe it if we fail */ + pathbias_count_use_attempt(circ); + if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_RENDEZVOUS, circ->rend_data->rend_cookie, @@ -316,6 +319,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, * state. */ introcirc->base_.timestamp_dirty = time(NULL); + pathbias_count_use_attempt(introcirc); + goto cleanup; perm_err: @@ -395,7 +400,7 @@ rend_client_introduction_acked(origin_circuit_t *circ, /* For path bias: This circuit was used successfully. Valid * nacks and acks count. */ - circ->path_state = PATH_STATE_USE_SUCCEEDED; + pathbias_mark_use_success(circ); if (request_len == 0) { /* It's an ACK; the introduction point relayed our introduction request. */ @@ -902,7 +907,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, * Waiting any longer opens us up to attacks from Bob. He could induce * Alice to attempt to connect to his hidden service and never reply * to her rend requests */ - circ->path_state = PATH_STATE_USE_SUCCEEDED; + pathbias_mark_use_success(circ); /* XXXX This is a pretty brute-force approach. It'd be better to * attach only the connections that are waiting on this circuit, rather diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 6ffa4f8f95..f85ac2c03b 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1384,9 +1384,6 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, goto err; memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN); - /* For path bias: This intro circuit was used successfully */ - circuit->path_state = PATH_STATE_USE_SUCCEEDED; - goto done; log_error: @@ -2511,6 +2508,9 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) goto err; } + /* We've attempted to use this circuit */ + pathbias_count_use_attempt(circuit); + goto done; err: @@ -2558,6 +2558,10 @@ rend_service_intro_established(origin_circuit_t *circuit, "Received INTRO_ESTABLISHED cell on circuit %d for service %s", circuit->base_.n_circ_id, serviceid); + /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully + * used the circ */ + pathbias_mark_use_success(circuit); + return 0; err: circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL); @@ -2589,6 +2593,9 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) if (!circuit->base_.timestamp_dirty) circuit->base_.timestamp_dirty = time(NULL); + /* This may be redundant */ + pathbias_count_use_attempt(circuit); + hop = circuit->build_state->service_pending_final_cpath_ref->cpath; base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4); @@ -3061,7 +3068,8 @@ rend_services_introduce(void) if (intro->time_expiring + INTRO_POINT_EXPIRATION_GRACE_PERIOD > now) { /* This intro point has completely expired. Remove it, and * mark the circuit for close if it's still alive. */ - if (intro_circ != NULL) { + if (intro_circ != NULL && + intro_circ->base_.purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { circuit_mark_for_close(TO_CIRCUIT(intro_circ), END_CIRC_REASON_FINISHED); } @@ -3296,7 +3304,7 @@ rend_service_dump_stats(int severity) for (i=0; i < smartlist_len(rend_service_list); ++i) { service = smartlist_get(rend_service_list, i); - log(severity, LD_GENERAL, "Service configured in \"%s\":", + tor_log(severity, LD_GENERAL, "Service configured in \"%s\":", service->directory); for (j=0; j < smartlist_len(service->intro_nodes); ++j) { intro = smartlist_get(service->intro_nodes, j); @@ -3304,11 +3312,11 @@ rend_service_dump_stats(int severity) circ = find_intro_circuit(intro, service->pk_digest); if (!circ) { - log(severity, LD_GENERAL, " Intro point %d at %s: no circuit", + tor_log(severity, LD_GENERAL, " Intro point %d at %s: no circuit", j, safe_name); continue; } - log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s", + tor_log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s", j, safe_name, circuit_state_to_string(circ->base_.state)); } } diff --git a/src/or/rephist.c b/src/or/rephist.c index 74d459f8a3..925ca88153 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -648,7 +648,7 @@ rep_hist_dump_stats(time_t now, int severity) rep_history_clean(now - get_options()->RephistTrackTime); - log(severity, LD_HIST, "--------------- Dumping history information:"); + tor_log(severity, LD_HIST, "--------------- Dumping history information:"); for (orhist_it = digestmap_iter_init(history_map); !digestmap_iter_done(orhist_it); @@ -673,7 +673,7 @@ rep_hist_dump_stats(time_t now, int severity) } else { uptime=1.0; } - log(severity, LD_HIST, + tor_log(severity, LD_HIST, "OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%); " "wmtbf %lu:%02lu:%02lu", name1, hexdigest1, @@ -707,7 +707,7 @@ rep_hist_dump_stats(time_t now, int severity) else len += ret; } - log(severity, LD_HIST, "%s", buffer); + tor_log(severity, LD_HIST, "%s", buffer); } } } @@ -2042,7 +2042,7 @@ note_crypto_pk_op(pk_op_t operation) void dump_pk_ops(int severity) { - log(severity, LD_HIST, + tor_log(severity, LD_HIST, "PK operations: %lu directory objects signed, " "%lu directory objects verified, " "%lu routerdescs signed, " diff --git a/src/or/router.c b/src/or/router.c index c584d6277f..db396f0d56 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -391,14 +391,14 @@ init_key_from_file(const char *fname, int generate, int severity) crypto_pk_t *prkey = NULL; if (!(prkey = crypto_pk_new())) { - log(severity, LD_GENERAL,"Error constructing key"); + tor_log(severity, LD_GENERAL,"Error constructing key"); goto error; } switch (file_status(fname)) { case FN_DIR: case FN_ERROR: - log(severity, LD_FS,"Can't read key from \"%s\"", fname); + tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); goto error; case FN_NOENT: if (generate) { @@ -406,8 +406,8 @@ init_key_from_file(const char *fname, int generate, int severity) if (try_locking(get_options(), 0)<0) { /* Make sure that --list-fingerprint only creates new keys * if there is no possibility for a deadlock. */ - log(severity, LD_FS, "Another Tor process has locked \"%s\". Not " - "writing any new keys.", fname); + tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". " + "Not writing any new keys.", fname); /*XXXX The 'other process' might make a key in a second or two; * maybe we should wait for it. */ goto error; @@ -416,16 +416,16 @@ init_key_from_file(const char *fname, int generate, int severity) log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.", fname); if (crypto_pk_generate_key(prkey)) { - log(severity, LD_GENERAL,"Error generating onion key"); + tor_log(severity, LD_GENERAL,"Error generating onion key"); goto error; } if (crypto_pk_check_key(prkey) <= 0) { - log(severity, LD_GENERAL,"Generated key seems invalid"); + tor_log(severity, LD_GENERAL,"Generated key seems invalid"); goto error; } log_info(LD_GENERAL, "Generated key seems valid"); if (crypto_pk_write_private_key_to_filename(prkey, fname)) { - log(severity, LD_FS, + tor_log(severity, LD_FS, "Couldn't write generated key to \"%s\".", fname); goto error; } @@ -435,7 +435,7 @@ init_key_from_file(const char *fname, int generate, int severity) return prkey; case FN_FILE: if (crypto_pk_read_private_key_from_filename(prkey, fname)) { - log(severity, LD_GENERAL,"Error loading private key."); + tor_log(severity, LD_GENERAL,"Error loading private key."); goto error; } return prkey; @@ -465,7 +465,7 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, switch (file_status(fname)) { case FN_DIR: case FN_ERROR: - log(severity, LD_FS,"Can't read key from \"%s\"", fname); + tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); goto error; case FN_NOENT: if (generate) { @@ -473,8 +473,8 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, if (try_locking(get_options(), 0)<0) { /* Make sure that --list-fingerprint only creates new keys * if there is no possibility for a deadlock. */ - log(severity, LD_FS, "Another Tor process has locked \"%s\". Not " - "writing any new keys.", fname); + tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". " + "Not writing any new keys.", fname); /*XXXX The 'other process' might make a key in a second or two; * maybe we should wait for it. */ goto error; @@ -485,7 +485,7 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, if (curve25519_keypair_generate(keys_out, 1) < 0) goto error; if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) { - log(severity, LD_FS, + tor_log(severity, LD_FS, "Couldn't write generated key to \"%s\".", fname); memset(keys_out, 0, sizeof(*keys_out)); goto error; @@ -498,12 +498,12 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, { char *tag_in=NULL; if (curve25519_keypair_read_from_file(keys_out, &tag_in, fname) < 0) { - log(severity, LD_GENERAL,"Error loading private key."); + tor_log(severity, LD_GENERAL,"Error loading private key."); tor_free(tag_in); goto error; } if (!tag_in || strcmp(tag_in, tag)) { - log(severity, LD_GENERAL,"Unexpected tag %s on private key.", + tor_log(severity, LD_GENERAL,"Unexpected tag %s on private key.", escaped(tag_in)); tor_free(tag_in); goto error; @@ -631,14 +631,14 @@ v3_authority_check_key_expiry(void) return; if (time_left <= 0) { - log(badness, LD_DIR, "Your v3 authority certificate has expired." - " Generate a new one NOW."); + tor_log(badness, LD_DIR, "Your v3 authority certificate has expired." + " Generate a new one NOW."); } else if (time_left <= 24*60*60) { - log(badness, LD_DIR, "Your v3 authority certificate expires in %d hours;" - " Generate a new one NOW.", time_left/(60*60)); + tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d " + "hours; Generate a new one NOW.", time_left/(60*60)); } else { - log(badness, LD_DIR, "Your v3 authority certificate expires in %d days;" - " Generate a new one soon.", time_left/(24*60*60)); + tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d " + "days; Generate a new one soon.", time_left/(24*60*60)); } last_warned = now; } @@ -902,7 +902,7 @@ init_keys(void) tor_free(cp); tor_free(keydir); - log(LOG_NOTICE, LD_GENERAL, + log_notice(LD_GENERAL, "Your Tor server's identity key fingerprint is '%s %s'", options->Nickname, fingerprint); if (!authdir_mode(options)) @@ -1062,10 +1062,10 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) if (advertising != new_choice) { if (new_choice == 1) { - log(LOG_NOTICE, LD_DIR, "Advertising DirPort as %d", dir_port); + log_notice(LD_DIR, "Advertising DirPort as %d", dir_port); } else { tor_assert(reason); - log(LOG_NOTICE, LD_DIR, "Not advertising DirPort (Reason: %s)", reason); + log_notice(LD_DIR, "Not advertising DirPort (Reason: %s)", reason); } advertising = new_choice; } diff --git a/src/or/routerlist.c b/src/or/routerlist.c index b294bfa080..8f19947600 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -42,6 +42,9 @@ /****************************************************************************/ /* static function prototypes */ +static int compute_weighted_bandwidths(const smartlist_t *sl, + bandwidth_weight_rule_t rule, + u64_dbl_t **bandwidths_out); static const routerstatus_t *router_pick_directory_server_impl( dirinfo_type_t auth, int flags); static const routerstatus_t *router_pick_trusteddirserver_impl( @@ -1681,9 +1684,35 @@ kb_to_bytes(uint32_t bw) * guards proportionally less. */ static const node_t * -smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, +smartlist_choose_node_by_bandwidth_weights(const smartlist_t *sl, bandwidth_weight_rule_t rule) { + u64_dbl_t *bandwidths=NULL; + + if (compute_weighted_bandwidths(sl, rule, &bandwidths) < 0) + return NULL; + + scale_array_elements_to_u64(bandwidths, smartlist_len(sl), + &sl_last_total_weighted_bw); + + { + int idx = choose_array_element_by_weight(bandwidths, + smartlist_len(sl)); + tor_free(bandwidths); + return idx < 0 ? NULL : smartlist_get(sl, idx); + } +} + +/** Given a list of routers and a weighting rule as in + * smartlist_choose_node_by_bandwidth_weights, compute weighted bandwidth + * values for each node and store them in a freshly allocated + * *<b>bandwidths_out</b> of the same length as <b>sl</b>, and holding results + * as doubles. Return 0 on success, -1 on failure. */ +static int +compute_weighted_bandwidths(const smartlist_t *sl, + bandwidth_weight_rule_t rule, + u64_dbl_t **bandwidths_out) +{ int64_t weight_scale; double Wg = -1, Wm = -1, We = -1, Wd = -1; double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1; @@ -1702,10 +1731,10 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, "Empty routerlist passed in to consensus weight node " "selection for rule %s", bandwidth_weight_rule_to_string(rule)); - return NULL; + return -1; } - weight_scale = circuit_build_times_get_bw_scale(NULL); + weight_scale = networkstatus_get_weight_scale_param(NULL); if (rule == WEIGHT_FOR_GUARD) { Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1); @@ -1756,7 +1785,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, log_debug(LD_CIRC, "Got negative bandwidth weights. Defaulting to old selection" " algorithm."); - return NULL; // Use old algorithm. + return -1; // Use old algorithm. } Wg /= weight_scale; @@ -1786,7 +1815,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, log_warn(LD_BUG, "Consensus is not listing bandwidths. Defaulting back to " "old router selection algorithm."); - return NULL; + return -1; } this_bw = kb_to_bytes(node->rs->bandwidth); } else if (node->ri) { @@ -1819,20 +1848,53 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, sl_last_weighted_bw_of_me = (uint64_t) bandwidths[node_sl_idx].dbl; } SMARTLIST_FOREACH_END(node); - log_debug(LD_CIRC, "Choosing node for rule %s based on weights " + log_debug(LD_CIRC, "Generated weighted bandwidths for rule %s based " + "on weights " "Wg=%f Wm=%f We=%f Wd=%f with total bw "U64_FORMAT, bandwidth_weight_rule_to_string(rule), Wg, Wm, We, Wd, U64_PRINTF_ARG(weighted_bw)); - scale_array_elements_to_u64(bandwidths, smartlist_len(sl), - &sl_last_total_weighted_bw); + *bandwidths_out = bandwidths; - { - int idx = choose_array_element_by_weight(bandwidths, - smartlist_len(sl)); - tor_free(bandwidths); - return idx < 0 ? NULL : smartlist_get(sl, idx); + return 0; +} + +/** For all nodes in <b>sl</b>, return the fraction of those nodes, weighted + * by their weighted bandwidths with rule <b>rule</b>, for which we have + * descriptors. */ +double +frac_nodes_with_descriptors(const smartlist_t *sl, + bandwidth_weight_rule_t rule) +{ + u64_dbl_t *bandwidths = NULL; + double total, present; + + if (smartlist_len(sl) == 0) + return 0.0; + + if (compute_weighted_bandwidths(sl, rule, &bandwidths) < 0) { + int n_with_descs = 0; + SMARTLIST_FOREACH(sl, const node_t *, node, { + if (node_has_descriptor(node)) + n_with_descs++; + }); + return ((double)n_with_descs) / (double)smartlist_len(sl); } + + total = present = 0.0; + SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { + const double bw = bandwidths[node_sl_idx].dbl; + total += bw; + if (node_has_descriptor(node)) + present += bw; + } SMARTLIST_FOREACH_END(node); + + tor_free(bandwidths); + + if (total < 1.0) + return 0; + + return present / total; } /** Helper function: @@ -1849,7 +1911,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, * guards proportionally less. */ static const node_t * -smartlist_choose_node_by_bandwidth(smartlist_t *sl, +smartlist_choose_node_by_bandwidth(const smartlist_t *sl, bandwidth_weight_rule_t rule) { unsigned int i; @@ -2055,7 +2117,7 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl, /** Choose a random element of status list <b>sl</b>, weighted by * the advertised bandwidth of each node */ const node_t * -node_sl_choose_by_bandwidth(smartlist_t *sl, +node_sl_choose_by_bandwidth(const smartlist_t *sl, bandwidth_weight_rule_t rule) { /*XXXX MOVE */ const node_t *ret; @@ -2585,7 +2647,7 @@ dump_routerlist_mem_usage(int severity) SMARTLIST_FOREACH(routerlist->old_routers, signed_descriptor_t *, sd, olddescs += sd->signed_descriptor_len); - log(severity, LD_DIR, + tor_log(severity, LD_DIR, "In %d live descriptors: "U64_FORMAT" bytes. " "In %d old descriptors: "U64_FORMAT" bytes.", smartlist_len(routerlist->routers), U64_PRINTF_ARG(livedescs), diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 798cebc58e..1849fff31c 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -47,8 +47,10 @@ const routerinfo_t *routerlist_find_my_routerinfo(void); uint32_t router_get_advertised_bandwidth(const routerinfo_t *router); uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router); -const node_t *node_sl_choose_by_bandwidth(smartlist_t *sl, +const node_t *node_sl_choose_by_bandwidth(const smartlist_t *sl, bandwidth_weight_rule_t rule); +double frac_nodes_with_descriptors(const smartlist_t *sl, + bandwidth_weight_rule_t rule); const node_t *router_choose_random_node(smartlist_t *excludedsmartlist, struct routerset_t *excludedset, diff --git a/src/or/routerparse.c b/src/or/routerparse.c index b945ea6aa6..2a3de12c35 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1029,7 +1029,7 @@ dump_distinct_digest_count(int severity) #ifdef COUNT_DISTINCT_DIGESTS if (!verified_digests) verified_digests = digestmap_new(); - log(severity, LD_GENERAL, "%d *distinct* router digests verified", + tor_log(severity, LD_GENERAL, "%d *distinct* router digests verified", digestmap_size(verified_digests)); #else (void)severity; /* suppress "unused parameter" warning */ @@ -2255,7 +2255,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns) const char *casename = NULL; int valid = 1; - weight_scale = circuit_build_times_get_bw_scale(ns); + weight_scale = networkstatus_get_weight_scale_param(ns); Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1); Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1); Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1); diff --git a/src/or/routerset.c b/src/or/routerset.c index 4b519034d3..e45516bb6c 100644 --- a/src/or/routerset.c +++ b/src/or/routerset.c @@ -95,7 +95,7 @@ routerset_refresh_countries(routerset_t *target) tor_assert(cc < target->n_countries); bitarray_set(target->countries, cc); } else { - log(LOG_WARN, LD_CONFIG, "Country code '%s' is not recognized.", + log_warn(LD_CONFIG, "Country code '%s' is not recognized.", country); } } SMARTLIST_FOREACH_END(country); diff --git a/src/or/statefile.c b/src/or/statefile.c index 53b6817ef7..bcb7b07417 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -52,6 +52,7 @@ static config_var_t state_vars_[] = { VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL), + VAR("EntryGuardPathUseBias", LINELIST_S, EntryGuards, NULL), V(EntryGuards, LINELIST_V, NULL), VAR("TransportProxy", LINELIST_S, TransportProxies, NULL), diff --git a/src/or/status.c b/src/or/status.c index 97d0e49e01..126167dcb9 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -108,7 +108,7 @@ log_heartbeat(time_t now) uptime, count_circuits(),bw_sent,bw_rcvd); if (stats_n_data_cells_packaged) - log(LOG_NOTICE, LD_HEARTBEAT, "Average packaged cell fullness: %2.3f%%", + log_notice(LD_HEARTBEAT, "Average packaged cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); diff --git a/src/test/test.c b/src/test/test.c index e3e989b0c1..b838172d5a 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1529,59 +1529,35 @@ test_geoip(void) *dirreq_stats_1 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips ab=8\n" - "dirreq-v2-ips \n" "dirreq-v3-reqs ab=8\n" - "dirreq-v2-reqs \n" "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" - "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0," - "busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n", + "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_2 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" - "dirreq-v2-ips \n" "dirreq-v3-reqs \n" - "dirreq-v2-reqs \n" "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" - "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0," - "busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n", + "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_3 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" - "dirreq-v2-ips \n" "dirreq-v3-reqs \n" - "dirreq-v2-reqs \n" "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" - "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0," - "busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n", + "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_4 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" - "dirreq-v2-ips \n" "dirreq-v3-reqs \n" - "dirreq-v2-reqs \n" "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" - "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0," - "busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n" - "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n" - "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n", + "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n", *entry_stats_1 = "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n" "entry-ips ab=8\n", @@ -1754,14 +1730,13 @@ test_geoip(void) /* Note a successful network status response and make sure that it * appears in the history string. */ - geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS); + geoip_note_ns_response(GEOIP_SUCCESS); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_3, s); tor_free(s); /* Start a tunneled directory request. */ - geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS, - DIRREQ_TUNNELED); + geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_4, s); diff --git a/src/test/test_util.c b/src/test/test_util.c index ad214b9e67..bed33fac25 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -17,6 +17,7 @@ #ifdef _WIN32 #include <tchar.h> #endif +#include <math.h> /* XXXX this is a minimal wrapper to make the unit tests compile with the * changed tor_timegm interface. */ @@ -3240,6 +3241,20 @@ test_util_set_env_var_in_sl(void *ptr) smartlist_free(expected_resulting_env_vars); } +static void +test_util_mathlog(void *arg) +{ + double d; + (void) arg; + + d = tor_mathlog(2.718281828); + tt_double_op(fabs(d - 1.0), <, .000001); + d = tor_mathlog(10); + tt_double_op(fabs(d - 2.30258509), <, .000001); + done: + ; +} + #define UTIL_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name } @@ -3296,6 +3311,7 @@ struct testcase_t util_tests[] = { UTIL_TEST(read_file_eof_tiny_limit, 0), UTIL_TEST(read_file_eof_two_loops, 0), UTIL_TEST(read_file_eof_zero_bytes, 0), + UTIL_TEST(mathlog, 0), END_OF_TESTCASES }; diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index c68aaa747c..3809b22d43 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -82,10 +82,11 @@ crypto_log_errors(int severity, const char *doing) if (!lib) lib = "(null)"; if (!func) func = "(null)"; if (doing) { - log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + doing, msg, lib, func); } else { - log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func); + tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", + msg, lib, func); } } } diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index 6e45a2928b..ef08fdb2be 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -151,6 +151,9 @@ /* Define to 1 iff NULL is represented by a 0 in memory. */ #define NULL_REP_IS_ZERO_BYTES 1 +/* Define to 1 iff memset(0) sets doubles to 0.0 */ +#define DOUBLE_0_REP_IS_ZERO_BYTES 1 + /* Name of package */ #define PACKAGE "tor" |