aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.am22
-rw-r--r--src/common/address.c9
-rw-r--r--src/common/address.h1
-rw-r--r--src/common/aes.c3
-rw-r--r--src/common/compat.c180
-rw-r--r--src/common/compat.h30
-rw-r--r--src/common/compat_libevent.c471
-rw-r--r--src/common/compat_libevent.h59
-rw-r--r--src/common/container.c185
-rw-r--r--src/common/container.h26
-rw-r--r--src/common/crypto.c315
-rw-r--r--src/common/crypto.h52
-rw-r--r--src/common/ht.h4
-rw-r--r--src/common/log.c73
-rw-r--r--src/common/log.h11
-rw-r--r--src/common/memarea.c43
-rw-r--r--src/common/sha256.c331
-rw-r--r--src/common/test.h184
-rw-r--r--src/common/torgzip.c7
-rw-r--r--src/common/torint.h3
-rw-r--r--src/common/tortls.c136
-rw-r--r--src/common/tortls_states.h414
-rw-r--r--src/common/util.c219
-rw-r--r--src/common/util.h18
-rw-r--r--src/common/util_codedigest.c11
25 files changed, 2337 insertions, 470 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 105c413343..eecfeb83fe 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -1,5 +1,7 @@
-noinst_LIBRARIES = libor.a libor-crypto.a
+noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
+
+EXTRA_DIST = common_sha1.i sha256.c
#CFLAGS = -Wall -Wpointer-arith -O2
@@ -10,7 +12,21 @@ libor_extra_source=
endif
libor_a_SOURCES = address.c log.c util.c compat.c container.c mempool.c \
- memarea.c $(libor_extra_source)
+ memarea.c util_codedigest.c $(libor_extra_source)
libor_crypto_a_SOURCES = crypto.c aes.c tortls.c torgzip.c
+libor_event_a_SOURCES = compat_libevent.c
+
+noinst_HEADERS = address.h log.h crypto.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc compat_libevent.h tortls_states.h
+
+common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
+ if test "@SHA1SUM@" != none; then \
+ @SHA1SUM@ $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
+ elif test "@OPENSSL@" != none; then \
+ @OPENSSL@ sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
+ else \
+ rm common_sha1.i; \
+ touch common_sha1.i; \
+ fi
-noinst_HEADERS = address.h log.h crypto.h test.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc
+util_codedigest.o: common_sha1.i
+crypto.o: sha256.c
diff --git a/src/common/address.c b/src/common/address.c
index 58ead3075a..e51b7d8125 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -760,6 +760,8 @@ tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
void
tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
{
+ if (src == dest)
+ return;
tor_assert(src);
tor_assert(dest);
memcpy(dest, src, sizeof(tor_addr_t));
@@ -912,13 +914,6 @@ tor_dup_addr(const tor_addr_t *addr)
return tor_strdup(buf);
}
-/** Copy the address in <b>src</b> to <b>dest</b> */
-void
-tor_addr_assign(tor_addr_t *dest, const tor_addr_t *src)
-{
- memcpy(dest, src, sizeof(tor_addr_t));
-}
-
/** Return a string representing the address <b>addr</b>. This string is
* statically allocated, and must not be freed. Each call to
* <b>fmt_addr</b> invalidates the last result of the function. This
diff --git a/src/common/address.h b/src/common/address.h
index 352e0d7237..6116bb4b1c 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -107,7 +107,6 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out);
char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
-void tor_addr_assign(tor_addr_t *dest, const tor_addr_t *src);
const char *fmt_addr(const tor_addr_t *addr);
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
diff --git a/src/common/aes.c b/src/common/aes.c
index 5a6bab242d..2b6f0234b7 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -263,7 +263,8 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
void
aes_free_cipher(aes_cnt_cipher_t *cipher)
{
- tor_assert(cipher);
+ if (!cipher)
+ return;
#ifdef USE_OPENSSL_EVP
EVP_CIPHER_CTX_cleanup(&cipher->key);
#endif
diff --git a/src/common/compat.c b/src/common/compat.c
index b2dab5c341..7f53704c69 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -398,6 +398,37 @@ const char TOR_TOLOWER_TABLE[256] = {
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
};
+/** Implementation of strtok_r for platforms whose coders haven't figured out
+ * how to write one. Hey guys! You can use this code here for free! */
+char *
+tor_strtok_r_impl(char *str, const char *sep, char **lasts)
+{
+ char *cp, *start;
+ if (str)
+ start = cp = *lasts = str;
+ else if (!*lasts)
+ return NULL;
+ else
+ start = cp = *lasts;
+
+ tor_assert(*sep);
+ if (sep[1]) {
+ while (*cp && !strchr(sep, *cp))
+ ++cp;
+ } else {
+ tor_assert(strlen(sep) == 1);
+ cp = strchr(cp, *sep);
+ }
+
+ if (!cp || !*cp) {
+ *lasts = NULL;
+ } else {
+ *cp++ = '\0';
+ *lasts = cp;
+ }
+ return start;
+}
+
#ifdef MS_WINDOWS
/** Take a filename and return a pointer to its final element. This
* function is called on __FILE__ to fix a MSVC nit where __FILE__
@@ -449,8 +480,8 @@ get_uint32(const char *cp)
return v;
}
/**
- * Read a 32-bit value beginning at <b>cp</b>. Equivalent to
- * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
+ * Read a 64-bit value beginning at <b>cp</b>. Equivalent to
+ * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid
* unaligned memory access.
*/
uint64_t
@@ -978,9 +1009,6 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
#if defined(CYGWIN) || defined(__CYGWIN__)
const char *platform = "Cygwin";
const unsigned long MAX_CONNECTIONS = 3200;
-#elif defined(IPHONE)
- const char *platform = "iPhone";
- const unsigned long MAX_CONNECTIONS = 9999;
#elif defined(MS_WINDOWS)
const char *platform = "Windows";
const unsigned long MAX_CONNECTIONS = 15000;
@@ -1577,13 +1605,13 @@ get_uname(void)
#ifdef MS_WINDOWS
OSVERSIONINFOEX info;
int i;
- unsigned int leftover_mask;
const char *plat = NULL;
const char *extra = NULL;
static struct {
unsigned major; unsigned minor; const char *version;
} win_version_table[] = {
- { 6, 0, "Windows \"Longhorn\"" },
+ { 6, 1, "Windows 7" },
+ { 6, 0, "Windows Vista" },
{ 5, 2, "Windows Server 2003" },
{ 5, 1, "Windows XP" },
{ 5, 0, "Windows 2000" },
@@ -1594,25 +1622,6 @@ get_uname(void)
{ 3, 51, "Windows NT 3.51" },
{ 0, 0, NULL }
};
-#ifdef VER_SUITE_BACKOFFICE
- static struct {
- unsigned int mask; const char *str;
- } win_mask_table[] = {
- { VER_SUITE_BACKOFFICE, " {backoffice}" },
- { VER_SUITE_BLADE, " {\"blade\" (2003, web edition)}" },
- { VER_SUITE_DATACENTER, " {datacenter}" },
- { VER_SUITE_ENTERPRISE, " {enterprise}" },
- { VER_SUITE_EMBEDDEDNT, " {embedded}" },
- { VER_SUITE_PERSONAL, " {personal}" },
- { VER_SUITE_SINGLEUSERTS,
- " {terminal services, single user}" },
- { VER_SUITE_SMALLBUSINESS, " {small business}" },
- { VER_SUITE_SMALLBUSINESS_RESTRICTED,
- " {small business, restricted}" },
- { VER_SUITE_TERMINAL, " {terminal services}" },
- { 0, NULL },
- };
-#endif
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
@@ -1652,7 +1661,7 @@ get_uname(void)
plat, extra);
} else {
if (info.dwMajorVersion > 6 ||
- (info.dwMajorVersion==6 && info.dwMinorVersion>0))
+ (info.dwMajorVersion==6 && info.dwMinorVersion>1))
tor_snprintf(uname_result, sizeof(uname_result),
"Very recent version of Windows [major=%d,minor=%d] %s",
(int)info.dwMajorVersion,(int)info.dwMinorVersion,
@@ -1671,18 +1680,6 @@ get_uname(void)
} else if (info.wProductType == VER_NT_WORKSTATION) {
strlcat(uname_result, " [workstation]", sizeof(uname_result));
}
- leftover_mask = info.wSuiteMask;
- for (i = 0; win_mask_table[i].mask; ++i) {
- if (info.wSuiteMask & win_mask_table[i].mask) {
- strlcat(uname_result, win_mask_table[i].str, sizeof(uname_result));
- leftover_mask &= ~win_mask_table[i].mask;
- }
- }
- if (leftover_mask) {
- size_t len = strlen(uname_result);
- tor_snprintf(uname_result+len, sizeof(uname_result)-len,
- " {0x%x}", info.wSuiteMask);
- }
#endif
#else
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
@@ -1792,7 +1789,6 @@ spawn_exit(void)
* call _exit, not exit, from child processes. */
_exit(0);
#endif
-
}
/** Set *timeval to the current time of day. On error, log and terminate.
@@ -2013,6 +2009,8 @@ tor_mutex_new(void)
void
tor_mutex_free(tor_mutex_t *m)
{
+ if (!m)
+ return;
tor_mutex_uninit(m);
tor_free(m);
}
@@ -2040,7 +2038,8 @@ tor_cond_new(void)
void
tor_cond_free(tor_cond_t *cond)
{
- tor_assert(cond);
+ if (!cond)
+ return;
if (pthread_cond_destroy(&cond->cond)) {
log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
return;
@@ -2097,7 +2096,8 @@ tor_cond_new(void)
void
tor_cond_free(tor_cond_t *cond)
{
- tor_assert(cond);
+ if (!cond)
+ return;
DeleteCriticalSection(&cond->mutex);
/* XXXX notify? */
smartlist_free(cond->events);
@@ -2173,6 +2173,102 @@ tor_threads_init(void)
}
#endif
+#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
+/** Attempt to raise the current and max rlimit to infinity for our process.
+ * This only needs to be done once and can probably only be done when we have
+ * not already dropped privileges.
+ */
+static int
+tor_set_max_memlock(void)
+{
+ /* Future consideration for Windows is probably SetProcessWorkingSetSize
+ * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK
+ * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
+ */
+
+ struct rlimit limit;
+ int ret;
+
+ /* Do we want to report current limits first? This is not really needed. */
+ ret = getrlimit(RLIMIT_MEMLOCK, &limit);
+ if (ret == -1) {
+ log_warn(LD_GENERAL, "Could not get RLIMIT_MEMLOCK: %s", strerror(errno));
+ return -1;
+ }
+
+ /* RLIM_INFINITY is -1 on some platforms. */
+ limit.rlim_cur = RLIM_INFINITY;
+ limit.rlim_max = RLIM_INFINITY;
+
+ ret = setrlimit(RLIMIT_MEMLOCK, &limit);
+ if (ret == -1) {
+ if (errno == EPERM) {
+ log_warn(LD_GENERAL, "You appear to lack permissions to change memory "
+ "limits. Are you root?");
+ log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s",
+ strerror(errno));
+ } else {
+ log_warn(LD_GENERAL, "Could not raise RLIMIT_MEMLOCK: %s",
+ strerror(errno));
+ }
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+/** Attempt to lock all current and all future memory pages.
+ * This should only be called once and while we're privileged.
+ * Like mlockall() we return 0 when we're successful and -1 when we're not.
+ * Unlike mlockall() we return 1 if we've already attempted to lock memory.
+ */
+int
+tor_mlockall(void)
+{
+ static int memory_lock_attempted = 0;
+
+ if (memory_lock_attempted) {
+ return 1;
+ }
+
+ memory_lock_attempted = 1;
+
+ /*
+ * Future consideration for Windows may be VirtualLock
+ * VirtualLock appears to implement mlock() but not mlockall()
+ *
+ * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
+ */
+
+#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
+ if (tor_set_max_memlock() == 0) {
+ /* Perhaps we only want to log this if we're in a verbose mode? */
+ log_notice(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY.");
+ }
+
+ if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) {
+ log_notice(LD_GENERAL, "Insecure OS paging is effectively disabled.");
+ return 0;
+ } else {
+ if (errno == ENOSYS) {
+ /* Apple - it's 2009! I'm looking at you. Grrr. */
+ log_notice(LD_GENERAL, "It appears that mlockall() is not available on "
+ "your platform.");
+ } else if (errno == EPERM) {
+ log_notice(LD_GENERAL, "It appears that you lack the permissions to "
+ "lock memory. Are you root?");
+ }
+ log_notice(LD_GENERAL, "Unable to lock all current and future memory "
+ "pages: %s", strerror(errno));
+ return -1;
+ }
+#else
+ log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?");
+ return -1;
+#endif
+}
+
/** Identity of the "main" thread */
static unsigned long main_thread_id = -1;
diff --git a/src/common/compat.h b/src/common/compat.h
index fbbbb3fc92..f5f8bb4283 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -196,18 +196,26 @@ size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2));
#define U64_SCANF_ARG(a) (a)
/** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */
#define U64_LITERAL(n) (n ## ui64)
+#define I64_PRINTF_ARG(a) (a)
+#define I64_SCANF_ARG(a) (a)
+#define I64_LITERAL(n) (n ## i64)
#else
#define U64_PRINTF_ARG(a) ((long long unsigned int)(a))
#define U64_SCANF_ARG(a) ((long long unsigned int*)(a))
#define U64_LITERAL(n) (n ## llu)
+#define I64_PRINTF_ARG(a) ((long long signed int)(a))
+#define I64_SCANF_ARG(a) ((long long signed int*)(a))
+#define I64_LITERAL(n) (n ## ll)
#endif
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
/** The formatting string used to put a uint64_t value in a printf() or
* scanf() function. See also U64_PRINTF_ARG and U64_SCANF_ARG. */
#define U64_FORMAT "%I64u"
+#define I64_FORMAT "%I64d"
#else
#define U64_FORMAT "%llu"
+#define I64_FORMAT "%lld"
#endif
/** Represents an mmaped file. Allocated via tor_mmap_file; freed with
@@ -267,6 +275,13 @@ extern const char TOR_TOLOWER_TABLE[];
#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c])
#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c])
+char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
+#ifdef HAVE_STRTOK_R
+#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts)
+#else
+#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts)
+#endif
+
#ifdef MS_WINDOWS
#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
@@ -502,6 +517,8 @@ typedef struct tor_mutex_t {
#endif
} 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);
@@ -536,6 +553,19 @@ 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.
+ * {With GCC extensions we could probably define a safer MIN/MAX. But
+ * depending on that safety would be dangerous, since not every platform
+ * has it.}
+ **/
+#ifndef MAX
+#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) )
+#endif
+#ifndef MIN
+#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) )
+#endif
+
/* Platform-specific helpers. */
#ifdef MS_WINDOWS
char *format_win32_error(DWORD err);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
new file mode 100644
index 0000000000..dcf51cbbd3
--- /dev/null
+++ b/src/common/compat_libevent.c
@@ -0,0 +1,471 @@
+/* Copyright (c) 2009, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file compat_libevent.c
+ * \brief Wrappers to handle porting between different versions of libevent.
+ *
+ * In an ideal world, we'd just use Libevent 2.0 from now on. But as of June
+ * 2009, Libevent 2.0 is still in alpha, and we will have old versions of
+ * Libevent for the forseeable future.
+ **/
+
+#include "orconfig.h"
+#include "compat_libevent.h"
+
+#include "compat.h"
+#include "util.h"
+#include "log.h"
+
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+/** A number representing a version of Libevent.
+
+ This is a 4-byte number, with the first three bytes representing the
+ major, minor, and patchlevel respectively of the library. The fourth
+ byte is unused.
+
+ This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent
+ 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the
+ format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a
+ to be equivalent to 1.0.1, and so on.
+*/
+typedef uint32_t le_version_t;
+
+/* Macros: returns the number of a libevent version. */
+#define V(major, minor, patch) \
+ (((major) << 24) | ((minor) << 16) | ((patch) << 8))
+#define V_OLD(major, minor, patch) \
+ V((major), (minor), (patch)-'a'+1)
+
+#define LE_OLD V(0,0,0)
+#define LE_OTHER V(0,0,99)
+
+static le_version_t tor_get_libevent_version(const char **v_out);
+
+#ifdef HAVE_EVENT_SET_LOG_CALLBACK
+/** A string which, if it appears in a libevent log, should be ignored. */
+static const char *suppress_msg = NULL;
+/** Callback function passed to event_set_log() so we can intercept
+ * log messages from libevent. */
+static void
+libevent_logging_callback(int severity, const char *msg)
+{
+ char buf[1024];
+ size_t n;
+ if (suppress_msg && strstr(msg, suppress_msg))
+ return;
+ n = strlcpy(buf, msg, sizeof(buf));
+ if (n && n < sizeof(buf) && buf[n-1] == '\n') {
+ buf[n-1] = '\0';
+ }
+ switch (severity) {
+ case _EVENT_LOG_DEBUG:
+ log(LOG_DEBUG, LD_NET, "Message from libevent: %s", buf);
+ break;
+ case _EVENT_LOG_MSG:
+ log(LOG_INFO, LD_NET, "Message from libevent: %s", buf);
+ break;
+ case _EVENT_LOG_WARN:
+ log(LOG_WARN, LD_GENERAL, "Warning from libevent: %s", buf);
+ break;
+ case _EVENT_LOG_ERR:
+ log(LOG_ERR, LD_GENERAL, "Error from libevent: %s", buf);
+ break;
+ default:
+ log(LOG_WARN, LD_GENERAL, "Message [%d] from libevent: %s",
+ severity, buf);
+ break;
+ }
+}
+/** Set hook to intercept log messages from libevent. */
+void
+configure_libevent_logging(void)
+{
+ event_set_log_callback(libevent_logging_callback);
+}
+/** Ignore any libevent log message that contains <b>msg</b>. */
+void
+suppress_libevent_log_msg(const char *msg)
+{
+ suppress_msg = msg;
+}
+#else
+void
+configure_libevent_logging(void)
+{
+}
+void
+suppress_libevent_log_msg(const char *msg)
+{
+ (void)msg;
+}
+#endif
+
+#ifndef HAVE_EVENT2_EVENT_H
+/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */
+struct event *
+tor_event_new(struct event_base *base, int sock, short what,
+ void (*cb)(int, short, void *), void *arg)
+{
+ struct event *e = tor_malloc_zero(sizeof(struct event));
+ event_set(e, sock, what, cb, arg);
+ if (! base)
+ base = tor_libevent_get_base();
+ event_base_set(base, e);
+ return e;
+}
+/** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */
+struct event *
+tor_evtimer_new(struct event_base *base,
+ void (*cb)(int, short, void *), void *arg)
+{
+ return tor_event_new(base, -1, 0, cb, arg);
+}
+/** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */
+struct event *
+tor_evsignal_new(struct event_base * base, int sig,
+ void (*cb)(int, short, void *), void *arg)
+{
+ return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
+}
+/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */
+void
+tor_event_free(struct event *ev)
+{
+ event_del(ev);
+ tor_free(ev);
+}
+#endif
+
+/** Global event base for use by the main thread. */
+struct event_base *the_event_base = NULL;
+
+/* This is what passes for version detection on OSX. We set
+ * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
+ * 10.4.0 (aka 1040). */
+#ifdef __APPLE__
+#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#define MACOSX_KQUEUE_IS_BROKEN \
+ (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
+#else
+#define MACOSX_KQUEUE_IS_BROKEN 0
+#endif
+#endif
+
+/** Initialize the Libevent library and set up the event base. */
+void
+tor_libevent_initialize(void)
+{
+ tor_assert(the_event_base == NULL);
+
+#ifdef __APPLE__
+ if (MACOSX_KQUEUE_IS_BROKEN ||
+ tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
+ setenv("EVENT_NOKQUEUE","1",1);
+ }
+#endif
+
+#ifdef HAVE_EVENT2_EVENT_H
+ the_event_base = event_base_new();
+#else
+ the_event_base = event_init();
+#endif
+
+#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
+ /* Making this a NOTICE for now so we can link bugs to a libevent versions
+ * or methods better. */
+ log(LOG_NOTICE, LD_GENERAL,
+ "Initialized libevent version %s using method %s. Good.",
+ event_get_version(), tor_libevent_get_method());
+#else
+ log(LOG_NOTICE, LD_GENERAL,
+ "Initialized old libevent (version 1.0b or earlier).");
+ log(LOG_WARN, LD_GENERAL,
+ "You have a *VERY* old version of libevent. It is likely to be buggy; "
+ "please build Tor with a more recent version.");
+#endif
+}
+
+/** Return the current Libevent event base that we're set up to use. */
+struct event_base *
+tor_libevent_get_base(void)
+{
+ return the_event_base;
+}
+
+#ifndef HAVE_EVENT_BASE_LOOPEXIT
+/* Replacement for event_base_loopexit on some very old versions of Libevent
+ that we are not yet brave enough to deprecate. */
+int
+tor_event_base_loopexit(struct event_base *base, struct timeval *tv)
+{
+ tor_assert(base == the_event_base);
+ return event_loopexit(tv);
+}
+#endif
+
+/** Return the name of the Libevent backend we're using. */
+const char *
+tor_libevent_get_method(void)
+{
+#ifdef HAVE_EVENT2_EVENT_H
+ return event_base_get_method(the_event_base);
+#elif defined(HAVE_EVENT_GET_METHOD)
+ return event_get_method();
+#else
+ return "<unknown>";
+#endif
+}
+
+/** Return the le_version_t for the current version of libevent. If the
+ * version is very new, return LE_OTHER. If the version is so old that it
+ * doesn't support event_get_version(), return LE_OLD. DOCDOC */
+static le_version_t
+tor_decode_libevent_version(const char *v)
+{
+ unsigned major, minor, patchlevel;
+ char c, extra;
+ int fields;
+
+ /* Try the new preferred "1.4.11-stable" format. */
+ fields = sscanf(v, "%u.%u.%u%c", &major, &minor, &patchlevel, &c);
+ if (fields == 3 ||
+ (fields == 4 && (c == '-' || c == '_'))) {
+ return V(major,minor,patchlevel);
+ }
+
+ /* Try the old "1.3e" format. */
+ fields = sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
+ if (fields == 3 && TOR_ISALPHA(c)) {
+ return V_OLD(major, minor, c);
+ } else if (fields == 2) {
+ return V(major, minor, 0);
+ }
+
+ return LE_OTHER;
+}
+
+/** Return an integer representing the binary interface of a Libevent library.
+ * Two different versions with different numbers are sure not to be binary
+ * compatible. Two different versions with the same numbers have a decent
+ * chance of binary compatibility.*/
+static int
+le_versions_compatibility(le_version_t v)
+{
+ if (v == LE_OTHER)
+ return 0;
+ if (v < V_OLD(1,0,'c'))
+ return 1;
+ else if (v < V(1,4,0))
+ return 2;
+ else if (v < V(1,4,99))
+ return 3;
+ else if (v < V(2,0,1))
+ return 4;
+ else /* Everything 2.0 and later should be compatible. */
+ return 5;
+}
+
+/** Return the version number of the currently running version of Libevent.
+ See le_version_t for info on the format.
+ */
+static le_version_t
+tor_get_libevent_version(const char **v_out)
+{
+ const char *v;
+ le_version_t r;
+#if defined(HAVE_EVENT_GET_VERSION_NUMBER)
+ v = event_get_version();
+ r = event_get_version_number();
+#elif defined (HAVE_EVENT_GET_VERSION)
+ v = event_get_version();
+ r = tor_decode_libevent_version(v);
+#else
+ v = "pre-1.0c";
+ r = LE_OLD;
+#endif
+ if (v_out)
+ *v_out = v;
+ return r;
+}
+
+/** Return a string representation of the version of the currently running
+ * version of Libevent. */
+const char *
+tor_libevent_get_version_str(void)
+{
+#ifdef HAVE_EVENT_GET_VERSION
+ return event_get_version();
+#else
+ return "pre-1.0c";
+#endif
+}
+
+/**
+ * Compare the current Libevent method and version to a list of versions
+ * which are known not to work. Warn the user as appropriate.
+ */
+void
+tor_check_libevent_version(const char *m, int server,
+ const char **badness_out)
+{
+ int buggy = 0, iffy = 0, slow = 0, thread_unsafe = 0;
+ le_version_t version;
+ const char *v = NULL;
+ const char *badness = NULL;
+ const char *sad_os = "";
+
+ version = tor_get_libevent_version(&v);
+
+ /* XXX Would it be worthwhile disabling the methods that we know
+ * are buggy, rather than just warning about them and then proceeding
+ * to use them? If so, we should probably not wrap this whole thing
+ * in HAVE_EVENT_GET_VERSION and HAVE_EVENT_GET_METHOD. -RD */
+ /* XXXX The problem is that it's not trivial to get libevent to change it's
+ * method once it's initialized, and it's not trivial to tell what method it
+ * will use without initializing it. I guess we could preemptively disable
+ * buggy libevent modes based on the version _before_ initializing it,
+ * though, but then there's no good way (afaict) to warn "I would have used
+ * kqueue, but instead I'm using select." -NM */
+ /* XXXX022 revist the above; it is fixable now. */
+ if (!strcmp(m, "kqueue")) {
+ if (version < V_OLD(1,1,'b'))
+ buggy = 1;
+ } else if (!strcmp(m, "epoll")) {
+ if (version < V(1,1,0))
+ iffy = 1;
+ } else if (!strcmp(m, "poll")) {
+ if (version < V_OLD(1,0,'e'))
+ buggy = 1;
+ if (version < V(1,1,0))
+ slow = 1;
+ } else if (!strcmp(m, "select")) {
+ if (version < V(1,1,0))
+ slow = 1;
+ } else if (!strcmp(m, "win32")) {
+ if (version < V_OLD(1,1,'b'))
+ buggy = 1;
+ }
+
+ /* Libevent versions before 1.3b do very badly on operating systems with
+ * user-space threading implementations. */
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ if (server && version < V_OLD(1,3,'b')) {
+ thread_unsafe = 1;
+ sad_os = "BSD variants";
+ }
+#elif defined(__APPLE__) || defined(__darwin__)
+ if (server && version < V_OLD(1,3,'b')) {
+ thread_unsafe = 1;
+ sad_os = "Mac OS X";
+ }
+#endif
+
+ if (thread_unsafe) {
+ log(LOG_WARN, LD_GENERAL,
+ "Libevent version %s often crashes when running a Tor server with %s. "
+ "Please use the latest version of libevent (1.3b or later)",v,sad_os);
+ badness = "BROKEN";
+ } else if (buggy) {
+ log(LOG_WARN, LD_GENERAL,
+ "There are serious bugs in using %s with libevent %s. "
+ "Please use the latest version of libevent.", m, v);
+ badness = "BROKEN";
+ } else if (iffy) {
+ log(LOG_WARN, LD_GENERAL,
+ "There are minor bugs in using %s with libevent %s. "
+ "You may want to use the latest version of libevent.", m, v);
+ badness = "BUGGY";
+ } else if (slow && server) {
+ log(LOG_WARN, LD_GENERAL,
+ "libevent %s can be very slow with %s. "
+ "When running a server, please use the latest version of libevent.",
+ v,m);
+ badness = "SLOW";
+ }
+
+ *badness_out = badness;
+}
+
+#if defined(LIBEVENT_VERSION)
+#define HEADER_VERSION LIBEVENT_VERSION
+#elif defined(_EVENT_VERSION)
+#define HEADER_VERSION _EVENT_VERSION
+#endif
+
+/** See whether the headers we were built against differ from the library we
+ * linked against so much that we're likely to crash. If so, warn the
+ * user. */
+void
+tor_check_libevent_header_compatibility(void)
+{
+ (void) le_versions_compatibility;
+ (void) tor_decode_libevent_version;
+
+ /* In libevent versions before 2.0, it's hard to keep binary compatibility
+ * between upgrades, and unpleasant to detect when the version we compiled
+ * against is unlike the version we have linked against. Here's how. */
+#if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
+ /* We have a header-file version and a function-call version. Easy. */
+ if (strcmp(HEADER_VERSION, event_get_version())) {
+ le_version_t v1, v2;
+ int compat1 = -1, compat2 = -1;
+ int verybad;
+ v1 = tor_decode_libevent_version(HEADER_VERSION);
+ v2 = tor_decode_libevent_version(event_get_version());
+ compat1 = le_versions_compatibility(v1);
+ compat2 = le_versions_compatibility(v2);
+
+ verybad = compat1 != compat2;
+
+ log(verybad ? LOG_WARN : LOG_NOTICE,
+ LD_GENERAL, "We were compiled with headers from version %s "
+ "of Libevent, but we're using a Libevent library that says it's "
+ "version %s.", HEADER_VERSION, event_get_version());
+ if (verybad)
+ log_warn(LD_GENERAL, "This will almost certainly make Tor crash.");
+ else
+ log_info(LD_GENERAL, "I think these versions are binary-compatible.");
+ }
+#elif defined(HAVE_EVENT_GET_VERSION)
+ /* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or
+ earlier, where that's normal. To see whether we were compiled with an
+ earlier version, let's see whether the struct event defines MIN_HEAP_IDX.
+ */
+#ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
+ /* The header files are 1.4.0-beta or later. If the version is not
+ * 1.4.0-beta, we are incompatible. */
+ {
+ if (strcmp(event_get_version(), "1.4.0-beta")) {
+ log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
+ "Libevent 1.4.0-beta header files, whereas you have linked "
+ "against Libevent %s. This will probably make Tor crash.",
+ event_get_version());
+ }
+ }
+#else
+ /* Our headers are 1.3e or earlier. If the library version is not 1.4.x or
+ later, we're probably fine. */
+ {
+ const char *v = event_get_version();
+ if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') {
+ log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
+ "Libevent header file from 1.3e or earlier, whereas you have "
+ "linked against Libevent %s. This will probably make Tor "
+ "crash.", event_get_version());
+ }
+ }
+#endif
+
+#elif defined(HEADER_VERSION)
+#warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
+#else
+ /* Your libevent is ancient. */
+#endif
+}
+
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
new file mode 100644
index 0000000000..eedd9da43d
--- /dev/null
+++ b/src/common/compat_libevent.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2009, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef _TOR_COMPAT_LIBEVENT_H
+#define _TOR_COMPAT_LIBEVENT_H
+
+#include "orconfig.h"
+
+struct event;
+struct event_base;
+
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/util.h>
+#else
+#define evutil_socket_t int
+#endif
+
+void configure_libevent_logging(void);
+void suppress_libevent_log_msg(const char *msg);
+
+#ifdef HAVE_EVENT2_EVENT_H
+#define tor_event_new event_new
+#define tor_evtimer_new evtimer_new
+#define tor_evsignal_new evsignal_new
+#define tor_event_free event_free
+#define tor_evdns_add_server_port(sock, tcp, cb, data) \
+ evdns_add_server_port_with_base(tor_libevent_get_base(), \
+ (sock),(tcp),(cb),(data));
+
+#else
+struct event *tor_event_new(struct event_base * base, evutil_socket_t sock,
+ short what, void (*cb)(evutil_socket_t, short, void *), void *arg);
+struct event *tor_evtimer_new(struct event_base * base,
+ void (*cb)(evutil_socket_t, short, void *), void *arg);
+struct event *tor_evsignal_new(struct event_base * base, int sig,
+ void (*cb)(evutil_socket_t, short, void *), void *arg);
+void tor_event_free(struct event *ev);
+#define tor_evdns_add_server_port evdns_add_server_port
+#endif
+
+/* XXXX022 If we can drop support for Libevent before 1.1, we can
+ * do without this wrapper. */
+#ifdef HAVE_EVENT_BASE_LOOPEXIT
+#define tor_event_base_loopexit event_base_loopexit
+#else
+struct timeval;
+int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
+#endif
+
+void tor_libevent_initialize(void);
+struct event_base *tor_libevent_get_base(void);
+const char *tor_libevent_get_method(void);
+void tor_check_libevent_version(const char *m, int server,
+ const char **badness_out);
+void tor_check_libevent_header_compatibility(void);
+const char *tor_libevent_get_version_str(void);
+
+#endif
+
diff --git a/src/common/container.c b/src/common/container.c
index 08fab5ced1..ab5a9b0325 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -44,7 +44,8 @@ smartlist_create(void)
void
smartlist_free(smartlist_t *sl)
{
- tor_assert(sl != NULL);
+ if (!sl)
+ return;
tor_free(sl->list);
tor_free(sl);
}
@@ -459,6 +460,42 @@ smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b))
(int (*)(const void *,const void*))compare);
}
+/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>,
+ * return the most frequent member in the list. Break ties in favor of
+ * later elements. If the list is empty, return NULL.
+ */
+void *
+smartlist_get_most_frequent(const smartlist_t *sl,
+ int (*compare)(const void **a, const void **b))
+{
+ const void *most_frequent = NULL;
+ int most_frequent_count = 0;
+
+ const void *cur = NULL;
+ int i, count=0;
+
+ if (!sl->num_used)
+ return NULL;
+ for (i = 0; i < sl->num_used; ++i) {
+ const void *item = sl->list[i];
+ if (cur && 0 == compare(&cur, &item)) {
+ ++count;
+ } else {
+ if (cur && count >= most_frequent_count) {
+ most_frequent = cur;
+ most_frequent_count = count;
+ }
+ cur = item;
+ count = 1;
+ }
+ }
+ if (cur && count >= most_frequent_count) {
+ most_frequent = cur;
+ most_frequent_count = count;
+ }
+ return (void*)most_frequent;
+}
+
/** Given a sorted smartlist <b>sl</b> and the comparison function used to
* sort it, remove all duplicate members. If free_fn is provided, calls
* free_fn on each duplicate. Otherwise, just removes them. Preserves order.
@@ -550,6 +587,13 @@ smartlist_sort_strings(smartlist_t *sl)
smartlist_sort(sl, _compare_string_ptrs);
}
+/** Return the most frequent string in the sorted list <b>sl</b> */
+char *
+smartlist_get_most_frequent_string(smartlist_t *sl)
+{
+ return smartlist_get_most_frequent(sl, _compare_string_ptrs);
+}
+
/** Remove duplicate strings from a sorted list, and free them with tor_free().
*/
void
@@ -561,6 +605,38 @@ smartlist_uniq_strings(smartlist_t *sl)
/* Heap-based priority queue implementation for O(lg N) insert and remove.
* Recall that the heap property is that, for every index I, h[I] <
* H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]].
+ *
+ * For us to remove items other than the topmost item, each item must store
+ * its own index within the heap. When calling the pqueue functions, tell
+ * them about the offset of the field that stores the index within the item.
+ *
+ * Example:
+ *
+ * typedef struct timer_t {
+ * struct timeval tv;
+ * int heap_index;
+ * } timer_t;
+ *
+ * static int compare(const void *p1, const void *p2) {
+ * const timer_t *t1 = p1, *t2 = p2;
+ * if (t1->tv.tv_sec < t2->tv.tv_sec) {
+ * return -1;
+ * } else if (t1->tv.tv_sec > t2->tv.tv_sec) {
+ * return 1;
+ * } else {
+ * return t1->tv.tv_usec - t2->tv_usec;
+ * }
+ * }
+ *
+ * void timer_heap_insert(smartlist_t *heap, timer_t *timer) {
+ * smartlist_pqueue_add(heap, compare, STRUCT_OFFSET(timer_t, heap_index),
+ * timer);
+ * }
+ *
+ * void timer_heap_pop(smartlist_t *heap) {
+ * return smartlist_pqueue_pop(heap, compare,
+ * STRUCT_OFFSET(timer_t, heap_index));
+ * }
*/
/* For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x]
@@ -572,12 +648,22 @@ smartlist_uniq_strings(smartlist_t *sl)
#define RIGHT_CHILD(i) ( 2*(i) + 2 )
#define PARENT(i) ( ((i)-1) / 2 )
+#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset))
+
+#define UPDATE_IDX(i) do { \
+ void *updated = sl->list[i]; \
+ *IDXP(updated) = i; \
+ } while (0)
+
+#define IDX_OF_ITEM(p) (*IDXP(p))
+
/** Helper. <b>sl</b> may have at most one violation of the heap property:
* the item at <b>idx</b> may be greater than one or both of its children.
* Restore the heap property. */
static INLINE void
smartlist_heapify(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
+ int idx_field_offset,
int idx)
{
while (1) {
@@ -600,21 +686,28 @@ smartlist_heapify(smartlist_t *sl,
void *tmp = sl->list[idx];
sl->list[idx] = sl->list[best_idx];
sl->list[best_idx] = tmp;
+ UPDATE_IDX(idx);
+ UPDATE_IDX(best_idx);
idx = best_idx;
}
}
}
-/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order
- * is determined by <b>compare</b>. */
+/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is
+ * determined by <b>compare</b> and the offset of the item in the heap is
+ * stored in an int-typed field at position <b>idx_field_offset</b> within
+ * item.
+ */
void
smartlist_pqueue_add(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
+ int idx_field_offset,
void *item)
{
int idx;
smartlist_add(sl,item);
+ UPDATE_IDX(sl->num_used-1);
for (idx = sl->num_used - 1; idx; ) {
int parent = PARENT(idx);
@@ -622,6 +715,8 @@ smartlist_pqueue_add(smartlist_t *sl,
void *tmp = sl->list[parent];
sl->list[parent] = sl->list[idx];
sl->list[idx] = tmp;
+ UPDATE_IDX(parent);
+ UPDATE_IDX(idx);
idx = parent;
} else {
return;
@@ -630,32 +725,63 @@ smartlist_pqueue_add(smartlist_t *sl,
}
/** Remove and return the top-priority item from the heap stored in <b>sl</b>,
- * where order is determined by <b>compare</b>. <b>sl</b> must not be
- * empty. */
+ * where order is determined by <b>compare</b> and the item's position is
+ * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must
+ * not be empty. */
void *
smartlist_pqueue_pop(smartlist_t *sl,
- int (*compare)(const void *a, const void *b))
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset)
{
void *top;
tor_assert(sl->num_used);
top = sl->list[0];
+ *IDXP(top)=-1;
if (--sl->num_used) {
sl->list[0] = sl->list[sl->num_used];
- smartlist_heapify(sl, compare, 0);
+ UPDATE_IDX(0);
+ smartlist_heapify(sl, compare, idx_field_offset, 0);
}
return top;
}
+/** Remove the item <b>item</b> from the heap stored in <b>sl</b>,
+ * where order is determined by <b>compare</b> and the item's position is
+ * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must
+ * not be empty. */
+void
+smartlist_pqueue_remove(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset,
+ void *item)
+{
+ int idx = IDX_OF_ITEM(item);
+ tor_assert(idx >= 0);
+ tor_assert(sl->list[idx] == item);
+ --sl->num_used;
+ *IDXP(item) = -1;
+ if (idx == sl->num_used) {
+ return;
+ } else {
+ sl->list[idx] = sl->list[sl->num_used];
+ UPDATE_IDX(idx);
+ smartlist_heapify(sl, compare, idx_field_offset, idx);
+ }
+}
+
/** Assert that the heap property is correctly maintained by the heap stored
* in <b>sl</b>, where order is determined by <b>compare</b>. */
void
smartlist_pqueue_assert_ok(smartlist_t *sl,
- int (*compare)(const void *a, const void *b))
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset)
{
int i;
- for (i = sl->num_used - 1; i > 0; --i) {
- tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0);
+ for (i = sl->num_used - 1; i >= 0; --i) {
+ if (i>0)
+ tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0);
+ tor_assert(IDX_OF_ITEM(sl->list[i]) == i);
}
}
@@ -681,6 +807,37 @@ smartlist_uniq_digests(smartlist_t *sl)
smartlist_uniq(sl, _compare_digests, _tor_free);
}
+/** Helper: compare two DIGEST256_LEN digests. */
+static int
+_compare_digests256(const void **_a, const void **_b)
+{
+ return memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN);
+}
+
+/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */
+void
+smartlist_sort_digests256(smartlist_t *sl)
+{
+ smartlist_sort(sl, _compare_digests256);
+}
+
+/** Return the most frequent member of the sorted list of DIGEST256_LEN
+ * digests in <b>sl</b> */
+char *
+smartlist_get_most_frequent_digest256(smartlist_t *sl)
+{
+ return smartlist_get_most_frequent(sl, _compare_digests256);
+}
+
+/** Remove duplicate 256-bit digests from a sorted list, and free them with
+ * tor_free().
+ */
+void
+smartlist_uniq_digests256(smartlist_t *sl)
+{
+ smartlist_uniq(sl, _compare_digests256, _tor_free);
+}
+
/** Helper: Declare an entry type and a map type to implement a mapping using
* ht.h. The map type will be called <b>maptype</b>. The key part of each
* entry is declared using the C declaration <b>keydecl</b>. All functions
@@ -1113,6 +1270,9 @@ void
strmap_free(strmap_t *map, void (*free_val)(void*))
{
strmap_entry_t **ent, **next, *this;
+ if (!map)
+ return;
+
for (ent = HT_START(strmap_impl, &map->head); ent != NULL; ent = next) {
this = *ent;
next = HT_NEXT_RMV(strmap_impl, &map->head, ent);
@@ -1134,6 +1294,8 @@ void
digestmap_free(digestmap_t *map, void (*free_val)(void*))
{
digestmap_entry_t **ent, **next, *this;
+ if (!map)
+ return;
for (ent = HT_START(digestmap_impl, &map->head); ent != NULL; ent = next) {
this = *ent;
next = HT_NEXT_RMV(digestmap_impl, &map->head, ent);
@@ -1220,6 +1382,7 @@ IMPLEMENT_ORDER_FUNC(find_nth_int, int)
IMPLEMENT_ORDER_FUNC(find_nth_time, time_t)
IMPLEMENT_ORDER_FUNC(find_nth_double, double)
IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t)
+IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t)
IMPLEMENT_ORDER_FUNC(find_nth_long, long)
/** Return a newly allocated digestset_t, optimized to hold a total of
@@ -1248,6 +1411,8 @@ digestset_new(int max_elements)
void
digestset_free(digestset_t *set)
{
+ if (!set)
+ return;
bitarray_free(set->ba);
tor_free(set);
}
diff --git a/src/common/container.h b/src/common/container.h
index c42b86977d..3568de0159 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -93,13 +93,22 @@ void smartlist_del_keeporder(smartlist_t *sl, int idx);
void smartlist_insert(smartlist_t *sl, int idx, void *val);
void smartlist_sort(smartlist_t *sl,
int (*compare)(const void **a, const void **b));
+void *smartlist_get_most_frequent(const smartlist_t *sl,
+ int (*compare)(const void **a, const void **b));
void smartlist_uniq(smartlist_t *sl,
int (*compare)(const void **a, const void **b),
void (*free_fn)(void *elt));
+
void smartlist_sort_strings(smartlist_t *sl);
void smartlist_sort_digests(smartlist_t *sl);
+void smartlist_sort_digests256(smartlist_t *sl);
+
+char *smartlist_get_most_frequent_string(smartlist_t *sl);
+char *smartlist_get_most_frequent_digest256(smartlist_t *sl);
+
void smartlist_uniq_strings(smartlist_t *sl);
void smartlist_uniq_digests(smartlist_t *sl);
+void smartlist_uniq_digests256(smartlist_t *sl);
void *smartlist_bsearch(smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member))
ATTR_PURE;
@@ -109,11 +118,18 @@ int smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
void smartlist_pqueue_add(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
+ int idx_field_offset,
void *item);
void *smartlist_pqueue_pop(smartlist_t *sl,
- int (*compare)(const void *a, const void *b));
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset);
+void smartlist_pqueue_remove(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset,
+ void *item);
void smartlist_pqueue_assert_ok(smartlist_t *sl,
- int (*compare)(const void *a, const void *b));
+ int (*compare)(const void *a, const void *b),
+ int idx_field_offset);
#define SPLIT_SKIP_SPACE 0x01
#define SPLIT_IGNORE_BLANK 0x02
@@ -627,6 +643,7 @@ void digestset_free(digestset_t* set);
int find_nth_int(int *array, int n_elements, int nth);
time_t find_nth_time(time_t *array, int n_elements, int nth);
double find_nth_double(double *array, int n_elements, int nth);
+int32_t find_nth_int32(int32_t *array, int n_elements, int nth);
uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth);
long find_nth_long(long *array, int n_elements, int nth);
static INLINE int
@@ -649,6 +666,11 @@ median_uint32(uint32_t *array, int n_elements)
{
return find_nth_uint32(array, n_elements, (n_elements-1)/2);
}
+static INLINE int32_t
+median_int32(int32_t *array, int n_elements)
+{
+ return find_nth_int32(array, n_elements, (n_elements-1)/2);
+}
static INLINE long
median_long(long *array, int n_elements)
{
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 8aef4771c3..1a1dad616c 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -27,6 +27,7 @@
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
+#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/opensslv.h>
#include <openssl/bn.h>
@@ -49,9 +50,9 @@
#define CRYPTO_PRIVATE
#include "crypto.h"
-#include "log.h"
+#include "../common/log.h"
#include "aes.h"
-#include "util.h"
+#include "../common/util.h"
#include "container.h"
#include "compat.h"
@@ -61,6 +62,33 @@
#include <openssl/engine.h>
+#ifdef ANDROID
+/* Android's OpenSSL seems to have removed all of its Engine support. */
+#define DISABLE_ENGINES
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000l
+/* On OpenSSL versions before 0.9.8, there is no working SHA256
+ * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
+ * to our needs */
+#define SHA256_CTX sha256_state
+#define SHA256_Init sha256_init
+#define SHA256_Update sha256_process
+#define LTC_ARGCHK(x) tor_assert(x)
+#include "sha256.c"
+#define SHA256_Final(a,b) sha256_done(b,a)
+
+static unsigned char *
+SHA256(const unsigned char *m, size_t len, unsigned char *d)
+{
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, m, len);
+ SHA256_Final(d, &ctx);
+ return d;
+}
+#endif
+
/** Macro: is k a valid RSA public or private key? */
#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
/** Macro: is k a valid RSA private key? */
@@ -94,7 +122,7 @@ struct crypto_dh_env_t {
};
static int setup_openssl_threading(void);
-static int tor_check_dh_key(BIGNUM *bn);
+static int tor_check_dh_key(int severity, BIGNUM *bn);
/** Return the number of bytes added by padding method <b>padding</b>.
*/
@@ -151,6 +179,7 @@ crypto_log_errors(int severity, const char *doing)
}
}
+#ifndef DISABLE_ENGINES
/** Log any OpenSSL engines we're using at NOTICE. */
static void
log_engine(const char *fn, ENGINE *e)
@@ -165,37 +194,82 @@ log_engine(const char *fn, ENGINE *e)
log(LOG_INFO, LD_CRYPTO, "Using default implementation for %s", fn);
}
}
+#endif
+
+#ifndef DISABLE_ENGINES
+/** Try to load an engine in a shared library via fully qualified path.
+ */
+static ENGINE *
+try_load_engine(const char *path, const char *engine)
+{
+ ENGINE *e = ENGINE_by_id("dynamic");
+ if (e) {
+ if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) ||
+ !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) ||
+ !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) ||
+ !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
+ ENGINE_free(e);
+ e = NULL;
+ }
+ }
+ return e;
+}
+#endif
/** Initialize the crypto library. Return 0 on success, -1 on failure.
*/
int
-crypto_global_init(int useAccel)
+crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
if (!_crypto_global_initialized) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
_crypto_global_initialized = 1;
setup_openssl_threading();
- /* XXX the below is a bug, since we can't know if we're supposed
- * to be using hardware acceleration or not. we should arrange
- * for this function to be called before init_keys. But make it
- * not complain loudly, at least until we make acceleration work. */
- if (useAccel < 0) {
- log_info(LD_CRYPTO, "Initializing OpenSSL via tor_tls_init().");
- }
if (useAccel > 0) {
+#ifdef DISABLE_ENGINES
+ (void)accelName;
+ (void)accelDir;
+ log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled.");
+#else
+ ENGINE *e = NULL;
+
log_info(LD_CRYPTO, "Initializing OpenSSL engine support.");
ENGINE_load_builtin_engines();
- if (!ENGINE_register_all_complete())
- return -1;
-
- /* XXXX make sure this isn't leaking. */
+ ENGINE_register_all_complete();
+
+ if (accelName) {
+ if (accelDir) {
+ log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\""
+ " via path \"%s\".", accelName, accelDir);
+ e = try_load_engine(accelName, accelDir);
+ } else {
+ log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\""
+ " acceleration support.", accelName);
+ e = ENGINE_by_id(accelName);
+ }
+ if (!e) {
+ log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".",
+ accelName);
+ } else {
+ log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".",
+ accelName);
+ }
+ }
+ if (e) {
+ log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine,"
+ " setting default ciphers.");
+ ENGINE_set_default(e, ENGINE_METHOD_ALL);
+ }
log_engine("RSA", ENGINE_get_default_RSA());
log_engine("DH", ENGINE_get_default_DH());
log_engine("RAND", ENGINE_get_default_RAND());
log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1));
log_engine("3DES", ENGINE_get_cipher_engine(NID_des_ede3_ecb));
log_engine("AES", ENGINE_get_cipher_engine(NID_aes_128_ecb));
+#endif
+ } else {
+ log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
return crypto_seed_rng(1);
}
@@ -217,7 +291,11 @@ crypto_global_cleanup(void)
EVP_cleanup();
ERR_remove_state(0);
ERR_free_strings();
+
+#ifndef DISABLE_ENGINES
ENGINE_cleanup();
+#endif
+
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
#ifdef TOR_IS_MULTITHREADED
@@ -259,7 +337,8 @@ _crypto_new_pk_env_evp_pkey(EVP_PKEY *pkey)
return _crypto_new_pk_env_rsa(rsa);
}
-/** Helper, used by tor-checkkey.c. Return the RSA from a crypto_pk_env_t. */
+/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
+ * crypto_pk_env_t. */
RSA *
_crypto_pk_env_get_rsa(crypto_pk_env_t *env)
{
@@ -321,7 +400,8 @@ crypto_new_pk_env(void)
void
crypto_free_pk_env(crypto_pk_env_t *env)
{
- tor_assert(env);
+ if (!env)
+ return;
if (--env->refs > 0)
return;
@@ -347,10 +427,7 @@ crypto_create_init_cipher(const char *key, int encrypt_mode)
return NULL;
}
- if (crypto_cipher_set_key(crypto, key)) {
- crypto_log_errors(LOG_WARN, "setting symmetric key");
- goto error;
- }
+ crypto_cipher_set_key(crypto, key);
if (encrypt_mode)
r = crypto_cipher_encrypt_init_cipher(crypto);
@@ -384,7 +461,8 @@ crypto_new_cipher_env(void)
void
crypto_free_cipher_env(crypto_cipher_env_t *env)
{
- tor_assert(env);
+ if (!env)
+ return;
tor_assert(env->cipher);
aes_free_cipher(env->cipher);
@@ -394,11 +472,11 @@ crypto_free_cipher_env(crypto_cipher_env_t *env)
/* public key crypto */
-/** Generate a new public/private keypair in <b>env</b>. Return 0 on
- * success, -1 on failure.
+/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
+ * Return 0 on success, -1 on failure.
*/
int
-crypto_pk_generate_key(crypto_pk_env_t *env)
+crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits)
{
tor_assert(env);
@@ -406,7 +484,7 @@ crypto_pk_generate_key(crypto_pk_env_t *env)
RSA_free(env->key);
#if OPENSSL_VERSION_NUMBER < 0x00908000l
/* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
- env->key = RSA_generate_key(PK_BYTES*8,65537, NULL, NULL);
+ env->key = RSA_generate_key(bits, 65537, NULL, NULL);
#else
/* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
{
@@ -419,7 +497,7 @@ crypto_pk_generate_key(crypto_pk_env_t *env)
r = RSA_new();
if (!r)
goto done;
- if (RSA_generate_key_ex(r, PK_BYTES*8, e, NULL) == -1)
+ if (RSA_generate_key_ex(r, bits, e, NULL) == -1)
goto done;
env->key = r;
@@ -1172,19 +1250,14 @@ crypto_cipher_generate_key(crypto_cipher_env_t *env)
/** Set the symmetric key for the cipher in <b>env</b> to the first
* CIPHER_KEY_LEN bytes of <b>key</b>. Does not initialize the cipher.
- * Return 0 on success, -1 on failure.
*/
-int
+void
crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key)
{
tor_assert(env);
tor_assert(key);
- if (!env->key)
- return -1;
-
memcpy(env->key, key, CIPHER_KEY_LEN);
- return 0;
}
/** Generate an initialization vector for our AES-CTR cipher; store it
@@ -1358,9 +1431,69 @@ crypto_digest(char *digest, const char *m, size_t len)
return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
}
+int
+crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA256);
+ return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
+}
+
+/** Set the digests_t in <b>ds_out</b> to contain every digest on the
+ * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on
+ * success, -1 on failure. */
+int
+crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
+{
+ digest_algorithm_t i;
+ tor_assert(ds_out);
+ memset(ds_out, 0, sizeof(*ds_out));
+ if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
+ return -1;
+ for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) {
+ if (crypto_digest256(ds_out->d[i], m, len, i) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/** Return the name of an algorithm, as used in directory documents. */
+const char *
+crypto_digest_algorithm_get_name(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return "sha1";
+ case DIGEST_SHA256:
+ return "sha256";
+ default:
+ tor_fragile_assert();
+ return "??unknown_digest??";
+ }
+}
+
+/** Given the name of a digest algorithm, return its integer value, or -1 if
+ * the name is not recognized. */
+int
+crypto_digest_algorithm_parse_name(const char *name)
+{
+ if (!strcmp(name, "sha1"))
+ return DIGEST_SHA1;
+ else if (!strcmp(name, "sha256"))
+ return DIGEST_SHA256;
+ else
+ return -1;
+}
+
/** Intermediate information about the digest of a stream of data. */
struct crypto_digest_env_t {
- SHA_CTX d;
+ union {
+ SHA_CTX sha1;
+ SHA256_CTX sha2;
+ } d;
+ digest_algorithm_t algorithm : 8;
};
/** Allocate and return a new digest object.
@@ -1370,7 +1503,19 @@ crypto_new_digest_env(void)
{
crypto_digest_env_t *r;
r = tor_malloc(sizeof(crypto_digest_env_t));
- SHA1_Init(&r->d);
+ SHA1_Init(&r->d.sha1);
+ r->algorithm = DIGEST_SHA1;
+ return r;
+}
+
+crypto_digest_env_t *
+crypto_new_digest256_env(digest_algorithm_t algorithm)
+{
+ crypto_digest_env_t *r;
+ tor_assert(algorithm == DIGEST_SHA256);
+ r = tor_malloc(sizeof(crypto_digest_env_t));
+ SHA256_Init(&r->d.sha2);
+ r->algorithm = algorithm;
return r;
}
@@ -1379,6 +1524,8 @@ crypto_new_digest_env(void)
void
crypto_free_digest_env(crypto_digest_env_t *digest)
{
+ if (!digest)
+ return;
memset(digest, 0, sizeof(crypto_digest_env_t));
tor_free(digest);
}
@@ -1391,30 +1538,51 @@ crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
{
tor_assert(digest);
tor_assert(data);
- /* Using the SHA1_*() calls directly means we don't support doing
- * SHA1 in hardware. But so far the delay of getting the question
+ /* Using the SHA*_*() calls directly means we don't support doing
+ * SHA in hardware. But so far the delay of getting the question
* to the hardware, and hearing the answer, is likely higher than
* just doing it ourselves. Hashes are fast.
*/
- SHA1_Update(&digest->d, (void*)data, len);
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Update(&digest->d.sha1, (void*)data, len);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Update(&digest->d.sha2, (void*)data, len);
+ break;
+ default:
+ tor_fragile_assert();
+ break;
+ }
}
/** Compute the hash of the data that has been passed to the digest
* object; write the first out_len bytes of the result to <b>out</b>.
- * <b>out_len</b> must be \<= DIGEST_LEN.
+ * <b>out_len</b> must be \<= DIGEST256_LEN.
*/
void
crypto_digest_get_digest(crypto_digest_env_t *digest,
char *out, size_t out_len)
{
- unsigned char r[DIGEST_LEN];
- SHA_CTX tmpctx;
+ unsigned char r[DIGEST256_LEN];
+ crypto_digest_env_t tmpenv;
tor_assert(digest);
tor_assert(out);
- tor_assert(out_len <= DIGEST_LEN);
- /* memcpy into a temporary ctx, since SHA1_Final clears the context */
- memcpy(&tmpctx, &digest->d, sizeof(SHA_CTX));
- SHA1_Final(r, &tmpctx);
+ /* memcpy into a temporary ctx, since SHA*_Final clears the context */
+ memcpy(&tmpenv, digest, sizeof(crypto_digest_env_t));
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ tor_assert(out_len <= DIGEST_LEN);
+ SHA1_Final(r, &tmpenv.d.sha1);
+ break;
+ case DIGEST_SHA256:
+ tor_assert(out_len <= DIGEST256_LEN);
+ SHA256_Final(r, &tmpenv.d.sha2);
+ break;
+ default:
+ tor_fragile_assert();
+ break;
+ }
memcpy(out, r, out_len);
memset(r, 0, sizeof(r));
}
@@ -1550,7 +1718,7 @@ crypto_dh_generate_public(crypto_dh_env_t *dh)
crypto_log_errors(LOG_WARN, "generating DH key");
return -1;
}
- if (tor_check_dh_key(dh->dh->pub_key)<0) {
+ if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) {
log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
"the-universe chances really do happen. Trying again.");
/* Free and clear the keys, so OpenSSL will actually try again. */
@@ -1597,7 +1765,7 @@ crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, size_t pubkey_len)
* See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips.
*/
static int
-tor_check_dh_key(BIGNUM *bn)
+tor_check_dh_key(int severity, BIGNUM *bn)
{
BIGNUM *x;
char *s;
@@ -1608,13 +1776,13 @@ tor_check_dh_key(BIGNUM *bn)
init_dh_param();
BN_set_word(x, 1);
if (BN_cmp(bn,x)<=0) {
- log_warn(LD_CRYPTO, "DH key must be at least 2.");
+ log_fn(severity, LD_CRYPTO, "DH key must be at least 2.");
goto err;
}
BN_copy(x,dh_param_p);
BN_sub_word(x, 1);
if (BN_cmp(bn,x)>=0) {
- log_warn(LD_CRYPTO, "DH key must be at most p-2.");
+ log_fn(severity, LD_CRYPTO, "DH key must be at most p-2.");
goto err;
}
BN_free(x);
@@ -1622,7 +1790,7 @@ tor_check_dh_key(BIGNUM *bn)
err:
BN_free(x);
s = BN_bn2hex(bn);
- log_warn(LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
+ log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
OPENSSL_free(s);
return -1;
}
@@ -1640,7 +1808,7 @@ tor_check_dh_key(BIGNUM *bn)
* where || is concatenation.)
*/
ssize_t
-crypto_dh_compute_secret(crypto_dh_env_t *dh,
+crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_bytes_out)
{
@@ -1655,9 +1823,9 @@ crypto_dh_compute_secret(crypto_dh_env_t *dh,
if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey,
(int)pubkey_len, NULL)))
goto error;
- if (tor_check_dh_key(pubkey_bn)<0) {
+ if (tor_check_dh_key(severity, pubkey_bn)<0) {
/* Check for invalid public keys. */
- log_warn(LD_CRYPTO,"Rejected invalid g^x");
+ log_fn(severity, LD_CRYPTO,"Rejected invalid g^x");
goto error;
}
secret_tmp = tor_malloc(crypto_dh_get_bytes(dh));
@@ -1729,7 +1897,8 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
void
crypto_dh_free(crypto_dh_env_t *dh)
{
- tor_assert(dh);
+ if (!dh)
+ return;
tor_assert(dh->dh);
DH_free(dh->dh);
tor_free(dh);
@@ -2147,6 +2316,44 @@ digest_from_base64(char *digest, const char *d64)
#endif
}
+/** Base-64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
+ * trailing = and newline characters, and store the nul-terminated result in
+ * the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
+int
+digest256_to_base64(char *d64, const char *digest)
+{
+ char buf[256];
+ base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN);
+ buf[BASE64_DIGEST256_LEN] = '\0';
+ memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
+ return 0;
+}
+
+/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
+ * trailing newline or = characters), decode it and store the result in the
+ * first DIGEST256_LEN bytes at <b>digest</b>. */
+int
+digest256_from_base64(char *digest, const char *d64)
+{
+#ifdef USE_OPENSSL_BASE64
+ char buf_in[BASE64_DIGEST256_LEN+3];
+ char buf[256];
+ if (strlen(d64) != BASE64_DIGEST256_LEN)
+ return -1;
+ memcpy(buf_in, d64, BASE64_DIGEST256_LEN);
+ memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3);
+ if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN)
+ return -1;
+ memcpy(digest, buf, DIGEST256_LEN);
+ return 0;
+#else
+ if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
+ return 0;
+ else
+ return -1;
+#endif
+}
+
/** Implements base32 encoding as in rfc3548. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 20fdfa4d2f..1b004dd4b8 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -18,6 +18,9 @@
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
+/** Length of the output of our second (improved) message digests. (For now
+ * this is just sha256, but any it can be any other 256-byte digest). */
+#define DIGEST256_LEN 32
/** Length of our symmetric cipher's keys. */
#define CIPHER_KEY_LEN 16
/** Length of our symmetric cipher's IV. */
@@ -27,9 +30,12 @@
/** Length of our DH keys. */
#define DH_BYTES (1024/8)
-/** Length of a message digest when encoded in base64 with trailing = signs
- * removed. */
+/** Length of a sha1 message digest when encoded in base64 with trailing =
+ * signs removed. */
#define BASE64_DIGEST_LEN 27
+/** Length of a sha256 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST256_LEN 43
/** Constants used to indicate no padding for public-key encryption */
#define PK_NO_PADDING 60000
@@ -48,6 +54,26 @@
#define FINGERPRINT_LEN 49
/** Length of hex encoding of SHA1 digest, not including final NUL. */
#define HEX_DIGEST_LEN 40
+/** Length of hex encoding of SHA256 digest, not including final NUL. */
+#define HEX_DIGEST256_LEN 64
+
+typedef enum {
+ DIGEST_SHA1 = 0,
+ DIGEST_SHA256 = 1,
+} digest_algorithm_t;
+#define N_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+
+/** A set of all the digests we know how to compute, taken on a single
+ * string. Any digests that are shorter than 256 bits are right-padded
+ * with 0 bits.
+ *
+ * Note that this representation wastes 12 bytes for the SHA1 case, so
+ * don't use it for anything where we need to allocate a whole bunch at
+ * once.
+ **/
+typedef struct {
+ char d[N_DIGEST_ALGORITHMS][DIGEST256_LEN];
+} digests_t;
typedef struct crypto_pk_env_t crypto_pk_env_t;
typedef struct crypto_cipher_env_t crypto_cipher_env_t;
@@ -55,7 +81,9 @@ typedef struct crypto_digest_env_t crypto_digest_env_t;
typedef struct crypto_dh_env_t crypto_dh_env_t;
/* global state */
-int crypto_global_init(int hardwareAccel);
+int crypto_global_init(int hardwareAccel,
+ const char *accelName,
+ const char *accelPath);
void crypto_thread_cleanup(void);
int crypto_global_cleanup(void);
@@ -71,7 +99,9 @@ crypto_cipher_env_t *crypto_new_cipher_env(void);
void crypto_free_cipher_env(crypto_cipher_env_t *env);
/* public key crypto */
-int crypto_pk_generate_key(crypto_pk_env_t *env);
+int crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits);
+#define crypto_pk_generate_key(env) \
+ crypto_pk_generate_key_with_bits((env), (PK_BYTES*8))
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env,
const char *keyfile);
@@ -121,7 +151,7 @@ int crypto_pk_check_fingerprint_syntax(const char *s);
/* symmetric crypto */
int crypto_cipher_generate_key(crypto_cipher_env_t *env);
-int crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key);
+void crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key);
void crypto_cipher_generate_iv(char *iv_out);
int crypto_cipher_set_iv(crypto_cipher_env_t *env, const char *iv);
const char *crypto_cipher_get_key(crypto_cipher_env_t *env);
@@ -141,9 +171,15 @@ int crypto_cipher_decrypt_with_iv(crypto_cipher_env_t *env,
char *to, size_t tolen,
const char *from, size_t fromlen);
-/* SHA-1 */
+/* SHA-1 and other digests. */
int crypto_digest(char *digest, const char *m, size_t len);
+int crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm);
+int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
+const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
+int crypto_digest_algorithm_parse_name(const char *name);
crypto_digest_env_t *crypto_new_digest_env(void);
+crypto_digest_env_t *crypto_new_digest256_env(digest_algorithm_t algorithm);
void crypto_free_digest_env(crypto_digest_env_t *digest);
void crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
size_t len);
@@ -162,7 +198,7 @@ int crypto_dh_get_bytes(crypto_dh_env_t *dh);
int crypto_dh_generate_public(crypto_dh_env_t *dh);
int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey_out,
size_t pubkey_out_len);
-ssize_t crypto_dh_compute_secret(crypto_dh_env_t *dh,
+ssize_t crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_out_len);
void crypto_dh_free(crypto_dh_env_t *dh);
@@ -191,6 +227,8 @@ int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
int digest_to_base64(char *d64, const char *digest);
int digest_from_base64(char *digest, const char *d64);
+int digest256_to_base64(char *d64, const char *digest);
+int digest256_from_base64(char *digest, const char *d64);
/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the
* 9th describes how much iteration to do. */
diff --git a/src/common/ht.h b/src/common/ht.h
index e6dd3d2b24..f598856d8a 100644
--- a/src/common/ht.h
+++ b/src/common/ht.h
@@ -42,6 +42,10 @@
#define HT_SIZE(head) \
((head)->hth_n_entries)
+/* Return memory usage for a hashtable (not counting the entries themselves) */
+#define HT_MEM_USAGE(head) \
+ (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
+
#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm))
#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm))
#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm))
diff --git a/src/common/log.c b/src/common/log.c
index 6baef8e26c..6bf94721f8 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -36,8 +36,6 @@
#include "log.h"
#include "container.h"
-#include <event.h>
-
#define TRUNCATED_STR "[...truncated]"
#define TRUNCATED_STR_LEN 14
@@ -83,7 +81,7 @@ should_log_function_name(log_domain_mask_t domain, int severity)
/* All debugging messages occur in interesting places. */
return 1;
case LOG_NOTICE:
- case LOG_WARN:
+ case LOG_WARN:
case LOG_ERR:
/* We care about places where bugs occur. */
return (domain == LD_BUG);
@@ -330,7 +328,7 @@ logv(int severity, log_domain_mask_t domain, const char *funcname,
/** Output a message to the log. */
void
-_log(int severity, log_domain_mask_t domain, const char *format, ...)
+tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (severity > _log_global_min_severity)
@@ -428,6 +426,8 @@ _log_err(log_domain_mask_t domain, const char *format, ...)
static void
log_free(logfile_t *victim)
{
+ if (!victim)
+ return;
tor_free(victim->severities);
tor_free(victim->filename);
tor_free(victim);
@@ -678,13 +678,11 @@ add_file_log(const log_severity_list_t *severity, const char *filename)
logfiles->needs_close = 1;
lf = logfiles;
_log_global_min_severity = get_min_log_level();
- UNLOCK_LOGS();
if (log_tor_version(lf, 0) < 0) {
- LOCK_LOGS();
delete_log(lf);
- UNLOCK_LOGS();
}
+ UNLOCK_LOGS();
return 0;
}
@@ -747,7 +745,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -925,65 +923,6 @@ switch_logs_debug(void)
UNLOCK_LOGS();
}
-#ifdef HAVE_EVENT_SET_LOG_CALLBACK
-/** A string which, if it appears in a libevent log, should be ignored. */
-static const char *suppress_msg = NULL;
-/** Callback function passed to event_set_log() so we can intercept
- * log messages from libevent. */
-static void
-libevent_logging_callback(int severity, const char *msg)
-{
- char buf[1024];
- size_t n;
- if (suppress_msg && strstr(msg, suppress_msg))
- return;
- n = strlcpy(buf, msg, sizeof(buf));
- if (n && n < sizeof(buf) && buf[n-1] == '\n') {
- buf[n-1] = '\0';
- }
- switch (severity) {
- case _EVENT_LOG_DEBUG:
- log(LOG_DEBUG, LD_NET, "Message from libevent: %s", buf);
- break;
- case _EVENT_LOG_MSG:
- log(LOG_INFO, LD_NET, "Message from libevent: %s", buf);
- break;
- case _EVENT_LOG_WARN:
- log(LOG_WARN, LD_GENERAL, "Warning from libevent: %s", buf);
- break;
- case _EVENT_LOG_ERR:
- log(LOG_ERR, LD_GENERAL, "Error from libevent: %s", buf);
- break;
- default:
- log(LOG_WARN, LD_GENERAL, "Message [%d] from libevent: %s",
- severity, buf);
- break;
- }
-}
-/** Set hook to intercept log messages from libevent. */
-void
-configure_libevent_logging(void)
-{
- event_set_log_callback(libevent_logging_callback);
-}
-/** Ignore any libevent log message that contains <b>msg</b>. */
-void
-suppress_libevent_log_msg(const char *msg)
-{
- suppress_msg = msg;
-}
-#else
-void
-configure_libevent_logging(void)
-{
-}
-void
-suppress_libevent_log_msg(const char *msg)
-{
- (void)msg;
-}
-#endif
-
#if 0
static void
dump_log_info(logfile_t *lf)
diff --git a/src/common/log.h b/src/common/log.h
index 6a45fc3d0b..21219569e3 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -90,9 +90,10 @@
#define LD_ACCT (1u<<17)
/** Router history */
#define LD_HIST (1u<<18)
-
+/** OR handshaking */
+#define LD_HANDSHAKE (1u<<19)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 19
+#define N_LOGGING_DOMAINS 20
typedef uint32_t log_domain_mask_t;
@@ -134,16 +135,14 @@ void add_temp_log(int min_severity);
void close_temp_logs(void);
void rollback_log_changes(void);
void mark_logs_temp(void);
-void configure_libevent_logging(void);
-void suppress_libevent_log_msg(const char *msg);
void change_callback_log_severity(int loglevelMin, int loglevelMax,
log_callback cb);
void log_set_application_name(const char *name);
/* Outputs a message to stdout */
-void _log(int severity, log_domain_mask_t domain, const char *format, ...)
+void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
-#define log _log /* hack it so we don't conflict with log() as much */
+#define log tor_log /* hack it so we don't conflict with log() as much */
#ifdef __GNUC__
extern int _log_global_min_severity;
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 9d908bae50..0402e5f208 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -13,6 +13,10 @@
#include "compat.h"
#include "log.h"
+/** If true, we try to detect any attempts to write beyond the length of a
+ * memarea. */
+#define USE_SENTINELS
+
/** All returned pointers should be aligned to the nearest multiple of this
* value. */
#define MEMAREA_ALIGN SIZEOF_VOID_P
@@ -25,6 +29,24 @@
#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff."
#endif
+#ifdef USE_SENTINELS
+#define SENTINEL_VAL 0x90806622u
+#define SENTINEL_LEN sizeof(uint32_t)
+#define SET_SENTINEL(chunk) \
+ STMT_BEGIN \
+ set_uint32( &(chunk)->u.mem[chunk->mem_size], SENTINEL_VAL ); \
+ STMT_END
+#define CHECK_SENTINEL(chunk) \
+ STMT_BEGIN \
+ uint32_t sent_val = get_uint32(&(chunk)->u.mem[chunk->mem_size]); \
+ tor_assert(sent_val == SENTINEL_VAL); \
+ STMT_END
+#else
+#define SENTINEL_LEN 0
+#define SET_SENTINEL(chunk) STMT_NIL
+#define CHECK_SENTINEL(chunk) STMT_NIL
+#endif
+
/** Increment <b>ptr</b> until it is aligned to MEMAREA_ALIGN. */
static INLINE void *
realign_pointer(void *ptr)
@@ -78,15 +100,20 @@ alloc_chunk(size_t sz, int freelist_ok)
freelist = res->next_chunk;
res->next_chunk = NULL;
--freelist_len;
+ CHECK_SENTINEL(res);
return res;
} else {
size_t chunk_size = freelist_ok ? CHUNK_SIZE : sz;
- memarea_chunk_t *res = tor_malloc_roundup(&chunk_size);
+ memarea_chunk_t *res;
+ chunk_size += SENTINEL_LEN;
+ res = tor_malloc_roundup(&chunk_size);
res->next_chunk = NULL;
- res->mem_size = chunk_size - CHUNK_HEADER_SIZE;
+ res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN;
res->next_mem = res->u.mem;
- tor_assert(res->next_mem+res->mem_size == ((char*)res)+chunk_size);
+ tor_assert(res->next_mem+res->mem_size+SENTINEL_LEN ==
+ ((char*)res)+chunk_size);
tor_assert(realign_pointer(res->next_mem) == res->next_mem);
+ SET_SENTINEL(res);
return res;
}
}
@@ -94,8 +121,9 @@ alloc_chunk(size_t sz, int freelist_ok)
/** Release <b>chunk</b> from a memarea, either by adding it to the freelist
* or by freeing it if the freelist is already too big. */
static void
-chunk_free(memarea_chunk_t *chunk)
+chunk_free_unchecked(memarea_chunk_t *chunk)
{
+ CHECK_SENTINEL(chunk);
if (freelist_len < MAX_FREELIST_LEN) {
++freelist_len;
chunk->next_chunk = freelist;
@@ -123,7 +151,7 @@ memarea_drop_all(memarea_t *area)
memarea_chunk_t *chunk, *next;
for (chunk = area->first; chunk; chunk = next) {
next = chunk->next_chunk;
- chunk_free(chunk);
+ chunk_free_unchecked(chunk);
}
area->first = NULL; /*fail fast on */
tor_free(area);
@@ -139,7 +167,7 @@ memarea_clear(memarea_t *area)
if (area->first->next_chunk) {
for (chunk = area->first->next_chunk; chunk; chunk = next) {
next = chunk->next_chunk;
- chunk_free(chunk);
+ chunk_free_unchecked(chunk);
}
area->first->next_chunk = NULL;
}
@@ -182,6 +210,7 @@ memarea_alloc(memarea_t *area, size_t sz)
memarea_chunk_t *chunk = area->first;
char *result;
tor_assert(chunk);
+ CHECK_SENTINEL(chunk);
if (sz == 0)
sz = 1;
if (chunk->next_mem+sz > chunk->u.mem+chunk->mem_size) {
@@ -258,6 +287,7 @@ memarea_get_stats(memarea_t *area, size_t *allocated_out, size_t *used_out)
size_t a = 0, u = 0;
memarea_chunk_t *chunk;
for (chunk = area->first; chunk; chunk = chunk->next_chunk) {
+ CHECK_SENTINEL(chunk);
a += CHUNK_HEADER_SIZE + chunk->mem_size;
tor_assert(chunk->next_mem >= chunk->u.mem);
u += CHUNK_HEADER_SIZE + (chunk->next_mem - chunk->u.mem);
@@ -274,6 +304,7 @@ memarea_assert_ok(memarea_t *area)
tor_assert(area->first);
for (chunk = area->first; chunk; chunk = chunk->next_chunk) {
+ CHECK_SENTINEL(chunk);
tor_assert(chunk->next_mem >= chunk->u.mem);
tor_assert(chunk->next_mem <=
(char*) realign_pointer(chunk->u.mem+chunk->mem_size));
diff --git a/src/common/sha256.c b/src/common/sha256.c
new file mode 100644
index 0000000000..d445ae4e6d
--- /dev/null
+++ b/src/common/sha256.c
@@ -0,0 +1,331 @@
+/* Copyright (c) 2009, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+/* This SHA256 implementation is adapted from the public domain one in
+ LibTomCrypt, version 1.6. Tor uses it on platforms where OpenSSL doesn't
+ have a SHA256. */
+
+
+typedef struct sha256_state {
+ uint64_t length;
+ uint32_t state[8], curlen;
+ unsigned char buf[64];
+} sha256_state;
+
+#define CRYPT_OK 0
+#define CRYPT_NOP -1
+#define CRYPT_INVALID_ARG -2
+
+#define LOAD32H(x,y) STMT_BEGIN x = ntohl(get_uint32((const char*)y)); STMT_END
+#define STORE32H(x,y) STMT_BEGIN set_uint32((char*)y, htonl(x)); STMT_END
+#define STORE64H(x,y) STMT_BEGIN \
+ set_uint32((char*)y, htonl((uint32_t)((x)>>32))); \
+ set_uint32(((char*)y)+4, htonl((uint32_t)((x)&0xffffffff))); \
+ STMT_END
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
+ */
+
+/**
+ @file sha256.c
+ SHA256 by Tom St Denis
+*/
+
+
+#ifdef LTC_SMALL_CODE
+/* the K array */
+static const uint32_t K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+#endif
+
+/* Various logical functions */
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x),(n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+/* compress 512-bits */
+#ifdef LTC_CLEAN_STACK
+static int _sha256_compress(sha256_state * md, unsigned char *buf)
+#else
+static int sha256_compress(sha256_state * md, unsigned char *buf)
+#endif
+{
+ uint32_t S[8], W[64], t0, t1;
+#ifdef LTC_SMALL_CODE
+ uint32_t t;
+#endif
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+
+ /* fill W[16..63] */
+ for (i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+ }
+
+ /* Compress */
+#ifdef LTC_SMALL_CODE
+#define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+ for (i = 0; i < 64; ++i) {
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+ }
+#else
+#define RND(a,b,c,d,e,f,g,h,i,ki) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
+
+#undef RND
+
+#endif
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int sha256_compress(sha256_state * md, unsigned char *buf)
+{
+ int err;
+ err = _sha256_compress(md, buf);
+ burn_stack(sizeof(uint32_t) * 74);
+ return err;
+}
+#endif
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+static int sha256_init(sha256_state * md)
+{
+ LTC_ARGCHK(md != NULL);
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+ return CRYPT_OK;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+static int sha256_process (sha256_state * md, const unsigned char *in, unsigned long inlen)
+{
+ unsigned long n;
+ int err;
+ LTC_ARGCHK(md != NULL);
+ LTC_ARGCHK(in != NULL);
+ if (md->curlen > sizeof(md->buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 64) {
+ if ((err = sha256_compress (md, (unsigned char *)in)) != CRYPT_OK) {
+ return err;
+ }
+ md->length += 64 * 8;
+ in += 64;
+ inlen -= 64;
+ } else {
+ n = MIN(inlen, (64 - md->curlen));
+ memcpy(md->buf + md->curlen, in, (size_t)n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 64) {
+ if ((err = sha256_compress (md, md->buf)) != CRYPT_OK) {
+ return err;
+ }
+ md->length += 8*64;
+ md->curlen = 0;
+ }
+ }
+ }
+ return CRYPT_OK;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return CRYPT_OK if successful
+*/
+static int sha256_done(sha256_state * md, unsigned char *out)
+{
+ int i;
+
+ LTC_ARGCHK(md != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (md->curlen >= sizeof(md->buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(md->length, md->buf+56);
+ sha256_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++) {
+ STORE32H(md->state[i], out+(4*i));
+ }
+#ifdef LTC_CLEAN_STACK
+ zeromem(md, sizeof(sha256_state));
+#endif
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/11/01 09:28:17 $ */
diff --git a/src/common/test.h b/src/common/test.h
deleted file mode 100644
index 1e3db58333..0000000000
--- a/src/common/test.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (c) 2001-2003, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2010, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#ifndef _TOR_TEST_H
-#define _TOR_TEST_H
-
-/**
- * \file test.h
- * \brief Macros used by unit tests.
- */
-
-#include "compat.h"
-
-#ifdef __GNUC__
-#define PRETTY_FUNCTION __PRETTY_FUNCTION__
-#else
-#define PRETTY_FUNCTION ""
-#endif
-
-#define test_fail_msg(msg) \
- STMT_BEGIN \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): %s", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- msg); \
- goto done; \
- STMT_END
-
-#define test_fail() test_fail_msg("Assertion failed.")
-
-#define test_assert(expr) \
- STMT_BEGIN \
- if (expr) { printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): assertion failed: (%s)\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr); \
- goto done; \
- } STMT_END
-
-#define test_eq_type(tp, fmt, expr1, expr2) \
- STMT_BEGIN \
- tp _test_v1=(tp)(expr1); \
- tp _test_v2=(tp)(expr2); \
- if (_test_v1==_test_v2) { printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
- " "fmt "!="fmt"\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2, \
- _test_v1, _test_v2); \
- goto done; \
- } STMT_END
-
-#define test_eq(expr1, expr2) \
- test_eq_type(long, "%ld", expr1, expr2)
-
-#define test_eq_ptr(expr1, expr2) \
- test_eq_type(void*, "%p", expr1, expr2)
-
-#define test_neq_type(tp, fmt, expr1, expr2) \
- STMT_BEGIN \
- tp _test_v1=(tp)(expr1); \
- tp _test_v2=(tp)(expr2); \
- if (_test_v1!=_test_v2) { printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n" \
- " ("fmt" == "fmt")\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2, \
- _test_v1, _test_v2); \
- goto done; \
- } STMT_END
-
-#define test_neq(expr1, expr2) \
- test_neq_type(long, "%ld", expr1, expr2)
-
-#define test_neq_ptr(expr1, expr2) \
- test_neq_type(void *, "%p", expr1, expr2)
-
-#define test_streq(expr1, expr2) \
- STMT_BEGIN \
- const char *_test_v1=(expr1), *_test_v2=(expr2); \
- if (!strcmp(_test_v1,_test_v2)) { printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n"\
- " (\"%s\" != \"%s\")\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2, \
- _test_v1, _test_v2); \
- goto done; \
- } STMT_END
-
-#define test_strneq(expr1, expr2) \
- STMT_BEGIN \
- const char *_test_v1=(expr1), *_test_v2=(expr2); \
- if (strcmp(_test_v1,_test_v2)) { printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\
- " (\"%s\" == \"%s\")\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2, \
- _test_v1, _test_v2); \
- goto done; \
- } STMT_END
-
-#define test_memeq(expr1, expr2, len) \
- STMT_BEGIN \
- const void *_test_v1=(expr1), *_test_v2=(expr2); \
- char *mem1, *mem2; \
- if (!memcmp(_test_v1,_test_v2,(len))) { \
- printf("."); fflush(stdout); } else { \
- have_failed = 1; \
- mem1 = tor_malloc(len*2+1); \
- mem2 = tor_malloc(len*2+1); \
- base16_encode(mem1, len*2+1, _test_v1, len); \
- base16_encode(mem2, len*2+1, _test_v2, len); \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
- " %s != %s\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2, mem1, mem2); \
- tor_free(mem1); \
- tor_free(mem2); \
- goto done; \
- } STMT_END
-
-#define test_memeq_hex(expr1, hex) \
- STMT_BEGIN \
- const char *_test_v1 = (char*)(expr1); \
- const char *_test_v2 = (hex); \
- size_t _len_v2 = strlen(_test_v2); \
- char *_mem2 = tor_malloc(_len_v2/2); \
- tor_assert((_len_v2 & 1) == 0); \
- base16_decode(_mem2, _len_v2/2, _test_v2, _len_v2); \
- if (!memcmp(_mem2, _test_v1, _len_v2/2)) { \
- printf("."); fflush(stdout); } else { \
- char *_mem1 = tor_malloc(_len_v2+1); \
- base16_encode(_mem1, _len_v2+1, _test_v1, _len_v2/2); \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
- " %s != %s\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, _test_v2, _mem1, _test_v2); \
- tor_free(_mem1); \
- tor_free(_mem2); \
- goto done; \
- } \
- tor_free(_mem2); \
- STMT_END
-
-#define test_memneq(expr1, expr2, len) \
- STMT_BEGIN \
- void *_test_v1=(expr1), *_test_v2=(expr2); \
- if (memcmp(_test_v1,_test_v2,(len))) { \
- printf("."); fflush(stdout); \
- } else { \
- have_failed = 1; \
- printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n", \
- _SHORT_FILE_, \
- __LINE__, \
- PRETTY_FUNCTION, \
- #expr1, #expr2); \
- goto done; \
- } STMT_END
-
-#endif
-
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index 10bce33283..27d9c42efd 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -165,9 +165,7 @@ tor_gzip_compress(char **out, size_t *out_len,
deflateEnd(stream);
tor_free(stream);
}
- if (*out) {
- tor_free(*out);
- }
+ tor_free(*out);
return -1;
}
@@ -423,7 +421,8 @@ tor_zlib_process(tor_zlib_state_t *state,
void
tor_zlib_free(tor_zlib_state_t *state)
{
- tor_assert(state);
+ if (!state)
+ return;
if (state->compress)
deflateEnd(&state->stream);
diff --git a/src/common/torint.h b/src/common/torint.h
index d9722868d2..57f18212ad 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -117,11 +117,10 @@ typedef unsigned int uint32_t;
#ifndef INT32_MAX
#define INT32_MAX 0x7fffffffu
#endif
-#endif
-
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
+#endif
#if (SIZEOF_LONG == 4)
#ifndef HAVE_INT32_T
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 066b429601..b4984802fb 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -184,30 +184,51 @@ static int tls_library_is_initialized = 0;
#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
+#include "tortls_states.h"
+
+/** Return the symbolic name of an OpenSSL state. */
+static const char *
+ssl_state_to_string(int ssl_state)
+{
+ static char buf[40];
+ int i;
+ for (i = 0; state_map[i].name; ++i) {
+ if (state_map[i].state == ssl_state)
+ return state_map[i].name;
+ }
+ tor_snprintf(buf, sizeof(buf), "Unknown state %d", ssl_state);
+ return buf;
+}
+
/** Log all pending tls errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
*/
static void
-tls_log_errors(tor_tls_t *tls, int severity, const char *doing)
+tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
{
+ const char *state = NULL;
+ int st;
unsigned long err;
const char *msg, *lib, *func, *addr;
addr = tls ? tls->address : NULL;
+ st = (tls && tls->ssl) ? tls->ssl->state : -1;
while ((err = ERR_get_error()) != 0) {
msg = (const char*)ERR_reason_error_string(err);
lib = (const char*)ERR_lib_error_string(err);
func = (const char*)ERR_func_error_string(err);
+ if (!state)
+ state = (st>=0)?ssl_state_to_string(st):"---";
if (!msg) msg = "(null)";
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, LD_NET, "TLS error while %s%s%s: %s (in %s:%s)",
+ log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
doing, addr?" with ":"", addr?addr:"",
- msg, lib, func);
+ msg, lib, func, state);
} else {
- log(severity, LD_NET, "TLS error%s%s: %s (in %s:%s)",
+ log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
addr?" with ":"", addr?addr:"",
- msg, lib, func);
+ msg, lib, func, state);
}
}
}
@@ -283,7 +304,7 @@ tor_tls_err_to_string(int err)
*/
static int
tor_tls_get_error(tor_tls_t *tls, int r, int extra,
- const char *doing, int severity)
+ const char *doing, int severity, int domain)
{
int err = SSL_get_error(tls->ssl, r);
int tor_error = TOR_TLS_ERROR_MISC;
@@ -298,25 +319,28 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
if (extra&CATCH_SYSCALL)
return _TOR_TLS_SYSCALL;
if (r == 0) {
- log(severity, LD_NET, "TLS error: unexpected close while %s", doing);
+ log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
+ doing, ssl_state_to_string(tls->ssl->state));
tor_error = TOR_TLS_ERROR_IO;
} else {
int e = tor_socket_errno(tls->socket);
log(severity, LD_NET,
- "TLS error: <syscall error while %s> (errno=%d: %s)",
- doing, e, tor_socket_strerror(e));
+ "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
+ doing, e, tor_socket_strerror(e),
+ ssl_state_to_string(tls->ssl->state));
tor_error = tor_errno_to_tls_error(e);
}
- tls_log_errors(tls, severity, doing);
+ tls_log_errors(tls, severity, domain, doing);
return tor_error;
case SSL_ERROR_ZERO_RETURN:
if (extra&CATCH_ZERO)
return _TOR_TLS_ZERORETURN;
- log(severity, LD_NET, "TLS connection closed while %s", doing);
- tls_log_errors(tls, severity, doing);
+ log(severity, LD_NET, "TLS connection closed while %s in state %s",
+ doing, ssl_state_to_string(tls->ssl->state));
+ tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_CLOSE;
default:
- tls_log_errors(tls, severity, doing);
+ tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_ERROR_MISC;
}
}
@@ -330,11 +354,10 @@ tor_tls_init(void)
long version;
SSL_library_init();
SSL_load_error_strings();
- crypto_global_init(-1);
version = SSLeay();
- /* OpenSSL 0.9.8l introdeced SSL3_FLAGS_ALLOW_UNSAGE_LEGACY_RENEGOTIATION
+ /* OpenSSL 0.9.8l introduced SSL3_FLAGS_ALLOW_UNSAGE_LEGACY_RENEGOTIATION
* here, but without thinking too hard about it: it turns out that the
* flag in question needed to be set at the last minute, and that it
* conflicted with an existing flag number that had already been added
@@ -353,8 +376,8 @@ tor_tls_init(void)
* leave their headers out of sync with their libraries.
*
* Yes, it _is_ almost as if the OpenSSL developers decided that no
- * program should be allowed to use renegotiation its first passed an
- * test of intelligence and determination.
+ * program should be allowed to use renegotiation unless it first passed
+ * a test of intelligence and determination.
*/
if (version >= 0x009080c0L && version < 0x009080d0L) {
log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l; "
@@ -498,7 +521,7 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
x509 = NULL;
}
done:
- tls_log_errors(NULL, LOG_WARN, "generating certificate");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate");
if (sign_pkey)
EVP_PKEY_free(sign_pkey);
if (pkey)
@@ -693,7 +716,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
return 0;
error:
- tls_log_errors(NULL, LOG_WARN, "creating TLS context");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
tor_free(nickname);
tor_free(nn2);
if (pkey)
@@ -889,7 +912,7 @@ tor_tls_new(int sock, int isServer)
tor_assert(global_tls_context); /* make sure somebody made it first */
if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
- tls_log_errors(NULL, LOG_WARN, "generating TLS context");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "generating TLS context");
tor_free(result);
return NULL;
}
@@ -905,7 +928,7 @@ tor_tls_new(int sock, int isServer)
if (!SSL_set_cipher_list(result->ssl,
isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
- tls_log_errors(NULL, LOG_WARN, "setting ciphers");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers");
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
@@ -918,7 +941,7 @@ tor_tls_new(int sock, int isServer)
result->socket = sock;
bio = BIO_new_socket(sock, BIO_NOCLOSE);
if (! bio) {
- tls_log_errors(NULL, LOG_WARN, "opening BIO");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
@@ -946,7 +969,7 @@ tor_tls_new(int sock, int isServer)
#endif
/* Not expected to get called. */
- tls_log_errors(NULL, LOG_WARN, "generating TLS context");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "generating TLS context");
return result;
}
@@ -1025,7 +1048,9 @@ void
tor_tls_free(tor_tls_t *tls)
{
tor_tls_t *removed;
- tor_assert(tls && tls->ssl);
+ if (!tls)
+ return;
+ tor_assert(tls->ssl);
removed = HT_REMOVE(tlsmap, &tlsmap_root, tls);
if (!removed) {
log_warn(LD_BUG, "Freeing a TLS that was not in the ssl->tls map.");
@@ -1068,7 +1093,7 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
#endif
return r;
}
- err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG);
+ err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
@@ -1104,7 +1129,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
tls->wantwrite_n = 0;
}
r = SSL_write(tls->ssl, cp, (int)n);
- err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO);
+ err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
if (err == TOR_TLS_DONE) {
return r;
}
@@ -1122,21 +1147,30 @@ int
tor_tls_handshake(tor_tls_t *tls)
{
int r;
+ int oldstate;
tor_assert(tls);
tor_assert(tls->ssl);
tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
check_no_tls_errors();
+ oldstate = tls->ssl->state;
if (tls->isServer) {
+ log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
+ ssl_state_to_string(tls->ssl->state));
r = SSL_accept(tls->ssl);
} else {
+ log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
+ ssl_state_to_string(tls->ssl->state));
r = SSL_connect(tls->ssl);
}
+ if (oldstate != tls->ssl->state)
+ log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
+ tls, ssl_state_to_string(tls->ssl->state));
/* We need to call this here and not earlier, since OpenSSL has a penchant
* for clearing its flags when you say accept or connect. */
tor_tls_unblock_renegotiation(tls);
- r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO);
+ r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE);
if (ERR_peek_error() != 0) {
- tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN,
+ tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE,
"handshaking");
return TOR_TLS_ERROR_MISC;
}
@@ -1157,7 +1191,8 @@ tor_tls_handshake(tor_tls_t *tls)
" get set. Fixing that.");
}
tls->wasV2Handshake = 1;
- log_debug(LD_NET, "Completed V2 TLS handshake with client; waiting "
+ log_debug(LD_HANDSHAKE,
+ "Completed V2 TLS handshake with client; waiting "
"for renegotiation.");
} else {
tls->wasV2Handshake = 0;
@@ -1169,10 +1204,13 @@ tor_tls_handshake(tor_tls_t *tls)
X509 *cert = SSL_get_peer_certificate(tls->ssl);
STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl);
int n_certs = sk_X509_num(chain);
- if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0)))
+ if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) {
+ log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it "
+ "looks like a v1 handshake on %p", tls);
tls->wasV2Handshake = 0;
- else {
- log_debug(LD_NET, "Server sent back a single certificate; looks like "
+ } else {
+ log_debug(LD_HANDSHAKE,
+ "Server sent back a single certificate; looks like "
"a v2 handshake on %p.", tls);
tls->wasV2Handshake = 1;
}
@@ -1180,7 +1218,7 @@ tor_tls_handshake(tor_tls_t *tls)
X509_free(cert);
#endif
if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) {
- tls_log_errors(NULL, LOG_WARN, "re-setting ciphers");
+ tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers");
r = TOR_TLS_ERROR_MISC;
}
}
@@ -1203,7 +1241,8 @@ tor_tls_renegotiate(tor_tls_t *tls)
if (tls->state != TOR_TLS_ST_RENEGOTIATE) {
int r = SSL_renegotiate(tls->ssl);
if (r <= 0) {
- return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN);
+ return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN,
+ LD_HANDSHAKE);
}
tls->state = TOR_TLS_ST_RENEGOTIATE;
}
@@ -1212,7 +1251,8 @@ tor_tls_renegotiate(tor_tls_t *tls)
tls->state = TOR_TLS_ST_OPEN;
return TOR_TLS_DONE;
} else
- return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO);
+ return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO,
+ LD_HANDSHAKE);
}
/** Shut down an open tls connection <b>tls</b>. When finished, returns
@@ -1236,7 +1276,7 @@ tor_tls_shutdown(tor_tls_t *tls)
r = SSL_read(tls->ssl, buf, 128);
} while (r>0);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
- LOG_INFO);
+ LOG_INFO, LD_NET);
if (err == _TOR_TLS_ZERORETURN) {
tls->state = TOR_TLS_ST_GOTCLOSE;
/* fall through... */
@@ -1252,7 +1292,7 @@ tor_tls_shutdown(tor_tls_t *tls)
return TOR_TLS_DONE;
}
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
- LOG_INFO);
+ LOG_INFO, LD_NET);
if (err == _TOR_TLS_SYSCALL) {
/* The underlying TCP connection closed while we were shutting down. */
tls->state = TOR_TLS_ST_CLOSED;
@@ -1284,7 +1324,7 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
{
X509 *cert;
cert = SSL_get_peer_certificate(tls->ssl);
- tls_log_errors(tls, LOG_WARN, "getting peer certificate");
+ tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
if (!cert)
return 0;
X509_free(cert);
@@ -1311,7 +1351,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end;
}
if (!(ASN1_TIME_print(bio, X509_get_notBefore(cert)))) {
- tls_log_errors(NULL, LOG_WARN, "printing certificate lifetime");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
goto end;
}
BIO_get_mem_ptr(bio, &buf);
@@ -1319,7 +1359,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
(void)BIO_reset(bio);
if (!(ASN1_TIME_print(bio, X509_get_notAfter(cert)))) {
- tls_log_errors(NULL, LOG_WARN, "printing certificate lifetime");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
goto end;
}
BIO_get_mem_ptr(bio, &buf);
@@ -1333,13 +1373,11 @@ log_cert_lifetime(X509 *cert, const char *problem)
end:
/* Not expected to get invoked */
- tls_log_errors(NULL, LOG_WARN, "getting certificate lifetime");
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime");
if (bio)
BIO_free(bio);
- if (s1)
- tor_free(s1);
- if (s2)
- tor_free(s2);
+ tor_free(s1);
+ tor_free(s2);
}
/** Helper function: try to extract a link certificate and an identity
@@ -1407,7 +1445,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
if (!(id_pkey = X509_get_pubkey(id_cert)) ||
X509_verify(cert, id_pkey) <= 0) {
log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
- tls_log_errors(tls, severity,"verifying certificate");
+ tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
goto done;
}
@@ -1426,7 +1464,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
/* This should never get invoked, but let's make sure in case OpenSSL
* acts unexpectedly. */
- tls_log_errors(tls, LOG_WARN, "finishing tor_tls_verify");
+ tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");
return r;
}
@@ -1465,7 +1503,7 @@ tor_tls_check_lifetime(tor_tls_t *tls, int tolerance)
if (cert)
X509_free(cert);
/* Not expected to get invoked */
- tls_log_errors(tls, LOG_WARN, "checking certificate lifetime");
+ tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
return r;
}
@@ -1533,7 +1571,7 @@ _check_no_tls_errors(const char *fname, int line)
return;
log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
tor_fix_source_file(fname), line);
- tls_log_errors(NULL, LOG_WARN, NULL);
+ tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}
/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2
diff --git a/src/common/tortls_states.h b/src/common/tortls_states.h
new file mode 100644
index 0000000000..986b5a8a0d
--- /dev/null
+++ b/src/common/tortls_states.h
@@ -0,0 +1,414 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Helper file: included only in tortls.c */
+
+#ifndef _TORTLS_STATES_H
+#define _TORTLS_STATES_H
+
+/* The main body of this file was mechanically generated with this
+ perl script:
+
+ my %keys = ();
+ for $fn (@ARGV) {
+ open(F, $fn);
+ while (<F>) {
+ next unless /^#define ((?:SSL|DTLS)\w*_ST_\w*)/;
+ $keys{$1} = 1;
+ }
+ close(F);
+ }
+ for $k (sort keys %keys) {
+ print "#ifdef $k\n S($k),\n#endif\n"
+ }
+*/
+
+/** Mapping from allowed value of SSL.state to the name of C macro for that
+ * state. Used for debugging an openssl connection. */
+static const struct { int state; const char *name; } state_map[] = {
+#define S(state) { state, #state }
+#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A
+ S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A),
+#endif
+#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B
+ S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B),
+#endif
+#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A
+ S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A),
+#endif
+#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B
+ S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B),
+#endif
+#ifdef SSL23_ST_CR_SRVR_HELLO_A
+ S(SSL23_ST_CR_SRVR_HELLO_A),
+#endif
+#ifdef SSL23_ST_CR_SRVR_HELLO_B
+ S(SSL23_ST_CR_SRVR_HELLO_B),
+#endif
+#ifdef SSL23_ST_CW_CLNT_HELLO_A
+ S(SSL23_ST_CW_CLNT_HELLO_A),
+#endif
+#ifdef SSL23_ST_CW_CLNT_HELLO_B
+ S(SSL23_ST_CW_CLNT_HELLO_B),
+#endif
+#ifdef SSL23_ST_SR_CLNT_HELLO_A
+ S(SSL23_ST_SR_CLNT_HELLO_A),
+#endif
+#ifdef SSL23_ST_SR_CLNT_HELLO_B
+ S(SSL23_ST_SR_CLNT_HELLO_B),
+#endif
+#ifdef SSL2_ST_CLIENT_START_ENCRYPTION
+ S(SSL2_ST_CLIENT_START_ENCRYPTION),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_FINISHED_A
+ S(SSL2_ST_GET_CLIENT_FINISHED_A),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_FINISHED_B
+ S(SSL2_ST_GET_CLIENT_FINISHED_B),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_HELLO_A
+ S(SSL2_ST_GET_CLIENT_HELLO_A),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_HELLO_B
+ S(SSL2_ST_GET_CLIENT_HELLO_B),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_HELLO_C
+ S(SSL2_ST_GET_CLIENT_HELLO_C),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_A
+ S(SSL2_ST_GET_CLIENT_MASTER_KEY_A),
+#endif
+#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_B
+ S(SSL2_ST_GET_CLIENT_MASTER_KEY_B),
+#endif
+#ifdef SSL2_ST_GET_SERVER_FINISHED_A
+ S(SSL2_ST_GET_SERVER_FINISHED_A),
+#endif
+#ifdef SSL2_ST_GET_SERVER_FINISHED_B
+ S(SSL2_ST_GET_SERVER_FINISHED_B),
+#endif
+#ifdef SSL2_ST_GET_SERVER_HELLO_A
+ S(SSL2_ST_GET_SERVER_HELLO_A),
+#endif
+#ifdef SSL2_ST_GET_SERVER_HELLO_B
+ S(SSL2_ST_GET_SERVER_HELLO_B),
+#endif
+#ifdef SSL2_ST_GET_SERVER_VERIFY_A
+ S(SSL2_ST_GET_SERVER_VERIFY_A),
+#endif
+#ifdef SSL2_ST_GET_SERVER_VERIFY_B
+ S(SSL2_ST_GET_SERVER_VERIFY_B),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_A
+ S(SSL2_ST_SEND_CLIENT_CERTIFICATE_A),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_B
+ S(SSL2_ST_SEND_CLIENT_CERTIFICATE_B),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_C
+ S(SSL2_ST_SEND_CLIENT_CERTIFICATE_C),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_D
+ S(SSL2_ST_SEND_CLIENT_CERTIFICATE_D),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_FINISHED_A
+ S(SSL2_ST_SEND_CLIENT_FINISHED_A),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_FINISHED_B
+ S(SSL2_ST_SEND_CLIENT_FINISHED_B),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_HELLO_A
+ S(SSL2_ST_SEND_CLIENT_HELLO_A),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_HELLO_B
+ S(SSL2_ST_SEND_CLIENT_HELLO_B),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_A
+ S(SSL2_ST_SEND_CLIENT_MASTER_KEY_A),
+#endif
+#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_B
+ S(SSL2_ST_SEND_CLIENT_MASTER_KEY_B),
+#endif
+#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_A
+ S(SSL2_ST_SEND_REQUEST_CERTIFICATE_A),
+#endif
+#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_B
+ S(SSL2_ST_SEND_REQUEST_CERTIFICATE_B),
+#endif
+#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_C
+ S(SSL2_ST_SEND_REQUEST_CERTIFICATE_C),
+#endif
+#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_D
+ S(SSL2_ST_SEND_REQUEST_CERTIFICATE_D),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_FINISHED_A
+ S(SSL2_ST_SEND_SERVER_FINISHED_A),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_FINISHED_B
+ S(SSL2_ST_SEND_SERVER_FINISHED_B),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_HELLO_A
+ S(SSL2_ST_SEND_SERVER_HELLO_A),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_HELLO_B
+ S(SSL2_ST_SEND_SERVER_HELLO_B),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_VERIFY_A
+ S(SSL2_ST_SEND_SERVER_VERIFY_A),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_VERIFY_B
+ S(SSL2_ST_SEND_SERVER_VERIFY_B),
+#endif
+#ifdef SSL2_ST_SEND_SERVER_VERIFY_C
+ S(SSL2_ST_SEND_SERVER_VERIFY_C),
+#endif
+#ifdef SSL2_ST_SERVER_START_ENCRYPTION
+ S(SSL2_ST_SERVER_START_ENCRYPTION),
+#endif
+#ifdef SSL2_ST_X509_GET_CLIENT_CERTIFICATE
+ S(SSL2_ST_X509_GET_CLIENT_CERTIFICATE),
+#endif
+#ifdef SSL2_ST_X509_GET_SERVER_CERTIFICATE
+ S(SSL2_ST_X509_GET_SERVER_CERTIFICATE),
+#endif
+#ifdef SSL3_ST_CR_CERT_A
+ S(SSL3_ST_CR_CERT_A),
+#endif
+#ifdef SSL3_ST_CR_CERT_B
+ S(SSL3_ST_CR_CERT_B),
+#endif
+#ifdef SSL3_ST_CR_CERT_REQ_A
+ S(SSL3_ST_CR_CERT_REQ_A),
+#endif
+#ifdef SSL3_ST_CR_CERT_REQ_B
+ S(SSL3_ST_CR_CERT_REQ_B),
+#endif
+#ifdef SSL3_ST_CR_CERT_STATUS_A
+ S(SSL3_ST_CR_CERT_STATUS_A),
+#endif
+#ifdef SSL3_ST_CR_CERT_STATUS_B
+ S(SSL3_ST_CR_CERT_STATUS_B),
+#endif
+#ifdef SSL3_ST_CR_CHANGE_A
+ S(SSL3_ST_CR_CHANGE_A),
+#endif
+#ifdef SSL3_ST_CR_CHANGE_B
+ S(SSL3_ST_CR_CHANGE_B),
+#endif
+#ifdef SSL3_ST_CR_FINISHED_A
+ S(SSL3_ST_CR_FINISHED_A),
+#endif
+#ifdef SSL3_ST_CR_FINISHED_B
+ S(SSL3_ST_CR_FINISHED_B),
+#endif
+#ifdef SSL3_ST_CR_KEY_EXCH_A
+ S(SSL3_ST_CR_KEY_EXCH_A),
+#endif
+#ifdef SSL3_ST_CR_KEY_EXCH_B
+ S(SSL3_ST_CR_KEY_EXCH_B),
+#endif
+#ifdef SSL3_ST_CR_SESSION_TICKET_A
+ S(SSL3_ST_CR_SESSION_TICKET_A),
+#endif
+#ifdef SSL3_ST_CR_SESSION_TICKET_B
+ S(SSL3_ST_CR_SESSION_TICKET_B),
+#endif
+#ifdef SSL3_ST_CR_SRVR_DONE_A
+ S(SSL3_ST_CR_SRVR_DONE_A),
+#endif
+#ifdef SSL3_ST_CR_SRVR_DONE_B
+ S(SSL3_ST_CR_SRVR_DONE_B),
+#endif
+#ifdef SSL3_ST_CR_SRVR_HELLO_A
+ S(SSL3_ST_CR_SRVR_HELLO_A),
+#endif
+#ifdef SSL3_ST_CR_SRVR_HELLO_B
+ S(SSL3_ST_CR_SRVR_HELLO_B),
+#endif
+#ifdef SSL3_ST_CW_CERT_A
+ S(SSL3_ST_CW_CERT_A),
+#endif
+#ifdef SSL3_ST_CW_CERT_B
+ S(SSL3_ST_CW_CERT_B),
+#endif
+#ifdef SSL3_ST_CW_CERT_C
+ S(SSL3_ST_CW_CERT_C),
+#endif
+#ifdef SSL3_ST_CW_CERT_D
+ S(SSL3_ST_CW_CERT_D),
+#endif
+#ifdef SSL3_ST_CW_CERT_VRFY_A
+ S(SSL3_ST_CW_CERT_VRFY_A),
+#endif
+#ifdef SSL3_ST_CW_CERT_VRFY_B
+ S(SSL3_ST_CW_CERT_VRFY_B),
+#endif
+#ifdef SSL3_ST_CW_CHANGE_A
+ S(SSL3_ST_CW_CHANGE_A),
+#endif
+#ifdef SSL3_ST_CW_CHANGE_B
+ S(SSL3_ST_CW_CHANGE_B),
+#endif
+#ifdef SSL3_ST_CW_CLNT_HELLO_A
+ S(SSL3_ST_CW_CLNT_HELLO_A),
+#endif
+#ifdef SSL3_ST_CW_CLNT_HELLO_B
+ S(SSL3_ST_CW_CLNT_HELLO_B),
+#endif
+#ifdef SSL3_ST_CW_FINISHED_A
+ S(SSL3_ST_CW_FINISHED_A),
+#endif
+#ifdef SSL3_ST_CW_FINISHED_B
+ S(SSL3_ST_CW_FINISHED_B),
+#endif
+#ifdef SSL3_ST_CW_FLUSH
+ S(SSL3_ST_CW_FLUSH),
+#endif
+#ifdef SSL3_ST_CW_KEY_EXCH_A
+ S(SSL3_ST_CW_KEY_EXCH_A),
+#endif
+#ifdef SSL3_ST_CW_KEY_EXCH_B
+ S(SSL3_ST_CW_KEY_EXCH_B),
+#endif
+#ifdef SSL3_ST_SR_CERT_A
+ S(SSL3_ST_SR_CERT_A),
+#endif
+#ifdef SSL3_ST_SR_CERT_B
+ S(SSL3_ST_SR_CERT_B),
+#endif
+#ifdef SSL3_ST_SR_CERT_VRFY_A
+ S(SSL3_ST_SR_CERT_VRFY_A),
+#endif
+#ifdef SSL3_ST_SR_CERT_VRFY_B
+ S(SSL3_ST_SR_CERT_VRFY_B),
+#endif
+#ifdef SSL3_ST_SR_CHANGE_A
+ S(SSL3_ST_SR_CHANGE_A),
+#endif
+#ifdef SSL3_ST_SR_CHANGE_B
+ S(SSL3_ST_SR_CHANGE_B),
+#endif
+#ifdef SSL3_ST_SR_CLNT_HELLO_A
+ S(SSL3_ST_SR_CLNT_HELLO_A),
+#endif
+#ifdef SSL3_ST_SR_CLNT_HELLO_B
+ S(SSL3_ST_SR_CLNT_HELLO_B),
+#endif
+#ifdef SSL3_ST_SR_CLNT_HELLO_C
+ S(SSL3_ST_SR_CLNT_HELLO_C),
+#endif
+#ifdef SSL3_ST_SR_FINISHED_A
+ S(SSL3_ST_SR_FINISHED_A),
+#endif
+#ifdef SSL3_ST_SR_FINISHED_B
+ S(SSL3_ST_SR_FINISHED_B),
+#endif
+#ifdef SSL3_ST_SR_KEY_EXCH_A
+ S(SSL3_ST_SR_KEY_EXCH_A),
+#endif
+#ifdef SSL3_ST_SR_KEY_EXCH_B
+ S(SSL3_ST_SR_KEY_EXCH_B),
+#endif
+#ifdef SSL3_ST_SW_CERT_A
+ S(SSL3_ST_SW_CERT_A),
+#endif
+#ifdef SSL3_ST_SW_CERT_B
+ S(SSL3_ST_SW_CERT_B),
+#endif
+#ifdef SSL3_ST_SW_CERT_REQ_A
+ S(SSL3_ST_SW_CERT_REQ_A),
+#endif
+#ifdef SSL3_ST_SW_CERT_REQ_B
+ S(SSL3_ST_SW_CERT_REQ_B),
+#endif
+#ifdef SSL3_ST_SW_CERT_STATUS_A
+ S(SSL3_ST_SW_CERT_STATUS_A),
+#endif
+#ifdef SSL3_ST_SW_CERT_STATUS_B
+ S(SSL3_ST_SW_CERT_STATUS_B),
+#endif
+#ifdef SSL3_ST_SW_CHANGE_A
+ S(SSL3_ST_SW_CHANGE_A),
+#endif
+#ifdef SSL3_ST_SW_CHANGE_B
+ S(SSL3_ST_SW_CHANGE_B),
+#endif
+#ifdef SSL3_ST_SW_FINISHED_A
+ S(SSL3_ST_SW_FINISHED_A),
+#endif
+#ifdef SSL3_ST_SW_FINISHED_B
+ S(SSL3_ST_SW_FINISHED_B),
+#endif
+#ifdef SSL3_ST_SW_FLUSH
+ S(SSL3_ST_SW_FLUSH),
+#endif
+#ifdef SSL3_ST_SW_HELLO_REQ_A
+ S(SSL3_ST_SW_HELLO_REQ_A),
+#endif
+#ifdef SSL3_ST_SW_HELLO_REQ_B
+ S(SSL3_ST_SW_HELLO_REQ_B),
+#endif
+#ifdef SSL3_ST_SW_HELLO_REQ_C
+ S(SSL3_ST_SW_HELLO_REQ_C),
+#endif
+#ifdef SSL3_ST_SW_KEY_EXCH_A
+ S(SSL3_ST_SW_KEY_EXCH_A),
+#endif
+#ifdef SSL3_ST_SW_KEY_EXCH_B
+ S(SSL3_ST_SW_KEY_EXCH_B),
+#endif
+#ifdef SSL3_ST_SW_SESSION_TICKET_A
+ S(SSL3_ST_SW_SESSION_TICKET_A),
+#endif
+#ifdef SSL3_ST_SW_SESSION_TICKET_B
+ S(SSL3_ST_SW_SESSION_TICKET_B),
+#endif
+#ifdef SSL3_ST_SW_SRVR_DONE_A
+ S(SSL3_ST_SW_SRVR_DONE_A),
+#endif
+#ifdef SSL3_ST_SW_SRVR_DONE_B
+ S(SSL3_ST_SW_SRVR_DONE_B),
+#endif
+#ifdef SSL3_ST_SW_SRVR_HELLO_A
+ S(SSL3_ST_SW_SRVR_HELLO_A),
+#endif
+#ifdef SSL3_ST_SW_SRVR_HELLO_B
+ S(SSL3_ST_SW_SRVR_HELLO_B),
+#endif
+#ifdef SSL_ST_ACCEPT
+ S(SSL_ST_ACCEPT),
+#endif
+#ifdef SSL_ST_BEFORE
+ S(SSL_ST_BEFORE),
+#endif
+#ifdef SSL_ST_CONNECT
+ S(SSL_ST_CONNECT),
+#endif
+#ifdef SSL_ST_INIT
+ S(SSL_ST_INIT),
+#endif
+#ifdef SSL_ST_MASK
+ S(SSL_ST_MASK),
+#endif
+#ifdef SSL_ST_OK
+ S(SSL_ST_OK),
+#endif
+#ifdef SSL_ST_READ_BODY
+ S(SSL_ST_READ_BODY),
+#endif
+#ifdef SSL_ST_READ_DONE
+ S(SSL_ST_READ_DONE),
+#endif
+#ifdef SSL_ST_READ_HEADER
+ S(SSL_ST_READ_HEADER),
+#endif
+#ifdef SSL_ST_RENEGOTIATE
+ S(SSL_ST_RENEGOTIATE),
+#endif
+ { 0, NULL }
+};
+
+#endif
+
diff --git a/src/common/util.c b/src/common/util.c
index 34bb9cc376..1c0db392d0 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -16,6 +16,7 @@
#include "orconfig.h"
#include "util.h"
#include "log.h"
+#undef log
#include "crypto.h"
#include "torint.h"
#include "container.h"
@@ -30,6 +31,11 @@
#include <pwd.h>
#endif
+/* math.h needs this on Linux */
+#ifndef __USE_ISOC99
+#define __USE_ISOC99 1
+#endif
+#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -278,7 +284,7 @@ tor_log_mallinfo(int severity)
struct mallinfo mi;
memset(&mi, 0, sizeof(mi));
mi = mallinfo();
- log(severity, LD_MM,
+ tor_log(severity, LD_MM,
"mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, "
"hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, "
"keepcost=%d",
@@ -301,6 +307,25 @@ tor_log_mallinfo(int severity)
* Math
* ===== */
+/**
+ * Returns the natural logarithm of d base 2. We define this wrapper here so
+ * as to make it easier not to conflict with Tor's log() macro.
+ */
+double
+tor_mathlog(double d)
+{
+ return log(d);
+}
+
+/** Return the long integer closest to d. We define this wrapper here so
+ * that not all users of math.h need to use the right incancations to get
+ * the c99 functions. */
+long
+tor_lround(double d)
+{
+ return lround(d);
+}
+
/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */
int
tor_log2(uint64_t u64)
@@ -345,6 +370,36 @@ round_to_power_of_2(uint64_t u64)
return low;
}
+/** Return the lowest x such that x is at least <b>number</b>, and x modulo
+ * <b>divisor</b> == 0. */
+unsigned
+round_to_next_multiple_of(unsigned number, unsigned divisor)
+{
+ number += divisor - 1;
+ number -= number % divisor;
+ return number;
+}
+
+/** Return the lowest x such that x is at least <b>number</b>, and x modulo
+ * <b>divisor</b> == 0. */
+uint32_t
+round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor)
+{
+ number += divisor - 1;
+ number -= number % divisor;
+ return number;
+}
+
+/** Return the lowest x such that x is at least <b>number</b>, and x modulo
+ * <b>divisor</b> == 0. */
+uint64_t
+round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
+{
+ number += divisor - 1;
+ number -= number % divisor;
+ return number;
+}
+
/* =====
* String manipulation
* ===== */
@@ -627,6 +682,29 @@ find_whitespace_eos(const char *s, const char *eos)
return s;
}
+/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that
+ * occurs at the start of a line (that is, at the beginning of <b>haystack</b>
+ * or immediately after a newline). Return NULL if no such string is found.
+ */
+const char *
+find_str_at_start_of_line(const char *haystack, const char *needle)
+{
+ size_t needle_len = strlen(needle);
+
+ do {
+ if (!strncmp(haystack, needle, needle_len))
+ return haystack;
+
+ haystack = strchr(haystack, '\n');
+ if (!haystack)
+ return NULL;
+ else
+ ++haystack;
+ } while (*haystack);
+
+ return NULL;
+}
+
/** Return true iff the 'len' bytes at 'mem' are all zero. */
int
tor_mem_is_zero(const char *mem, size_t len)
@@ -654,6 +732,13 @@ tor_digest_is_zero(const char *digest)
return tor_mem_is_zero(digest, DIGEST_LEN);
}
+/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
+int
+tor_digest256_is_zero(const char *digest)
+{
+ return tor_mem_is_zero(digest, DIGEST256_LEN);
+}
+
/* Helper: common code to check whether the result of a strtol or strtoul or
* strtoll is correct. */
#define CHECK_STRTOX_RESULT() \
@@ -705,7 +790,18 @@ tor_parse_ulong(const char *s, int base, unsigned long min,
CHECK_STRTOX_RESULT();
}
-/** As tor_parse_log, but return a unit64_t. Only base 10 is guaranteed to
+/** As tor_parse_long(), but return a double. */
+double
+tor_parse_double(const char *s, double min, double max, int *ok, char **next)
+{
+ char *endptr;
+ double r;
+
+ r = strtod(s, &endptr);
+ CHECK_STRTOX_RESULT();
+}
+
+/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to
* work for now. */
uint64_t
tor_parse_uint64(const char *s, int base, uint64_t min,
@@ -905,8 +1001,7 @@ const char *
escaped(const char *s)
{
static char *_escaped_val = NULL;
- if (_escaped_val)
- tor_free(_escaped_val);
+ tor_free(_escaped_val);
if (s)
_escaped_val = esc_for_log(s);
@@ -993,6 +1088,42 @@ wrap_string(smartlist_t *out, const char *string, size_t width,
* Time
* ===== */
+/**
+ * Converts struct timeval to a double value.
+ * Preserves microsecond precision, but just barely.
+ * Error is approx +/- 0.1 usec when dealing with epoch values.
+ */
+double
+tv_to_double(const struct timeval *tv)
+{
+ double conv = tv->tv_sec;
+ conv += tv->tv_usec/1000000.0;
+ return conv;
+}
+
+/**
+ * Converts timeval to milliseconds.
+ */
+int64_t
+tv_to_msec(const struct timeval *tv)
+{
+ int64_t conv = ((int64_t)tv->tv_sec)*1000L;
+ /* Round ghetto-style */
+ conv += ((int64_t)tv->tv_usec+500)/1000L;
+ return conv;
+}
+
+/**
+ * Converts timeval to microseconds.
+ */
+int64_t
+tv_to_usec(const struct timeval *tv)
+{
+ int64_t conv = ((int64_t)tv->tv_sec)*1000000L;
+ conv += tv->tv_usec;
+ return conv;
+}
+
/** Return the number of microseconds elapsed between *start and *end.
*/
long
@@ -1002,7 +1133,8 @@ tv_udiff(const struct timeval *start, const struct timeval *end)
long secdiff = end->tv_sec - start->tv_sec;
if (labs(secdiff+1) > LONG_MAX/1000000) {
- log_warn(LD_GENERAL, "comparing times too far apart.");
+ log_warn(LD_GENERAL, "comparing times on microsecond detail too far "
+ "apart: %ld seconds", secdiff);
return LONG_MAX;
}
@@ -1010,6 +1142,26 @@ tv_udiff(const struct timeval *start, const struct timeval *end)
return udiff;
}
+/** Return the number of milliseconds elapsed between *start and *end.
+ */
+long
+tv_mdiff(const struct timeval *start, const struct timeval *end)
+{
+ long mdiff;
+ long secdiff = end->tv_sec - start->tv_sec;
+
+ if (labs(secdiff+1) > LONG_MAX/1000) {
+ log_warn(LD_GENERAL, "comparing times on millisecond detail too far "
+ "apart: %ld seconds", secdiff);
+ return LONG_MAX;
+ }
+
+ /* Subtract and round */
+ mdiff = secdiff*1000L +
+ ((long)end->tv_usec - (long)start->tv_usec + 500L) / 1000L;
+ return mdiff;
+}
+
/** Yield true iff <b>y</b> is a leap-year. */
#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */
@@ -1085,7 +1237,7 @@ format_rfc1123_time(char *buf, time_t t)
memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
}
-/** Parse the the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
+/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
* and store the result in *<b>t</b>.
*
* Return 0 on success, -1 on failure.
@@ -1546,12 +1698,12 @@ check_private_dir(const char *dirname, cpd_check_t check)
tor_free(f);
if (r) {
if (errno != ENOENT) {
- log(LOG_WARN, LD_FS, "Directory %s cannot be read: %s", dirname,
- strerror(errno));
+ log_warn(LD_FS, "Directory %s cannot be read: %s", dirname,
+ strerror(errno));
return -1;
}
if (check == CPD_NONE) {
- log(LOG_WARN, LD_FS, "Directory %s does not exist.", dirname);
+ log_warn(LD_FS, "Directory %s does not exist.", dirname);
return -1;
} else if (check == CPD_CREATE) {
log_info(LD_GENERAL, "Creating directory %s", dirname);
@@ -1561,7 +1713,7 @@ check_private_dir(const char *dirname, cpd_check_t check)
r = mkdir(dirname, 0700);
#endif
if (r) {
- log(LOG_WARN, LD_FS, "Error creating directory %s: %s", dirname,
+ log_warn(LD_FS, "Error creating directory %s: %s", dirname,
strerror(errno));
return -1;
}
@@ -1571,7 +1723,7 @@ check_private_dir(const char *dirname, cpd_check_t check)
return 0;
}
if (!(st.st_mode & S_IFDIR)) {
- log(LOG_WARN, LD_FS, "%s is not a directory", dirname);
+ log_warn(LD_FS, "%s is not a directory", dirname);
return -1;
}
#ifndef MS_WINDOWS
@@ -1584,7 +1736,7 @@ check_private_dir(const char *dirname, cpd_check_t check)
pw = getpwuid(st.st_uid);
- log(LOG_WARN, LD_FS, "%s is not owned by this user (%s, %d) but by "
+ log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by "
"%s (%d). Perhaps you are running Tor as the wrong user?",
dirname, process_ownername, (int)getuid(),
pw ? pw->pw_name : "<unknown>", (int)st.st_uid);
@@ -1593,9 +1745,9 @@ check_private_dir(const char *dirname, cpd_check_t check)
return -1;
}
if (st.st_mode & 0077) {
- log(LOG_WARN, LD_FS, "Fixing permissions on directory %s", dirname);
+ log_warn(LD_FS, "Fixing permissions on directory %s", dirname);
if (chmod(dirname, 0700)) {
- log(LOG_WARN, LD_FS, "Could not chmod directory %s: %s", dirname,
+ log_warn(LD_FS, "Could not chmod directory %s: %s", dirname,
strerror(errno));
return -1;
} else {
@@ -1626,12 +1778,13 @@ write_str_to_file(const char *fname, const char *str, int bin)
}
/** Represents a file that we're writing to, with support for atomic commit:
- * we can write into a a temporary file, and either remove the file on
+ * we can write into a temporary file, and either remove the file on
* failure, or replace the original file on success. */
struct open_file_t {
char *tempname; /**< Name of the temporary file. */
char *filename; /**< Name of the original file. */
- int rename_on_close; /**< Are we using the temporary file or not? */
+ unsigned rename_on_close:1; /**< Are we using the temporary file or not? */
+ unsigned binary:1; /**< Did we open in binary mode? */
int fd; /**< fd for the open file. */
FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */
};
@@ -1679,7 +1832,7 @@ start_writing_to_file(const char *fname, int open_flags, int mode,
} else {
open_name = new_file->tempname = tor_malloc(tempname_len);
if (tor_snprintf(new_file->tempname, tempname_len, "%s.tmp", fname)<0) {
- log(LOG_WARN, LD_GENERAL, "Failed to generate filename");
+ log_warn(LD_GENERAL, "Failed to generate filename");
goto err;
}
/* We always replace an existing temporary file if there is one. */
@@ -1687,9 +1840,11 @@ start_writing_to_file(const char *fname, int open_flags, int mode,
open_flags &= ~O_EXCL;
new_file->rename_on_close = 1;
}
+ if (open_flags & O_BINARY)
+ new_file->binary = 1;
if ((new_file->fd = open(open_name, open_flags, mode)) < 0) {
- log(LOG_WARN, LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
+ log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
open_name, fname, strerror(errno));
goto err;
}
@@ -1725,7 +1880,8 @@ fdopen_file(open_file_t *file_data)
if (file_data->stdio_file)
return file_data->stdio_file;
tor_assert(file_data->fd >= 0);
- if (!(file_data->stdio_file = fdopen(file_data->fd, "a"))) {
+ if (!(file_data->stdio_file = fdopen(file_data->fd,
+ file_data->binary?"ab":"a"))) {
log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename,
file_data->fd, strerror(errno));
}
@@ -1825,7 +1981,7 @@ write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks,
{
result = write_all(fd, chunk->bytes, chunk->len, 0);
if (result < 0) {
- log(LOG_WARN, LD_FS, "Error writing to \"%s\": %s", fname,
+ log_warn(LD_FS, "Error writing to \"%s\": %s", fname,
strerror(errno));
goto err;
}
@@ -2156,6 +2312,9 @@ char *
expand_filename(const char *filename)
{
tor_assert(filename);
+#ifdef MS_WINDOWS
+ return tor_strdup(filename);
+#else
if (*filename == '~') {
size_t len;
char *home, *result;
@@ -2205,11 +2364,13 @@ expand_filename(const char *filename)
} else {
return tor_strdup(filename);
}
+#endif
}
#define MAX_SCANF_WIDTH 9999
-/** DOCDOC */
+/** Helper: given an ASCII-encoded decimal digit, return its numeric value.
+ * NOTE: requires that its input be in-bounds. */
static int
digit_to_num(char d)
{
@@ -2218,7 +2379,10 @@ digit_to_num(char d)
return num;
}
-/** DOCDOC */
+/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b>
+ * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
+ * success, store the result in <b>out</b>, advance bufp to the next
+ * character, and return 0. On failure, return -1. */
static int
scan_unsigned(const char **bufp, unsigned *out, int width)
{
@@ -2245,7 +2409,9 @@ scan_unsigned(const char **bufp, unsigned *out, int width)
return 0;
}
-/** DOCDOC */
+/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
+ * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
+ * to the next non-space character or the EOS. */
static int
scan_string(const char **bufp, char *out, int width)
{
@@ -2334,7 +2500,12 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
* and store the results in the corresponding argument fields. Differs from
* sscanf in that it: Only handles %u and %Ns. Does not handle arbitrarily
* long widths. %u does not consume any space. Is locale-independent.
- * Returns -1 on malformed patterns. */
+ * Returns -1 on malformed patterns.
+ *
+ * (As with other locale-independent functions, we need this to parse data that
+ * is in ASCII without worrying that the C library's locale-handling will make
+ * miscellaneous characters look like numbers, spaces, and so on.)
+ */
int
tor_sscanf(const char *buf, const char *pattern, ...)
{
diff --git a/src/common/util.h b/src/common/util.h
index fa66d7cf40..ba38f4c7ed 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -43,7 +43,7 @@
* stderr. */
#define tor_assert(expr) STMT_BEGIN \
if (PREDICT_UNLIKELY(!(expr))) { \
- log(LOG_ERR, LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
+ log_err(LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
_SHORT_FILE_, __LINE__, __func__, #expr); \
fprintf(stderr,"%s:%d %s: Assertion %s failed; aborting.\n", \
_SHORT_FILE_, __LINE__, __func__, #expr); \
@@ -152,8 +152,13 @@ void tor_log_mallinfo(int severity);
#define bool_neq(a,b) (!(a)!=!(b))
/* Math functions */
+double tor_mathlog(double d) ATTR_CONST;
+long tor_lround(double d) ATTR_CONST;
int tor_log2(uint64_t u64) ATTR_CONST;
uint64_t round_to_power_of_2(uint64_t u64);
+unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
+uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
+uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
/* String manipulation */
@@ -179,6 +184,8 @@ long tor_parse_long(const char *s, int base, long min,
long max, int *ok, char **next);
unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
unsigned long max, int *ok, char **next);
+double tor_parse_double(const char *s, double min, double max, int *ok,
+ char **next);
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
uint64_t max, int *ok, char **next);
const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1));
@@ -188,8 +195,11 @@ const char *eat_whitespace_no_nl(const char *s) ATTR_PURE;
const char *eat_whitespace_eos_no_nl(const char *s, const char *eos) ATTR_PURE;
const char *find_whitespace(const char *s) ATTR_PURE;
const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
+const char *find_str_at_start_of_line(const char *haystack, const char *needle)
+ ATTR_PURE;
int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE;
int tor_digest_is_zero(const char *digest) ATTR_PURE;
+int tor_digest256_is_zero(const char *digest) ATTR_PURE;
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
struct smartlist_t;
@@ -207,7 +217,11 @@ void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
/* Time helpers */
+double tv_to_double(const struct timeval *tv);
+int64_t tv_to_msec(const struct timeval *tv);
+int64_t tv_to_usec(const struct timeval *tv);
long tv_udiff(const struct timeval *start, const struct timeval *end);
+long tv_mdiff(const struct timeval *start, const struct timeval *end);
time_t tor_timegm(struct tm *tm);
#define RFC1123_TIME_LEN 29
void format_rfc1123_time(char *buf, time_t t);
@@ -294,5 +308,7 @@ void start_daemon(void);
void finish_daemon(const char *desired_cwd);
void write_pidfile(char *filename);
+const char *libor_get_digests(void);
+
#endif
diff --git a/src/common/util_codedigest.c b/src/common/util_codedigest.c
new file mode 100644
index 0000000000..88fe508b92
--- /dev/null
+++ b/src/common/util_codedigest.c
@@ -0,0 +1,11 @@
+
+#include "util.h"
+
+const char *
+libor_get_digests(void)
+{
+ return ""
+#include "common_sha1.i"
+ ;
+}
+