summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog117
-rw-r--r--Makefile.am11
-rw-r--r--ReleaseNotes48
-rw-r--r--changes/122074
-rw-r--r--changes/bug113024
-rw-r--r--changes/bug116838
-rw-r--r--changes/bug122023
-rw-r--r--changes/bug125033
-rw-r--r--changes/bug125735
-rw-r--r--changes/bug98015
-rw-r--r--changes/coverage-html5
-rw-r--r--changes/feature55832
-rw-r--r--changes/no-wince4
-rw-r--r--changes/threads-required12
-rw-r--r--configure.ac30
-rw-r--r--contrib/win32build/tor-mingw.nsi.in2
-rw-r--r--doc/HACKING22
-rw-r--r--doc/tor.1.txt4
-rw-r--r--src/common/compat.c30
-rw-r--r--src/common/compat.h38
-rw-r--r--src/common/crypto.c15
-rw-r--r--src/common/log.c20
-rw-r--r--src/common/torlog.h4
-rw-r--r--src/common/tortls.c4
-rw-r--r--src/common/util.c2
-rw-r--r--src/or/config.c57
-rw-r--r--src/or/connection.c12
-rw-r--r--src/or/cpuworker.c10
-rw-r--r--src/or/directory.c6
-rw-r--r--src/or/dirserv.c2
-rw-r--r--src/or/entrynodes.c220
-rw-r--r--src/or/entrynodes.h29
-rw-r--r--src/or/main.c54
-rw-r--r--src/or/ntmain.h2
-rw-r--r--src/or/or.h2
-rw-r--r--src/or/reasons.c4
-rw-r--r--src/or/router.c3
-rw-r--r--src/or/routerlist.c24
-rw-r--r--src/or/routerlist.h3
-rw-r--r--src/test/include.am4
-rw-r--r--src/test/test.c13
-rw-r--r--src/test/test_config.c10
-rw-r--r--src/test/test_descriptors.inc305
-rw-r--r--src/test/test_entrynodes.c636
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_util.c100
-rw-r--r--src/win32/orconfig.h13
47 files changed, 1609 insertions, 304 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a2918490e..688d6554ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,120 @@
+Changes in version 0.2.6.1-alpha - 2014-??-??
+
+
+Changes in version 0.2.5.6-alpha - 2014-07-28
+ Tor 0.2.5.6-alpha brings us a big step closer to slowing down the
+ risk from guard rotation, and fixes a variety of other issues to get
+ us closer to a release candidate.
+
+ o Major features (also in 0.2.4.23):
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes (also in 0.2.4.23):
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Major bugfixes:
+ - Perform circuit cleanup operations even when circuit
+ construction operations are disabled (because the network is
+ disabled, or because there isn't enough directory information).
+ Previously, when we were not building predictive circuits, we
+ were not closing expired circuits either. Fixes bug 8387; bugfix on
+ 0.1.1.11-alpha. This bug became visible in 0.2.4.10-alpha when we
+ became more strict about when we have "enough directory information
+ to build circuits".
+
+ o Minor features:
+ - Authorities now assign the Guard flag to the fastest 25% of the
+ network (it used to be the fastest 50%). Also raise the consensus
+ weight that guarantees the Guard flag from 250 to 2000. For the
+ current network, this results in about 1100 guards, down from 2500.
+ This step paves the way for moving the number of entry guards
+ down to 1 (proposal 236) while still providing reasonable expected
+ performance for most users. Implements ticket 12690.
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+ - Slightly enhance the diagnostic message for bug 12184.
+
+ o Minor bugfixes (also in 0.2.4.23):
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes:
+ - Fix compilation when building with bufferevents enabled. (This
+ configuration is still not expected to work, however.)
+ Fixes bugs 12438, 12474, 11578; bugfixes on 0.2.5.1-alpha and
+ 0.2.5.3-alpha. Patches from Anthony G. Basile and Sathyanarayanan
+ Gunasekaran.
+ - Compile correctly with builds and forks of OpenSSL (such as
+ LibreSSL) that disable compression. Fixes bug 12602; bugfix on
+ 0.2.1.1-alpha. Patch from "dhill".
+
+
+Changes in version 0.2.4.23 - 2014-07-28
+ Tor 0.2.4.23 brings us a big step closer to slowing down the risk from
+ guard rotation, and also backports several important fixes from the
+ Tor 0.2.5 alpha release series.
+
+ o Major features:
+ - Clients now look at the "usecreatefast" consensus parameter to
+ decide whether to use CREATE_FAST or CREATE cells for the first hop
+ of their circuit. This approach can improve security on connections
+ where Tor's circuit handshake is stronger than the available TLS
+ connection security levels, but the tradeoff is more computational
+ load on guard relays. Implements proposal 221. Resolves ticket 9386.
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes:
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Minor bugfixes:
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+ - Avoid an illegal read from stack when initializing the TLS
+ module using a version of OpenSSL without all of the ciphers
+ used by the v2 link handshake. Fixes bug 12227; bugfix on
+ 0.2.4.8-alpha. Found by "starlight".
+
+ o Minor features:
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+
+
Changes in version 0.2.5.5-alpha - 2014-06-18
Tor 0.2.5.5-alpha fixes a wide variety of remaining issues in the Tor
0.2.5.x release series, including a couple of DoS issues, some
diff --git a/Makefile.am b/Makefile.am
index 6eceb761f4..910cb12005 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -74,6 +74,17 @@ test-network: all
reset-gcov:
rm -f src/*/*.gcda
+HTML_COVER_DIR=./coverage_html
+coverage-html: all
+ test -e "`which lcov`" || (echo "lcov must be installed. See <http://ltp.sourceforge.net/coverage/lcov.php>." && false)
+ test -d "$(HTML_COVER_DIR)" || mkdir -p "$(HTML_COVER_DIR)"
+ lcov --rc lcov_branch_coverage=1 --directory ./src --zerocounters
+ $(MAKE) reset-gcov
+ $(MAKE) check
+ lcov --capture --rc lcov_branch_coverage=1 --no-external --directory . --output-file "$(HTML_COVER_DIR)/lcov.tmp"
+ lcov --remove "$(HTML_COVER_DIR)/lcov.tmp" --rc lcov_branch_coverage=1 'test/*' 'ext/tinytest*' '/usr/*' --output-file "$(HTML_COVER_DIR)/lcov.info"
+ genhtml --branch-coverage -o "$(HTML_COVER_DIR)" "$(HTML_COVER_DIR)/lcov.info"
+
# Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c,
# eventdns.[hc], tinytest*.[ch]
check-spaces:
diff --git a/ReleaseNotes b/ReleaseNotes
index 19185a2968..2ad0f1ede5 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -3,6 +3,54 @@ This document summarizes new features and bugfixes in each stable release
of Tor. If you want to see more detailed descriptions of the changes in
each development snapshot, see the ChangeLog file.
+Changes in version 0.2.4.23 - 2014-07-28
+ Tor 0.2.4.23 brings us a big step closer to slowing down the risk from
+ guard rotation, and also backports several important fixes from the
+ Tor 0.2.5 alpha release series.
+
+ o Major features:
+ - Clients now look at the "usecreatefast" consensus parameter to
+ decide whether to use CREATE_FAST or CREATE cells for the first hop
+ of their circuit. This approach can improve security on connections
+ where Tor's circuit handshake is stronger than the available TLS
+ connection security levels, but the tradeoff is more computational
+ load on guard relays. Implements proposal 221. Resolves ticket 9386.
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes:
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Minor bugfixes:
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+ - Avoid an illegal read from stack when initializing the TLS
+ module using a version of OpenSSL without all of the ciphers
+ used by the v2 link handshake. Fixes bug 12227; bugfix on
+ 0.2.4.8-alpha. Found by "starlight".
+
+ o Minor features:
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+
+
Changes in version 0.2.4.22 - 2014-05-16
Tor 0.2.4.22 backports numerous high-priority fixes from the Tor 0.2.5
alpha release series. These include blocking all authority signing
diff --git a/changes/12207 b/changes/12207
new file mode 100644
index 0000000000..53c14a4ffd
--- /dev/null
+++ b/changes/12207
@@ -0,0 +1,4 @@
+ - Testing:
+ - Refactor the function that chooses guard nodes so that it can
+ more easily be tested; write some tests for it.
+
diff --git a/changes/bug11302 b/changes/bug11302
new file mode 100644
index 0000000000..7416c69be6
--- /dev/null
+++ b/changes/bug11302
@@ -0,0 +1,4 @@
+ o Bugfixes:
+ - Check for orconns and use connection_or_close_for_error() rather than
+ connection_mark_for_close() directly in the getsockopt() failure case
+ of connection_handle_write_impl(). Fixes bug #11302.
diff --git a/changes/bug11683 b/changes/bug11683
new file mode 100644
index 0000000000..ccbd2a5233
--- /dev/null
+++ b/changes/bug11683
@@ -0,0 +1,8 @@
+ o Minor bugfixes:
+ - Always believe that v3 directory authorities serve extra-info
+ documents, regardless of whether their server descriptor contains a
+ "caches-extra-info" line or not. Fixes part of #11683. Bugfix on
+ 0.2.0.1-alpha.
+ - When running as a v3 directory authority, advertise that you serve
+ extra-info documents so that clients who want them can find them from
+ you too. Fixes part of bug #11683. Bugfix on 0.2.0.1-alpha.
diff --git a/changes/bug12202 b/changes/bug12202
new file mode 100644
index 0000000000..566d37efda
--- /dev/null
+++ b/changes/bug12202
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Change the entry_is_live() function to take named bitfield elements
+ instead of an unnamed list of booleans. Closes ticket 12202.
diff --git a/changes/bug12503 b/changes/bug12503
new file mode 100644
index 0000000000..ff96fa2cf5
--- /dev/null
+++ b/changes/bug12503
@@ -0,0 +1,3 @@
+ o Testing:
+ - Fix and re-enable the fgets_eagain unit test. Fixes bug 12503;
+ bugfix on 0.2.3.1-alpha. Patch from "cypherpunks."
diff --git a/changes/bug12573 b/changes/bug12573
new file mode 100644
index 0000000000..46e3ee2fa0
--- /dev/null
+++ b/changes/bug12573
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Relays should not be assigned the HSDir flag if they are
+ considered invalid. Also, do not assign the HSDir flag to relays
+ that are currently hibernating. Fixes #12573. Bugfix on
+ tor-0.2.0.10-alpha
diff --git a/changes/bug9801 b/changes/bug9801
new file mode 100644
index 0000000000..6b23b71806
--- /dev/null
+++ b/changes/bug9801
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - When GeoIPExcludeUnkonwn is enabled, do not incorrectly decide
+ that our options have changed every time we SIGHUP. Fixes bug
+ 9801; bugfix on 0.2.4.10-alpha. Patch from "qwerty1".
+
diff --git a/changes/coverage-html b/changes/coverage-html
new file mode 100644
index 0000000000..1c38c76fa6
--- /dev/null
+++ b/changes/coverage-html
@@ -0,0 +1,5 @@
+ o Minor features (testing):
+
+ - Add a "coverage-html" make target to generate HTML-visualized
+ coverage results when building with --enable-coverage. (Requires lcov.)
+ Patch from Kevin Murray.
diff --git a/changes/feature5583 b/changes/feature5583
new file mode 100644
index 0000000000..cd5eb69281
--- /dev/null
+++ b/changes/feature5583
@@ -0,0 +1,2 @@
+ o Minor features:
+ - Add an option to overwrite logs (TruncateLogFile). Closes ticket #5583.
diff --git a/changes/no-wince b/changes/no-wince
new file mode 100644
index 0000000000..833bf46630
--- /dev/null
+++ b/changes/no-wince
@@ -0,0 +1,4 @@
+ o Removed platform support:
+ - We no longer include special code to build on Windows CE; as far
+ as we know, nobody has used Tor on Windows CE in a very long
+ time. Closes ticket 11446.
diff --git a/changes/threads-required b/changes/threads-required
new file mode 100644
index 0000000000..a56cfe345b
--- /dev/null
+++ b/changes/threads-required
@@ -0,0 +1,12 @@
+ o Removed features:
+ - Tor no longer supports systems without threading support.
+ When we began working on Tor, there were several systems that didn't
+ have threads, or where the thread support wasn't able to run the
+ threads of a single process on multiple CPUs. That no longer holds:
+ every system where Tor needs to run well now has threading support.
+ Resolves ticket 12439.
+
+ o Minor features:
+ - Threads are no longer disabled by default on Solaris; we believe that
+ the versions of Solaris with broken threading support are all obsolete
+ by now. Resolves ticket 9495.
diff --git a/configure.ac b/configure.ac
index c37f154222..414c72a42c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
dnl Copyright (c) 2007-2013, The Tor Project, Inc.
dnl See LICENSE for licensing information
-AC_INIT([tor],[0.2.5.6-alpha])
+AC_INIT([tor],[0.2.6.0-alpha-dev])
AC_CONFIG_SRCDIR([src/or/main.c])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE
@@ -107,26 +107,6 @@ AC_ARG_ENABLE(upnp,
* ) AC_MSG_ERROR(bad value for --enable-upnp) ;;
esac], [upnp=false])
-
-AC_ARG_ENABLE(threads,
- AS_HELP_STRING(--disable-threads, disable multi-threading support))
-
-if test x$enable_threads = x; then
- case $host in
- *-*-solaris* )
- # Don't try multithreading on solaris -- cpuworkers seem to lock.
- AC_MSG_NOTICE([You are running Solaris; Sometimes threading makes
-cpu workers lock up here, so I will disable threads.])
- enable_threads="no";;
- *)
- enable_threads="yes";;
- esac
-fi
-
-if test "$enable_threads" = "yes"; then
- AC_DEFINE(ENABLE_THREADS, 1, [Defined if we will try to use multithreading])
-fi
-
case $host in
*-*-solaris* )
AC_DEFINE(_REENTRANT, 1, [Define on some platforms to activate x_r() functions in time.h])
@@ -326,10 +306,8 @@ if test "$LIBS" != "$saved_LIBS"; then
have_rt=yes
fi
-if test "$enable_threads" = "yes"; then
- AC_SEARCH_LIBS(pthread_create, [pthread])
- AC_SEARCH_LIBS(pthread_detach, [pthread])
-fi
+AC_SEARCH_LIBS(pthread_create, [pthread])
+AC_SEARCH_LIBS(pthread_detach, [pthread])
dnl -------------------------------------------------------------------
dnl Check for functions before libevent, since libevent-1.2 apparently
@@ -372,7 +350,7 @@ AC_CHECK_FUNCS(
_vscprintf
)
-if test "$enable_threads" = "yes"; then
+if test "$bwin32" != true; then
AC_CHECK_HEADERS(pthread.h)
AC_CHECK_FUNCS(pthread_create)
fi
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index 5d94fd9e58..f5c02dbb84 100644
--- a/contrib/win32build/tor-mingw.nsi.in
+++ b/contrib/win32build/tor-mingw.nsi.in
@@ -8,7 +8,7 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.2.5.6-alpha"
+!define VERSION "0.2.6.0-alpha-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
diff --git a/doc/HACKING b/doc/HACKING
index c69b2a6fee..6b21426497 100644
--- a/doc/HACKING
+++ b/doc/HACKING
@@ -114,6 +114,26 @@ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/or/tor
pass --undef-value-errors=no to valgrind, or rebuild your openssl
with -DPURIFY.)
+Running lcov for unit test coverage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Lcov is a utility that generates pretty HTML reports of test code coverage.
+To generate such a report:
+
+-----
+ ./configure --enable-coverage
+ make
+ make coverage-html
+ $BROWSER ./coverage_html/index.html
+-----
+
+This will run the tor unit test suite `./src/test/test` and generate the HTML
+coverage code report under the directory ./coverage_html/. To change the
+output directory, use `make coverage-html HTML_COVER_DIR=./funky_new_cov_dir`.
+
+Coverage diffs using lcov are not currently implemented, but are being
+investigated (as of July 2014).
+
Running gcov for unit test coverage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -460,7 +480,7 @@ interesting and understandable.
Standard idioms:
"Fixes bug 9999; bugfix on 0.3.3.3-alpha."
- One period after a space.
+ One space after a period.
Make stuff very terse
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index abe613e569..7b1d7d9bb2 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -561,6 +561,10 @@ GENERAL OPTIONS
messages to affect times logged by a controller, times attached to
syslog messages, or the mtime fields on log files. (Default: 1 second)
+[[TruncateLogFile]] **TruncateLogFile** **0**|**1**::
+ If 1, Tor will overwrite logs at startup and in response to a HUP signal,
+ instead of appending to them. (Default: 0)
+
[[SafeLogging]] **SafeLogging** **0**|**1**|**relay**::
Tor can scrub potentially sensitive strings from log messages (e.g.
addresses) by replacing them with the string [scrubbed]. This way logs can
diff --git a/src/common/compat.c b/src/common/compat.c
index e25ecc462d..dcdf78d49f 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1004,6 +1004,23 @@ tor_fd_setpos(int fd, off_t pos)
#endif
}
+/** Replacement for ftruncate(fd, 0): move to the front of the file and remove
+ * all the rest of the file. Return -1 on error, 0 on success. */
+int
+tor_ftruncate(int fd)
+{
+ /* Rumor has it that some versions of ftruncate do not move the file pointer.
+ */
+ if (tor_fd_setpos(fd, 0) < 0)
+ return -1;
+
+#ifdef _WIN32
+ return _chsize(fd, 0);
+#else
+ return ftruncate(fd, 0);
+#endif
+}
+
#undef DEBUG_SOCKET_COUNTING
#ifdef DEBUG_SOCKET_COUNTING
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
@@ -2485,14 +2502,12 @@ get_uname(void)
"Unrecognized version of Windows [major=%d,minor=%d]",
(int)info.dwMajorVersion,(int)info.dwMinorVersion);
}
-#if !defined (WINCE)
#ifdef VER_NT_SERVER
if (info.wProductType == VER_NT_SERVER ||
info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
strlcat(uname_result, " [server]", sizeof(uname_result));
}
#endif
-#endif
#else
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
#endif
@@ -2697,15 +2712,8 @@ tor_gettimeofday(struct timeval *timeval)
uint64_t ft_64;
FILETIME ft_ft;
} ft;
-#if defined (WINCE)
- /* wince do not have GetSystemTimeAsFileTime */
- SYSTEMTIME stime;
- GetSystemTime(&stime);
- SystemTimeToFileTime(&stime,&ft.ft_ft);
-#else
/* number of 100-nsec units since Jan 1, 1601 */
GetSystemTimeAsFileTime(&ft.ft_ft);
-#endif
if (ft.ft_64 < EPOCH_BIAS) {
log_err(LD_GENERAL,"System time is before 1970; failing.");
exit(1);
@@ -2731,7 +2739,7 @@ tor_gettimeofday(struct timeval *timeval)
return;
}
-#if defined(TOR_IS_MULTITHREADED) && !defined(_WIN32)
+#if !defined(_WIN32)
/** Defined iff we need to add locks when defining fake versions of reentrant
* versions of time-related functions. */
#define TIME_FNS_NEED_LOCKS
@@ -2991,7 +2999,6 @@ tor_get_thread_id(void)
}
#endif
-#ifdef TOR_IS_MULTITHREADED
/** Return a newly allocated, ready-for-use mutex. */
tor_mutex_t *
tor_mutex_new(void)
@@ -3009,7 +3016,6 @@ tor_mutex_free(tor_mutex_t *m)
tor_mutex_uninit(m);
tor_free(m);
}
-#endif
/* Conditions. */
#ifdef USE_PTHREADS
diff --git a/src/common/compat.h b/src/common/compat.h
index ec7d2415ed..852a432187 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -56,21 +56,6 @@
#include <stdio.h>
#include <errno.h>
-#if defined (WINCE)
-#include <fcntl.h>
-#include <io.h>
-#include <math.h>
-#include <projects.h>
-/* this is not exported as W .... */
-#define SHGetPathFromIDListW SHGetPathFromIDList
-/* wcecompat has vasprintf */
-#define HAVE_VASPRINTF
-/* no service here */
-#ifdef NT_SERVICE
-#undef NT_SERVICE
-#endif
-#endif // WINCE
-
#ifndef NULL_REP_IS_ZERO_BYTES
#error "It seems your platform does not represent NULL as zero. We can't cope."
#endif
@@ -423,6 +408,7 @@ void tor_lockfile_unlock(tor_lockfile_t *lockfile);
off_t tor_fd_getpos(int fd);
int tor_fd_setpos(int fd, off_t pos);
int tor_fd_seekend(int fd);
+int tor_ftruncate(int fd);
#ifdef _WIN32
#define PATH_SEPARATOR "\\"
@@ -648,15 +634,12 @@ int get_total_system_memory(size_t *mem_out);
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
-#if defined(ENABLE_THREADS) && defined(_WIN32)
+#if defined(_WIN32)
#define USE_WIN32_THREADS
-#define TOR_IS_MULTITHREADED 1
-#elif (defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H) && \
- defined(HAVE_PTHREAD_CREATE))
+#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
#define USE_PTHREADS
-#define TOR_IS_MULTITHREADED 1
#else
-#undef TOR_IS_MULTITHREADED
+#error "No threading system was found"
#endif
int compute_num_cpus(void);
@@ -682,7 +665,6 @@ typedef struct tor_mutex_t {
int tor_mlockall(void);
-#ifdef TOR_IS_MULTITHREADED
tor_mutex_t *tor_mutex_new(void);
void tor_mutex_init(tor_mutex_t *m);
void tor_mutex_acquire(tor_mutex_t *m);
@@ -691,21 +673,10 @@ void tor_mutex_free(tor_mutex_t *m);
void tor_mutex_uninit(tor_mutex_t *m);
unsigned long tor_get_thread_id(void);
void tor_threads_init(void);
-#else
-#define tor_mutex_new() ((tor_mutex_t*)tor_malloc(sizeof(int)))
-#define tor_mutex_init(m) STMT_NIL
-#define tor_mutex_acquire(m) STMT_VOID(m)
-#define tor_mutex_release(m) STMT_NIL
-#define tor_mutex_free(m) STMT_BEGIN tor_free(m); STMT_END
-#define tor_mutex_uninit(m) STMT_NIL
-#define tor_get_thread_id() (1UL)
-#define tor_threads_init() STMT_NIL
-#endif
void set_main_thread(void);
int in_main_thread(void);
-#ifdef TOR_IS_MULTITHREADED
#if 0
typedef struct tor_cond_t tor_cond_t;
tor_cond_t *tor_cond_new(void);
@@ -714,7 +685,6 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex);
void tor_cond_signal_one(tor_cond_t *cond);
void tor_cond_signal_all(tor_cond_t *cond);
#endif
-#endif
/** Macros for MIN/MAX. Never use these when the arguments could have
* side-effects.
diff --git a/src/common/crypto.c b/src/common/crypto.c
index a247a87d48..16292455b5 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -75,12 +75,10 @@
/** Macro: is k a valid RSA private key? */
#define PRIVATE_KEY_OK(k) ((k) && (k)->key && (k)->key->p)
-#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
static int n_openssl_mutexes_ = 0;
-#endif
/** A public key, or a public/private key-pair. */
struct crypto_pk_t
@@ -3090,8 +3088,6 @@ memwipe(void *mem, uint8_t byte, size_t sz)
memset(mem, byte, sz);
}
-#ifdef TOR_IS_MULTITHREADED
-
#ifndef OPENSSL_THREADS
#error OpenSSL has been built without thread support. Tor requires an \
OpenSSL library with thread support enabled.
@@ -3178,13 +3174,6 @@ setup_openssl_threading(void)
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
return 0;
}
-#else
-static int
-setup_openssl_threading(void)
-{
- return 0;
-}
-#endif
/** Uninitialize the crypto library. Return 0 on success, -1 on failure.
*/
@@ -3208,7 +3197,7 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
-#ifdef TOR_IS_MULTITHREADED
+
if (n_openssl_mutexes_) {
int n = n_openssl_mutexes_;
tor_mutex_t **ms = openssl_mutexes_;
@@ -3220,7 +3209,7 @@ crypto_global_cleanup(void)
}
tor_free(ms);
}
-#endif
+
tor_free(crypto_openssl_version_str);
tor_free(crypto_openssl_header_version_str);
return 0;
diff --git a/src/common/log.c b/src/common/log.c
index 517fa4faaa..2e51e5c578 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1010,12 +1010,16 @@ mark_logs_temp(void)
* logfile fails, -1 is returned and errno is set appropriately (by open(2)).
*/
int
-add_file_log(const log_severity_list_t *severity, const char *filename)
+add_file_log(const log_severity_list_t *severity, const char *filename,
+ const int truncate)
{
int fd;
logfile_t *lf;
- fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ int open_flags = O_WRONLY|O_CREAT;
+ open_flags |= truncate ? O_TRUNC : O_APPEND;
+
+ fd = tor_open_cloexec(filename, open_flags, 0644);
if (fd<0)
return -1;
if (tor_fd_seekend(fd)<0) {
@@ -1297,3 +1301,15 @@ switch_logs_debug(void)
UNLOCK_LOGS();
}
+/** Truncate all the log files. */
+void
+truncate_logs(void)
+{
+ logfile_t *lf;
+ for (lf = logfiles; lf; lf = lf->next) {
+ if (lf->fd >= 0) {
+ tor_ftruncate(lf->fd);
+ }
+ }
+}
+
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 34f70f3c00..34e39b4b94 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -130,7 +130,8 @@ void set_log_severity_config(int minSeverity, int maxSeverity,
log_severity_list_t *severity_out);
void add_stream_log(const log_severity_list_t *severity, const char *name,
int fd);
-int add_file_log(const log_severity_list_t *severity, const char *filename);
+int add_file_log(const log_severity_list_t *severity, const char *filename,
+ const int truncate);
#ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity);
#endif
@@ -148,6 +149,7 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
void flush_pending_log_callbacks(void);
void log_set_application_name(const char *name);
void set_log_time_granularity(int granularity_msec);
+void truncate_logs(void);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 4fd9bba380..0f989684cf 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -16,10 +16,6 @@
#include "orconfig.h"
-#if defined (WINCE)
-#include <WinSock2.h>
-#endif
-
#include <assert.h>
#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
#ifndef _WIN32_WINNT
diff --git a/src/common/util.c b/src/common/util.c
index 2d7893b38a..8589344dbe 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1893,7 +1893,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
}
if (check & CPD_CREATE) {
log_info(LD_GENERAL, "Creating directory %s", dirname);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
r = mkdir(dirname);
#else
r = mkdir(dirname, 0700);
diff --git a/src/or/config.c b/src/or/config.c
index 2661ce3b73..bff3e40b8c 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -302,6 +302,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("LogLevel"),
OBSOLETE("LogFile"),
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
+ V(TruncateLogFile, BOOL, "0"),
V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
@@ -557,7 +558,8 @@ static int check_server_ports(const smartlist_t *ports,
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static int options_init_logs(or_options_t *options, int validate_only);
+static int options_init_logs(const or_options_t *old_options,
+ or_options_t *options, int validate_only);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
@@ -1145,7 +1147,8 @@ 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 tor_log(s) */
+ /* Configure the tor_log(s) */
+ if (options_init_logs(old_options, options, 0)<0) {
*msg = tor_strdup("Failed to init Log options. See logs for details.");
goto rollback;
}
@@ -1592,6 +1595,20 @@ options_act(const or_options_t *old_options)
return -1;
}
+ config_maybe_load_geoip_files_(options, old_options);
+
+ if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
+ /* ExcludeUnknown is true or "auto" */
+ const int is_auto = options->GeoIPExcludeUnknown == -1;
+ int changed;
+
+ changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
+ changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
+
+ if (changed)
+ routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
+ }
+
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@@ -1687,20 +1704,6 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options);
}
- config_maybe_load_geoip_files_(options, old_options);
-
- if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
- /* ExcludeUnknown is true or "auto" */
- const int is_auto = options->GeoIPExcludeUnknown == -1;
- int changed;
-
- changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
- changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
-
- if (changed)
- routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
- }
-
if (options->CellStatistics || options->DirReqStatistics ||
options->EntryStatistics || options->ExitPortStatistics ||
options->ConnDirectionStatistics ||
@@ -2547,7 +2550,8 @@ 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 tor_log(s) */
+ /* Validate the tor_log(s) */
+ if (options_init_logs(old_options, options, 1)<0)
REJECT("Failed to validate Log options. See logs for details.");
if (authdir_mode(options)) {
@@ -4446,7 +4450,8 @@ addressmap_register_auto(const char *from, const char *to,
* Initialize the logs based on the configuration file.
*/
static int
-options_init_logs(or_options_t *options, int validate_only)
+options_init_logs(const or_options_t *old_options, or_options_t *options,
+ int validate_only)
{
config_line_t *opt;
int ok;
@@ -4539,7 +4544,21 @@ options_init_logs(or_options_t *options, int validate_only)
!strcasecmp(smartlist_get(elts,0), "file")) {
if (!validate_only) {
char *fname = expand_filename(smartlist_get(elts, 1));
- if (add_file_log(severity, fname) < 0) {
+ /* Truncate if TruncateLogFile is set and we haven't seen this option
+ line before. */
+ int truncate = 0;
+ if (options->TruncateLogFile) {
+ truncate = 1;
+ if (old_options) {
+ config_line_t *opt2;
+ for (opt2 = old_options->Logs; opt2; opt2 = opt2->next)
+ if (!strcmp(opt->value, opt2->value)) {
+ truncate = 0;
+ break;
+ }
+ }
+ }
+ if (add_file_log(severity, fname, truncate) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
opt->value, strerror(errno));
ok = 0;
diff --git a/src/or/connection.c b/src/or/connection.c
index 4788bdf950..4d7cec7f9a 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -3715,9 +3715,15 @@ connection_handle_write_impl(connection_t *conn, int force)
if (connection_state_is_connecting(conn)) {
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) {
log_warn(LD_BUG, "getsockopt() syscall failed");
- if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(TO_EDGE_CONN(conn));
- connection_mark_for_close(conn);
+ if (conn->type == CONN_TYPE_OR) {
+ or_connection_t *orconn = TO_OR_CONN(conn);
+ connection_or_close_for_error(orconn, 0);
+ } else {
+ if (CONN_IS_EDGE(conn)) {
+ connection_edge_end_errno(TO_EDGE_CONN(conn));
+ }
+ connection_mark_for_close(conn);
+ }
return -1;
}
if (e) {
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 61b2c29b38..62af8e2f50 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -414,12 +414,6 @@ cpuworker_main(void *data)
cpuworker_reply_t rpl;
fd = fdarray[1]; /* this side is ours */
-#ifndef TOR_IS_MULTITHREADED
- tor_close_socket(fdarray[0]); /* this is the side of the socketpair the
- * parent uses */
- tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
- handle_signals(0); /* ignore interrupts from the keyboard, etc */
-#endif
tor_free(data);
setup_server_onion_keys(&onion_keys);
@@ -535,10 +529,6 @@ spawn_cpuworker(void)
return -1;
}
log_debug(LD_OR,"just spawned a cpu worker.");
-#ifndef TOR_IS_MULTITHREADED
- tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */
- tor_free(fdarray);
-#endif
conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
diff --git a/src/or/directory.c b/src/or/directory.c
index 51ea312689..d8492cbbec 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -197,9 +197,9 @@ dir_conn_purpose_to_string(int purpose)
return "(unknown)";
}
-/** Return true iff <b>identity_digest</b> is the digest of a router we
- * believe to support extrainfo downloads. (If <b>is_authority</b> we do
- * additional checking that's only valid for authorities.) */
+/** Return true iff <b>identity_digest</b> is the digest of a router which
+ * says that it caches extrainfos. (If <b>is_authority</b> we always
+ * believe that to be true.) */
int
router_supports_extrainfo(const char *identity_digest, int is_authority)
{
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 49fafafab2..f72f19f025 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1468,7 +1468,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
* to fix the bug was 0.2.2.25-alpha. */
return (router->wants_to_be_hs_dir && router->dir_port &&
uptime >= get_options()->MinUptimeHidServDirectoryV2 &&
- node->is_running);
+ router_is_active(router, node, now));
}
/** Don't consider routers with less bandwidth than this when computing
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 66b7201187..365b9274ec 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -12,6 +12,8 @@
* circumvention).
**/
+#define ENTRYNODES_PRIVATE
+
#include "or.h"
#include "circpathbias.h"
#include "circuitbuild.h"
@@ -155,7 +157,7 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node,
/** Return true iff enough time has passed since we last tried to connect
* to the unreachable guard <b>e</b> that we're willing to try again. */
static int
-entry_is_time_to_retry(entry_guard_t *e, time_t now)
+entry_is_time_to_retry(const entry_guard_t *e, time_t now)
{
long diff;
if (e->last_attempted < e->unreachable_since)
@@ -188,12 +190,17 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now)
* If need_descriptor is true, only return the node if we currently have
* a descriptor (routerinfo or microdesc) for it.
*/
-static INLINE const node_t *
-entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
- int assume_reachable, int need_descriptor, const char **msg)
+STATIC const node_t *
+entry_is_live(const entry_guard_t *e, entry_is_live_flags_t flags,
+ const char **msg)
{
const node_t *node;
const or_options_t *options = get_options();
+ int need_uptime = (flags & ENTRY_NEED_UPTIME) != 0;
+ int need_capacity = (flags & ENTRY_NEED_CAPACITY) != 0;
+ const int assume_reachable = (flags & ENTRY_ASSUME_REACHABLE) != 0;
+ const int need_descriptor = (flags & ENTRY_NEED_DESCRIPTOR) != 0;
+
tor_assert(msg);
if (e->path_bias_disabled) {
@@ -255,12 +262,18 @@ num_live_entry_guards(int for_directory)
{
int n = 0;
const char *msg;
+ /* Set the entry node attributes we are interested in. */
+ entry_is_live_flags_t entry_flags = ENTRY_NEED_CAPACITY;
+ if (!for_directory) {
+ entry_flags |= ENTRY_NEED_DESCRIPTOR;
+ }
+
if (! entry_guards)
return 0;
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
if (for_directory && !entry->is_dir_cache)
continue;
- if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg))
+ if (entry_is_live(entry, entry_flags, &msg))
++n;
} SMARTLIST_FOREACH_END(entry);
return n;
@@ -289,7 +302,7 @@ log_entry_guards(int severity)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
{
const char *msg = NULL;
- if (entry_is_live(e, 0, 1, 0, 0, &msg))
+ if (entry_is_live(e, ENTRY_NEED_CAPACITY, &msg))
smartlist_add_asprintf(elements, "%s [%s] (up %s)",
e->nickname,
hex_str(e->identity, DIGEST_LEN),
@@ -350,7 +363,7 @@ control_event_guard_deferred(void)
* If <b>chosen</b> is defined, use that one, and if it's not
* already in our entry_guards list, put it at the *beginning*.
* Else, put the one we pick at the end of the list. */
-static const node_t *
+STATIC const node_t *
add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
int for_discovery, int for_directory)
{
@@ -437,7 +450,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
/** Choose how many entry guards or directory guards we'll use. If
* <b>for_directory</b> is true, we return how many directory guards to
* use; else we return how many entry guards to use. */
-static int
+STATIC int
decide_num_guards(const or_options_t *options, int for_directory)
{
if (for_directory) {
@@ -676,7 +689,7 @@ entry_guards_compute_status(const or_options_t *options, time_t now)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
const char *reason = digestmap_get(reasons, entry->identity);
const char *live_msg = "";
- const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg);
+ const node_t *r = entry_is_live(entry, ENTRY_NEED_CAPACITY, &live_msg);
log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
entry->nickname,
hex_str(entry->identity, DIGEST_LEN),
@@ -794,7 +807,9 @@ entry_guard_register_connect_status(const char *digest, int succeeded,
break;
if (e->made_contact) {
const char *msg;
- const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg);
+ const node_t *r = entry_is_live(e,
+ ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE,
+ &msg);
if (r && e->unreachable_since) {
refuse_conn = 1;
e->can_retry = 1;
@@ -847,7 +862,7 @@ update_node_guard_status(void)
/** Adjust the entry guards list so that it only contains entries from
* EntryNodes, adding new entries from EntryNodes to the list as needed. */
-static void
+STATIC void
entry_guards_set_from_config(const or_options_t *options)
{
smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
@@ -1007,47 +1022,61 @@ choose_random_dirguard(dirinfo_type_t type)
return choose_random_entry_impl(NULL, 1, type, NULL);
}
-/** Helper for choose_random{entry,dirguard}. */
-static const node_t *
-choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
- dirinfo_type_t dirinfo_type, int *n_options_out)
+/** Filter <b>all_entry_guards</b> for usable entry guards and put them
+ * in <b>live_entry_guards</b>. We filter based on whether the node is
+ * currently alive, and on whether it satisfies the restrictions
+ * imposed by the other arguments of this function.
+ *
+ * We don't place more guards than NumEntryGuards in <b>live_entry_guards</b>.
+ *
+ * If <b>chosen_exit</b> is set, it contains the exit node of this
+ * circuit. Make sure to not use it or its family as an entry guard.
+ *
+ * If <b>need_uptime</b> is set, we are looking for a stable entry guard.
+ * if <b>need_capacity</b> is set, we are looking for a fast entry guard.
+ *
+ * The rest of the arguments are the same as in choose_random_entry_impl().
+ *
+ * Return 1 if we should choose a guard right away. Return 0 if we
+ * should try to add more nodes to our list before deciding on a
+ * guard.
+ */
+STATIC int
+populate_live_entry_guards(smartlist_t *live_entry_guards,
+ const smartlist_t *all_entry_guards,
+ const node_t *chosen_exit,
+ dirinfo_type_t dirinfo_type,
+ int for_directory,
+ int need_uptime, int need_capacity)
{
const or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_new();
- smartlist_t *exit_family = smartlist_new();
- const node_t *chosen_exit =
- state?build_state_get_exit_node(state) : NULL;
const node_t *node = NULL;
- int need_uptime = state ? state->need_uptime : 0;
- int need_capacity = state ? state->need_capacity : 0;
- int preferred_min, consider_exit_family = 0;
- int need_descriptor = !for_directory;
const int num_needed = decide_num_guards(options, for_directory);
+ smartlist_t *exit_family = smartlist_new();
+ int retval = 0;
+ entry_is_live_flags_t entry_flags = 0;
- if (n_options_out)
- *n_options_out = 0;
+ { /* Set the flags we want our entry node to have */
+ if (need_uptime) {
+ entry_flags |= ENTRY_NEED_UPTIME;
+ }
+ if (need_capacity) {
+ entry_flags |= ENTRY_NEED_CAPACITY;
+ }
+ if (!for_directory) {
+ entry_flags |= ENTRY_NEED_DESCRIPTOR;
+ }
+ }
+
+ tor_assert(all_entry_guards);
if (chosen_exit) {
nodelist_add_node_and_family(exit_family, chosen_exit);
- consider_exit_family = 1;
}
- if (!entry_guards)
- entry_guards = smartlist_new();
-
- if (should_add_entry_nodes)
- entry_guards_set_from_config(options);
-
- if (!entry_list_is_constrained(options) &&
- smartlist_len(entry_guards) < num_needed)
- pick_entry_guards(options, for_directory);
-
- retry:
- smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
const char *msg;
- node = entry_is_live(entry, need_uptime, need_capacity, 0,
- need_descriptor, &msg);
+ node = entry_is_live(entry, entry_flags, &msg);
if (!node)
continue; /* down, no point */
if (for_directory) {
@@ -1056,39 +1085,94 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
}
if (node == chosen_exit)
continue; /* don't pick the same node for entry and exit */
- if (consider_exit_family && smartlist_contains(exit_family, node))
+ if (smartlist_contains(exit_family, node))
continue; /* avoid relays that are family members of our exit */
if (dirinfo_type != NO_DIRINFO &&
!node_can_handle_dirinfo(node, dirinfo_type))
continue; /* this node won't be able to answer our dir questions */
-#if 0 /* since EntryNodes is always strict now, this clause is moot */
- if (options->EntryNodes &&
- !routerset_contains_node(options->EntryNodes, node)) {
- /* We've come to the end of our preferred entry nodes. */
- if (smartlist_len(live_entry_guards))
- goto choose_and_finish; /* only choose from the ones we like */
- if (options->StrictNodes) {
- /* in theory this case should never happen, since
- * entry_guards_set_from_config() drops unwanted relays */
- tor_fragile_assert();
- } else {
- log_info(LD_CIRC,
- "No relays from EntryNodes available. Using others.");
- }
- }
-#endif
smartlist_add(live_entry_guards, (void*)node);
if (!entry->made_contact) {
/* Always start with the first not-yet-contacted entry
* guard. Otherwise we might add several new ones, pick
* the second new one, and now we've expanded our entry
* guard list without needing to. */
- goto choose_and_finish;
+ retval = 1;
+ goto done;
+ }
+ if (smartlist_len(live_entry_guards) >= num_needed) {
+ retval = 1;
+ goto done; /* We picked enough entry guards. Done! */
}
- if (smartlist_len(live_entry_guards) >= num_needed)
- goto choose_and_finish; /* we have enough */
} SMARTLIST_FOREACH_END(entry);
+ done:
+ smartlist_free(exit_family);
+
+ return retval;
+}
+
+/** Pick a node to be used as the entry guard of a circuit.
+ *
+ * If <b>state</b> is set, it contains the information we know about
+ * the upcoming circuit.
+ *
+ * If <b>for_directory</b> is set, we are looking for a directory guard.
+ *
+ * <b>dirinfo_type</b> contains the kind of directory information we
+ * are looking for in our node.
+ *
+ * If <b>n_options_out</b> is set, we set it to the number of
+ * candidate guard nodes we had before picking a specific guard node.
+ *
+ * On success, return the node that should be used as the entry guard
+ * of the circuit. Return NULL if no such node could be found.
+ *
+ * Helper for choose_random{entry,dirguard}.
+*/
+static const node_t *
+choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
+ dirinfo_type_t dirinfo_type, int *n_options_out)
+{
+ const or_options_t *options = get_options();
+ smartlist_t *live_entry_guards = smartlist_new();
+ const node_t *chosen_exit =
+ state?build_state_get_exit_node(state) : NULL;
+ const node_t *node = NULL;
+ int need_uptime = state ? state->need_uptime : 0;
+ int need_capacity = state ? state->need_capacity : 0;
+ int preferred_min = 0;
+ const int num_needed = decide_num_guards(options, for_directory);
+ int retval = 0;
+
+ if (n_options_out)
+ *n_options_out = 0;
+
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+
+ if (should_add_entry_nodes)
+ entry_guards_set_from_config(options);
+
+ if (!entry_list_is_constrained(options) &&
+ smartlist_len(entry_guards) < num_needed)
+ pick_entry_guards(options, for_directory);
+
+ retry:
+ smartlist_clear(live_entry_guards);
+
+ /* Populate the list of live entry guards so that we pick one of
+ them. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ entry_guards,
+ chosen_exit,
+ dirinfo_type,
+ for_directory,
+ need_uptime, need_capacity);
+
+ if (retval == 1) { /* We should choose a guard right now. */
+ goto choose_and_finish;
+ }
+
if (entry_list_is_constrained(options)) {
/* If we prefer the entry nodes we've got, and we have at least
* one choice, that's great. Use it. */
@@ -1127,18 +1211,7 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
need_capacity = 0;
goto retry;
}
-#if 0
- /* Removing this retry logic: if we only allow one exit, and it is in the
- same family as all our entries, then we are just plain not going to win
- here. */
- if (!node && entry_list_is_constrained(options) && consider_exit_family) {
- /* still no? if we're using bridges or have strictentrynodes
- * set, and our chosen exit is in the same family as all our
- * bridges/entry guards, then be flexible about families. */
- consider_exit_family = 0;
- goto retry;
- }
-#endif
+
/* live_entry_guards may be empty below. Oh well, we tried. */
}
@@ -1156,7 +1229,6 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
if (n_options_out)
*n_options_out = smartlist_len(live_entry_guards);
smartlist_free(live_entry_guards);
- smartlist_free(exit_family);
return node;
}
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index e229f3b79a..5d91756aa4 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -77,6 +77,35 @@ int num_live_entry_guards(int for_directory);
#endif
+#ifdef ENTRYNODES_PRIVATE
+STATIC const node_t *add_an_entry_guard(const node_t *chosen,
+ int reset_status, int prepend,
+ int for_discovery, int for_directory);
+
+STATIC int populate_live_entry_guards(smartlist_t *live_entry_guards,
+ const smartlist_t *all_entry_guards,
+ const node_t *chosen_exit,
+ dirinfo_type_t dirinfo_type,
+ int for_directory,
+ int need_uptime, int need_capacity);
+STATIC int decide_num_guards(const or_options_t *options, int for_directory);
+
+STATIC void entry_guards_set_from_config(const or_options_t *options);
+
+/** Flags to be passed to entry_is_live() to indicate what kind of
+ * entry nodes we are looking for. */
+typedef enum {
+ ENTRY_NEED_UPTIME = 1<<0,
+ ENTRY_NEED_CAPACITY = 1<<1,
+ ENTRY_ASSUME_REACHABLE = 1<<2,
+ ENTRY_NEED_DESCRIPTOR = 1<<3,
+} entry_is_live_flags_t;
+
+STATIC const node_t *entry_is_live(const entry_guard_t *e,
+ entry_is_live_flags_t flags,
+ const char **msg);
+#endif
+
void remove_all_entry_guards(void);
void entry_guards_compute_status(const or_options_t *options, time_t now);
diff --git a/src/or/main.c b/src/or/main.c
index 9c1cabf037..c7b532bbab 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1861,6 +1861,10 @@ do_hup(void)
return -1;
}
options = get_options(); /* they have changed now */
+ /* Logs are only truncated the first time they are opened, but were
+ probably intended to be cleaned up on signal. */
+ if (options->TruncateLogFile)
+ truncate_logs();
} else {
char *msg = NULL;
log_notice(LD_GENERAL, "Not reloading config file: the controller told "
@@ -2709,31 +2713,6 @@ do_dump_config(void)
return 0;
}
-#if defined (WINCE)
-int
-find_flashcard_path(PWCHAR path, size_t size)
-{
- WIN32_FIND_DATA d = {0};
- HANDLE h = NULL;
-
- if (!path)
- return -1;
-
- h = FindFirstFlashCard(&d);
- if (h == INVALID_HANDLE_VALUE)
- return -1;
-
- if (wcslen(d.cFileName) == 0) {
- FindClose(h);
- return -1;
- }
-
- wcsncpy(path,d.cFileName,size);
- FindClose(h);
- return 0;
-}
-#endif
-
static void
init_addrinfo(void)
{
@@ -2962,31 +2941,6 @@ int
tor_main(int argc, char *argv[])
{
int result = 0;
-#if defined (WINCE)
- WCHAR path [MAX_PATH] = {0};
- WCHAR fullpath [MAX_PATH] = {0};
- PWCHAR p = NULL;
- FILE* redir = NULL;
- FILE* redirdbg = NULL;
-
- // this is to facilitate debugging by opening
- // a file on a folder shared by the wm emulator.
- // if no flashcard (real or emulated) is present,
- // log files will be written in the root folder
- if (find_flashcard_path(path,MAX_PATH) == -1) {
- redir = _wfreopen( L"\\stdout.log", L"w", stdout );
- redirdbg = _wfreopen( L"\\stderr.log", L"w", stderr );
- } else {
- swprintf(fullpath,L"\\%s\\tor",path);
- CreateDirectory(fullpath,NULL);
-
- swprintf(fullpath,L"\\%s\\tor\\stdout.log",path);
- redir = _wfreopen( fullpath, L"w", stdout );
-
- swprintf(fullpath,L"\\%s\\tor\\stderr.log",path);
- redirdbg = _wfreopen( fullpath, L"w", stderr );
- }
-#endif
#ifdef _WIN32
/* Call SetProcessDEPPolicy to permanently enable DEP.
diff --git a/src/or/ntmain.h b/src/or/ntmain.h
index d3027936cd..d09a413aee 100644
--- a/src/or/ntmain.h
+++ b/src/or/ntmain.h
@@ -13,10 +13,8 @@
#define TOR_NTMAIN_H
#ifdef _WIN32
-#if !defined (WINCE)
#define NT_SERVICE
#endif
-#endif
#ifdef NT_SERVICE
int nt_service_parse_options(int argc, char **argv, int *should_exit);
diff --git a/src/or/or.h b/src/or/or.h
index 131bce3e11..0419111a4e 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3402,6 +3402,8 @@ typedef struct {
int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which
* each log message occurs? */
+ int TruncateLogFile; /**< Boolean: Should we truncate the log file
+ before we start writing? */
char *DebugLogFile; /**< Where to send verbose log messages. */
char *DataDirectory; /**< OR only: where to store long-term data. */
diff --git a/src/or/reasons.c b/src/or/reasons.c
index 750e89bbe7..1a53a93d88 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -367,7 +367,7 @@ circuit_end_reason_to_control_string(int reason)
}
}
-/** Return a string corresponding to a SOCKS4 reponse code. */
+/** Return a string corresponding to a SOCKS4 response code. */
const char *
socks4_response_code_to_string(uint8_t code)
{
@@ -385,7 +385,7 @@ socks4_response_code_to_string(uint8_t code)
}
}
-/** Return a string corresponding to a SOCKS5 reponse code. */
+/** Return a string corresponding to a SOCKS5 response code. */
const char *
socks5_response_code_to_string(uint8_t code)
{
diff --git a/src/or/router.c b/src/or/router.c
index 2cdbb0c8bb..4fcd4a5b89 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2371,7 +2371,8 @@ router_dump_router_to_string(routerinfo_t *router,
has_extra_info_digest ? "extra-info-digest " : "",
has_extra_info_digest ? extra_info_digest : "",
has_extra_info_digest ? "\n" : "",
- options->DownloadExtraInfo ? "caches-extra-info\n" : "",
+ (options->DownloadExtraInfo || options->V3AuthoritativeDir) ?
+ "caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
we_are_hibernating() ? "hibernating 1\n" : "",
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index b5e924522e..9493c8094a 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -448,9 +448,10 @@ trusted_dirs_flush_certs_to_disk(void)
trusted_dir_servers_certs_changed = 0;
}
-/** Remove all v3 authority certificates that have been superseded for more
- * than 48 hours. (If the most recent cert was published more than 48 hours
- * ago, then we aren't going to get any consensuses signed with older
+/** Remove all expired v3 authority certificates that have been superseded for
+ * more than 48 hours or, if not expired, that were published more than 7 days
+ * before being superseded. (If the most recent cert was published more than 48
+ * hours ago, then we aren't going to get any consensuses signed with older
* keys.) */
static void
trusted_dirs_remove_old_certs(void)
@@ -488,6 +489,7 @@ trusted_dirs_remove_old_certs(void)
} SMARTLIST_FOREACH_END(cert);
}
} DIGESTMAP_FOREACH_END;
+#undef DEAD_CERT_LIFETIME
#undef OLD_CERT_LIFETIME
trusted_dirs_flush_certs_to_disk();
@@ -1438,7 +1440,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- int is_trusted;
+ int is_trusted, is_trusted_extrainfo;
int is_overloaded;
tor_addr_t addr;
const routerstatus_t *status = node->rs;
@@ -1453,8 +1455,10 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
if (requireother && router_digest_is_me(node->identity))
continue;
is_trusted = router_digest_is_trusted_dir(node->identity);
+ is_trusted_extrainfo = router_digest_is_trusted_dir_type(
+ node->identity, EXTRAINFO_DIRINFO);
if ((type & EXTRAINFO_DIRINFO) &&
- !router_supports_extrainfo(node->identity, 0))
+ !router_supports_extrainfo(node->identity, is_trusted_extrainfo))
continue;
if ((type & MICRODESC_DIRINFO) && !is_trusted &&
!node->rs->version_supports_microdesc_cache)
@@ -3292,6 +3296,14 @@ routerlist_reset_warnings(void)
networkstatus_reset_warnings();
}
+/** Return 1 if the signed descriptor of this router is older than
+ * <b>seconds</b> seconds. Otherwise return 0. */
+MOCK_IMPL(int,
+router_descriptor_is_older_than,(const routerinfo_t *router, int seconds))
+{
+ return router->cache_info.published_on < time(NULL) - seconds;
+}
+
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
* older entries (if any) with the same key. Note: Callers should not hold
* their pointers to <b>router</b> if this function fails; <b>router</b>
@@ -3461,7 +3473,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
}
if (!in_consensus && from_cache &&
- router->cache_info.published_on < time(NULL) - OLD_ROUTER_DESC_MAX_AGE) {
+ router_descriptor_is_older_than(router, OLD_ROUTER_DESC_MAX_AGE)) {
*msg = "Router descriptor was really old.";
routerinfo_free(router);
return ROUTER_WAS_NOT_NEW;
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index 6e2f2eaea0..52f2303c7c 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -212,6 +212,9 @@ STATIC int choose_array_element_by_weight(const u64_dbl_t *entries,
int n_entries);
STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
uint64_t *total_out);
+
+MOCK_DECL(int, router_descriptor_is_older_than, (const routerinfo_t *router,
+ int seconds));
#endif
#endif
diff --git a/src/test/include.am b/src/test/include.am
index fba439a616..d5163aac2f 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -28,6 +28,7 @@ src_test_test_SOURCES = \
src/test/test_cell_queue.c \
src/test/test_data.c \
src/test/test_dir.c \
+ src/test/test_entrynodes.c \
src/test/test_extorport.c \
src/test/test_introduce.c \
src/test/test_logging.c \
@@ -71,7 +72,8 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
noinst_HEADERS+= \
- src/test/test.h
+ src/test/test.h \
+ src/test/test_descriptors.inc
if CURVE25519_ENABLED
noinst_PROGRAMS+= src/test/test-ntor-cl
diff --git a/src/test/test.c b/src/test/test.c
index 8bce9c91f4..5786f3ca54 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -106,11 +106,18 @@ setup_directory(void)
{
char buf[MAX_PATH];
const char *tmp = buf;
+ const char *extra_backslash = "";
/* If this fails, we're probably screwed anyway */
if (!GetTempPathA(sizeof(buf),buf))
- tmp = "c:\\windows\\temp";
+ tmp = "c:\\windows\\temp\\";
+ if (strcmpend(tmp, "\\")) {
+ /* According to MSDN, it should be impossible for GetTempPath to give us
+ * an answer that doesn't end with \. But let's make sure. */
+ extra_backslash = "\\";
+ }
tor_snprintf(temp_dir, sizeof(temp_dir),
- "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32);
+ "%s%stor_test_%d_%s", tmp, extra_backslash,
+ (int)getpid(), rnd32);
r = mkdir(temp_dir);
}
#else
@@ -1306,6 +1313,7 @@ extern struct testcase_t circuitmux_tests[];
extern struct testcase_t cell_queue_tests[];
extern struct testcase_t options_tests[];
extern struct testcase_t socks_tests[];
+extern struct testcase_t entrynodes_tests[];
extern struct testcase_t extorport_tests[];
extern struct testcase_t controller_event_tests[];
extern struct testcase_t logging_tests[];
@@ -1337,6 +1345,7 @@ static struct testgroup_t testgroups[] = {
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
{ "options/", options_tests },
+ { "entrynodes/", entrynodes_tests },
{ "extorport/", extorport_tests },
{ "control/", controller_event_tests },
{ "hs/", hs_tests },
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 94ac4dca13..b35984f761 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -184,7 +184,7 @@ is_private_dir(const char* path)
if (r) {
return 0;
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
if ((st.st_mode & (S_IFDIR | 0777)) != (S_IFDIR | 0700)) {
return 0;
}
@@ -201,7 +201,7 @@ test_config_check_or_create_data_subdir(void *arg)
char *subpath;
struct stat st;
int r;
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
unsigned group_permission;
#endif
(void)arg;
@@ -210,7 +210,7 @@ test_config_check_or_create_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0"));
subpath = get_datadir_fname(subdir);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
tt_int_op(mkdir(options->DataDirectory), ==, 0);
#else
tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
@@ -233,7 +233,7 @@ test_config_check_or_create_data_subdir(void *arg)
tt_abort_perror("stat");
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
group_permission = st.st_mode | 0070;
r = chmod(subpath, group_permission);
@@ -284,7 +284,7 @@ test_config_write_to_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1"));
filepath = get_datadir_fname2(subdir, fname);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
tt_int_op(mkdir(options->DataDirectory), ==, 0);
#else
tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
diff --git a/src/test/test_descriptors.inc b/src/test/test_descriptors.inc
new file mode 100644
index 0000000000..ecbccbd43a
--- /dev/null
+++ b/src/test/test_descriptors.inc
@@ -0,0 +1,305 @@
+const char TEST_DESCRIPTORS[] =
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test000a 127.0.0.1 5000 0 7000\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint C7E7 CCB8 179F 8CC3 7F5C 8A04 2B3A 180B 934B 14BA\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 67A152A4C7686FB07664F872620635F194D76D95\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAOuBUIEBARMkkka/TGyaQNgUEDLP0KG7sy6KNQTNOlZHUresPr/vlVjo\n"
+"HPpLMfu9M2z18c51YX/muWwY9x4MyQooD56wI4+AqXQcJRwQfQlPn3Ay82uZViA9\n"
+"DpBajRieLlKKkl145KjArpD7F5BVsqccvjErgFYXvhhjSrx7BVLnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAN6NLnSxWQnFXxqZi5D3b0BMgV6y9NJLGjYQVP+eWtPZWgqyv4zeYsqv\n"
+"O9y6c5lvxyUxmNHfoAbe/s8f2Vf3/YaC17asAVSln4ktrr3e9iY74a9RMWHv1Gzk\n"
+"3042nMcqj3PEhRN0PoLkcOZNjjmNbaqki6qy9bWWZDNTdo+uI44dAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth0@test.test\n"
+"ntor-onion-key pK4bs08ERYN591jj7ca17Rn9Q02TIEfhnjR6hSq+fhU=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"rx88DuM3Y7tODlHNDDEVzKpwh3csaG1or+T4l2Xs1oq3iHHyPEtB6QTLYrC60trG\n"
+"aAPsj3DEowGfjga1b248g2dtic8Ab+0exfjMm1RHXfDam5TXXZU3A0wMyoHjqHuf\n"
+"eChGPgFNUvEc+5YtD27qEDcUjcinYztTs7/dzxBT4PE=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test001a 127.0.0.1 5001 0 7001\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 35DA 711C FC62 F88B C243 DE32 DC0B C28A 3F62 2610\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 9E12278D6CF7608071FE98CE9DCEE48FA264518A\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAPbyUrorqoXMW4oezqd307ZGxgobqvQs2nb3TdQyWrwsHtJmS3utdrJS\n"
+"xJUZPNHOQ2hrDWW1VvevYqRTGeXGZr9TDZ3+t/gVUttqYRhuzzgEKVAZSsTo5ctO\n"
+"QNHnzJ6Xx/w/trhWqPTeJ7R0TCyAbWW7aE3KaKdwvZilRZp/oRUnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALwOJ7XZHBnjJEuwF3Os6eashNbTH9YnH8TBZBdKgu3iFJYqDslcMIPX\n"
+"gWCJ9apPHyh1+/8OLRWeEYlwoZzgGi0rjm/+BNeOOmJbjfyjk97DuB9/2O5zr1BM\n"
+"CvOHqQSzMD+vz1ebvfM039a2mO8lXruUFPZQaFVxk8371XP2khqhAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth1@test.test\n"
+"ntor-onion-key t5bI1ksTdigOksMKRHUDwx/34ajEvDN1IpArOxIEWgk=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"KtMW7A/pzu+np6aKJSy6d7drIb4yjz8SPCo+oQNxj2IqNHJir2O2nWu69xy+K0c1\n"
+"RL05KkcDaYzr5hC80FD1H+sTpGYD28SPkQkzPw+0pReSDl93pVXh0rU6Cdcm75FC\n"
+"t0UZzDt4TsMuFB0ZYpM3phKcQPpiDG6aR0LskL/YUvY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test004r 127.0.0.1 5004 0 7004\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:10\n"
+"fingerprint CC6A 48BD 52BD 9A2C 6670 5863 AC31 AE17 6E63 8B02\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest B5CC249CEF394B5AFCA0C77FA7D5605615FA487C\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAMze36Hupy7HACcF3TMv5mJuZbx3d3cS0WYLl6vTeChBgpS5CEXq6zIu\n"
+"d31YmtUcxH6fOjDOudhbnXuoh1nH4CP+LocVHAdlGG1giAm7u8yZudVvVJiIqFgQ\n"
+"wVDcWx8LbGCi5P9J/ZPKAIVsSyS7xkOqHjz3VMo/uYLbQCFAwfkdAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAM/qGP365x6bH+ug7rKVy7V5lC9Ff2Jfk0wlTFIzzwn+DMSG6xDvulKe\n"
+"wcIzgGNdQu7qlKlQUif3GPMr0KSS32cRsmoRQJcsm9+lGUK871NyZ8AyrHT+LhyF\n"
+"cs718P0iN5yKF2FikNr727kEANCzvC1l9eP4qF5GGzsNtglbJ7bTAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key a9Pavqnx7DFhMWUO0d17qF9Py8+iie4FnxTHaTgfIXY=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"HVW7kjBgEt+Qdvcrq+NQE1F9B8uV9D38KA2Bp6cYHLWCxL6N4GS8JQqbOEtnqaj7\n"
+"Vxrv7uy1Fzb15Zr+1sUVMxNv+LLRfr+JzfETMNYVkYDrNgr1cAAVEQzFWbIziond\n"
+"xMFp64yjEW9/I+82lb5GBZEiKdEd4QqWMmQosoYMTM8=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test002a 127.0.0.1 5002 0 7002\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 29C7 BBB6 C437 32D5 BDF1 5671 F5C5 F1FB 6E36 4B47\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 9BB181EA86E0130680C3CC04AD7DE4C341ADC2C7\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALNH19oF8Ajf+djlH/g7L+enFBf5Wwjmf3bPwNKWZ9G+B+Lg8SpfhZiw\n"
+"rUqi7h21f45BV/dN05dK6leWD8rj1T9kuM9TKBOEZxIWeq7zbXihyu4XPxP4FNTS\n"
+"+0G7BhdP4biALENmeyLhUCZaw5Ic/jFkHT4gV9S0iVZiEDwC9twXAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALeyQGMQBHgTxpO/i30uHjflTm9MNi3ZBNcOKpvBXWYgY42qTqOZ7Uam\n"
+"c5pmZhTLrQ1W8XlGDw8Cl8ktZ0ylodLZyUNajBtJvSFWTb8iwdZsshW6Ahb8TyfI\n"
+"Y7MwTlQ/7xw4mj1NEaui6bwGgEZUs18RTqhDrUc2Mcj1Yf61Rq+7AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth2@test.test\n"
+"ntor-onion-key ukR41RjtiZ69KO0SrFTvL0LoZK/ZTT01FQWmCXTCUlE=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"IY2s/RY4tdahrgfGG+vW7lOvpfofoxxSo7guGpSKGxVApiroCQtumoYifnnJ88G2\n"
+"K4IbxwEO8pgO8fnz1mibblUWw2vdDNjCifc1wtXJUE+ONA0UcLRlfQ94GbL8h2PG\n"
+"72z6i1+NN0QahXMk7MUbzI7bOXTJOiO8e2Zjk9vRnxI=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test006r 127.0.0.1 5006 0 7006\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 829B 3FAA A42B 605A EB0B F380 8F32 8ED1 73E7 0D25\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 7ECB757002EB9B5838B13AE6F2357A5E585131B8\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALsNBChcLVndlS4HNXL3hxBJVgXctATz6yXcJt3bkDB5cjv7Q9fqN3Ue\n"
+"j3SI1OUBx4YrLcSLD/hELHVilLrrfbaraAFfAsydlRLjTVcMRx5FFlDd0E7TAadc\n"
+"71CkTipNnjwqz1mTRKkEFeepnh/JaFDidY9ER1rMBA5JRyBvqrD9AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAPgipA8yLj1kqrMlAH7cK7IQEdmqmfNHGXdkYQ+TKtfLh0zeEIvvh9yh\n"
+"k+vKHS+HVoHo3tecB9QjJyDyyJTiETXCupSOY+ebG648JADAvv8v1WiE+KBXtjpl\n"
+"qgDTrDj5CwGuY6cvQdej5yg1UAVlMMZSg3thL3tCYtQbOq66lAlnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key q02F3AQsCX7+zXNpfTqBF8O8lusPhRJpQVxOnBvbOwc=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"L1fdgoN/eXgdzIIXO63W4yGoC9lRozMU+T0Fimhd/XFV8qxeUT83Vgf63vxLUHIb\n"
+"D4a80Wj7Pm4y5a766qLGXxlz2FYjCdkp070UpgZneB+VifUlFd/bNAjsiYTstBKM\n"
+"EI2L0mhl9d/7KK8vgtadHdX1z1u7QjyF6ccnzhfqeiY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test003r 127.0.0.1 5003 0 7003\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 71FD 3A35 F705 8020 D595 B711 D52A 9A0A 99BB B467\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 3796BE0A95B699595445DFD3453CA2074E75BCE8\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAL44ctIioIfCYFzMTYNfK5qFAPGGUpsAFmS8pThQEY/tJU14+frJDBrC\n"
+"BkLvBs05Bw7xOUb0f2geiYGowBA6028smiq5HzTO7Kaga8vfV7AnANPX+n9cfHCr\n"
+"/2cMnKkT/GZzpdk0WbUw5Kc/G1ATIPFQHA8gZAi1fsSIDDn3GRV5AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALlPo5AI1mVTi+194yOSf40caoFlxSTfXt8KjGVa1dO/bpX7L3noOjYg\n"
+"goU4Aqim7BHmBWQDE/tZNTrchFoLQFHi9N4pv/0ND3sY904pzqGpe3FeTuU8P9Jg\n"
+"q2w3MeO3GwG8CJf4FOdSkgi8UKkJhOld4g4kViQbrFLXfdFvnT/zAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key qluYCRrsesOTkavCLnNK6H1ToywyDquCyYeP0h/qol4=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"d09K7rW/OpVzoUpfZXJuJW7a+P4pROCOZTgvDUIy/Nv+EAjcYqv95PlJ8cAMqnn3\n"
+"1oQibRmmQwn0OmG5cB8NaZiueaVIRheGzHEM8rndpHn5oFXdFvV7KKjScvfuBbTk\n"
+"RYME8XyawRaqsEZnwirDDlZuiZOjdQs8bbGsko3grJE=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test005r 127.0.0.1 5005 0 7005\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint EB6E 42ED E6BF 5EE0 19F5 EFC1 53AD 094C 1327 7B76\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest C031EE4E1AE826C1E3C4E21D81C961869E63F5D2\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAMd9Fm4KTSjFDzEABPZ1fwBCC2DNgee6nAmlde8FRbCVfcIHRiJyv9YG\n"
+"h530yUJal3hBfiWwy/SBA4LDz1flNCEwJm81s3waj4T9c676dAOLPcnOcJM5SbaQ\n"
+"hYPDrIZLEZHAk+IoM+avKYYocwCJXwx6WTtsedF0wJBZ9mQAJERJAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAKT7ldhV43S1CgoER/pU0Rigf0NzcSy25DQJrMRQnNmXnL03Dwuv/Iu7\n"
+"dCjgg64odnvSkXHFhkbjGcg8aXikvfbMyZTbsD8NrrP6FS6pfgPgZD9W2TK7QdHI\n"
+"QXwx1IYaaJK4nDUNfJhjrclydEdxmHbO1nLG1aS0ypn/G0EBpOSnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key umFmyRPA0dIsi0CFYCbGIPe2+OUkyslTkKKDEohjQQg=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"JiXEbqPgDPWEb9DzCYINRXfmvMIc/IRtvshS8Vmmn7DW67TrTLKCEAnisGo92gMA\n"
+"bhxGb9G5Mxq/8YqGoqdI2Vp6tfKlz/9AmjHzFAo01y42gafXIdr1oUS2RimA8jfF\n"
+"hwfQkbG0FYEsJrH3EUa8sMhcjsEaohK/kgklMR7OgQY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test007r 127.0.0.1 5007 0 7007\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint DABD 2AAF 8C9F 3B71 7839 9C08 DCD8 CD9D 341D 0002\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest F80104A0DFFB4EB429325D41D1F71E5BF8C6C726\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAL42fYAriR/JeB/9NpVq5Y5EEHca+ugIpaSdRfbopWDtFjXLEk2jmO5A\n"
+"KoAGIkTKDr7e9101x63H+0Nh/7w3uYs/WqTXEH8/1sHwe+0PY2HL0S6qhlOo6X54\n"
+"EfK0nDDBAWFOpyiAMHRk8JVikKb56+FVIhCJgi1RIbLIiUQK2/kxAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAKQj2U5hmB68V6NQBqD8DfIkJjovvM8t6nGfYpkT8ORsROnmgI5mjM38\n"
+"cmh5GIjY9RgoOWolLmsWQ4SXtS0FvrPft1M61UMTSHzlrEeuod5KenV7vGlX2TxT\n"
+"0DoA5TL9yY7CmxCk8CNRCtN/g7WocgIiP4KCIiEZ4VE6LIb6sxUnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key 1UBS8rTlL39u9YxRJWhz+GTG1dS15VRi4au1i5qZOyI=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"m7xHh+XPdLN+qcMLz1dBAEAmcdCFrtdseMHCc0FyAP2kXdayxqe3o2IOOHN++bTH\n"
+"Y5iHsZembsIJJ+D/d0YEKWKh42TUWCXBu0Gbfc4OcNuR6PFlTWO2wk7rDT3HOiFr\n"
+"pe3wJqZYkLxlBDamROAlMMRe71iag89H/4EulC18opw=\n"
+"-----END SIGNATURE-----\n";
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
new file mode 100644
index 0000000000..ede93fb43a
--- /dev/null
+++ b/src/test/test_entrynodes.c
@@ -0,0 +1,636 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define STATEFILE_PRIVATE
+#define ENTRYNODES_PRIVATE
+#define ROUTERLIST_PRIVATE
+
+#include "or.h"
+#include "test.h"
+#include "entrynodes.h"
+#include "routerparse.h"
+#include "nodelist.h"
+#include "util.h"
+#include "routerlist.h"
+#include "routerset.h"
+#include "statefile.h"
+#include "config.h"
+
+#include "test_descriptors.inc"
+
+/* TODO:
+ * choose_random_entry() test with state set.
+ *
+ * parse_state() tests with more than one guards.
+ *
+ * More tests for set_from_config(): Multiple nodes, use fingerprints,
+ * use country codes.
+ */
+
+/** Dummy Tor state used in unittests. */
+static or_state_t *dummy_state = NULL;
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return dummy_state;
+}
+
+/* NOP replacement for router_descriptor_is_older_than() */
+static int
+router_descriptor_is_older_than_replacement(const routerinfo_t *router,
+ int seconds)
+{
+ (void) router;
+ (void) seconds;
+ return 0;
+}
+
+/* Number of descriptors contained in test_descriptors.txt. */
+#define NUMBER_OF_DESCRIPTORS 8
+
+/** Parse a file containing router descriptors and load them to our
+ routerlist. This function is used to setup an artificial network
+ so that we can conduct entry guard tests. */
+static void
+setup_fake_routerlist(void)
+{
+ int retval;
+ routerlist_t *our_routerlist = NULL;
+ smartlist_t *our_nodelist = NULL;
+
+ /* Read the file that contains our test descriptors. */
+
+ /* We need to mock this function otherwise the descriptors will not
+ accepted as they are too old. */
+ MOCK(router_descriptor_is_older_than,
+ router_descriptor_is_older_than_replacement);
+
+ /* Load all the test descriptors to the routerlist. */
+ retval = router_load_routers_from_string(TEST_DESCRIPTORS,
+ NULL, SAVED_IN_JOURNAL,
+ NULL, 0, NULL);
+ tt_int_op(retval, ==, NUMBER_OF_DESCRIPTORS);
+
+ /* Sanity checking of routerlist and nodelist. */
+ our_routerlist = router_get_routerlist();
+ tt_int_op(smartlist_len(our_routerlist->routers), ==, NUMBER_OF_DESCRIPTORS);
+ routerlist_assert_ok(our_routerlist);
+
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS);
+
+ /* Mark all routers as non-guards but up and running! */
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) {
+ node->is_running = 1;
+ node->is_valid = 1;
+ node->is_possible_guard = 0;
+ } SMARTLIST_FOREACH_END(node);
+
+ done:
+ UNMOCK(router_descriptor_is_older_than);
+}
+
+/* Unittest cleanup function: Cleanup the fake network. */
+static int
+fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ (void) testcase;
+ (void) ptr;
+
+ routerlist_free_all();
+ nodelist_free_all();
+ entry_guards_free_all();
+ or_state_free(dummy_state);
+
+ return 1; /* NOP */
+}
+
+/* Unittest setup function: Setup a fake network. */
+static void *
+fake_network_setup(const struct testcase_t *testcase)
+{
+ (void) testcase;
+
+ /* Setup fake state */
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ MOCK(get_or_state,
+ get_or_state_replacement);
+
+ /* Setup fake routerlist. */
+ setup_fake_routerlist();
+
+ /* Return anything but NULL (it's interpreted as test fail) */
+ return dummy_state;
+}
+
+/** Test choose_random_entry() with none of our routers being guard nodes. */
+static void
+test_choose_random_entry_no_guards(void *arg)
+{
+ const node_t *chosen_entry = NULL;
+
+ (void) arg;
+
+ /* Try to pick an entry even though none of our routers are guards. */
+ chosen_entry = choose_random_entry(NULL);
+
+ /* Unintuitively, we actually pick a random node as our entry,
+ because router_choose_random_node() relaxes its constraints if it
+ can't find a proper entry guard. */
+ test_assert(chosen_entry);
+
+ done:
+ ;
+}
+
+/** Test choose_random_entry() with only one of our routers being a
+ guard node. */
+static void
+test_choose_random_entry_one_possible_guard(void *arg)
+{
+ const node_t *chosen_entry = NULL;
+ node_t *the_guard = NULL;
+ smartlist_t *our_nodelist = NULL;
+
+ (void) arg;
+
+ /* Set one of the nodes to be a guard. */
+ our_nodelist = nodelist_get_list();
+ the_guard = smartlist_get(our_nodelist, 4); /* chosen by fair dice roll */
+ the_guard->is_possible_guard = 1;
+
+ /* Pick an entry. Make sure we pick the node we marked as guard. */
+ chosen_entry = choose_random_entry(NULL);
+ tt_ptr_op(chosen_entry, ==, the_guard);
+
+ done:
+ ;
+}
+
+/** Helper to conduct tests for populate_live_entry_guards().
+
+ This test adds some entry guards to our list, and then tests
+ populate_live_entry_guards() to mke sure it filters them correctly.
+
+ <b>num_needed</b> is the number of guard nodes we support. It's
+ configurable to make sure we function properly with 1 or 3 guard
+ nodes configured.
+*/
+static void
+populate_live_entry_guards_test_helper(int num_needed)
+{
+ smartlist_t *our_nodelist = NULL;
+ smartlist_t *live_entry_guards = smartlist_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ or_options_t *options = get_options_mutable();
+ int retval;
+
+ /* Set NumEntryGuards to the provided number. */
+ options->NumEntryGuards = num_needed;
+ tt_int_op(num_needed, ==, decide_num_guards(options, 0));
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, 0);
+
+ /* Walk the nodelist and add all nodes as entry guards. */
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS);
+
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
+ const node_t *node_tmp;
+ node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
+ test_assert(node_tmp);
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Make sure the nodes were added as entry guards. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, NUMBER_OF_DESCRIPTORS);
+
+ /* Ensure that all the possible entry guards are enough to satisfy us. */
+ tt_int_op(smartlist_len(all_entry_guards), >=, num_needed);
+
+ /* Walk the entry guard list for some sanity checking */
+ SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
+ /* Since we called add_an_entry_guard() with 'for_discovery' being
+ False, all guards should have made_contact enabled. */
+ tt_int_op(entry->made_contact, ==, 1);
+
+ /* Since we don't have a routerstatus, all of the entry guards are
+ not directory servers. */
+ tt_int_op(entry->is_dir_cache, ==, 0);
+ } SMARTLIST_FOREACH_END(entry);
+
+ /* First, try to get some fast guards. This should fail. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO, /* Don't care about DIRINFO*/
+ 0, 0,
+ 1); /* We want fast guard! */
+ tt_int_op(retval, ==, 0);
+ tt_int_op(smartlist_len(live_entry_guards), ==, 0);
+
+ /* Now try to get some stable guards. This should fail too. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO,
+ 0,
+ 1, /* We want stable guard! */
+ 0);
+ tt_int_op(retval, ==, 0);
+ tt_int_op(smartlist_len(live_entry_guards), ==, 0);
+
+ /* Now try to get any guard we can find. This should succeed. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO,
+ 0, 0, 0); /* No restrictions! */
+
+ /* Since we had more than enough guards in 'all_entry_guards', we
+ should have added 'num_needed' of them to live_entry_guards.
+ 'retval' should be 1 since we now have enough live entry guards
+ to pick one. */
+ tt_int_op(retval, ==, 1);
+ tt_int_op(smartlist_len(live_entry_guards), ==, num_needed);
+
+ done:
+ smartlist_free(live_entry_guards);
+}
+
+/* Test populate_live_entry_guards() for 1 guard node. */
+static void
+test_populate_live_entry_guards_1guard(void *arg)
+{
+ (void) arg;
+
+ populate_live_entry_guards_test_helper(1);
+}
+
+/* Test populate_live_entry_guards() for 3 guard nodes. */
+static void
+test_populate_live_entry_guards_3guards(void *arg)
+{
+ (void) arg;
+
+ populate_live_entry_guards_test_helper(3);
+}
+
+/** Append some EntryGuard lines to the Tor state at <b>state</b>.
+
+ <b>entry_guard_lines</b> is a smartlist containing 2-tuple
+ smartlists that carry the key and values of the statefile.
+ As an example:
+ entry_guard_lines =
+ (("EntryGuard", "name 67E72FF33D7D41BF11C569646A0A7B4B188340DF DirCache"),
+ ("EntryGuardDownSince", "2014-06-07 16:02:46 2014-06-07 16:02:46"))
+*/
+static void
+state_insert_entry_guard_helper(or_state_t *state,
+ smartlist_t *entry_guard_lines)
+{
+ config_line_t **next, *line;
+
+ next = &state->EntryGuards;
+ *next = NULL;
+
+ /* Loop over all the state lines in the smartlist */
+ SMARTLIST_FOREACH_BEGIN(entry_guard_lines, const smartlist_t *,state_lines) {
+ /* Get key and value for each line */
+ const char *state_key = smartlist_get(state_lines, 0);
+ const char *state_value = smartlist_get(state_lines, 1);
+
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup(state_key);
+ tor_asprintf(&line->value, "%s", state_value);
+ next = &(line->next);
+ } SMARTLIST_FOREACH_END(state_lines);
+}
+
+/** Free memory occupied by <b>entry_guard_lines</b>. */
+static void
+state_lines_free(smartlist_t *entry_guard_lines)
+{
+ SMARTLIST_FOREACH_BEGIN(entry_guard_lines, smartlist_t *, state_lines) {
+ char *state_key = smartlist_get(state_lines, 0);
+ char *state_value = smartlist_get(state_lines, 1);
+
+ tor_free(state_key);
+ tor_free(state_value);
+ smartlist_free(state_lines);
+ } SMARTLIST_FOREACH_END(state_lines);
+
+ smartlist_free(entry_guard_lines);
+}
+
+/* Tests entry_guards_parse_state(). It creates a fake Tor state with
+ a saved entry guard and makes sure that Tor can parse it and
+ creates the right entry node out of it.
+*/
+static void
+test_entry_guards_parse_state_simple(void *arg)
+{
+ or_state_t *state = or_state_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ smartlist_t *entry_state_lines = smartlist_new();
+ char *msg = NULL;
+ int retval;
+
+ /* Details of our fake guard node */
+ const char *nickname = "hagbard";
+ const char *fpr = "B29D536DD1752D542E1FBB3C9CE4449D51298212";
+ const char *tor_version = "0.2.5.3-alpha-dev";
+ const char *added_at = "2014-05-22 02:40:47";
+ const char *unlisted_since = "2014-06-08 16:16:50";
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, 0);
+
+ { /* Prepare the state entry */
+
+ /* Prepare the smartlist to hold the key/value of each line */
+ smartlist_t *state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuard");
+ smartlist_add_asprintf(state_line, "%s %s %s", nickname, fpr, "DirCache");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
+ smartlist_add_asprintf(state_line, "%s %s %s", fpr, tor_version, added_at);
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
+ smartlist_add_asprintf(state_line, "%s", unlisted_since);
+ smartlist_add(entry_state_lines, state_line);
+ }
+
+ /* Inject our lines in the state */
+ state_insert_entry_guard_helper(state, entry_state_lines);
+
+ /* Parse state */
+ retval = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(retval, >=, 0);
+
+ /* Test that the guard was registered.
+ We need to re-get the entry guard list since its pointer was
+ overwritten in entry_guards_parse_state(). */
+ all_entry_guards = get_entry_guards();
+ tt_int_op(smartlist_len(all_entry_guards), ==, 1);
+
+ { /* Test the entry guard structure */
+ char hex_digest[1024];
+ char str_time[1024];
+
+ const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
+ tt_str_op(e->nickname, ==, nickname); /* Verify nickname */
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ e->identity, DIGEST_LEN);
+ tt_str_op(hex_digest, ==, fpr); /* Verify fingerprint */
+
+ tt_assert(e->is_dir_cache); /* Verify dirness */
+
+ tt_str_op(e->chosen_by_version, ==, tor_version); /* Verify tor version */
+
+ tt_assert(e->made_contact); /* All saved guards have been contacted */
+
+ tt_assert(e->bad_since); /* Verify bad_since timestamp */
+ format_iso_time(str_time, e->bad_since);
+ tt_str_op(str_time, ==, unlisted_since);
+
+ /* The rest should be unset */
+ tt_assert(!e->unreachable_since);
+ tt_assert(!e->can_retry);
+ tt_assert(!e->path_bias_noticed);
+ tt_assert(!e->path_bias_warned);
+ tt_assert(!e->path_bias_extreme);
+ tt_assert(!e->path_bias_disabled);
+ tt_assert(!e->path_bias_use_noticed);
+ tt_assert(!e->path_bias_use_extreme);
+ tt_assert(!e->last_attempted);
+ }
+
+ done:
+ state_lines_free(entry_state_lines);
+ or_state_free(state);
+}
+
+/** Similar to test_entry_guards_parse_state_simple() but aims to test
+ the PathBias-related details of the entry guard. */
+static void
+test_entry_guards_parse_state_pathbias(void *arg)
+{
+ or_state_t *state = or_state_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ char *msg = NULL;
+ int retval;
+ smartlist_t *entry_state_lines = smartlist_new();
+
+ /* Path bias details of the fake guard */
+ const double circ_attempts = 9;
+ const double circ_successes = 8;
+ const double successful_closed = 4;
+ const double collapsed = 2;
+ const double unusable = 0;
+ const double timeouts = 1;
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, 0);
+
+ { /* Prepare the state entry */
+
+ /* Prepare the smartlist to hold the key/value of each line */
+ smartlist_t *state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuard");
+ smartlist_add_asprintf(state_line,
+ "givethanks B29D536DD1752D542E1FBB3C9CE4449D51298212 NoDirCache");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
+ smartlist_add_asprintf(state_line,
+ "B29D536DD1752D542E1FBB3C9CE4449D51298212 0.2.5.3-alpha-dev "
+ "2014-05-22 02:40:47");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
+ smartlist_add_asprintf(state_line, "2014-06-08 16:16:50");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardPathBias");
+ smartlist_add_asprintf(state_line, "%f %f %f %f %f %f",
+ circ_attempts, circ_successes, successful_closed,
+ collapsed, unusable, timeouts);
+ smartlist_add(entry_state_lines, state_line);
+ }
+
+ /* Inject our lines in the state */
+ state_insert_entry_guard_helper(state, entry_state_lines);
+
+ /* Parse state */
+ retval = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(retval, >=, 0);
+
+ /* Test that the guard was registered */
+ all_entry_guards = get_entry_guards();
+ tt_int_op(smartlist_len(all_entry_guards), ==, 1);
+
+ { /* Test the path bias of this guard */
+ const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
+
+ tt_assert(!e->is_dir_cache);
+ tt_assert(!e->can_retry);
+
+ /* XXX tt_double_op doesn't support equality. Cast to int for now. */
+ tt_int_op((int)e->circ_attempts, ==, (int)circ_attempts);
+ tt_int_op((int)e->circ_successes, ==, (int)circ_successes);
+ tt_int_op((int)e->successful_circuits_closed, ==, (int)successful_closed);
+ tt_int_op((int)e->timeouts, ==, (int)timeouts);
+ tt_int_op((int)e->collapsed_circuits, ==, (int)collapsed);
+ tt_int_op((int)e->unusable_circuits, ==, (int)unusable);
+ }
+
+ done:
+ or_state_free(state);
+ state_lines_free(entry_state_lines);
+}
+
+/* Simple test of entry_guards_set_from_config() by specifying a
+ particular EntryNode and making sure it gets picked. */
+static void
+test_entry_guards_set_from_config(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ const char *entrynodes_str = "test003r";
+ const node_t *chosen_entry = NULL;
+ int retval;
+
+ (void) arg;
+
+ /* Prase EntryNodes as a routerset. */
+ options->EntryNodes = routerset_new();
+ retval = routerset_parse(options->EntryNodes,
+ entrynodes_str,
+ "test_entrynodes");
+ tt_int_op(retval, >=, 0);
+
+ /* Read nodes from EntryNodes */
+ entry_guards_set_from_config(options);
+
+ /* Test that only one guard was added. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, 1);
+
+ /* Make sure it was the guard we specified. */
+ chosen_entry = choose_random_entry(NULL);
+ tt_str_op(chosen_entry->ri->nickname, ==, entrynodes_str);
+
+ done:
+ routerset_free(options->EntryNodes);
+}
+
+/** XXX Do some tests that entry_is_live() */
+static void
+test_entry_is_live(void *arg)
+{
+ smartlist_t *our_nodelist = NULL;
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ const node_t *test_node = NULL;
+ const entry_guard_t *test_entry = NULL;
+ const char *msg;
+ int which_node;
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, 0);
+
+ /* Walk the nodelist and add all nodes as entry guards. */
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS);
+
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
+ const node_t *node_tmp;
+ node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
+ test_assert(node_tmp);
+
+ tt_int_op(node->is_stable, ==, 0);
+ tt_int_op(node->is_fast, ==, 0);
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Make sure the nodes were added as entry guards. */
+ tt_int_op(smartlist_len(all_entry_guards), ==, NUMBER_OF_DESCRIPTORS);
+
+ /* Now get a random test entry that we will use for this unit test. */
+ which_node = 3; /* (chosen by fair dice roll) */
+ test_entry = smartlist_get(all_entry_guards, which_node);
+
+ /* Let's do some entry_is_live() tests! */
+
+ /* Require the node to be stable, but it's not. Should fail.
+ Also enable 'assume_reachable' because why not. */
+ test_node = entry_is_live(test_entry,
+ ENTRY_NEED_UPTIME | ENTRY_ASSUME_REACHABLE,
+ &msg);
+ test_assert(!test_node);
+
+ /* Require the node to be fast, but it's not. Should fail. */
+ test_node = entry_is_live(test_entry,
+ ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE,
+ &msg);
+ test_assert(!test_node);
+
+ /* Don't impose any restrictions on the node. Should succeed. */
+ test_node = entry_is_live(test_entry, 0, &msg);
+ test_assert(test_node);
+ tt_ptr_op(test_node, ==, node_get_by_id(test_entry->identity));
+
+ /* Require descriptor for this node. It has one so it should succeed. */
+ test_node = entry_is_live(test_entry, ENTRY_NEED_DESCRIPTOR, &msg);
+ test_assert(test_node);
+ tt_ptr_op(test_node, ==, node_get_by_id(test_entry->identity));
+
+ done:
+ ; /* XXX */
+}
+
+static const struct testcase_setup_t fake_network = {
+ fake_network_setup, fake_network_cleanup
+};
+
+struct testcase_t entrynodes_tests[] = {
+ { "choose_random_entry_no_guards", test_choose_random_entry_no_guards,
+ TT_FORK, &fake_network, NULL },
+ { "choose_random_entry_one_possibleguard",
+ test_choose_random_entry_one_possible_guard,
+ TT_FORK, &fake_network, NULL },
+ { "populate_live_entry_guards_1guard",
+ test_populate_live_entry_guards_1guard,
+ TT_FORK, &fake_network, NULL },
+ { "populate_live_entry_guards_3guards",
+ test_populate_live_entry_guards_3guards,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_parse_state_simple",
+ test_entry_guards_parse_state_simple,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_parse_state_pathbias",
+ test_entry_guards_parse_state_pathbias,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_set_from_config",
+ test_entry_guards_set_from_config,
+ TT_FORK, &fake_network, NULL },
+ { "entry_is_live",
+ test_entry_is_live,
+ TT_FORK, &fake_network, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 7e558f83b1..9f57000bea 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -89,7 +89,7 @@ test_sigsafe_err(void *arg)
init_logging();
mark_logs_temp();
- add_file_log(&include_bug, fn);
+ add_file_log(&include_bug, fn, 0);
tor_log_update_sigsafe_err_fds();
close_temp_logs();
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 151ec69127..3f840cdfc2 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1383,12 +1383,6 @@ test_util_threads(void)
tv.tv_sec=0;
tv.tv_usec=100*1000;
#endif
-#ifndef TOR_IS_MULTITHREADED
- /* Skip this test if we aren't threading. We should be threading most
- * everywhere by now. */
- if (1)
- return;
-#endif
thread_test_mutex_ = tor_mutex_new();
thread_test_start1_ = tor_mutex_new();
thread_test_start2_ = tor_mutex_new();
@@ -2391,6 +2385,54 @@ test_util_parent_dir(void *ptr)
tor_free(cp);
}
+static void
+test_util_ftruncate(void *ptr)
+{
+ char *buf = NULL;
+ const char *fname;
+ int fd = -1;
+ const char *message = "Hello world";
+ const char *message2 = "Hola mundo";
+ struct stat st;
+
+ (void) ptr;
+
+ fname = get_fname("ftruncate");
+
+ fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT, 0600);
+ tt_int_op(fd, >=, 0);
+
+ /* Make the file be there. */
+ tt_int_op(strlen(message), ==, write_all(fd, message, strlen(message), 0));
+ tt_int_op((int)tor_fd_getpos(fd), ==, strlen(message));
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op((int)st.st_size, ==, strlen(message));
+
+ /* Truncate and see if it got truncated */
+ tt_int_op(0, ==, tor_ftruncate(fd));
+ tt_int_op((int)tor_fd_getpos(fd), ==, 0);
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op((int)st.st_size, ==, 0);
+
+ /* Replace, and see if it got replaced */
+ tt_int_op(strlen(message2), ==,
+ write_all(fd, message2, strlen(message2), 0));
+ tt_int_op((int)tor_fd_getpos(fd), ==, strlen(message2));
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op((int)st.st_size, ==, strlen(message2));
+
+ close(fd);
+ fd = -1;
+
+ buf = read_file_to_str(fname, 0, NULL);
+ tt_str_op(message2, ==, buf);
+
+ done:
+ if (fd >= 0)
+ close(fd);
+ tor_free(buf);
+}
+
#ifdef _WIN32
static void
test_util_load_win_lib(void *ptr)
@@ -2453,8 +2495,9 @@ test_util_exit_status(void *ptr)
#endif
#ifndef _WIN32
-/** Check that fgets waits until a full line, and not return a partial line, on
- * a EAGAIN with a non-blocking pipe */
+/* Check that fgets with a non-blocking pipe returns partial lines and sets
+ * EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
+ * sets no error */
static void
test_util_fgets_eagain(void *ptr)
{
@@ -2463,17 +2506,19 @@ test_util_fgets_eagain(void *ptr)
ssize_t retlen;
char *retptr;
FILE *test_stream = NULL;
- char buf[10];
+ char buf[4] = { 0 };
(void)ptr;
+ errno = 0;
+
/* Set up a pipe to test on */
retval = pipe(test_pipe);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, ==, 0);
/* Set up the read-end to be non-blocking */
retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, ==, 0);
/* Open it as a stdio stream */
test_stream = fdopen(test_pipe[0], "r");
@@ -2483,51 +2528,69 @@ test_util_fgets_eagain(void *ptr)
retlen = write(test_pipe[1], "A", 1);
tt_int_op(retlen, ==, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_want(retptr == NULL);
tt_int_op(errno, ==, EAGAIN);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "A");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "B\n", 2);
tt_int_op(retlen, ==, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "AB\n");
+ tt_str_op(buf, ==, "B\n");
+ errno = 0;
/* Send in a full line */
retlen = write(test_pipe[1], "CD\n", 3);
tt_int_op(retlen, ==, 3);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
tt_str_op(buf, ==, "CD\n");
+ errno = 0;
/* Send in a partial line */
retlen = write(test_pipe[1], "E", 1);
tt_int_op(retlen, ==, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, NULL);
tt_int_op(errno, ==, EAGAIN);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "E");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "F\n", 2);
tt_int_op(retlen, ==, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "EF\n");
+ tt_str_op(buf, ==, "F\n");
+ errno = 0;
/* Send in a full line and close */
retlen = write(test_pipe[1], "GH", 2);
tt_int_op(retlen, ==, 2);
retval = close(test_pipe[1]);
- test_pipe[1] = -1;
tt_int_op(retval, ==, 0);
+ test_pipe[1] = -1;
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
tt_str_op(buf, ==, "GH");
+ errno = 0;
/* Check for EOF */
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, NULL);
- tt_int_op(feof(test_stream), >, 0);
+ retval = feof(test_stream);
+ tt_int_op(retval, !=, 0);
+ errno = 0;
+
+ /* Check that buf is unchanged according to C99 and C11 */
+ tt_str_op(buf, ==, "GH");
done:
if (test_stream != NULL)
@@ -3783,12 +3846,13 @@ struct testcase_t util_tests[] = {
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
UTIL_TEST(parent_dir, 0),
+ UTIL_TEST(ftruncate, 0),
#ifdef _WIN32
UTIL_TEST(load_win_lib, 0),
#endif
#ifndef _WIN32
UTIL_TEST(exit_status, 0),
- UTIL_TEST(fgets_eagain, TT_SKIP),
+ UTIL_TEST(fgets_eagain, 0),
#endif
UTIL_TEST(spawn_background_ok, 0),
UTIL_TEST(spawn_background_fail, 0),
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 8c2472c323..030341af34 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -14,8 +14,6 @@
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H
-#define ENABLE_THREADS
-
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H
@@ -86,18 +84,11 @@
#define HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
-#if defined (WINCE)
-#define HAVE_STRLCAT
-#else
#undef HAVE_STRLCAT
-#endif
/* Define to 1 if you have the `strlcpy' function. */
-#if defined (WINCE)
-#define HAVE_STRLCPY
-#else
#undef HAVE_STRLCPY
-#endif
+
/* Define to 1 if you have the `strptime' function. */
#undef HAVE_STRPTIME
@@ -241,7 +232,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.5.6-alpha"
+#define VERSION "0.2.6.0-alpha-dev"