summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/arch/bytes.h6
-rw-r--r--src/lib/arch/include.am1
-rw-r--r--src/lib/buf/include.am2
-rw-r--r--src/lib/cc/compat_compiler.h14
-rw-r--r--src/lib/cc/ctassert.h6
-rw-r--r--src/lib/cc/include.am1
-rw-r--r--src/lib/cc/torint.h17
-rw-r--r--src/lib/compress/compress_zstd.c16
-rw-r--r--src/lib/compress/include.am2
-rw-r--r--src/lib/container/bitarray.h2
-rw-r--r--src/lib/container/include.am5
-rw-r--r--src/lib/container/map.h2
-rw-r--r--src/lib/container/namemap.c184
-rw-r--r--src/lib/container/namemap.h35
-rw-r--r--src/lib/container/namemap_st.h34
-rw-r--r--src/lib/container/order.h2
-rw-r--r--src/lib/container/smartlist.h2
-rw-r--r--src/lib/crypt_ops/crypto_cipher.h2
-rw-r--r--src/lib/crypt_ops/crypto_curve25519.h4
-rw-r--r--src/lib/crypt_ops/crypto_dh_openssl.c8
-rw-r--r--src/lib/crypt_ops/crypto_digest.c705
-rw-r--r--src/lib/crypt_ops/crypto_digest.h2
-rw-r--r--src/lib/crypt_ops/crypto_digest_nss.c560
-rw-r--r--src/lib/crypt_ops/crypto_digest_openssl.c522
-rw-r--r--src/lib/crypt_ops/crypto_ed25519.c2
-rw-r--r--src/lib/crypt_ops/crypto_format.c90
-rw-r--r--src/lib/crypt_ops/crypto_format.h12
-rw-r--r--src/lib/crypt_ops/crypto_hkdf.c10
-rw-r--r--src/lib/crypt_ops/crypto_init.c15
-rw-r--r--src/lib/crypt_ops/crypto_init.h2
-rw-r--r--src/lib/crypt_ops/crypto_nss_mgt.h4
-rw-r--r--src/lib/crypt_ops/crypto_ope.c4
-rw-r--r--src/lib/crypt_ops/crypto_ope.h4
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.c8
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.h2
-rw-r--r--src/lib/crypt_ops/crypto_rand.c15
-rw-r--r--src/lib/crypt_ops/crypto_rand.h27
-rw-r--r--src/lib/crypt_ops/crypto_rand_fast.c220
-rw-r--r--src/lib/crypt_ops/crypto_rand_numeric.c30
-rw-r--r--src/lib/crypt_ops/crypto_rsa.c2
-rw-r--r--src/lib/crypt_ops/crypto_rsa.h8
-rw-r--r--src/lib/crypt_ops/crypto_rsa_nss.c2
-rw-r--r--src/lib/crypt_ops/crypto_s2k.c4
-rw-r--r--src/lib/crypt_ops/crypto_util.c2
-rw-r--r--src/lib/crypt_ops/digestset.h2
-rw-r--r--src/lib/crypt_ops/include.am4
-rw-r--r--src/lib/ctime/include.am2
-rw-r--r--src/lib/defs/dh_sizes.h2
-rw-r--r--src/lib/defs/digest_sizes.h2
-rw-r--r--src/lib/defs/include.am2
-rw-r--r--src/lib/defs/logging_types.h23
-rw-r--r--src/lib/defs/time.h2
-rw-r--r--src/lib/defs/x25519_sizes.h2
-rw-r--r--src/lib/dispatch/.may_include11
-rw-r--r--src/lib/dispatch/dispatch.h114
-rw-r--r--src/lib/dispatch/dispatch_cfg.c141
-rw-r--r--src/lib/dispatch/dispatch_cfg.h45
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h25
-rw-r--r--src/lib/dispatch/dispatch_core.c260
-rw-r--r--src/lib/dispatch/dispatch_naming.c63
-rw-r--r--src/lib/dispatch/dispatch_naming.h46
-rw-r--r--src/lib/dispatch/dispatch_new.c176
-rw-r--r--src/lib/dispatch/dispatch_st.h108
-rw-r--r--src/lib/dispatch/include.am27
-rw-r--r--src/lib/dispatch/msgtypes.h80
-rw-r--r--src/lib/encoding/binascii.c10
-rw-r--r--src/lib/encoding/binascii.h2
-rw-r--r--src/lib/encoding/confline.c13
-rw-r--r--src/lib/encoding/confline.h2
-rw-r--r--src/lib/encoding/include.am4
-rw-r--r--src/lib/encoding/keyval.h2
-rw-r--r--src/lib/encoding/kvline.c72
-rw-r--r--src/lib/encoding/kvline.h2
-rw-r--r--src/lib/encoding/pem.h2
-rw-r--r--src/lib/encoding/qstring.c90
-rw-r--r--src/lib/encoding/qstring.h18
-rw-r--r--src/lib/encoding/time_fmt.h2
-rw-r--r--src/lib/err/.may_include3
-rw-r--r--src/lib/err/backtrace.c32
-rw-r--r--src/lib/err/backtrace.h7
-rw-r--r--src/lib/err/include.am2
-rw-r--r--src/lib/err/torerr.c64
-rw-r--r--src/lib/err/torerr.h9
-rw-r--r--src/lib/err/torerr_sys.c5
-rw-r--r--src/lib/evloop/include.am3
-rw-r--r--src/lib/evloop/token_bucket.h4
-rw-r--r--src/lib/evloop/workqueue.c10
-rw-r--r--src/lib/fdio/include.am2
-rw-r--r--src/lib/fs/conffile.h2
-rw-r--r--src/lib/fs/dir.h2
-rw-r--r--src/lib/fs/files.h14
-rw-r--r--src/lib/fs/include.am2
-rw-r--r--src/lib/fs/lockfile.h2
-rw-r--r--src/lib/fs/mmap.c2
-rw-r--r--src/lib/fs/mmap.h2
-rw-r--r--src/lib/fs/path.h2
-rw-r--r--src/lib/fs/userdb.h4
-rw-r--r--src/lib/fs/winlib.h4
-rw-r--r--src/lib/geoip/country.h2
-rw-r--r--src/lib/geoip/include.am2
-rw-r--r--src/lib/intmath/addsub.h2
-rw-r--r--src/lib/intmath/include.am2
-rw-r--r--src/lib/intmath/logic.h2
-rw-r--r--src/lib/intmath/weakrng.h2
-rw-r--r--src/lib/lock/compat_mutex.c10
-rw-r--r--src/lib/lock/compat_mutex.h2
-rw-r--r--src/lib/lock/compat_mutex_pthreads.c16
-rw-r--r--src/lib/lock/include.am2
-rw-r--r--src/lib/log/.may_include1
-rw-r--r--src/lib/log/escape.h2
-rw-r--r--src/lib/log/include.am2
-rw-r--r--src/lib/log/log.c106
-rw-r--r--src/lib/log/log.h112
-rw-r--r--src/lib/log/ratelim.h2
-rw-r--r--src/lib/log/util_bug.c72
-rw-r--r--src/lib/log/util_bug.h55
-rw-r--r--src/lib/log/win32err.h2
-rw-r--r--src/lib/malloc/include.am2
-rw-r--r--src/lib/malloc/malloc.h4
-rw-r--r--src/lib/malloc/map_anon.c78
-rw-r--r--src/lib/malloc/map_anon.h36
-rw-r--r--src/lib/math/fp.h2
-rw-r--r--src/lib/math/include.am3
-rw-r--r--src/lib/math/laplace.h2
-rw-r--r--src/lib/math/prob_distr.c165
-rw-r--r--src/lib/math/prob_distr.h101
-rw-r--r--src/lib/memarea/include.am2
-rw-r--r--src/lib/meminfo/include.am2
-rw-r--r--src/lib/meminfo/meminfo.h2
-rw-r--r--src/lib/net/address.c10
-rw-r--r--src/lib/net/alertsock.h2
-rw-r--r--src/lib/net/buffers_net.h2
-rw-r--r--src/lib/net/gethostname.h2
-rw-r--r--src/lib/net/inaddr.h2
-rw-r--r--src/lib/net/inaddr_st.h2
-rw-r--r--src/lib/net/include.am2
-rw-r--r--src/lib/net/nettypes.h2
-rw-r--r--src/lib/net/resolve.c4
-rw-r--r--src/lib/net/resolve.h2
-rw-r--r--src/lib/net/socket.c8
-rw-r--r--src/lib/net/socket.h2
-rw-r--r--src/lib/net/socketpair.c4
-rw-r--r--src/lib/net/socketpair.h2
-rw-r--r--src/lib/net/socks5_status.h2
-rw-r--r--src/lib/osinfo/include.am2
-rw-r--r--src/lib/osinfo/uname.h2
-rw-r--r--src/lib/process/daemon.h2
-rw-r--r--src/lib/process/env.h2
-rw-r--r--src/lib/process/include.am2
-rw-r--r--src/lib/process/pidfile.h2
-rw-r--r--src/lib/process/process.c10
-rw-r--r--src/lib/process/process.h6
-rw-r--r--src/lib/process/process_unix.c2
-rw-r--r--src/lib/process/process_unix.h6
-rw-r--r--src/lib/process/process_win32.c4
-rw-r--r--src/lib/process/process_win32.h6
-rw-r--r--src/lib/process/setuid.h2
-rw-r--r--src/lib/process/winprocess_sys.c2
-rw-r--r--src/lib/pubsub/.may_include10
-rw-r--r--src/lib/pubsub/include.am28
-rw-r--r--src/lib/pubsub/pub_binding_st.h38
-rw-r--r--src/lib/pubsub/pubsub.h89
-rw-r--r--src/lib/pubsub/pubsub_build.c307
-rw-r--r--src/lib/pubsub/pubsub_build.h92
-rw-r--r--src/lib/pubsub/pubsub_builder_st.h161
-rw-r--r--src/lib/pubsub/pubsub_check.c428
-rw-r--r--src/lib/pubsub/pubsub_connect.h54
-rw-r--r--src/lib/pubsub/pubsub_flags.h32
-rw-r--r--src/lib/pubsub/pubsub_macros.h373
-rw-r--r--src/lib/pubsub/pubsub_publish.c72
-rw-r--r--src/lib/pubsub/pubsub_publish.h15
-rw-r--r--src/lib/sandbox/include.am2
-rw-r--r--src/lib/sandbox/sandbox.c2
-rw-r--r--src/lib/smartlist_core/include.am2
-rw-r--r--src/lib/smartlist_core/smartlist_core.c26
-rw-r--r--src/lib/smartlist_core/smartlist_core.h3
-rw-r--r--src/lib/smartlist_core/smartlist_split.h2
-rw-r--r--src/lib/string/compat_string.h8
-rw-r--r--src/lib/string/include.am2
-rw-r--r--src/lib/string/parse_int.h2
-rw-r--r--src/lib/string/printf.c8
-rw-r--r--src/lib/string/printf.h2
-rw-r--r--src/lib/string/scanf.h2
-rw-r--r--src/lib/string/util_string.c9
-rw-r--r--src/lib/string/util_string.h5
-rw-r--r--src/lib/subsys/include.am1
-rw-r--r--src/lib/subsys/subsys.h6
-rw-r--r--src/lib/term/getpass.h2
-rw-r--r--src/lib/term/include.am2
-rw-r--r--src/lib/testsupport/include.am1
-rw-r--r--src/lib/testsupport/testsupport.h2
-rw-r--r--src/lib/thread/compat_threads.c10
-rw-r--r--src/lib/thread/include.am2
-rw-r--r--src/lib/thread/numcpus.h2
-rw-r--r--src/lib/thread/threads.h12
-rw-r--r--src/lib/time/compat_time.c20
-rw-r--r--src/lib/time/compat_time.h52
-rw-r--r--src/lib/time/include.am2
-rw-r--r--src/lib/time/tvdiff.h2
-rw-r--r--src/lib/tls/include.am2
-rw-r--r--src/lib/tls/nss_countbytes.h2
-rw-r--r--src/lib/tls/tortls.h10
-rw-r--r--src/lib/tls/tortls_internal.h6
-rw-r--r--src/lib/tls/tortls_openssl.c14
-rw-r--r--src/lib/tls/tortls_st.h4
-rw-r--r--src/lib/tls/x509.h6
-rw-r--r--src/lib/tls/x509_internal.h2
-rw-r--r--src/lib/tls/x509_nss.c8
-rw-r--r--src/lib/tls/x509_openssl.c4
-rw-r--r--src/lib/trace/debug.h2
-rw-r--r--src/lib/trace/events.h6
-rw-r--r--src/lib/trace/include.am3
-rw-r--r--src/lib/trace/trace.h2
-rw-r--r--src/lib/version/include.am2
-rw-r--r--src/lib/wallclock/approx_time.h2
-rw-r--r--src/lib/wallclock/include.am2
-rw-r--r--src/lib/wallclock/time_to_tm.h2
-rw-r--r--src/lib/wallclock/timeval.h23
-rw-r--r--src/lib/wallclock/tor_gettimeofday.h2
219 files changed, 5826 insertions, 1191 deletions
diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h
index fa82241b28..b8b6288139 100644
--- a/src/lib/arch/bytes.h
+++ b/src/lib/arch/bytes.h
@@ -129,7 +129,7 @@ tor_ntohll(uint64_t a)
{
return a;
}
-#else
+#else /* !(defined(WORDS_BIGENDIAN)) */
static inline uint16_t
tor_htons(uint16_t a)
{
@@ -177,6 +177,6 @@ tor_ntohll(uint64_t a)
{
return tor_htonll(a);
}
-#endif
+#endif /* defined(WORDS_BIGENDIAN) */
-#endif
+#endif /* !defined(TOR_BYTES_H) */
diff --git a/src/lib/arch/include.am b/src/lib/arch/include.am
index f92ee9222f..c5926c6330 100644
--- a/src/lib/arch/include.am
+++ b/src/lib/arch/include.am
@@ -1,3 +1,4 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/arch/bytes.h
diff --git a/src/lib/buf/include.am b/src/lib/buf/include.am
index 3338c3dbdb..27430d1d38 100644
--- a/src/lib/buf/include.am
+++ b/src/lib/buf/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-buf-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_buf_a_SOURCES = \
src/lib/buf/buffers.c
@@ -13,5 +14,6 @@ src_lib_libtor_buf_testing_a_SOURCES = \
src_lib_libtor_buf_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_buf_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/buf/buffers.h
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index 3a0f307186..a8d1593214 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -217,4 +217,16 @@
/** Macro: Yields the number of elements in array x. */
#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0]))
-#endif /* !defined(TOR_COMPAT_H) */
+/**
+ * "Eat" a semicolon that somebody puts at the end of a top-level macro.
+ *
+ * Frequently, we want to declare a macro that people will use at file scope,
+ * and we want to allow people to put a semicolon after the macro.
+ *
+ * This declaration of a struct can be repeated any number of times, and takes
+ * a trailing semicolon afterwards.
+ **/
+#define EAT_SEMICOLON \
+ struct dummy_semicolon_eater__
+
+#endif /* !defined(TOR_COMPAT_COMPILER_H) */
diff --git a/src/lib/cc/ctassert.h b/src/lib/cc/ctassert.h
index e42976360f..bedf0b83a6 100644
--- a/src/lib/cc/ctassert.h
+++ b/src/lib/cc/ctassert.h
@@ -22,7 +22,7 @@
/* If C11 is available, just use _Static_assert. */
#define CTASSERT(x) _Static_assert((x), #x)
-#else
+#else /* !(__STDC_VERSION__ >= 201112L) */
/*
* If C11 is not available, expand __COUNTER__, or __INCLUDE_LEVEL__
@@ -42,12 +42,12 @@
#else
/* hope it's unique enough */
#define CTASSERT(x) CTASSERT_EXPN((x), l, __LINE__)
-#endif
+#endif /* defined(__COUNTER__) || ... */
#define CTASSERT_EXPN(x, a, b) CTASSERT_DECL(x, a, b)
#define CTASSERT_DECL(x, a, b) \
typedef char tor_ctassert_##a##_##b[(x) ? 1 : -1] ATTR_UNUSED
-#endif
+#endif /* __STDC_VERSION__ >= 201112L */
#endif /* !defined(TOR_CTASSERT_H) */
diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am
index 52cf8a9f72..1aa722dd82 100644
--- a/src/lib/cc/include.am
+++ b/src/lib/cc/include.am
@@ -1,4 +1,5 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/cc/compat_compiler.h \
src/lib/cc/ctassert.h \
diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h
index c9b2d329f2..523f378ed7 100644
--- a/src/lib/cc/torint.h
+++ b/src/lib/cc/torint.h
@@ -96,9 +96,9 @@ typedef int32_t ssize_t;
# else
# define TOR_PRIuSZ PRIu32
# endif
-#else
+#else /* !(defined(_WIN32)) */
# define TOR_PRIuSZ "zu"
-#endif
+#endif /* defined(_WIN32) */
#ifdef _WIN32
# ifdef _WIN64
@@ -106,9 +106,9 @@ typedef int32_t ssize_t;
# else
# define TOR_PRIdSZ PRId32
# endif
-#else
+#else /* !(defined(_WIN32)) */
# define TOR_PRIdSZ "zd"
-#endif
+#endif /* defined(_WIN32) */
#ifndef SSIZE_MAX
#if (SIZEOF_SIZE_T == 4)
@@ -125,4 +125,13 @@ typedef int32_t ssize_t;
/** Any size_t larger than this amount is likely to be an underflow. */
#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16))
+#if SIZEOF_INT > SIZEOF_VOID_P
+#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!"
+#endif
+
+#if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P
+#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \
+platform!"
+#endif
+
#endif /* !defined(TOR_TORINT_H) */
diff --git a/src/lib/compress/compress_zstd.c b/src/lib/compress/compress_zstd.c
index 45d0d4d602..a99ea67e0b 100644
--- a/src/lib/compress/compress_zstd.c
+++ b/src/lib/compress/compress_zstd.c
@@ -25,7 +25,7 @@
* all invocations of zstd's static-only functions in a check to make sure
* that the compile-time version matches the run-time version. */
#define ZSTD_STATIC_LINKING_ONLY
-#endif
+#endif /* defined(ENABLE_ZSTD_ADVANCED_APIS) */
#ifdef HAVE_ZSTD
#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE
@@ -35,7 +35,7 @@ DISABLE_GCC_WARNING(unused-const-variable)
#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE
ENABLE_GCC_WARNING(unused-const-variable)
#endif
-#endif
+#endif /* defined(HAVE_ZSTD) */
/** Total number of bytes allocated for Zstandard state. */
static atomic_counter_t total_zstd_allocation;
@@ -77,7 +77,7 @@ tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number)
version_number / 100 % 100,
version_number % 100);
}
-#endif
+#endif /* defined(HAVE_ZSTD) */
#define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */
@@ -125,9 +125,9 @@ tor_zstd_can_use_static_apis(void)
}
#endif
return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber());
-#else
+#else /* !(defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD)) */
return 0;
-#endif
+#endif /* defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD) */
}
/** Internal Zstandard state for incremental compression/decompression.
@@ -237,7 +237,7 @@ tor_zstd_state_size_precalc(int compress, int preset)
#endif
}
}
-#endif
+#endif /* defined(ZSTD_STATIC_LINKING_ONLY) */
return tor_zstd_state_size_precalc_fake(compress, preset);
}
#endif /* defined(HAVE_ZSTD) */
@@ -527,7 +527,7 @@ tor_zstd_warn_if_version_mismatched(void)
"For safety, we'll avoid using advanced zstd functionality.",
header_version, runtime_version);
}
-#endif
+#endif /* defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS) */
}
#ifdef TOR_UNIT_TESTS
@@ -538,4 +538,4 @@ tor_zstd_set_static_apis_disabled_for_testing(int disabled)
{
static_apis_disable_for_testing = disabled;
}
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/lib/compress/include.am b/src/lib/compress/include.am
index b952779578..60dd447d4e 100644
--- a/src/lib/compress/include.am
+++ b/src/lib/compress/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-compress-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_compress_a_SOURCES = \
src/lib/compress/compress.c \
src/lib/compress/compress_buf.c \
@@ -18,6 +19,7 @@ src_lib_libtor_compress_testing_a_SOURCES = \
src_lib_libtor_compress_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_compress_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/compress/compress.h \
src/lib/compress/compress_lzma.h \
diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h
index 910d5fea65..45992796af 100644
--- a/src/lib/container/bitarray.h
+++ b/src/lib/container/bitarray.h
@@ -83,4 +83,4 @@ bitarray_is_set(bitarray_t *b, int bit)
return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK));
}
-#endif /* !defined(TOR_CONTAINER_H) */
+#endif /* !defined(TOR_BITARRAY_H) */
diff --git a/src/lib/container/include.am b/src/lib/container/include.am
index 032e4033da..00d7b8e587 100644
--- a/src/lib/container/include.am
+++ b/src/lib/container/include.am
@@ -5,9 +5,11 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-container-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_container_a_SOURCES = \
src/lib/container/bloomfilt.c \
src/lib/container/map.c \
+ src/lib/container/namemap.c \
src/lib/container/order.c \
src/lib/container/smartlist.c
@@ -16,10 +18,13 @@ src_lib_libtor_container_testing_a_SOURCES = \
src_lib_libtor_container_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_container_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/container/bitarray.h \
src/lib/container/bloomfilt.h \
src/lib/container/handles.h \
src/lib/container/map.h \
+ src/lib/container/namemap.h \
+ src/lib/container/namemap_st.h \
src/lib/container/order.h \
src/lib/container/smartlist.h
diff --git a/src/lib/container/map.h b/src/lib/container/map.h
index d61b1ec18f..9da1d3072c 100644
--- a/src/lib/container/map.h
+++ b/src/lib/container/map.h
@@ -258,4 +258,4 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
return digestmap_iter_done((digestmap_iter_t*)iter); \
}
-#endif /* !defined(TOR_CONTAINER_H) */
+#endif /* !defined(TOR_MAP_H) */
diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c
new file mode 100644
index 0000000000..a90057b32c
--- /dev/null
+++ b/src/lib/container/namemap.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "lib/container/smartlist.h"
+#include "lib/container/namemap.h"
+#include "lib/container/namemap_st.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/printf.h"
+
+#include "ext/siphash.h"
+
+#include <string.h>
+
+/** Helper for namemap hashtable implementation: compare two entries. */
+static inline int
+mapped_name_eq(const mapped_name_t *a, const mapped_name_t *b)
+{
+ return !strcmp(a->name, b->name);
+}
+
+/** Helper for namemap hashtable implementation: hash an entry. */
+static inline unsigned
+mapped_name_hash(const mapped_name_t *a)
+{
+ return (unsigned) siphash24g(a->name, strlen(a->name));
+}
+
+HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash,
+ mapped_name_eq)
+HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash,
+ mapped_name_eq, 0.6, tor_reallocarray_, tor_free_)
+
+/** Set up an uninitialized <b>map</b>. */
+void
+namemap_init(namemap_t *map)
+{
+ memset(map, 0, sizeof(*map));
+ HT_INIT(namemap_ht, &map->ht);
+ map->names = smartlist_new();
+}
+
+/** Return the name that <b>map</b> associates with a given <b>id</b>, or
+ * NULL if there is no such name. */
+const char *
+namemap_get_name(const namemap_t *map, unsigned id)
+{
+ if (map->names && id < (unsigned)smartlist_len(map->names)) {
+ mapped_name_t *name = smartlist_get(map->names, (int)id);
+ return name->name;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Return the name that <b>map</b> associates with a given <b>id</b>, or a
+ * pointer to a statically allocated string describing the value of <b>id</b>
+ * if no such name exists.
+ **/
+const char *
+namemap_fmt_name(const namemap_t *map, unsigned id)
+{
+ static char buf[32];
+
+ const char *name = namemap_get_name(map, id);
+ if (name)
+ return name;
+
+ tor_snprintf(buf, sizeof(buf), "{%u}", id);
+
+ return buf;
+}
+
+/**
+ * Helper: As namemap_get_id(), but requires that <b>name</b> is
+ * <b>namelen</b> charaters long, and that <b>namelen</b> is no more than
+ * MAX_NAMEMAP_NAME_LEN.
+ */
+static unsigned
+namemap_get_id_unchecked(const namemap_t *map,
+ const char *name,
+ size_t namelen)
+{
+ union {
+ mapped_name_t n;
+ char storage[MAX_NAMEMAP_NAME_LEN + sizeof(mapped_name_t) + 1];
+ } u;
+ memcpy(u.n.name, name, namelen);
+ u.n.name[namelen] = 0;
+ const mapped_name_t *found = HT_FIND(namemap_ht, &map->ht, &u.n);
+ if (found) {
+ tor_assert(map->names);
+ tor_assert(smartlist_get(map->names, found->intval) == found);
+ return found->intval;
+ }
+
+ return NAMEMAP_ERR;
+}
+
+/**
+ * Return the identifier currently associated by <b>map</b> with the name
+ * <b>name</b>, or NAMEMAP_ERR if no such identifier exists.
+ **/
+unsigned
+namemap_get_id(const namemap_t *map,
+ const char *name)
+{
+ size_t namelen = strlen(name);
+ if (namelen > MAX_NAMEMAP_NAME_LEN) {
+ return NAMEMAP_ERR;
+ }
+
+ return namemap_get_id_unchecked(map, name, namelen);
+}
+
+/**
+ * Return the identifier associated by <b>map</b> with the name
+ * <b>name</b>, allocating a new identifier in <b>map</b> if none exists.
+ *
+ * Return NAMEMAP_ERR if <b>name</b> is too long, or if there are no more
+ * identifiers we can allocate.
+ **/
+unsigned
+namemap_get_or_create_id(namemap_t *map,
+ const char *name)
+{
+ size_t namelen = strlen(name);
+ if (namelen > MAX_NAMEMAP_NAME_LEN) {
+ return NAMEMAP_ERR;
+ }
+
+ if (PREDICT_UNLIKELY(map->names == NULL))
+ map->names = smartlist_new();
+
+ unsigned found = namemap_get_id_unchecked(map, name, namelen);
+ if (found != NAMEMAP_ERR)
+ return found;
+
+ unsigned new_id = (unsigned)smartlist_len(map->names);
+ if (new_id == NAMEMAP_ERR)
+ return NAMEMAP_ERR; /* Can't allocate any more. */
+
+ mapped_name_t *insert = tor_malloc_zero(
+ offsetof(mapped_name_t, name) + namelen + 1);
+ memcpy(insert->name, name, namelen+1);
+ insert->intval = new_id;
+
+ HT_INSERT(namemap_ht, &map->ht, insert);
+ smartlist_add(map->names, insert);
+
+ return new_id;
+}
+
+/** Return the number of entries in 'names' */
+size_t
+namemap_get_size(const namemap_t *map)
+{
+ if (PREDICT_UNLIKELY(map->names == NULL))
+ return 0;
+
+ return smartlist_len(map->names);
+}
+
+/**
+ * Release all storage held in <b>map</b>.
+ */
+void
+namemap_clear(namemap_t *map)
+{
+ if (!map)
+ return;
+
+ HT_CLEAR(namemap_ht, &map->ht);
+ if (map->names) {
+ SMARTLIST_FOREACH(map->names, mapped_name_t *, n,
+ tor_free(n));
+ smartlist_free(map->names);
+ }
+ memset(map, 0, sizeof(*map));
+}
diff --git a/src/lib/container/namemap.h b/src/lib/container/namemap.h
new file mode 100644
index 0000000000..b96bc13f3a
--- /dev/null
+++ b/src/lib/container/namemap.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_NAMEMAP_H
+#define TOR_NAMEMAP_H
+
+/**
+ * \file namemap.h
+ *
+ * \brief Header for namemap.c
+ **/
+
+#include "lib/cc/compat_compiler.h"
+#include "ext/ht.h"
+
+#include <stddef.h>
+
+typedef struct namemap_t namemap_t;
+
+/** Returned in place of an identifier when an error occurs. */
+#define NAMEMAP_ERR UINT_MAX
+
+void namemap_init(namemap_t *map);
+const char *namemap_get_name(const namemap_t *map, unsigned id);
+const char *namemap_fmt_name(const namemap_t *map, unsigned id);
+unsigned namemap_get_id(const namemap_t *map,
+ const char *name);
+unsigned namemap_get_or_create_id(namemap_t *map,
+ const char *name);
+size_t namemap_get_size(const namemap_t *map);
+void namemap_clear(namemap_t *map);
+
+#endif /* !defined(TOR_NAMEMAP_H) */
diff --git a/src/lib/container/namemap_st.h b/src/lib/container/namemap_st.h
new file mode 100644
index 0000000000..5008fd5855
--- /dev/null
+++ b/src/lib/container/namemap_st.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef NAMEMAP_ST_H
+#define NAMEMAP_ST_H
+
+#include "lib/cc/compat_compiler.h"
+#include "ext/ht.h"
+
+struct smartlist_t;
+
+/** Longest allowed name that's allowed in a namemap_t. */
+#define MAX_NAMEMAP_NAME_LEN 128
+
+/** An entry inside a namemap_t. Maps a string to a numeric identifier. */
+typedef struct mapped_name_t {
+ HT_ENTRY(mapped_name_t) node;
+ unsigned intval;
+ char name[FLEXIBLE_ARRAY_MEMBER];
+} mapped_name_t;
+
+/** A structure that allocates small numeric identifiers for names and maps
+ * back and forth between them. */
+struct namemap_t {
+ HT_HEAD(namemap_ht, mapped_name_t) ht;
+ struct smartlist_t *names;
+};
+
+/** Macro to initialize a namemap. */
+#define NAMEMAP_INIT() { HT_INITIALIZER(), NULL }
+
+#endif /* !defined(NAMEMAP_ST_H) */
diff --git a/src/lib/container/order.h b/src/lib/container/order.h
index a176d6d8a6..3f2fd054a0 100644
--- a/src/lib/container/order.h
+++ b/src/lib/container/order.h
@@ -57,4 +57,4 @@ third_quartile_uint32(uint32_t *array, int n_elements)
return find_nth_uint32(array, n_elements, (n_elements*3)/4);
}
-#endif /* !defined(TOR_CONTAINER_H) */
+#endif /* !defined(TOR_ORDER_H) */
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index 77682db03e..81b0151433 100644
--- a/src/lib/container/smartlist.h
+++ b/src/lib/container/smartlist.h
@@ -165,4 +165,4 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
} \
STMT_END
-#endif /* !defined(TOR_CONTAINER_H) */
+#endif /* !defined(TOR_SMARTLIST_H) */
diff --git a/src/lib/crypt_ops/crypto_cipher.h b/src/lib/crypt_ops/crypto_cipher.h
index cc4fbf7a41..88d63c1df2 100644
--- a/src/lib/crypt_ops/crypto_cipher.h
+++ b/src/lib/crypt_ops/crypto_cipher.h
@@ -54,4 +54,4 @@ int crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen);
-#endif /* !defined(TOR_CRYPTO_H) */
+#endif /* !defined(TOR_CRYPTO_CIPHER_H) */
diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h
index 061a7a3505..cd23169cd5 100644
--- a/src/lib/crypt_ops/crypto_curve25519.h
+++ b/src/lib/crypt_ops/crypto_curve25519.h
@@ -76,8 +76,8 @@ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret);
int curve25519_public_from_base64(curve25519_public_key_t *pkey,
const char *input);
-int curve25519_public_to_base64(char *output,
- const curve25519_public_key_t *pkey);
+void curve25519_public_to_base64(char *output,
+ const curve25519_public_key_t *pkey);
void curve25519_set_impl_params(int use_ed);
void curve25519_init(void);
diff --git a/src/lib/crypt_ops/crypto_dh_openssl.c b/src/lib/crypt_ops/crypto_dh_openssl.c
index 8c6388fd5d..75cee1b596 100644
--- a/src/lib/crypt_ops/crypto_dh_openssl.c
+++ b/src/lib/crypt_ops/crypto_dh_openssl.c
@@ -34,7 +34,7 @@ static int tor_check_dh_key(int severity, const BIGNUM *bn);
struct crypto_dh_t {
DH *dh; /**< The openssl DH object */
};
-#endif
+#endif /* !defined(ENABLE_NSS) */
static DH *new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g);
@@ -100,7 +100,7 @@ crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g)
DH_free(dh);
return ret;
}
-#endif
+#endif /* 0 */
/**
* Helper: convert <b>hex<b> to a bignum, and return it. Assert that the
@@ -202,7 +202,7 @@ crypto_dh_new(int dh_type)
tor_free(res); // sets res to NULL.
return res;
}
-#endif
+#endif /* !defined(ENABLE_NSS) */
/** Create and return a new openssl DH from a given prime and generator. */
static DH *
@@ -461,7 +461,7 @@ crypto_dh_free_(crypto_dh_t *dh)
DH_free(dh->dh);
tor_free(dh);
}
-#endif
+#endif /* !defined(ENABLE_NSS) */
void
crypto_dh_free_all_openssl(void)
diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c
index 26f06c6c79..64a7d2d52c 100644
--- a/src/lib/crypt_ops/crypto_digest.c
+++ b/src/lib/crypt_ops/crypto_digest.c
@@ -23,171 +23,6 @@
#include "lib/arch/bytes.h"
-#ifdef ENABLE_NSS
-DISABLE_GCC_WARNING(strict-prototypes)
-#include <pk11pub.h>
-ENABLE_GCC_WARNING(strict-prototypes)
-#else
-
-#include "lib/crypt_ops/crypto_openssl_mgt.h"
-
-DISABLE_GCC_WARNING(redundant-decls)
-
-#include <openssl/hmac.h>
-#include <openssl/sha.h>
-
-ENABLE_GCC_WARNING(redundant-decls)
-#endif
-
-#ifdef ENABLE_NSS
-/**
- * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS).
- * On failure, return SEC_OID_UNKNOWN. */
-static SECOidTag
-digest_alg_to_nss_oid(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1: return SEC_OID_SHA1;
- case DIGEST_SHA256: return SEC_OID_SHA256;
- case DIGEST_SHA512: return SEC_OID_SHA512;
- case DIGEST_SHA3_256: /* Fall through */
- case DIGEST_SHA3_512: /* Fall through */
- default:
- return SEC_OID_UNKNOWN;
- }
-}
-
-/* Helper: get an unkeyed digest via pk11wrap */
-static int
-digest_nss_internal(SECOidTag alg,
- char *digest, unsigned len_out,
- const char *msg, size_t msg_len)
-{
- if (alg == SEC_OID_UNKNOWN)
- return -1;
- tor_assert(msg_len <= UINT_MAX);
-
- int rv = -1;
- SECStatus s;
- PK11Context *ctx = PK11_CreateDigestContext(alg);
- if (!ctx)
- return -1;
-
- s = PK11_DigestBegin(ctx);
- if (s != SECSuccess)
- goto done;
-
- s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len);
- if (s != SECSuccess)
- goto done;
-
- unsigned int len = 0;
- s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out);
- if (s != SECSuccess)
- goto done;
-
- rv = 0;
- done:
- PK11_DestroyContext(ctx, PR_TRUE);
- return rv;
-}
-
-/** True iff alg is implemented in our crypto library, and we want to use that
- * implementation */
-static bool
-library_supports_digest(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1: /* Fall through */
- case DIGEST_SHA256: /* Fall through */
- case DIGEST_SHA512: /* Fall through */
- return true;
- case DIGEST_SHA3_256: /* Fall through */
- case DIGEST_SHA3_512: /* Fall through */
- default:
- return false;
- }
-}
-#endif
-
-/* Crypto digest functions */
-
-/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
- * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
- * Return 0 on success, -1 on failure.
- */
-MOCK_IMPL(int,
-crypto_digest,(char *digest, const char *m, size_t len))
-{
- tor_assert(m);
- tor_assert(digest);
-#ifdef ENABLE_NSS
- return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len);
-#else
- if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) {
- return -1;
- }
-#endif
- return 0;
-}
-
-/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-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 || algorithm == DIGEST_SHA3_256);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA256) {
-#ifdef ENABLE_NSS
- return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len);
-#else
- ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
-#endif
- } else {
- ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
- > -1);
- }
-
- if (!ret)
- return -1;
- return 0;
-}
-
-/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-int
-crypto_digest512(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm)
-{
- tor_assert(m);
- tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA512) {
-#ifdef ENABLE_NSS
- return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len);
-#else
- ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
- != NULL);
-#endif
- } else {
- ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
- > -1);
- }
-
- if (!ret)
- return -1;
- return 0;
-}
-
/** Set the common_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. */
@@ -267,485 +102,6 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg)
}
}
-/** Intermediate information about the digest of a stream of data. */
-struct crypto_digest_t {
- digest_algorithm_t algorithm; /**< Which algorithm is in use? */
- /** State for the digest we're using. Only one member of the
- * union is usable, depending on the value of <b>algorithm</b>. Note also
- * that space for other members might not even be allocated!
- */
- union {
-#ifdef ENABLE_NSS
- PK11Context *ctx;
-#else
- SHA_CTX sha1; /**< state for SHA1 */
- SHA256_CTX sha2; /**< state for SHA256 */
- SHA512_CTX sha512; /**< state for SHA512 */
-#endif
- keccak_state sha3; /**< state for SHA3-[256,512] */
- } d;
-};
-
-#ifdef TOR_UNIT_TESTS
-
-digest_algorithm_t
-crypto_digest_get_algorithm(crypto_digest_t *digest)
-{
- tor_assert(digest);
-
- return digest->algorithm;
-}
-
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/**
- * Return the number of bytes we need to malloc in order to get a
- * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
- * when we free one.
- */
-static size_t
-crypto_digest_alloc_bytes(digest_algorithm_t alg)
-{
- /* Helper: returns the number of bytes in the 'f' field of 'st' */
-#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
- /* Gives the length of crypto_digest_t through the end of the field 'd' */
-#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
- STRUCT_FIELD_SIZE(crypto_digest_t, f))
- switch (alg) {
-#ifdef ENABLE_NSS
- case DIGEST_SHA1: /* Fall through */
- case DIGEST_SHA256: /* Fall through */
- case DIGEST_SHA512:
- return END_OF_FIELD(d.ctx);
-#else
- case DIGEST_SHA1:
- return END_OF_FIELD(d.sha1);
- case DIGEST_SHA256:
- return END_OF_FIELD(d.sha2);
- case DIGEST_SHA512:
- return END_OF_FIELD(d.sha512);
-#endif
- case DIGEST_SHA3_256:
- case DIGEST_SHA3_512:
- return END_OF_FIELD(d.sha3);
- default:
- tor_assert(0); // LCOV_EXCL_LINE
- return 0; // LCOV_EXCL_LINE
- }
-#undef END_OF_FIELD
-#undef STRUCT_FIELD_SIZE
-}
-
-/**
- * Internal function: create and return a new digest object for 'algorithm'.
- * Does not typecheck the algorithm.
- */
-static crypto_digest_t *
-crypto_digest_new_internal(digest_algorithm_t algorithm)
-{
- crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
- r->algorithm = algorithm;
-
- switch (algorithm)
- {
-#ifdef ENABLE_NSS
- case DIGEST_SHA1: /* fall through */
- case DIGEST_SHA256: /* fall through */
- case DIGEST_SHA512:
- r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm));
- if (BUG(!r->d.ctx)) {
- tor_free(r);
- return NULL;
- }
- if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) {
- crypto_digest_free(r);
- return NULL;
- }
- break;
-#else
- case DIGEST_SHA1:
- SHA1_Init(&r->d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Init(&r->d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Init(&r->d.sha512);
- break;
-#endif
- case DIGEST_SHA3_256:
- keccak_digest_init(&r->d.sha3, 256);
- break;
- case DIGEST_SHA3_512:
- keccak_digest_init(&r->d.sha3, 512);
- break;
- default:
- tor_assert_unreached();
- }
-
- return r;
-}
-
-/** Allocate and return a new digest object to compute SHA1 digests.
- */
-crypto_digest_t *
-crypto_digest_new(void)
-{
- return crypto_digest_new_internal(DIGEST_SHA1);
-}
-
-/** Allocate and return a new digest object to compute 256-bit digests
- * using <b>algorithm</b>.
- *
- * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new`
- * C_RUST_COUPLED: `crypto::digest::Sha256::default`
- */
-crypto_digest_t *
-crypto_digest256_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Allocate and return a new digest object to compute 512-bit digests
- * using <b>algorithm</b>. */
-crypto_digest_t *
-crypto_digest512_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Deallocate a digest object.
- */
-void
-crypto_digest_free_(crypto_digest_t *digest)
-{
- if (!digest)
- return;
-#ifdef ENABLE_NSS
- if (library_supports_digest(digest->algorithm)) {
- PK11_DestroyContext(digest->d.ctx, PR_TRUE);
- }
-#endif
- size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
- memwipe(digest, 0, bytes);
- tor_free(digest);
-}
-
-/** Add <b>len</b> bytes from <b>data</b> to the digest object.
- *
- * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess`
- * C_RUST_COUPLED: `crypto::digest::Sha256::process`
- */
-void
-crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
- size_t len)
-{
- tor_assert(digest);
- tor_assert(data);
- /* 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.
- */
- switch (digest->algorithm) {
-#ifdef ENABLE_NSS
- case DIGEST_SHA1: /* fall through */
- case DIGEST_SHA256: /* fall through */
- case DIGEST_SHA512:
- tor_assert(len <= UINT_MAX);
- SECStatus s = PK11_DigestOp(digest->d.ctx,
- (const unsigned char *)data,
- (unsigned int)len);
- tor_assert(s == SECSuccess);
- break;
-#else
- case DIGEST_SHA1:
- SHA1_Update(&digest->d.sha1, (void*)data, len);
- break;
- case DIGEST_SHA256:
- SHA256_Update(&digest->d.sha2, (void*)data, len);
- break;
- case DIGEST_SHA512:
- SHA512_Update(&digest->d.sha512, (void*)data, len);
- break;
-#endif
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
- break;
- default:
- /* LCOV_EXCL_START */
- tor_fragile_assert();
- break;
- /* LCOV_EXCL_STOP */
- }
-}
-
-/** 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 \<= DIGEST512_LEN.
- *
- * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest`
- * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256`
- */
-void
-crypto_digest_get_digest(crypto_digest_t *digest,
- char *out, size_t out_len)
-{
- unsigned char r[DIGEST512_LEN];
- tor_assert(digest);
- tor_assert(out);
- tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
-
- /* The SHA-3 code handles copying into a temporary ctx, and also can handle
- * short output buffers by truncating appropriately. */
- if (digest->algorithm == DIGEST_SHA3_256 ||
- digest->algorithm == DIGEST_SHA3_512) {
- keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
- return;
- }
-
-#ifdef ENABLE_NSS
- /* Copy into a temporary buffer since DigestFinal (alters) the context */
- unsigned char buf[1024];
- unsigned int saved_len = 0;
- unsigned rlen;
- unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx,
- buf, sizeof(buf),
- &saved_len);
- tor_assert(saved);
- SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r));
- tor_assert(s == SECSuccess);
- tor_assert(rlen >= out_len);
- s = PK11_RestoreContext(digest->d.ctx, saved, saved_len);
- tor_assert(s == SECSuccess);
- if (saved != buf) {
- PORT_ZFree(saved, saved_len);
- }
-#else
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- crypto_digest_t tmpenv;
- /* memcpy into a temporary ctx, since SHA*_Final clears the context */
- memcpy(&tmpenv, digest, alloc_bytes);
- switch (digest->algorithm) {
- case DIGEST_SHA1:
- SHA1_Final(r, &tmpenv.d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Final(r, &tmpenv.d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Final(r, &tmpenv.d.sha512);
- break;
-//LCOV_EXCL_START
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- default:
- log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
- /* This is fatal, because it should never happen. */
- tor_assert_unreached();
- break;
-//LCOV_EXCL_STOP
- }
-#endif
- memcpy(out, r, out_len);
- memwipe(r, 0, sizeof(r));
-}
-
-/** Allocate and return a new digest object with the same state as
- * <b>digest</b>
- *
- * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup`
- * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256`
- */
-crypto_digest_t *
-crypto_digest_dup(const crypto_digest_t *digest)
-{
- tor_assert(digest);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- crypto_digest_t *result = tor_memdup(digest, alloc_bytes);
-#ifdef ENABLE_NSS
- if (library_supports_digest(digest->algorithm)) {
- result->d.ctx = PK11_CloneContext(digest->d.ctx);
- }
-#endif
- return result;
-}
-
-/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
- * Asserts that <b>digest</b> is a SHA1 digest object.
- */
-void
-crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
- const crypto_digest_t *digest)
-{
- const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
- tor_assert(bytes <= sizeof(checkpoint->mem));
-#ifdef ENABLE_NSS
- if (library_supports_digest(digest->algorithm)) {
- unsigned char *allocated;
- allocated = PK11_SaveContextAlloc(digest->d.ctx,
- (unsigned char *)checkpoint->mem,
- sizeof(checkpoint->mem),
- &checkpoint->bytes_used);
- /* No allocation is allowed here. */
- tor_assert(allocated == checkpoint->mem);
- return;
- }
-#endif
- memcpy(checkpoint->mem, digest, bytes);
-}
-
-/** Restore the state of <b>digest</b> from <b>checkpoint</b>.
- * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the
- * state was previously stored with crypto_digest_checkpoint() */
-void
-crypto_digest_restore(crypto_digest_t *digest,
- const crypto_digest_checkpoint_t *checkpoint)
-{
- const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
-#ifdef ENABLE_NSS
- if (library_supports_digest(digest->algorithm)) {
- SECStatus s = PK11_RestoreContext(digest->d.ctx,
- (unsigned char *)checkpoint->mem,
- checkpoint->bytes_used);
- tor_assert(s == SECSuccess);
- return;
- }
-#endif
- memcpy(digest, checkpoint->mem, bytes);
-}
-
-/** Replace the state of the digest object <b>into</b> with the state
- * of the digest object <b>from</b>. Requires that 'into' and 'from'
- * have the same digest type.
- */
-void
-crypto_digest_assign(crypto_digest_t *into,
- const crypto_digest_t *from)
-{
- tor_assert(into);
- tor_assert(from);
- tor_assert(into->algorithm == from->algorithm);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
-#ifdef ENABLE_NSS
- if (library_supports_digest(from->algorithm)) {
- PK11_DestroyContext(into->d.ctx, PR_TRUE);
- into->d.ctx = PK11_CloneContext(from->d.ctx);
- return;
- }
-#endif
- memcpy(into,from,alloc_bytes);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of those strings,
- * plus the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>out_len</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist(char *digest_out, size_t len_out,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of: the
- * optional string <b>prepend</b>, those strings,
- * and the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>len_out</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
- const char *prepend,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_t *d = crypto_digest_new_internal(alg);
- if (prepend)
- crypto_digest_add_bytes(d, prepend, strlen(prepend));
- SMARTLIST_FOREACH(lst, const char *, cp,
- crypto_digest_add_bytes(d, cp, strlen(cp)));
- if (append)
- crypto_digest_add_bytes(d, append, strlen(append));
- crypto_digest_get_digest(d, digest_out, len_out);
- crypto_digest_free(d);
-}
-
-/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
- * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
- * result in <b>hmac_out</b>. Asserts on failure.
- */
-void
-crypto_hmac_sha256(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len)
-{
- /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
- tor_assert(hmac_out);
-#ifdef ENABLE_NSS
- PK11SlotInfo *slot = NULL;
- PK11SymKey *symKey = NULL;
- PK11Context *hmac = NULL;
-
- int ok = 0;
- SECStatus s;
- SECItem keyItem, paramItem;
- keyItem.data = (unsigned char *)key;
- keyItem.len = (unsigned)key_len;
- paramItem.type = siBuffer;
- paramItem.data = NULL;
- paramItem.len = 0;
-
- slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL);
- if (!slot)
- goto done;
- symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC,
- PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);
- if (!symKey)
- goto done;
-
- hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey,
- &paramItem);
- if (!hmac)
- goto done;
- s = PK11_DigestBegin(hmac);
- if (s != SECSuccess)
- goto done;
- s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len);
- if (s != SECSuccess)
- goto done;
- unsigned int len=0;
- s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN);
- if (s != SECSuccess || len != DIGEST256_LEN)
- goto done;
- ok = 1;
-
- done:
- if (hmac)
- PK11_DestroyContext(hmac, PR_TRUE);
- if (symKey)
- PK11_FreeSymKey(symKey);
- if (slot)
- PK11_FreeSlot(slot);
-
- tor_assert(ok);
-#else
- unsigned char *rv = NULL;
- rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
- (unsigned char*)hmac_out, NULL);
- tor_assert(rv);
-#endif
-}
-
/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
* <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length
* <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in
@@ -779,7 +135,23 @@ crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
/** Internal state for a eXtendable-Output Function (XOF). */
struct crypto_xof_t {
+#ifdef OPENSSL_HAS_SHAKE3_EVP
+ /* XXXX We can't enable this yet, because OpenSSL's
+ * DigestFinalXOF function can't be called repeatedly on the same
+ * XOF.
+ *
+ * We could in theory use the undocumented SHA3_absorb and SHA3_squeeze
+ * functions, but let's not mess with undocumented OpenSSL internals any
+ * more than we have to.
+ *
+ * We could also revise our XOF code so that it only allows a single
+ * squeeze operation; we don't require streaming squeeze operations
+ * outside the tests yet.
+ */
+ EVP_MD_CTX *ctx;
+#else /* !(defined(OPENSSL_HAS_SHAKE3_EVP)) */
keccak_state s;
+#endif /* defined(OPENSSL_HAS_SHAKE3_EVP) */
};
/** Allocate a new XOF object backed by SHAKE-256. The security level
@@ -792,7 +164,14 @@ crypto_xof_new(void)
{
crypto_xof_t *xof;
xof = tor_malloc(sizeof(crypto_xof_t));
+#ifdef OPENSSL_HAS_SHAKE256
+ xof->ctx = EVP_MD_CTX_new();
+ tor_assert(xof->ctx);
+ int r = EVP_DigestInit(xof->ctx, EVP_shake256());
+ tor_assert(r == 1);
+#else /* !(defined(OPENSSL_HAS_SHAKE256)) */
keccak_xof_init(&xof->s, 256);
+#endif /* defined(OPENSSL_HAS_SHAKE256) */
return xof;
}
@@ -803,8 +182,13 @@ crypto_xof_new(void)
void
crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
{
+#ifdef OPENSSL_HAS_SHAKE256
+ int r = EVP_DigestUpdate(xof->ctx, data, len);
+ tor_assert(r == 1);
+#else
int i = keccak_xof_absorb(&xof->s, data, len);
tor_assert(i == 0);
+#endif /* defined(OPENSSL_HAS_SHAKE256) */
}
/** Squeeze bytes out of a XOF object. Calling this routine will render
@@ -813,8 +197,13 @@ crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
void
crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
{
+#ifdef OPENSSL_HAS_SHAKE256
+ int r = EVP_DigestFinalXOF(xof->ctx, out, len);
+ tor_assert(r == 1);
+#else
int i = keccak_xof_squeeze(&xof->s, out, len);
tor_assert(i == 0);
+#endif /* defined(OPENSSL_HAS_SHAKE256) */
}
/** Cleanse and deallocate a XOF object. */
@@ -823,6 +212,34 @@ crypto_xof_free_(crypto_xof_t *xof)
{
if (!xof)
return;
+#ifdef OPENSSL_HAS_SHAKE256
+ if (xof->ctx)
+ EVP_MD_CTX_free(xof->ctx);
+#endif
memwipe(xof, 0, sizeof(crypto_xof_t));
tor_free(xof);
}
+
+/** Compute the XOF (SHAKE256) of a <b>input_len</b> bytes at <b>input</b>,
+ * putting <b>output_len</b> bytes at <b>output</b>. */
+void
+crypto_xof(uint8_t *output, size_t output_len,
+ const uint8_t *input, size_t input_len)
+{
+#ifdef OPENSSL_HAS_SHA3
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ tor_assert(ctx);
+ int r = EVP_DigestInit(ctx, EVP_shake256());
+ tor_assert(r == 1);
+ r = EVP_DigestUpdate(ctx, input, input_len);
+ tor_assert(r == 1);
+ r = EVP_DigestFinalXOF(ctx, output, output_len);
+ tor_assert(r == 1);
+ EVP_MD_CTX_free(ctx);
+#else /* !(defined(OPENSSL_HAS_SHA3)) */
+ crypto_xof_t *xof = crypto_xof_new();
+ crypto_xof_add_bytes(xof, input, input_len);
+ crypto_xof_squeeze_bytes(xof, output, output_len);
+ crypto_xof_free(xof);
+#endif /* defined(OPENSSL_HAS_SHA3) */
+}
diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h
index 47e60ce617..5869db7800 100644
--- a/src/lib/crypt_ops/crypto_digest.h
+++ b/src/lib/crypt_ops/crypto_digest.h
@@ -124,6 +124,8 @@ void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
void crypto_xof_free_(crypto_xof_t *xof);
#define crypto_xof_free(xof) \
FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
+void crypto_xof(uint8_t *output, size_t output_len,
+ const uint8_t *input, size_t input_len);
#ifdef TOR_UNIT_TESTS
digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c
new file mode 100644
index 0000000000..b73f0736fd
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_digest_nss.c
@@ -0,0 +1,560 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest_nss.c
+ * \brief Block of functions related with digest and xof utilities and
+ * operations (NSS specific implementations).
+ **/
+
+#include "lib/container/smartlist.h"
+#include "lib/crypt_ops/crypto_digest.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+
+#include "keccak-tiny/keccak-tiny.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/arch/bytes.h"
+
+DISABLE_GCC_WARNING(strict-prototypes)
+#include <pk11pub.h>
+ENABLE_GCC_WARNING(strict-prototypes)
+
+/**
+ * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS).
+ * On failure, return SEC_OID_UNKNOWN. */
+static SECOidTag
+digest_alg_to_nss_oid(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1: return SEC_OID_SHA1;
+ case DIGEST_SHA256: return SEC_OID_SHA256;
+ case DIGEST_SHA512: return SEC_OID_SHA512;
+ case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_512: /* Fall through */
+ default:
+ return SEC_OID_UNKNOWN;
+ }
+}
+
+/* Helper: get an unkeyed digest via pk11wrap */
+static int
+digest_nss_internal(SECOidTag alg,
+ char *digest, unsigned len_out,
+ const char *msg, size_t msg_len)
+{
+ if (alg == SEC_OID_UNKNOWN)
+ return -1;
+ tor_assert(msg_len <= UINT_MAX);
+
+ int rv = -1;
+ SECStatus s;
+ PK11Context *ctx = PK11_CreateDigestContext(alg);
+ if (!ctx)
+ return -1;
+
+ s = PK11_DigestBegin(ctx);
+ if (s != SECSuccess)
+ goto done;
+
+ s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len);
+ if (s != SECSuccess)
+ goto done;
+
+ unsigned int len = 0;
+ s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out);
+ if (s != SECSuccess)
+ goto done;
+
+ rv = 0;
+ done:
+ PK11_DestroyContext(ctx, PR_TRUE);
+ return rv;
+}
+
+/** True iff alg is implemented in our crypto library, and we want to use that
+ * implementation */
+static bool
+library_supports_digest(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1: /* Fall through */
+ case DIGEST_SHA256: /* Fall through */
+ case DIGEST_SHA512: /* Fall through */
+ return true;
+ case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_512: /* Fall through */
+ default:
+ return false;
+ }
+}
+
+/* Crypto digest functions */
+
+/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
+ * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
+ * Return 0 on success, -1 on failure.
+ */
+MOCK_IMPL(int,
+crypto_digest,(char *digest, const char *m, size_t len))
+{
+ tor_assert(m);
+ tor_assert(digest);
+ return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len);
+}
+
+/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+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 || algorithm == DIGEST_SHA3_256);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA256) {
+ return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len);
+ } else {
+ ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ > -1);
+ }
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA512) {
+ return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len);
+ } else {
+ ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ > -1);
+ }
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Intermediate information about the digest of a stream of data. */
+struct crypto_digest_t {
+ digest_algorithm_t algorithm; /**< Which algorithm is in use? */
+ /** State for the digest we're using. Only one member of the
+ * union is usable, depending on the value of <b>algorithm</b>. Note also
+ * that space for other members might not even be allocated!
+ */
+ union {
+ PK11Context *ctx;
+ keccak_state sha3; /**< state for SHA3-[256,512] */
+ } d;
+};
+
+#ifdef TOR_UNIT_TESTS
+
+digest_algorithm_t
+crypto_digest_get_algorithm(crypto_digest_t *digest)
+{
+ tor_assert(digest);
+
+ return digest->algorithm;
+}
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Return the number of bytes we need to malloc in order to get a
+ * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
+ * when we free one.
+ */
+static size_t
+crypto_digest_alloc_bytes(digest_algorithm_t alg)
+{
+ /* Helper: returns the number of bytes in the 'f' field of 'st' */
+#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
+ /* Gives the length of crypto_digest_t through the end of the field 'd' */
+#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
+ STRUCT_FIELD_SIZE(crypto_digest_t, f))
+ switch (alg) {
+ case DIGEST_SHA1: /* Fall through */
+ case DIGEST_SHA256: /* Fall through */
+ case DIGEST_SHA512:
+ return END_OF_FIELD(d.ctx);
+ case DIGEST_SHA3_256:
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.sha3);
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; // LCOV_EXCL_LINE
+ }
+#undef END_OF_FIELD
+#undef STRUCT_FIELD_SIZE
+}
+
+/**
+ * Internal function: create and return a new digest object for 'algorithm'.
+ * Does not typecheck the algorithm.
+ */
+static crypto_digest_t *
+crypto_digest_new_internal(digest_algorithm_t algorithm)
+{
+ crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ r->algorithm = algorithm;
+
+ switch (algorithm)
+ {
+ case DIGEST_SHA1: /* fall through */
+ case DIGEST_SHA256: /* fall through */
+ case DIGEST_SHA512:
+ r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm));
+ if (BUG(!r->d.ctx)) {
+ tor_free(r);
+ return NULL;
+ }
+ if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) {
+ crypto_digest_free(r);
+ return NULL;
+ }
+ break;
+ case DIGEST_SHA3_256:
+ keccak_digest_init(&r->d.sha3, 256);
+ break;
+ case DIGEST_SHA3_512:
+ keccak_digest_init(&r->d.sha3, 512);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return r;
+}
+
+/** Allocate and return a new digest object to compute SHA1 digests.
+ */
+crypto_digest_t *
+crypto_digest_new(void)
+{
+ return crypto_digest_new_internal(DIGEST_SHA1);
+}
+
+/** Allocate and return a new digest object to compute 256-bit digests
+ * using <b>algorithm</b>.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::default`
+ */
+crypto_digest_t *
+crypto_digest256_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Allocate and return a new digest object to compute 512-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest512_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Deallocate a digest object.
+ */
+void
+crypto_digest_free_(crypto_digest_t *digest)
+{
+ if (!digest)
+ return;
+ if (library_supports_digest(digest->algorithm)) {
+ PK11_DestroyContext(digest->d.ctx, PR_TRUE);
+ }
+ size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memwipe(digest, 0, bytes);
+ tor_free(digest);
+}
+
+/** Add <b>len</b> bytes from <b>data</b> to the digest object.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::process`
+ */
+void
+crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len)
+{
+ tor_assert(digest);
+ tor_assert(data);
+ /* 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.
+ */
+ switch (digest->algorithm) {
+ case DIGEST_SHA1: /* fall through */
+ case DIGEST_SHA256: /* fall through */
+ case DIGEST_SHA512:
+ tor_assert(len <= UINT_MAX);
+ SECStatus s = PK11_DigestOp(digest->d.ctx,
+ (const unsigned char *)data,
+ (unsigned int)len);
+ tor_assert(s == SECSuccess);
+ break;
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
+ break;
+ default:
+ /* LCOV_EXCL_START */
+ tor_fragile_assert();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+}
+
+/** 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 \<= DIGEST512_LEN.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest`
+ * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256`
+ */
+void
+crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len)
+{
+ unsigned char r[DIGEST512_LEN];
+ tor_assert(digest);
+ tor_assert(out);
+ tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
+
+ /* The SHA-3 code handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
+ return;
+ }
+
+ /* Copy into a temporary buffer since DigestFinal (alters) the context */
+ unsigned char buf[1024];
+ unsigned int saved_len = 0;
+ unsigned rlen;
+ unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx,
+ buf, sizeof(buf),
+ &saved_len);
+ tor_assert(saved);
+ SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r));
+ tor_assert(s == SECSuccess);
+ tor_assert(rlen >= out_len);
+ s = PK11_RestoreContext(digest->d.ctx, saved, saved_len);
+ tor_assert(s == SECSuccess);
+
+ if (saved != buf) {
+ PORT_ZFree(saved, saved_len);
+ }
+ memcpy(out, r, out_len);
+ memwipe(r, 0, sizeof(r));
+}
+
+/** Allocate and return a new digest object with the same state as
+ * <b>digest</b>
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup`
+ * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256`
+ */
+crypto_digest_t *
+crypto_digest_dup(const crypto_digest_t *digest)
+{
+ tor_assert(digest);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ crypto_digest_t *result = tor_memdup(digest, alloc_bytes);
+
+ if (library_supports_digest(digest->algorithm)) {
+ result->d.ctx = PK11_CloneContext(digest->d.ctx);
+ }
+
+ return result;
+}
+
+/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object.
+ */
+void
+crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ tor_assert(bytes <= sizeof(checkpoint->mem));
+ if (library_supports_digest(digest->algorithm)) {
+ unsigned char *allocated;
+ allocated = PK11_SaveContextAlloc(digest->d.ctx,
+ (unsigned char *)checkpoint->mem,
+ sizeof(checkpoint->mem),
+ &checkpoint->bytes_used);
+ /* No allocation is allowed here. */
+ tor_assert(allocated == checkpoint->mem);
+ return;
+ }
+ memcpy(checkpoint->mem, digest, bytes);
+}
+
+/** Restore the state of <b>digest</b> from <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the
+ * state was previously stored with crypto_digest_checkpoint() */
+void
+crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ if (library_supports_digest(digest->algorithm)) {
+ SECStatus s = PK11_RestoreContext(digest->d.ctx,
+ (unsigned char *)checkpoint->mem,
+ checkpoint->bytes_used);
+ tor_assert(s == SECSuccess);
+ return;
+ }
+ memcpy(digest, checkpoint->mem, bytes);
+}
+
+/** Replace the state of the digest object <b>into</b> with the state
+ * of the digest object <b>from</b>. Requires that 'into' and 'from'
+ * have the same digest type.
+ */
+void
+crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from)
+{
+ tor_assert(into);
+ tor_assert(from);
+ tor_assert(into->algorithm == from->algorithm);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
+ if (library_supports_digest(from->algorithm)) {
+ PK11_DestroyContext(into->d.ctx, PR_TRUE);
+ into->d.ctx = PK11_CloneContext(from->d.ctx);
+ return;
+ }
+ memcpy(into,from,alloc_bytes);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of: the
+ * optional string <b>prepend</b>, those strings,
+ * and the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>len_out</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d = crypto_digest_new_internal(alg);
+ if (prepend)
+ crypto_digest_add_bytes(d, prepend, strlen(prepend));
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
+/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
+ * result in <b>hmac_out</b>. Asserts on failure.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+ /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+ tor_assert(hmac_out);
+
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *symKey = NULL;
+ PK11Context *hmac = NULL;
+
+ int ok = 0;
+ SECStatus s;
+ SECItem keyItem, paramItem;
+ keyItem.data = (unsigned char *)key;
+ keyItem.len = (unsigned)key_len;
+ paramItem.type = siBuffer;
+ paramItem.data = NULL;
+ paramItem.len = 0;
+
+ slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL);
+ if (!slot)
+ goto done;
+ symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC,
+ PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);
+ if (!symKey)
+ goto done;
+
+ hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey,
+ &paramItem);
+ if (!hmac)
+ goto done;
+ s = PK11_DigestBegin(hmac);
+ if (s != SECSuccess)
+ goto done;
+ s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len);
+ if (s != SECSuccess)
+ goto done;
+ unsigned int len=0;
+ s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN);
+ if (s != SECSuccess || len != DIGEST256_LEN)
+ goto done;
+ ok = 1;
+
+ done:
+ if (hmac)
+ PK11_DestroyContext(hmac, PR_TRUE);
+ if (symKey)
+ PK11_FreeSymKey(symKey);
+ if (slot)
+ PK11_FreeSlot(slot);
+
+ tor_assert(ok);
+}
+
diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c
new file mode 100644
index 0000000000..c631b0eac0
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_digest_openssl.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest_openssl.c
+ * \brief Block of functions related with digest and xof utilities and
+ * operations (OpenSSL specific implementations).
+ **/
+
+#include "lib/container/smartlist.h"
+#include "lib/crypt_ops/crypto_digest.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+
+#include "keccak-tiny/keccak-tiny.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/arch/bytes.h"
+
+#include "lib/crypt_ops/crypto_openssl_mgt.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+/* Crypto digest functions */
+
+/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
+ * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
+ * Return 0 on success, -1 on failure.
+ */
+MOCK_IMPL(int,
+crypto_digest,(char *digest, const char *m, size_t len))
+{
+ tor_assert(m);
+ tor_assert(digest);
+ if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+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 || algorithm == DIGEST_SHA3_256);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA256) {
+ ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
+ } else {
+#ifdef OPENSSL_HAS_SHA3
+ unsigned int dlen = DIGEST256_LEN;
+ ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_256(), NULL);
+#else
+ ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ > -1);
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ }
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA512) {
+ ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
+ != NULL);
+ } else {
+#ifdef OPENSSL_HAS_SHA3
+ unsigned int dlen = DIGEST512_LEN;
+ ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_512(), NULL);
+#else
+ ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ > -1);
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ }
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Intermediate information about the digest of a stream of data. */
+struct crypto_digest_t {
+ digest_algorithm_t algorithm; /**< Which algorithm is in use? */
+ /** State for the digest we're using. Only one member of the
+ * union is usable, depending on the value of <b>algorithm</b>. Note also
+ * that space for other members might not even be allocated!
+ */
+ union {
+ SHA_CTX sha1; /**< state for SHA1 */
+ SHA256_CTX sha2; /**< state for SHA256 */
+ SHA512_CTX sha512; /**< state for SHA512 */
+#ifdef OPENSSL_HAS_SHA3
+ EVP_MD_CTX *md;
+#else
+ keccak_state sha3; /**< state for SHA3-[256,512] */
+#endif
+ } d;
+};
+
+#ifdef TOR_UNIT_TESTS
+
+digest_algorithm_t
+crypto_digest_get_algorithm(crypto_digest_t *digest)
+{
+ tor_assert(digest);
+
+ return digest->algorithm;
+}
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Return the number of bytes we need to malloc in order to get a
+ * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
+ * when we free one.
+ */
+static size_t
+crypto_digest_alloc_bytes(digest_algorithm_t alg)
+{
+ /* Helper: returns the number of bytes in the 'f' field of 'st' */
+#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
+ /* Gives the length of crypto_digest_t through the end of the field 'd' */
+#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
+ STRUCT_FIELD_SIZE(crypto_digest_t, f))
+ switch (alg) {
+ case DIGEST_SHA1:
+ return END_OF_FIELD(d.sha1);
+ case DIGEST_SHA256:
+ return END_OF_FIELD(d.sha2);
+ case DIGEST_SHA512:
+ return END_OF_FIELD(d.sha512);
+#ifdef OPENSSL_HAS_SHA3
+ case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.md);
+#else
+ case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.sha3);
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; // LCOV_EXCL_LINE
+ }
+#undef END_OF_FIELD
+#undef STRUCT_FIELD_SIZE
+}
+
+/**
+ * Internal function: create and return a new digest object for 'algorithm'.
+ * Does not typecheck the algorithm.
+ */
+static crypto_digest_t *
+crypto_digest_new_internal(digest_algorithm_t algorithm)
+{
+ crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ r->algorithm = algorithm;
+
+ switch (algorithm)
+ {
+ case DIGEST_SHA1:
+ SHA1_Init(&r->d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Init(&r->d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Init(&r->d.sha512);
+ break;
+#ifdef OPENSSL_HAS_SHA3
+ case DIGEST_SHA3_256:
+ r->d.md = EVP_MD_CTX_new();
+ if (!EVP_DigestInit(r->d.md, EVP_sha3_256())) {
+ crypto_digest_free(r);
+ return NULL;
+ }
+ break;
+ case DIGEST_SHA3_512:
+ r->d.md = EVP_MD_CTX_new();
+ if (!EVP_DigestInit(r->d.md, EVP_sha3_512())) {
+ crypto_digest_free(r);
+ return NULL;
+ }
+ break;
+#else /* !(defined(OPENSSL_HAS_SHA3)) */
+ case DIGEST_SHA3_256:
+ keccak_digest_init(&r->d.sha3, 256);
+ break;
+ case DIGEST_SHA3_512:
+ keccak_digest_init(&r->d.sha3, 512);
+ break;
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ default:
+ tor_assert_unreached();
+ }
+
+ return r;
+}
+
+/** Allocate and return a new digest object to compute SHA1 digests.
+ */
+crypto_digest_t *
+crypto_digest_new(void)
+{
+ return crypto_digest_new_internal(DIGEST_SHA1);
+}
+
+/** Allocate and return a new digest object to compute 256-bit digests
+ * using <b>algorithm</b>.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::default`
+ */
+crypto_digest_t *
+crypto_digest256_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Allocate and return a new digest object to compute 512-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest512_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Deallocate a digest object.
+ */
+void
+crypto_digest_free_(crypto_digest_t *digest)
+{
+ if (!digest)
+ return;
+#ifdef OPENSSL_HAS_SHA3
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ if (digest->d.md) {
+ EVP_MD_CTX_free(digest->d.md);
+ }
+ }
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memwipe(digest, 0, bytes);
+ tor_free(digest);
+}
+
+/** Add <b>len</b> bytes from <b>data</b> to the digest object.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess`
+ * C_RUST_COUPLED: `crypto::digest::Sha256::process`
+ */
+void
+crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len)
+{
+ tor_assert(digest);
+ tor_assert(data);
+ /* 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.
+ */
+ 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;
+ case DIGEST_SHA512:
+ SHA512_Update(&digest->d.sha512, (void*)data, len);
+ break;
+#ifdef OPENSSL_HAS_SHA3
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512: {
+ int r = EVP_DigestUpdate(digest->d.md, data, len);
+ tor_assert(r);
+ }
+ break;
+#else /* !(defined(OPENSSL_HAS_SHA3)) */
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
+ break;
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ default:
+ /* LCOV_EXCL_START */
+ tor_fragile_assert();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+}
+
+/** 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 \<= DIGEST512_LEN.
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest`
+ * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256`
+ */
+void
+crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len)
+{
+ unsigned char r[DIGEST512_LEN];
+ tor_assert(digest);
+ tor_assert(out);
+ tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
+
+ /* The SHA-3 code handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+#ifdef OPENSSL_HAS_SHA3
+ unsigned dlen = (unsigned)
+ crypto_digest_algorithm_get_length(digest->algorithm);
+ EVP_MD_CTX *tmp = EVP_MD_CTX_new();
+ EVP_MD_CTX_copy(tmp, digest->d.md);
+ memset(r, 0xff, sizeof(r));
+ int res = EVP_DigestFinal(tmp, r, &dlen);
+ EVP_MD_CTX_free(tmp);
+ tor_assert(res == 1);
+ goto done;
+#else /* !(defined(OPENSSL_HAS_SHA3)) */
+ /* Tiny-Keccak handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
+ return;
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ }
+
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ crypto_digest_t tmpenv;
+ /* memcpy into a temporary ctx, since SHA*_Final clears the context */
+ memcpy(&tmpenv, digest, alloc_bytes);
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Final(r, &tmpenv.d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Final(r, &tmpenv.d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Final(r, &tmpenv.d.sha512);
+ break;
+//LCOV_EXCL_START
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ default:
+ log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
+ /* This is fatal, because it should never happen. */
+ tor_assert_unreached();
+ break;
+//LCOV_EXCL_STOP
+ }
+#ifdef OPENSSL_HAS_SHA3
+ done:
+#endif
+ memcpy(out, r, out_len);
+ memwipe(r, 0, sizeof(r));
+}
+
+/** Allocate and return a new digest object with the same state as
+ * <b>digest</b>
+ *
+ * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup`
+ * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256`
+ */
+crypto_digest_t *
+crypto_digest_dup(const crypto_digest_t *digest)
+{
+ tor_assert(digest);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ crypto_digest_t *result = tor_memdup(digest, alloc_bytes);
+
+#ifdef OPENSSL_HAS_SHA3
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ result->d.md = EVP_MD_CTX_new();
+ EVP_MD_CTX_copy(result->d.md, digest->d.md);
+ }
+#endif /* defined(OPENSSL_HAS_SHA3) */
+ return result;
+}
+
+/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object.
+ */
+void
+crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ tor_assert(bytes <= sizeof(checkpoint->mem));
+ memcpy(checkpoint->mem, digest, bytes);
+}
+
+/** Restore the state of <b>digest</b> from <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the
+ * state was previously stored with crypto_digest_checkpoint() */
+void
+crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memcpy(digest, checkpoint->mem, bytes);
+}
+
+/** Replace the state of the digest object <b>into</b> with the state
+ * of the digest object <b>from</b>. Requires that 'into' and 'from'
+ * have the same digest type.
+ */
+void
+crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from)
+{
+ tor_assert(into);
+ tor_assert(from);
+ tor_assert(into->algorithm == from->algorithm);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
+
+#ifdef OPENSSL_HAS_SHA3
+ if (from->algorithm == DIGEST_SHA3_256 ||
+ from->algorithm == DIGEST_SHA3_512) {
+ EVP_MD_CTX_copy(into->d.md, from->d.md);
+ return;
+ }
+#endif /* defined(OPENSSL_HAS_SHA3) */
+
+ memcpy(into,from,alloc_bytes);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of: the
+ * optional string <b>prepend</b>, those strings,
+ * and the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>len_out</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d = crypto_digest_new_internal(alg);
+ if (prepend)
+ crypto_digest_add_bytes(d, prepend, strlen(prepend));
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
+/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
+ * result in <b>hmac_out</b>. Asserts on failure.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+ /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+ tor_assert(hmac_out);
+ unsigned char *rv = NULL;
+ rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
+ (unsigned char*)hmac_out, NULL);
+ tor_assert(rv);
+}
+
diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c
index 400f963898..0581529125 100644
--- a/src/lib/crypt_ops/crypto_ed25519.c
+++ b/src/lib/crypt_ops/crypto_ed25519.c
@@ -226,7 +226,7 @@ ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong)
int
ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey)
{
- return tor_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN);
+ return safe_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN);
}
/* Return a heap-allocated array that contains <b>msg</b> prefixed by the
diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c
index 84f73e5272..118cd79045 100644
--- a/src/lib/crypt_ops/crypto_format.c
+++ b/src/lib/crypt_ops/crypto_format.c
@@ -104,7 +104,7 @@ crypto_read_tagged_contents_from_file(const char *fname,
prefix[32] = 0;
/* Check type, extract tag. */
if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
- ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
+ ! fast_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
saved_errno = EINVAL;
goto end;
}
@@ -131,20 +131,27 @@ crypto_read_tagged_contents_from_file(const char *fname,
return r;
}
-/** Encode <b>pkey</b> as a base64-encoded string, without trailing "="
+/** Encode <b>pkey</b> as a base64-encoded string, including trailing "="
* characters, in the buffer <b>output</b>, which must have at least
- * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on
- * failure. */
-int
+ * CURVE25519_BASE64_PADDED_LEN+1 bytes available.
+ * Can not fail.
+ *
+ * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
+ * ED25519_BASE64_LEN.
+ */
+void
curve25519_public_to_base64(char *output,
const curve25519_public_key_t *pkey)
{
char buf[128];
- base64_encode(buf, sizeof(buf),
- (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN, 0);
- buf[CURVE25519_BASE64_PADDED_LEN] = '\0';
+ int n = base64_encode(buf, sizeof(buf),
+ (const char*)pkey->public_key,
+ CURVE25519_PUBKEY_LEN, 0);
+ /* These asserts should always succeed, unless there is a bug in
+ * base64_encode(). */
+ tor_assert(n == CURVE25519_BASE64_PADDED_LEN);
+ tor_assert(buf[CURVE25519_BASE64_PADDED_LEN] == '\0');
memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1);
- return 0;
}
/** Try to decode a base64-encoded curve25519 public key from <b>input</b>
@@ -181,8 +188,7 @@ ed25519_fmt(const ed25519_public_key_t *pkey)
if (ed25519_public_key_is_zero(pkey)) {
strlcpy(formatted, "<unset>", sizeof(formatted));
} else {
- int r = ed25519_public_to_base64(formatted, pkey);
- tor_assert(!r);
+ ed25519_public_to_base64(formatted, pkey);
}
} else {
strlcpy(formatted, "<null>", sizeof(formatted));
@@ -202,28 +208,35 @@ ed25519_public_from_base64(ed25519_public_key_t *pkey,
/** Encode the public key <b>pkey</b> into the buffer at <b>output</b>,
* which must have space for ED25519_BASE64_LEN bytes of encoded key,
- * plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
+ * plus one byte for a terminating NUL.
+ * Can not fail.
+ *
+ * Careful! ED25519_BASE64_LEN is one byte shorter than
+ * CURVE25519_BASE64_PADDED_LEN.
*/
-int
+void
ed25519_public_to_base64(char *output,
const ed25519_public_key_t *pkey)
{
- return digest256_to_base64(output, (const char *)pkey->pubkey);
+ digest256_to_base64(output, (const char *)pkey->pubkey);
}
/** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
* which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
- * plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
+ * plus one byte for a terminating NUL.
+ * Can not fail.
*/
-int
+void
ed25519_signature_to_base64(char *output,
const ed25519_signature_t *sig)
{
char buf[256];
int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
+ /* These asserts should always succeed, unless there is a bug in
+ * base64_encode_nopad(). */
tor_assert(n == ED25519_SIG_BASE64_LEN);
+ tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0');
memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
- return 0;
}
/** Try to decode the string <b>input</b> into an ed25519 signature. On
@@ -233,16 +246,11 @@ int
ed25519_signature_from_base64(ed25519_signature_t *sig,
const char *input)
{
-
if (strlen(input) != ED25519_SIG_BASE64_LEN)
return -1;
- char buf[ED25519_SIG_BASE64_LEN+3];
- memcpy(buf, input, ED25519_SIG_BASE64_LEN);
- buf[ED25519_SIG_BASE64_LEN+0] = '=';
- buf[ED25519_SIG_BASE64_LEN+1] = '=';
- buf[ED25519_SIG_BASE64_LEN+2] = 0;
char decoded[128];
- int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf));
+ int n = base64_decode(decoded, sizeof(decoded), input,
+ ED25519_SIG_BASE64_LEN);
if (n < 0 || n != ED25519_SIG_LEN)
return -1;
memcpy(sig->sig, decoded, ED25519_SIG_LEN);
@@ -250,24 +258,26 @@ ed25519_signature_from_base64(ed25519_signature_t *sig,
return 0;
}
-/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
+/** Base64 encode DIGEST_LEN bytes from <b>digest</b>, remove the trailing =
* characters, and store the nul-terminated result in the first
- * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
-/* XXXX unify with crypto_format.c code */
-int
+ * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>.
+ * Can not fail. */
+void
digest_to_base64(char *d64, const char *digest)
{
char buf[256];
- base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0);
- buf[BASE64_DIGEST_LEN] = '\0';
+ int n = base64_encode_nopad(buf, sizeof(buf),
+ (const uint8_t *)digest, DIGEST_LEN);
+ /* These asserts should always succeed, unless there is a bug in
+ * base64_encode_nopad(). */
+ tor_assert(n == BASE64_DIGEST_LEN);
+ tor_assert(buf[BASE64_DIGEST_LEN] == '\0');
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
- return 0;
}
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST_LEN bytes at <b>digest</b>. */
-/* XXXX unify with crypto_format.c code */
int
digest_from_base64(char *digest, const char *d64)
{
@@ -279,22 +289,24 @@ digest_from_base64(char *digest, const char *d64)
/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
* trailing = characters, and store the nul-terminated result in the first
- * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
- /* XXXX unify with crypto_format.c code */
-int
+ * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>.
+ * Can not fail. */
+void
digest256_to_base64(char *d64, const char *digest)
{
char buf[256];
- base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0);
- buf[BASE64_DIGEST256_LEN] = '\0';
+ int n = base64_encode_nopad(buf, sizeof(buf),
+ (const uint8_t *)digest, DIGEST256_LEN);
+ /* These asserts should always succeed, unless there is a bug in
+ * base64_encode_nopad(). */
+ tor_assert(n == BASE64_DIGEST256_LEN);
+ tor_assert(buf[BASE64_DIGEST256_LEN] == '\0');
memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
- return 0;
}
/** Given a base64 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>. */
-/* XXXX unify with crypto_format.c code */
int
digest256_from_base64(char *digest, const char *d64)
{
diff --git a/src/lib/crypt_ops/crypto_format.h b/src/lib/crypt_ops/crypto_format.h
index fe852e6a61..b4b3aa189c 100644
--- a/src/lib/crypt_ops/crypto_format.h
+++ b/src/lib/crypt_ops/crypto_format.h
@@ -33,18 +33,18 @@ ssize_t crypto_read_tagged_contents_from_file(const char *fname,
int ed25519_public_from_base64(struct ed25519_public_key_t *pkey,
const char *input);
-int ed25519_public_to_base64(char *output,
- const struct ed25519_public_key_t *pkey);
+void ed25519_public_to_base64(char *output,
+ const struct ed25519_public_key_t *pkey);
const char *ed25519_fmt(const struct ed25519_public_key_t *pkey);
int ed25519_signature_from_base64(struct ed25519_signature_t *sig,
const char *input);
-int ed25519_signature_to_base64(char *output,
- const struct ed25519_signature_t *sig);
+void ed25519_signature_to_base64(char *output,
+ const struct ed25519_signature_t *sig);
-int digest_to_base64(char *d64, const char *digest);
+void 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);
+void digest256_to_base64(char *d64, const char *digest);
int digest256_from_base64(char *digest, const char *d64);
#endif /* !defined(TOR_CRYPTO_FORMAT_H) */
diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c
index fd2e701651..e0f3d65ad1 100644
--- a/src/lib/crypt_ops/crypto_hkdf.c
+++ b/src/lib/crypt_ops/crypto_hkdf.c
@@ -25,7 +25,7 @@
#include <openssl/kdf.h>
#define HAVE_OPENSSL_HKDF 1
#endif
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#include <string.h>
@@ -109,7 +109,7 @@ crypto_expand_key_material_rfc5869_sha256_openssl(
return 0;
}
-#else
+#else /* !(defined(HAVE_OPENSSL_HKDF)) */
/**
* Perform RFC5869 HKDF computation using our own legacy implementation.
@@ -166,7 +166,7 @@ crypto_expand_key_material_rfc5869_sha256_legacy(
memwipe(mac, 0, sizeof(mac));
return 0;
}
-#endif
+#endif /* defined(HAVE_OPENSSL_HKDF) */
/** Expand some secret key material according to RFC5869, using SHA256 as the
* underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the
@@ -191,11 +191,11 @@ crypto_expand_key_material_rfc5869_sha256(
salt_in_len, info_in,
info_in_len,
key_out, key_out_len);
-#else
+#else /* !(defined(HAVE_OPENSSL_HKDF)) */
return crypto_expand_key_material_rfc5869_sha256_legacy(key_in,
key_in_len, salt_in,
salt_in_len, info_in,
info_in_len,
key_out, key_out_len);
-#endif
+#endif /* defined(HAVE_OPENSSL_HKDF) */
}
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index 4040085c76..a16bf4e11a 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -12,6 +12,8 @@
#include "orconfig.h"
+#define CRYPTO_PRIVATE
+
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_curve25519.h"
@@ -69,6 +71,8 @@ crypto_early_init(void)
if (crypto_init_siphash_key() < 0)
return -1;
+ crypto_rand_fast_init();
+
curve25519_init();
ed25519_init();
}
@@ -95,7 +99,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
(void)useAccel;
(void)accelName;
(void)accelDir;
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
if (crypto_nss_late_init() < 0)
return -1;
@@ -111,6 +115,7 @@ crypto_thread_cleanup(void)
#ifdef ENABLE_OPENSSL
crypto_openssl_thread_cleanup();
#endif
+ destroy_thread_fast_rng();
}
/**
@@ -129,6 +134,8 @@ crypto_global_cleanup(void)
crypto_nss_global_cleanup();
#endif
+ crypto_rand_fast_shutdown();
+
crypto_early_initialized_ = 0;
crypto_global_initialized_ = 0;
have_seeded_siphash = 0;
@@ -145,6 +152,12 @@ crypto_prefork(void)
#ifdef ENABLE_NSS
crypto_nss_prefork();
#endif
+ /* It is not safe to share a fast_rng object across a fork boundary unless
+ * we actually have zero-on-fork support in map_anon.c. If we have
+ * drop-on-fork support, we will crash; if we have neither, we will yield
+ * a copy of the parent process's rng, which is scary and insecure.
+ */
+ destroy_thread_fast_rng();
}
/** Run operations that the crypto library requires to be happy again
diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h
index 540d08eb56..8de3eb03ed 100644
--- a/src/lib/crypt_ops/crypto_init.h
+++ b/src/lib/crypt_ops/crypto_init.h
@@ -33,4 +33,4 @@ const char *crypto_get_header_version_string(void);
int tor_is_using_nss(void);
-#endif /* !defined(TOR_CRYPTO_H) */
+#endif /* !defined(TOR_CRYPTO_INIT_H) */
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.h b/src/lib/crypt_ops/crypto_nss_mgt.h
index 72fd2a1229..4cfa9b42a4 100644
--- a/src/lib/crypt_ops/crypto_nss_mgt.h
+++ b/src/lib/crypt_ops/crypto_nss_mgt.h
@@ -29,6 +29,6 @@ void crypto_nss_global_cleanup(void);
void crypto_nss_prefork(void);
void crypto_nss_postfork(void);
-#endif
+#endif /* defined(ENABLE_NSS) */
-#endif /* !defined(TOR_CRYPTO_NSS_H) */
+#endif /* !defined(TOR_CRYPTO_NSS_MGT_H) */
diff --git a/src/lib/crypt_ops/crypto_ope.c b/src/lib/crypt_ops/crypto_ope.c
index 2186d2a939..4bd4b35706 100644
--- a/src/lib/crypt_ops/crypto_ope.c
+++ b/src/lib/crypt_ops/crypto_ope.c
@@ -57,9 +57,9 @@ ope_val_from_le(ope_val_t x)
((x) >> 8) |
(((x)&0xff) << 8);
}
-#else
+#else /* !(defined(WORDS_BIGENDIAN)) */
#define ope_val_from_le(x) (x)
-#endif
+#endif /* defined(WORDS_BIGENDIAN) */
/**
* Return a new AES256-CTR stream cipher object for <b>ope</b>, ready to yield
diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h
index 610d956335..9778dfe0f0 100644
--- a/src/lib/crypt_ops/crypto_ope.h
+++ b/src/lib/crypt_ops/crypto_ope.h
@@ -41,6 +41,6 @@ struct aes_cnt_cipher;
STATIC struct aes_cnt_cipher *ope_get_cipher(const crypto_ope_t *ope,
uint32_t initial_idx);
STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher *c, size_t n);
-#endif
+#endif /* defined(CRYPTO_OPE_PRIVATE) */
-#endif
+#endif /* !defined(CRYPTO_OPE_H) */
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c
index c97815f9a4..6d8364ebf8 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.c
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.c
@@ -176,6 +176,10 @@ crypto_openssl_free_all(void)
tor_free(crypto_openssl_version_str);
tor_free(crypto_openssl_header_version_str);
+ /* Destroying a locked mutex is undefined behaviour. This mutex may be
+ * locked, because multiple threads can access it. But we need to destroy
+ * it, otherwise re-initialisation will trigger undefined behaviour.
+ * See #31735 for details. */
#ifndef NEW_THREAD_API
if (n_openssl_mutexes_) {
int n = n_openssl_mutexes_;
@@ -200,10 +204,10 @@ crypto_openssl_early_init(void)
OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
OPENSSL_INIT_ADD_ALL_CIPHERS |
OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
-#else
+#else /* !(defined(OPENSSL_1_1_API)) */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
setup_openssl_threading();
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h
index a3dd03aa04..111a2d12ed 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.h
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.h
@@ -84,6 +84,6 @@ int crypto_openssl_late_init(int useAccel, const char *accelName,
void crypto_openssl_thread_cleanup(void);
void crypto_openssl_global_cleanup(void);
-#endif /* ENABLE_OPENSSL */
+#endif /* defined(ENABLE_OPENSSL) */
#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */
diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c
index 0b1cb96c1b..a80a98f267 100644
--- a/src/lib/crypt_ops/crypto_rand.c
+++ b/src/lib/crypt_ops/crypto_rand.c
@@ -36,6 +36,7 @@
#include "lib/defs/digest_sizes.h"
#include "lib/crypt_ops/crypto_digest.h"
+#include "lib/ctime/di_ops.h"
#ifdef ENABLE_NSS
#include "lib/crypt_ops/crypto_nss_mgt.h"
@@ -46,7 +47,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/rand.h>
#include <openssl/sha.h>
ENABLE_GCC_WARNING(redundant-decls)
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
#include <pk11pub.h>
@@ -314,7 +315,7 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
}
}
- if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len))
+ if ((out_len < sanity_min_size) || !safe_mem_is_zero((char*)out, out_len))
return 0;
}
@@ -418,7 +419,7 @@ crypto_seed_openssl_rng(void)
else
return -1;
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
/**
@@ -441,7 +442,7 @@ crypto_seed_nss_rng(void)
return load_entropy_ok ? 0 : -1;
}
-#endif
+#endif /* defined(ENABLE_NSS) */
/**
* Seed the RNG for any and all crypto libraries that we're using with bytes
@@ -519,13 +520,13 @@ crypto_rand_unmocked(char *to, size_t n)
#undef BUFLEN
}
-#else
+#else /* !(defined(ENABLE_NSS)) */
int r = RAND_bytes((unsigned char*)to, (int)n);
/* We consider a PRNG failure non-survivable. Let's assert so that we get a
* stack trace about where it happened.
*/
tor_assert(r >= 0);
-#endif
+#endif /* defined(ENABLE_NSS) */
}
/**
@@ -626,6 +627,6 @@ crypto_force_rand_ssleay(void)
RAND_set_rand_method(default_method);
return 1;
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
return 0;
}
diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h
index 8a81a4acdc..a019287aa9 100644
--- a/src/lib/crypt_ops/crypto_rand.h
+++ b/src/lib/crypt_ops/crypto_rand.h
@@ -66,12 +66,37 @@ void crypto_fast_rng_free_(crypto_fast_rng_t *);
unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit);
uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit);
+uint32_t crypto_fast_rng_get_u32(crypto_fast_rng_t *rng);
+uint64_t crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng,
+ uint64_t min, uint64_t max);
double crypto_fast_rng_get_double(crypto_fast_rng_t *rng);
+/**
+ * Using the fast_rng <b>rng</b>, yield true with probability
+ * 1/<b>n</b>. Otherwise yield false.
+ *
+ * <b>n</b> must not be zero.
+ **/
+#define crypto_fast_rng_one_in_n(rng, n) \
+ (0 == (crypto_fast_rng_get_uint((rng), (n))))
+
+crypto_fast_rng_t *get_thread_fast_rng(void);
+
+#ifdef CRYPTO_PRIVATE
+/* These are only used from crypto_init.c */
+void destroy_thread_fast_rng(void);
+void crypto_rand_fast_init(void);
+void crypto_rand_fast_shutdown(void);
+#endif /* defined(CRYPTO_PRIVATE) */
+
#if defined(TOR_UNIT_TESTS)
/* Used for white-box testing */
size_t crypto_fast_rng_get_bytes_used_per_stream(void);
-#endif
+/* For deterministic prng implementations */
+void crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng);
+/* To override the prng for testing. */
+crypto_fast_rng_t *crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng);
+#endif /* defined(TOR_UNIT_TESTS) */
#ifdef CRYPTO_RAND_PRIVATE
diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c
index 34e763bf51..e6ceb42ccb 100644
--- a/src/lib/crypt_ops/crypto_rand_fast.c
+++ b/src/lib/crypt_ops/crypto_rand_fast.c
@@ -33,6 +33,7 @@
*/
#define CRYPTO_RAND_FAST_PRIVATE
+#define CRYPTO_PRIVATE
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_cipher.h"
@@ -41,11 +42,29 @@
#include "lib/intmath/cmp.h"
#include "lib/cc/ctassert.h"
#include "lib/malloc/map_anon.h"
+#include "lib/thread/threads.h"
#include "lib/log/util_bug.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include <string.h>
+#ifdef NOINHERIT_CAN_FAIL
+#define CHECK_PID
+#endif
+
+#ifdef CHECK_PID
+#define PID_FIELD_LEN sizeof(pid_t)
+#else
+#define PID_FIELD_LEN 0
+#endif
+
/* Alias for CRYPTO_FAST_RNG_SEED_LEN to make our code shorter.
*/
#define SEED_LEN (CRYPTO_FAST_RNG_SEED_LEN)
@@ -57,7 +76,7 @@
/* The number of random bytes that we can yield to the user after each
* time we fill a crypto_fast_rng_t's buffer.
*/
-#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN)
+#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN - PID_FIELD_LEN)
/* The number of buffer refills after which we should fetch more
* entropy from crypto_strongest_rand().
@@ -76,10 +95,20 @@ CTASSERT(KEY_BITS == 128 || KEY_BITS == 192 || KEY_BITS == 256);
struct crypto_fast_rng_t {
/** How many more fills does this buffer have before we should mix
- * in the output of crypto_rand()? */
- uint16_t n_till_reseed;
+ * in the output of crypto_strongest_rand()?
+ *
+ * This value may be negative if unit tests are enabled. If so, it
+ * indicates that we should never mix in extra data from
+ * crypto_strongest_rand().
+ */
+ int16_t n_till_reseed;
/** How many bytes are remaining in cbuf.bytes? */
uint16_t bytes_left;
+#ifdef CHECK_PID
+ /** Which process owns this fast_rng? If this value is zero, we do not
+ * need to test the owner. */
+ pid_t owner;
+#endif
struct cbuf {
/** The seed (key and IV) that we will use the next time that we refill
* cbuf. */
@@ -122,24 +151,57 @@ crypto_fast_rng_new(void)
* long.
*
* Note that this object is NOT thread-safe. If you need a thread-safe
- * prng, use crypto_rand(), or wrap this in a mutex.
+ * prng, you should probably look at get_thread_fast_rng(). Alternatively,
+ * use crypto_rand(), wrap this in a mutex.
**/
crypto_fast_rng_t *
crypto_fast_rng_new_from_seed(const uint8_t *seed)
{
+ unsigned inherit = INHERIT_RES_KEEP;
/* We try to allocate this object as securely as we can, to avoid
* having it get dumped, swapped, or shared after fork.
*/
crypto_fast_rng_t *result = tor_mmap_anonymous(sizeof(*result),
- ANONMAP_PRIVATE | ANONMAP_NOINHERIT);
-
+ ANONMAP_PRIVATE | ANONMAP_NOINHERIT,
+ &inherit);
memcpy(result->buf.seed, seed, SEED_LEN);
/* Causes an immediate refill once the user asks for data. */
result->bytes_left = 0;
result->n_till_reseed = RESEED_AFTER;
+#ifdef CHECK_PID
+ if (inherit == INHERIT_RES_KEEP) {
+ /* This value will neither be dropped nor zeroed after fork, so we need to
+ * check our pid to make sure we are not sharing it across a fork. This
+ * can be expensive if the pid value isn't cached, sadly.
+ */
+ result->owner = getpid();
+ }
+#elif defined(_WIN32)
+ /* Windows can't fork(), so there's no need to noinherit. */
+#else
+ /* We decided above that noinherit would always do _something_. Assert here
+ * that we were correct. */
+ tor_assertf(inherit != INHERIT_RES_KEEP,
+ "We failed to create a non-inheritable memory region, even "
+ "though we believed such a failure to be impossible! This is "
+ "probably a bug in Tor support for your platform; please report "
+ "it.");
+#endif /* defined(CHECK_PID) || ... */
return result;
}
+#ifdef TOR_UNIT_TESTS
+/**
+ * Unit tests only: prevent a crypto_fast_rng_t from ever mixing in more
+ * entropy.
+ */
+void
+crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng)
+{
+ rng->n_till_reseed = -1;
+}
+#endif /* defined(TOR_UNIT_TESTS) */
+
/**
* Helper: create a crypto_cipher_t object from SEED_LEN bytes of
* input. The first KEY_LEN bytes are used as the stream cipher's key,
@@ -152,6 +214,26 @@ cipher_from_seed(const uint8_t *seed)
}
/**
+ * Helper: mix additional entropy into <b>rng</b> by using our XOF to mix the
+ * old value for the seed with some additional bytes from
+ * crypto_strongest_rand().
+ **/
+static void
+crypto_fast_rng_add_entopy(crypto_fast_rng_t *rng)
+{
+ crypto_xof_t *xof = crypto_xof_new();
+ crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN);
+ {
+ uint8_t seedbuf[SEED_LEN];
+ crypto_strongest_rand(seedbuf, SEED_LEN);
+ crypto_xof_add_bytes(xof, seedbuf, SEED_LEN);
+ memwipe(seedbuf, 0, SEED_LEN);
+ }
+ crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN);
+ crypto_xof_free(xof);
+}
+
+/**
* Helper: refill the seed bytes and output buffer of <b>rng</b>, using
* the input seed bytes as input (key and IV) for the stream cipher.
*
@@ -161,22 +243,19 @@ cipher_from_seed(const uint8_t *seed)
static void
crypto_fast_rng_refill(crypto_fast_rng_t *rng)
{
- if (rng->n_till_reseed-- == 0) {
- /* It's time to reseed the RNG. We'll do this by using our XOF to mix the
- * old value for the seed with some additional bytes from
- * crypto_strongest_rand(). */
- crypto_xof_t *xof = crypto_xof_new();
- crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN);
- {
- uint8_t seedbuf[SEED_LEN];
- crypto_strongest_rand(seedbuf, SEED_LEN);
- crypto_xof_add_bytes(xof, seedbuf, SEED_LEN);
- memwipe(seedbuf, 0, SEED_LEN);
- }
- crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN);
- crypto_xof_free(xof);
-
+ rng->n_till_reseed--;
+ if (rng->n_till_reseed == 0) {
+ /* It's time to reseed the RNG. */
+ crypto_fast_rng_add_entopy(rng);
rng->n_till_reseed = RESEED_AFTER;
+ } else if (rng->n_till_reseed < 0) {
+#ifdef TOR_UNIT_TESTS
+ /* Reseeding is disabled for testing; never do it on this prng. */
+ rng->n_till_reseed = -1;
+#else
+ /* If testing is disabled, this shouldn't be able to become negative. */
+ tor_assert_unreached();
+#endif /* defined(TOR_UNIT_TESTS) */
}
/* Now fill rng->buf with output from our stream cipher, initialized from
* that seed value. */
@@ -208,6 +287,27 @@ static void
crypto_fast_rng_getbytes_impl(crypto_fast_rng_t *rng, uint8_t *out,
const size_t n)
{
+#ifdef CHECK_PID
+ if (rng->owner) {
+ /* Note that we only need to do this check when we have owner set: that
+ * is, when our attempt to block inheriting failed, and the result was
+ * INHERIT_RES_KEEP.
+ *
+ * If the result was INHERIT_RES_DROP, then any attempt to access the rng
+ * memory after forking will crash.
+ *
+ * If the result was INHERIT_RES_ZERO, then forking will set the bytes_left
+ * and n_till_reseed fields to zero. This function will call
+ * crypto_fast_rng_refill(), which will in turn reseed the PRNG.
+ *
+ * So we only need to do this test in the case when mmap_anonymous()
+ * returned INHERIT_KEEP. We avoid doing it needlessly, since getpid() is
+ * often a system call, and that can be slow.
+ */
+ tor_assert(rng->owner == getpid());
+ }
+#endif /* defined(CHECK_PID) */
+
size_t bytes_to_yield = n;
while (bytes_to_yield) {
@@ -260,4 +360,80 @@ crypto_fast_rng_get_bytes_used_per_stream(void)
{
return BUFLEN;
}
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Thread-local instance for our fast RNG.
+ **/
+static tor_threadlocal_t thread_rng;
+
+/**
+ * Return a per-thread fast RNG, initializing it if necessary.
+ *
+ * You do not need to free this yourself.
+ *
+ * It is NOT safe to share this value across threads.
+ **/
+crypto_fast_rng_t *
+get_thread_fast_rng(void)
+{
+ crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng);
+
+ if (PREDICT_UNLIKELY(rng == NULL)) {
+ rng = crypto_fast_rng_new();
+ tor_threadlocal_set(&thread_rng, rng);
+ }
+
+ return rng;
+}
+
+/**
+ * Used when a thread is exiting: free the per-thread fast RNG if needed.
+ * Invoked from the crypto subsystem's thread-cleanup code.
+ **/
+void
+destroy_thread_fast_rng(void)
+{
+ crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng);
+ if (!rng)
+ return;
+ crypto_fast_rng_free(rng);
+ tor_threadlocal_set(&thread_rng, NULL);
+}
+
+#ifdef TOR_UNIT_TESTS
+/**
+ * Replace the current thread's rng with <b>rng</b>. For use by the
+ * unit tests only. Returns the previous thread rng.
+ **/
+crypto_fast_rng_t *
+crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng)
+{
+ crypto_fast_rng_t *old_rng = tor_threadlocal_get(&thread_rng);
+ tor_threadlocal_set(&thread_rng, rng);
+ return old_rng;
+}
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Initialize the global thread-local key that will be used to keep track
+ * of per-thread fast RNG instances. Called from the crypto subsystem's
+ * initialization code.
+ **/
+void
+crypto_rand_fast_init(void)
+{
+ tor_threadlocal_init(&thread_rng);
+}
+
+/**
+ * Initialize the global thread-local key that will be used to keep track
+ * of per-thread fast RNG instances. Called from the crypto subsystem's
+ * shutdown code.
+ **/
+void
+crypto_rand_fast_shutdown(void)
+{
+ destroy_thread_fast_rng();
+ tor_threadlocal_destroy(&thread_rng);
+}
diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c
index d02c5cdcfa..ffbfa2d56c 100644
--- a/src/lib/crypt_ops/crypto_rand_numeric.c
+++ b/src/lib/crypt_ops/crypto_rand_numeric.c
@@ -155,7 +155,34 @@ crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit)
}
/**
- * As crypto_rand_, but extract the result from a crypto_fast_rng_t.
+ * As crypto_rand_u32, but extract the result from a crypto_fast_rng_t.
+ */
+uint32_t
+crypto_fast_rng_get_u32(crypto_fast_rng_t *rng)
+{
+ uint32_t val;
+ crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val));
+ return val;
+}
+
+/**
+ * As crypto_rand_uint64_range(), but extract the result from a
+ * crypto_fast_rng_t.
+ */
+uint64_t
+crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng,
+ uint64_t min, uint64_t max)
+{
+ /* Handle corrupted input */
+ if (BUG(min >= max)) {
+ return min;
+ }
+
+ return min + crypto_fast_rng_get_uint64(rng, max - min);
+}
+
+/**
+ * As crypto_rand_get_double() but extract the result from a crypto_fast_rng_t.
*/
double
crypto_fast_rng_get_double(crypto_fast_rng_t *rng)
@@ -164,3 +191,4 @@ crypto_fast_rng_get_double(crypto_fast_rng_t *rng)
crypto_fast_rng_getbytes(rng, (void*)&u, sizeof(u));
return ((double)u) / UINT_MAX_AS_DOUBLE;
}
+
diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c
index c9189b0dfc..c39d2e18d1 100644
--- a/src/lib/crypt_ops/crypto_rsa.c
+++ b/src/lib/crypt_ops/crypto_rsa.c
@@ -59,7 +59,7 @@ crypto_get_rsa_padding(int padding)
default: tor_assert(0); return -1; // LCOV_EXCL_LINE
}
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
/** Compare the public-key components of a and b. Return non-zero iff
* a==b. A NULL key is considered to be distinct from all non-NULL
diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h
index c1ea767f85..e9bfec2f85 100644
--- a/src/lib/crypt_ops/crypto_rsa.h
+++ b/src/lib/crypt_ops/crypto_rsa.h
@@ -119,7 +119,7 @@ struct rsa_st *crypto_pk_get_openssl_rsa_(crypto_pk_t *env);
crypto_pk_t *crypto_new_pk_from_openssl_rsa_(struct rsa_st *rsa);
MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_openssl_evp_pkey_,(
crypto_pk_t *env,int private));
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
struct SECKEYPublicKeyStr;
@@ -129,7 +129,7 @@ const struct SECKEYPublicKeyStr *crypto_pk_get_nss_pubkey(
const crypto_pk_t *key);
const struct SECKEYPrivateKeyStr *crypto_pk_get_nss_privkey(
const crypto_pk_t *key);
-#endif
+#endif /* defined(ENABLE_NSS) */
void crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src);
void crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src);
@@ -140,6 +140,6 @@ struct SECItemStr;
STATIC int secitem_uint_cmp(const struct SECItemStr *a,
const struct SECItemStr *b);
#endif
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
-#endif
+#endif /* !defined(TOR_CRYPTO_RSA_H) */
diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c
index ad2ad38b66..612b7a0e64 100644
--- a/src/lib/crypt_ops/crypto_rsa_nss.c
+++ b/src/lib/crypt_ops/crypto_rsa_nss.c
@@ -156,7 +156,7 @@ crypto_pk_get_openssl_evp_pkey_,(crypto_pk_t *pk, int private))
tor_free(buf);
return result;
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
/** Allocate and return storage for a public key. The key itself will not yet
* be set.
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index 42276597d4..5cf98e3e64 100644
--- a/src/lib/crypt_ops/crypto_s2k.c
+++ b/src/lib/crypt_ops/crypto_s2k.c
@@ -285,7 +285,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
if (rv < 0)
return S2K_FAILED;
return (int)key_out_len;
-#else
+#else /* !(defined(ENABLE_OPENSSL)) */
SECItem passItem = { .type = siBuffer,
.data = (unsigned char *) secret,
.len = (int)secret_len };
@@ -325,7 +325,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
if (alg)
SECOID_DestroyAlgorithmID(alg, PR_TRUE);
return rv;
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
}
case S2K_TYPE_SCRYPT: {
diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c
index 67a1a9eb92..5e3f4a87a1 100644
--- a/src/lib/crypt_ops/crypto_util.c
+++ b/src/lib/crypt_ops/crypto_util.c
@@ -30,7 +30,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/crypto.h>
ENABLE_GCC_WARNING(redundant-decls)
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h
index 91d53a0542..7d6d687342 100644
--- a/src/lib/crypt_ops/digestset.h
+++ b/src/lib/crypt_ops/digestset.h
@@ -26,4 +26,4 @@ void digestset_add(digestset_t *set, const char *addr);
int digestset_probably_contains(const digestset_t *set,
const char *addr);
-#endif
+#endif /* !defined(TOR_DIGESTSET_H) */
diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am
index 4730440143..1f58a33d38 100644
--- a/src/lib/crypt_ops/include.am
+++ b/src/lib/crypt_ops/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-crypt-ops-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_crypt_ops_a_SOURCES = \
src/lib/crypt_ops/crypto_cipher.c \
src/lib/crypt_ops/crypto_curve25519.c \
@@ -27,12 +28,14 @@ src_lib_libtor_crypt_ops_a_SOURCES = \
if USE_NSS
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/aes_nss.c \
+ src/lib/crypt_ops/crypto_digest_nss.c \
src/lib/crypt_ops/crypto_dh_nss.c \
src/lib/crypt_ops/crypto_nss_mgt.c \
src/lib/crypt_ops/crypto_rsa_nss.c
else
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/aes_openssl.c \
+ src/lib/crypt_ops/crypto_digest_openssl.c \
src/lib/crypt_ops/crypto_rsa_openssl.c
endif
@@ -50,6 +53,7 @@ src_lib_libtor_crypt_ops_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_crypt_ops_testing_a_CFLAGS = \
$(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/crypt_ops/aes.h \
src/lib/crypt_ops/compat_openssl.h \
diff --git a/src/lib/ctime/include.am b/src/lib/ctime/include.am
index b46c43ba0c..83942ca4e0 100644
--- a/src/lib/ctime/include.am
+++ b/src/lib/ctime/include.am
@@ -11,6 +11,7 @@ else
mulodi4_source=
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_ctime_a_SOURCES = \
$(mulodi4_source) \
src/ext/csiphash.c \
@@ -21,5 +22,6 @@ src_lib_libtor_ctime_testing_a_SOURCES = \
src_lib_libtor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@
src_lib_libtor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/ctime/di_ops.h
diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h
index a2ffbc51c2..b0d1eba0c5 100644
--- a/src/lib/defs/dh_sizes.h
+++ b/src/lib/defs/dh_sizes.h
@@ -19,4 +19,4 @@
/** Length of our legacy DH keys. */
#define DH1024_KEY_LEN (1024/8)
-#endif
+#endif /* !defined(TOR_DH_SIZES_H) */
diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h
index 525e5209d6..a0dd97a74d 100644
--- a/src/lib/defs/digest_sizes.h
+++ b/src/lib/defs/digest_sizes.h
@@ -24,4 +24,4 @@
/** Length of the output of our 64-bit optimized message digests (SHA512). */
#define DIGEST512_LEN 64
-#endif
+#endif /* !defined(TOR_DIGEST_SIZES_H) */
diff --git a/src/lib/defs/include.am b/src/lib/defs/include.am
index 6a7f9114ea..84ee403771 100644
--- a/src/lib/defs/include.am
+++ b/src/lib/defs/include.am
@@ -1,6 +1,8 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/defs/dh_sizes.h \
src/lib/defs/digest_sizes.h \
+ src/lib/defs/logging_types.h \
src/lib/defs/time.h \
src/lib/defs/x25519_sizes.h
diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h
new file mode 100644
index 0000000000..57db818007
--- /dev/null
+++ b/src/lib/defs/logging_types.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file logging_types.h
+ *
+ * \brief Global definition for types used by logging systems.
+ **/
+
+#ifndef TOR_LOGGING_TYPES_H
+#define TOR_LOGGING_TYPES_H
+
+/* We define this here so that it can be used both by backtrace.h and
+ * log.h.
+ */
+
+/** Mask of zero or more log domains, OR'd together. */
+typedef uint64_t log_domain_mask_t;
+
+#endif
diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h
index c25f5022c5..459afbf42d 100644
--- a/src/lib/defs/time.h
+++ b/src/lib/defs/time.h
@@ -20,4 +20,4 @@
/* How many nanoseconds per millisecond */
#define TOR_NSEC_PER_MSEC (1000*1000)
-#endif
+#endif /* !defined(TOR_TIME_DEFS_H) */
diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h
index 8933a8866b..6431f0a2dd 100644
--- a/src/lib/defs/x25519_sizes.h
+++ b/src/lib/defs/x25519_sizes.h
@@ -33,4 +33,4 @@
#define ED25519_BASE64_LEN 43
#define ED25519_SIG_BASE64_LEN 86
-#endif
+#endif /* !defined(TOR_X25519_SIZES_H) */
diff --git a/src/lib/dispatch/.may_include b/src/lib/dispatch/.may_include
new file mode 100644
index 0000000000..884f4c0dbc
--- /dev/null
+++ b/src/lib/dispatch/.may_include
@@ -0,0 +1,11 @@
+orconfig.h
+
+ext/tor_queue.h
+
+lib/cc/*.h
+lib/container/*.h
+lib/dispatch/*.h
+lib/intmath/*.h
+lib/log/*.h
+lib/malloc/*.h
+lib/testsupport/*.h \ No newline at end of file
diff --git a/src/lib/dispatch/dispatch.h b/src/lib/dispatch/dispatch.h
new file mode 100644
index 0000000000..a9e655409a
--- /dev/null
+++ b/src/lib/dispatch/dispatch.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_DISPATCH_H
+#define TOR_DISPATCH_H
+
+#include "lib/dispatch/msgtypes.h"
+
+/**
+ * \file dispatch.h
+ * \brief Low-level APIs for message-passing system.
+ *
+ * This module implements message dispatch based on a set of short integer
+ * identifiers. For a higher-level interface, see pubsub.h.
+ *
+ * Each message is represented as a generic msg_t object, and is discriminated
+ * by its message_id_t. Messages are delivered by a dispatch_t object, which
+ * delivers each message to its recipients by a configured "channel".
+ *
+ * A "channel" is a means of delivering messages. Every message_id_t must
+ * be associated with exactly one channel, identified by channel_id_t.
+ * When a channel receives messages, a callback is invoked to either process
+ * the messages immediately, or to cause them to be processed later.
+ *
+ * Every message_id_t has zero or more associated receiver functions set up in
+ * the dispatch_t object. Once the dispatch_t object is created, receivers
+ * can be enabled or disabled [TODO], but not added or removed.
+ *
+ * Every message_id_t has an associated datatype, identified by a
+ * msg_type_id_t. These datatypes can be associated with functions to
+ * (for example) free them, or format them for debugging.
+ *
+ * To setup a dispatch_t object, first create a dispatch_cfg_t object, and
+ * configure messages with their types, channels, and receivers. Then, use
+ * dispatch_new() with that dispatch_cfg_t to create the dispatch_t object.
+ *
+ * (We use a two-phase contruction procedure here to enable better static
+ * reasoning about publish/subscribe relationships.)
+ *
+ * Once you have a dispatch_t, you can queue messages on it with
+ * dispatch_send*(), and cause those messages to be delivered with
+ * dispatch_flush().
+ **/
+
+/**
+ * A "dispatcher" is the highest-level object; it handles making sure that
+ * messages are received and delivered properly. Only the mainloop
+ * should handle this type directly.
+ */
+typedef struct dispatch_t dispatch_t;
+
+struct dispatch_cfg_t;
+
+dispatch_t *dispatch_new(const struct dispatch_cfg_t *cfg);
+
+/**
+ * Free a dispatcher. Tor does this at exit.
+ */
+#define dispatch_free(d) \
+ FREE_AND_NULL(dispatch_t, dispatch_free_, (d))
+
+void dispatch_free_(dispatch_t *);
+
+int dispatch_send(dispatch_t *d,
+ subsys_id_t sender,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ msg_aux_data_t auxdata);
+
+int dispatch_send_msg(dispatch_t *d, msg_t *m);
+
+int dispatch_send_msg_unchecked(dispatch_t *d, msg_t *m);
+
+/* Flush up to <b>max_msgs</b> currently pending messages from the
+ * dispatcher. Messages that are not pending when this function are
+ * called, are not flushed by this call. Return 0 on success, -1 on
+ * unrecoverable error.
+ */
+int dispatch_flush(dispatch_t *, channel_id_t chan, int max_msgs);
+
+/**
+ * Function callback type used to alert some other module when a channel's
+ * queue changes from empty to nonempty.
+ *
+ * Ex 1: To cause messages to be processed immediately on-stack, this callback
+ * should invoke dispatch_flush() directly.
+ *
+ * Ex 2: To cause messages to be processed very soon, from the event queue,
+ * this callback should schedule an event callback to run dispatch_flush().
+ *
+ * Ex 3: To cause messages to be processed periodically, this function should
+ * do nothing, and a periodic event should invoke dispatch_flush().
+ **/
+typedef void (*dispatch_alertfn_t)(struct dispatch_t *,
+ channel_id_t, void *);
+
+int dispatch_set_alert_fn(dispatch_t *d, channel_id_t chan,
+ dispatch_alertfn_t fn, void *userdata);
+
+#define dispatch_free_msg(d,msg) \
+ STMT_BEGIN { \
+ msg_t **msg_tmp_ptr__ = &(msg); \
+ dispatch_free_msg_((d), *msg_tmp_ptr__); \
+ *msg_tmp_ptr__= NULL; \
+ } STMT_END
+void dispatch_free_msg_(const dispatch_t *d, msg_t *msg);
+
+char *dispatch_fmt_msg_data(const dispatch_t *d, const msg_t *msg);
+
+#endif /* !defined(TOR_DISPATCH_H) */
diff --git a/src/lib/dispatch/dispatch_cfg.c b/src/lib/dispatch/dispatch_cfg.c
new file mode 100644
index 0000000000..b3a72ec22f
--- /dev/null
+++ b/src/lib/dispatch/dispatch_cfg.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file dispatch_cfg.c
+ * \brief Create and configure a dispatch_cfg_t.
+ *
+ * A dispatch_cfg_t object is used to configure a set of messages and
+ * associated information before creating a dispatch_t.
+ */
+
+#define DISPATCH_PRIVATE
+
+#include "orconfig.h"
+#include "lib/dispatch/dispatch_cfg.h"
+#include "lib/dispatch/dispatch_cfg_st.h"
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_st.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/malloc/malloc.h"
+
+/**
+ * Create and return a new dispatch_cfg_t.
+ **/
+dispatch_cfg_t *
+dcfg_new(void)
+{
+ dispatch_cfg_t *cfg = tor_malloc(sizeof(dispatch_cfg_t));
+ cfg->type_by_msg = smartlist_new();
+ cfg->chan_by_msg = smartlist_new();
+ cfg->fns_by_type = smartlist_new();
+ cfg->recv_by_msg = smartlist_new();
+ return cfg;
+}
+
+/**
+ * Associate a message with a datatype. Return 0 on success, -1 if a
+ * different type was previously associated with the message ID.
+ **/
+int
+dcfg_msg_set_type(dispatch_cfg_t *cfg, message_id_t msg,
+ msg_type_id_t type)
+{
+ smartlist_grow(cfg->type_by_msg, msg+1);
+ msg_type_id_t *oldval = smartlist_get(cfg->type_by_msg, msg);
+ if (oldval != NULL && *oldval != type) {
+ return -1;
+ }
+ if (!oldval)
+ smartlist_set(cfg->type_by_msg, msg, tor_memdup(&type, sizeof(type)));
+ return 0;
+}
+
+/**
+ * Associate a message with a channel. Return 0 on success, -1 if a
+ * different channel was previously associated with the message ID.
+ **/
+int
+dcfg_msg_set_chan(dispatch_cfg_t *cfg, message_id_t msg,
+ channel_id_t chan)
+{
+ smartlist_grow(cfg->chan_by_msg, msg+1);
+ channel_id_t *oldval = smartlist_get(cfg->chan_by_msg, msg);
+ if (oldval != NULL && *oldval != chan) {
+ return -1;
+ }
+ if (!oldval)
+ smartlist_set(cfg->chan_by_msg, msg, tor_memdup(&chan, sizeof(chan)));
+ return 0;
+}
+
+/**
+ * Associate a set of functions with a datatype. Return 0 on success, -1 if
+ * different functions were previously associated with the type.
+ **/
+int
+dcfg_type_set_fns(dispatch_cfg_t *cfg, msg_type_id_t type,
+ const dispatch_typefns_t *fns)
+{
+ smartlist_grow(cfg->fns_by_type, type+1);
+ dispatch_typefns_t *oldfns = smartlist_get(cfg->fns_by_type, type);
+ if (oldfns && (oldfns->free_fn != fns->free_fn ||
+ oldfns->fmt_fn != fns->fmt_fn))
+ return -1;
+ if (!oldfns)
+ smartlist_set(cfg->fns_by_type, type, tor_memdup(fns, sizeof(*fns)));
+ return 0;
+}
+
+/**
+ * Associate a receiver with a message ID. Multiple receivers may be
+ * associated with a single messasge ID.
+ *
+ * Return 0 on success, on failure.
+ **/
+int
+dcfg_add_recv(dispatch_cfg_t *cfg, message_id_t msg,
+ subsys_id_t sys, recv_fn_t fn)
+{
+ smartlist_grow(cfg->recv_by_msg, msg+1);
+ smartlist_t *receivers = smartlist_get(cfg->recv_by_msg, msg);
+ if (!receivers) {
+ receivers = smartlist_new();
+ smartlist_set(cfg->recv_by_msg, msg, receivers);
+ }
+
+ dispatch_rcv_t *rcv = tor_malloc(sizeof(dispatch_rcv_t));
+ rcv->sys = sys;
+ rcv->enabled = true;
+ rcv->fn = fn;
+ smartlist_add(receivers, (void*)rcv);
+ return 0;
+}
+
+/** Helper: release all storage held by <b>cfg</b>. */
+void
+dcfg_free_(dispatch_cfg_t *cfg)
+{
+ if (!cfg)
+ return;
+
+ SMARTLIST_FOREACH(cfg->type_by_msg, msg_type_id_t *, id, tor_free(id));
+ SMARTLIST_FOREACH(cfg->chan_by_msg, channel_id_t *, id, tor_free(id));
+ SMARTLIST_FOREACH(cfg->fns_by_type, dispatch_typefns_t *, f, tor_free(f));
+ smartlist_free(cfg->type_by_msg);
+ smartlist_free(cfg->chan_by_msg);
+ smartlist_free(cfg->fns_by_type);
+ SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, receivers) {
+ if (!receivers)
+ continue;
+ SMARTLIST_FOREACH(receivers, dispatch_rcv_t *, rcv, tor_free(rcv));
+ smartlist_free(receivers);
+ } SMARTLIST_FOREACH_END(receivers);
+ smartlist_free(cfg->recv_by_msg);
+
+ tor_free(cfg);
+}
diff --git a/src/lib/dispatch/dispatch_cfg.h b/src/lib/dispatch/dispatch_cfg.h
new file mode 100644
index 0000000000..348dce8d40
--- /dev/null
+++ b/src/lib/dispatch/dispatch_cfg.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_DISPATCH_CFG_H
+#define TOR_DISPATCH_CFG_H
+
+#include "lib/dispatch/msgtypes.h"
+#include "lib/testsupport/testsupport.h"
+
+/**
+ * A "dispatch_cfg" is the configuration used to set up a dispatcher.
+ * It is created and accessed with a set of dcfg_* functions, and then
+ * used with dispatcher_new() to make the dispatcher.
+ */
+typedef struct dispatch_cfg_t dispatch_cfg_t;
+
+dispatch_cfg_t *dcfg_new(void);
+
+int dcfg_msg_set_type(dispatch_cfg_t *cfg, message_id_t msg,
+ msg_type_id_t type);
+
+int dcfg_msg_set_chan(dispatch_cfg_t *cfg, message_id_t msg,
+ channel_id_t chan);
+
+int dcfg_type_set_fns(dispatch_cfg_t *cfg, msg_type_id_t type,
+ const dispatch_typefns_t *fns);
+
+int dcfg_add_recv(dispatch_cfg_t *cfg, message_id_t msg,
+ subsys_id_t sys, recv_fn_t fn);
+
+/** Free a dispatch_cfg_t. */
+#define dcfg_free(cfg) \
+ FREE_AND_NULL(dispatch_cfg_t, dcfg_free_, (cfg))
+
+void dcfg_free_(dispatch_cfg_t *cfg);
+
+#ifdef DISPATCH_NEW_PRIVATE
+struct smartlist_t;
+STATIC int max_in_u16_sl(const struct smartlist_t *sl, int dflt);
+#endif
+
+#endif /* !defined(TOR_DISPATCH_CFG_H) */
diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h
new file mode 100644
index 0000000000..57b6f0347f
--- /dev/null
+++ b/src/lib/dispatch/dispatch_cfg_st.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_DISPATCH_CFG_ST_H
+#define TOR_DISPATCH_CFG_ST_H
+
+struct smartlist_t;
+
+/* Information needed to create a dispatcher, but in a less efficient, more
+ * mutable format. */
+struct dispatch_cfg_t {
+ /** A list of msg_type_id_t (cast to void*), indexed by msg_t. */
+ struct smartlist_t *type_by_msg;
+ /** A list of channel_id_t (cast to void*), indexed by msg_t. */
+ struct smartlist_t *chan_by_msg;
+ /** A list of dispatch_rcv_t, indexed by msg_type_id_t. */
+ struct smartlist_t *fns_by_type;
+ /** A list of dispatch_typefns_t, indexed by msg_t. */
+ struct smartlist_t *recv_by_msg;
+};
+
+#endif /* !defined(TOR_DISPATCH_CFG_ST_H) */
diff --git a/src/lib/dispatch/dispatch_core.c b/src/lib/dispatch/dispatch_core.c
new file mode 100644
index 0000000000..da54f9b437
--- /dev/null
+++ b/src/lib/dispatch/dispatch_core.c
@@ -0,0 +1,260 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file dispatch_core.c
+ * \brief Core module for sending and receiving messages.
+ */
+
+#define DISPATCH_PRIVATE
+#include "orconfig.h"
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_st.h"
+#include "lib/dispatch/dispatch_naming.h"
+
+#include "lib/malloc/malloc.h"
+#include "lib/log/util_bug.h"
+
+#include <string.h>
+
+/**
+ * Use <b>d</b> to drop all storage held for <b>msg</b>.
+ *
+ * (We need the dispatcher so we know how to free the auxiliary data.)
+ **/
+void
+dispatch_free_msg_(const dispatch_t *d, msg_t *msg)
+{
+ if (!msg)
+ return;
+
+ d->typefns[msg->type].free_fn(msg->aux_data__);
+ tor_free(msg);
+}
+
+/**
+ * Format the auxiliary data held by msg.
+ **/
+char *
+dispatch_fmt_msg_data(const dispatch_t *d, const msg_t *msg)
+{
+ if (!msg)
+ return NULL;
+
+ return d->typefns[msg->type].fmt_fn(msg->aux_data__);
+}
+
+/**
+ * Release all storage held by <b>d</b>.
+ **/
+void
+dispatch_free_(dispatch_t *d)
+{
+ if (d == NULL)
+ return;
+
+ size_t n_queues = d->n_queues;
+ for (size_t i = 0; i < n_queues; ++i) {
+ msg_t *m, *mtmp;
+ TOR_SIMPLEQ_FOREACH_SAFE(m, &d->queues[i].queue, next, mtmp) {
+ dispatch_free_msg(d, m);
+ }
+ }
+
+ size_t n_msgs = d->n_msgs;
+
+ for (size_t i = 0; i < n_msgs; ++i) {
+ tor_free(d->table[i]);
+ }
+ tor_free(d->table);
+ tor_free(d->typefns);
+ tor_free(d->queues);
+
+ // This is the only time we will treat d->cfg as non-const.
+ //dispatch_cfg_free_((dispatch_items_t *) d->cfg);
+
+ tor_free(d);
+}
+
+/**
+ * Tell the dispatcher to call <b>fn</b> with <b>userdata</b> whenever
+ * <b>chan</b> becomes nonempty. Return 0 on success, -1 on error.
+ **/
+int
+dispatch_set_alert_fn(dispatch_t *d, channel_id_t chan,
+ dispatch_alertfn_t fn, void *userdata)
+{
+ if (BUG(chan >= d->n_queues))
+ return -1;
+
+ dqueue_t *q = &d->queues[chan];
+ q->alert_fn = fn;
+ q->alert_fn_arg = userdata;
+ return 0;
+}
+
+/**
+ * Send a message on the appropriate channel notifying that channel if
+ * necessary.
+ *
+ * This function takes ownership of the auxiliary data; it can't be static or
+ * stack-allocated, and the caller is not allowed to use it afterwards.
+ *
+ * This function does not check the various vields of the message object for
+ * consistency.
+ **/
+int
+dispatch_send(dispatch_t *d,
+ subsys_id_t sender,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ msg_aux_data_t auxdata)
+{
+ if (!d->table[msg]) {
+ /* Fast path: nobody wants this data. */
+
+ d->typefns[type].free_fn(auxdata);
+ return 0;
+ }
+
+ msg_t *m = tor_malloc(sizeof(msg_t));
+
+ m->sender = sender;
+ m->channel = channel;
+ m->msg = msg;
+ m->type = type;
+ memcpy(&m->aux_data__, &auxdata, sizeof(msg_aux_data_t));
+
+ return dispatch_send_msg(d, m);
+}
+
+int
+dispatch_send_msg(dispatch_t *d, msg_t *m)
+{
+ if (BUG(!d))
+ goto err;
+ if (BUG(!m))
+ goto err;
+ if (BUG(m->channel >= d->n_queues))
+ goto err;
+ if (BUG(m->msg >= d->n_msgs))
+ goto err;
+
+ dtbl_entry_t *ent = d->table[m->msg];
+ if (ent) {
+ if (BUG(m->type != ent->type))
+ goto err;
+ if (BUG(m->channel != ent->channel))
+ goto err;
+ }
+
+ return dispatch_send_msg_unchecked(d, m);
+ err:
+ /* Probably it isn't safe to free m, since type could be wrong. */
+ return -1;
+}
+
+/**
+ * Send a message on the appropriate queue, notifying that queue if necessary.
+ *
+ * This function takes ownership of the message object and its auxiliary data;
+ * it can't be static or stack-allocated, and the caller isn't allowed to use
+ * it afterwards.
+ *
+ * This function does not check the various fields of the message object for
+ * consistency, and can crash if they are out of range. Only functions that
+ * have already constructed the message in a safe way, or checked it for
+ * correctness themselves, should call this function.
+ **/
+int
+dispatch_send_msg_unchecked(dispatch_t *d, msg_t *m)
+{
+ /* Find the right queue. */
+ dqueue_t *q = &d->queues[m->channel];
+ bool was_empty = TOR_SIMPLEQ_EMPTY(&q->queue);
+
+ /* Append the message. */
+ TOR_SIMPLEQ_INSERT_TAIL(&q->queue, m, next);
+
+ if (debug_logging_enabled()) {
+ char *arg = dispatch_fmt_msg_data(d, m);
+ log_debug(LD_MESG,
+ "Queued: %s (%s) from %s, on %s.",
+ get_message_id_name(m->msg),
+ arg,
+ get_subsys_id_name(m->sender),
+ get_channel_id_name(m->channel));
+ tor_free(arg);
+ }
+
+ /* If we just made the queue nonempty for the first time, call the alert
+ * function. */
+ if (was_empty) {
+ q->alert_fn(d, m->channel, q->alert_fn_arg);
+ }
+
+ return 0;
+}
+
+/**
+ * Run all of the callbacks on <b>d</b> associated with <b>m</b>.
+ **/
+static void
+dispatcher_run_msg_cbs(const dispatch_t *d, msg_t *m)
+{
+ tor_assert(m->msg <= d->n_msgs);
+ dtbl_entry_t *ent = d->table[m->msg];
+ int n_fns = ent->n_fns;
+
+ if (debug_logging_enabled()) {
+ char *arg = dispatch_fmt_msg_data(d, m);
+ log_debug(LD_MESG,
+ "Delivering: %s (%s) from %s, on %s:",
+ get_message_id_name(m->msg),
+ arg,
+ get_subsys_id_name(m->sender),
+ get_channel_id_name(m->channel));
+ tor_free(arg);
+ }
+
+ int i;
+ for (i=0; i < n_fns; ++i) {
+ if (ent->rcv[i].enabled) {
+ log_debug(LD_MESG, " Delivering to %s.",
+ get_subsys_id_name(ent->rcv[i].sys));
+ ent->rcv[i].fn(m);
+ }
+ }
+}
+
+/**
+ * Run up to <b>max_msgs</b> callbacks for messages on the channel <b>ch</b>
+ * on the given dispatcher. Return 0 on success or recoverable failure,
+ * -1 on unrecoverable error.
+ **/
+int
+dispatch_flush(dispatch_t *d, channel_id_t ch, int max_msgs)
+{
+ if (BUG(ch >= d->n_queues))
+ return 0;
+
+ int n_flushed = 0;
+ dqueue_t *q = &d->queues[ch];
+
+ while (n_flushed < max_msgs) {
+ msg_t *m = TOR_SIMPLEQ_FIRST(&q->queue);
+ if (!m)
+ break;
+ TOR_SIMPLEQ_REMOVE_HEAD(&q->queue, next);
+ dispatcher_run_msg_cbs(d, m);
+ dispatch_free_msg(d, m);
+ ++n_flushed;
+ }
+
+ return 0;
+}
diff --git a/src/lib/dispatch/dispatch_naming.c b/src/lib/dispatch/dispatch_naming.c
new file mode 100644
index 0000000000..83d9a2d604
--- /dev/null
+++ b/src/lib/dispatch/dispatch_naming.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#include "lib/cc/compat_compiler.h"
+
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/dispatch/msgtypes.h"
+
+#include "lib/container/namemap.h"
+#include "lib/container/namemap_st.h"
+
+#include "lib/log/util_bug.h"
+#include "lib/log/log.h"
+
+#include <stdlib.h>
+
+/** Global namemap for message IDs. */
+static namemap_t message_id_map = NAMEMAP_INIT();
+/** Global namemap for subsystem IDs. */
+static namemap_t subsys_id_map = NAMEMAP_INIT();
+/** Global namemap for channel IDs. */
+static namemap_t channel_id_map = NAMEMAP_INIT();
+/** Global namemap for message type IDs. */
+static namemap_t msg_type_id_map = NAMEMAP_INIT();
+
+void
+dispatch_naming_init(void)
+{
+}
+
+/* Helper macro: declare functions to map IDs to and from names for a given
+ * type in a namemap_t.
+ */
+#define DECLARE_ID_MAP_FNS(type) \
+ type##_id_t \
+ get_##type##_id(const char *name) \
+ { \
+ unsigned u = namemap_get_or_create_id(&type##_id_map, name); \
+ tor_assert(u != NAMEMAP_ERR); \
+ tor_assert(u != ERROR_ID); \
+ return (type##_id_t) u; \
+ } \
+ const char * \
+ get_##type##_id_name(type##_id_t id) \
+ { \
+ return namemap_fmt_name(&type##_id_map, id); \
+ } \
+ size_t \
+ get_num_##type##_ids(void) \
+ { \
+ return namemap_get_size(&type##_id_map); \
+ } \
+ EAT_SEMICOLON
+
+DECLARE_ID_MAP_FNS(message);
+DECLARE_ID_MAP_FNS(channel);
+DECLARE_ID_MAP_FNS(subsys);
+DECLARE_ID_MAP_FNS(msg_type);
diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h
new file mode 100644
index 0000000000..fd6c83cc12
--- /dev/null
+++ b/src/lib/dispatch/dispatch_naming.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_DISPATCH_NAMING_H
+#define TOR_DISPATCH_NAMING_H
+
+#include "lib/dispatch/msgtypes.h"
+#include <stddef.h>
+
+/**
+ * Return an existing channel ID by name, allocating the channel ID if
+ * if necessary. Returns ERROR_ID if we have run out of
+ * channels
+ */
+channel_id_t get_channel_id(const char *);
+/**
+ * Return the name corresponding to a given channel ID.
+ **/
+const char *get_channel_id_name(channel_id_t);
+/**
+ * Return the total number of _named_ channel IDs.
+ **/
+size_t get_num_channel_ids(void);
+
+/* As above, but for messages. */
+message_id_t get_message_id(const char *);
+const char *get_message_id_name(message_id_t);
+size_t get_num_message_ids(void);
+
+/* As above, but for subsystems */
+subsys_id_t get_subsys_id(const char *);
+const char *get_subsys_id_name(subsys_id_t);
+size_t get_num_subsys_ids(void);
+
+/* As above, but for types. Note that types additionally must be
+ * "defined", if any message is to use them. */
+msg_type_id_t get_msg_type_id(const char *);
+const char *get_msg_type_id_name(msg_type_id_t);
+size_t get_num_msg_type_ids(void);
+
+void dispatch_naming_init(void);
+
+#endif /* !defined(TOR_DISPATCH_NAMING_H) */
diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c
new file mode 100644
index 0000000000..d8e59d610a
--- /dev/null
+++ b/src/lib/dispatch/dispatch_new.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file dispatch_new.c
+ * \brief Code to construct a dispatch_t from a dispatch_cfg_t.
+ **/
+
+#define DISPATCH_NEW_PRIVATE
+#define DISPATCH_PRIVATE
+#include "orconfig.h"
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_st.h"
+#include "lib/dispatch/dispatch_cfg.h"
+#include "lib/dispatch/dispatch_cfg_st.h"
+
+#include "lib/cc/ctassert.h"
+#include "lib/intmath/cmp.h"
+#include "lib/malloc/malloc.h"
+#include "lib/log/util_bug.h"
+
+#include <string.h>
+
+/** Given a smartlist full of (possibly NULL) pointers to uint16_t values,
+ * return the largest value, or dflt if the list is empty. */
+STATIC int
+max_in_u16_sl(const smartlist_t *sl, int dflt)
+{
+ uint16_t *maxptr = NULL;
+ SMARTLIST_FOREACH_BEGIN(sl, uint16_t *, u) {
+ if (!maxptr)
+ maxptr = u;
+ else if (u && *u > *maxptr)
+ maxptr = u;
+ } SMARTLIST_FOREACH_END(u);
+
+ return maxptr ? *maxptr : dflt;
+}
+
+/* The above function is only safe to call if we are sure that channel_id_t
+ * and msg_type_id_t are really uint16_t. They should be so defined in
+ * msgtypes.h, but let's be extra cautious.
+ */
+CTASSERT(sizeof(uint16_t) == sizeof(msg_type_id_t));
+CTASSERT(sizeof(uint16_t) == sizeof(channel_id_t));
+
+/** Helper: Format an unformattable message auxiliary data item: just return a
+* copy of the string <>. */
+static char *
+type_fmt_nop(msg_aux_data_t arg)
+{
+ (void)arg;
+ return tor_strdup("<>");
+}
+
+/** Helper: Free an unfreeable message auxiliary data item: do nothing. */
+static void
+type_free_nop(msg_aux_data_t arg)
+{
+ (void)arg;
+}
+
+/** Type functions to use when no type functions are provided. */
+static dispatch_typefns_t nop_typefns = {
+ .free_fn = type_free_nop,
+ .fmt_fn = type_fmt_nop
+};
+
+/**
+ * Alert function to use when none is configured: do nothing.
+ **/
+static void
+alert_fn_nop(dispatch_t *d, channel_id_t ch, void *arg)
+{
+ (void)d;
+ (void)ch;
+ (void)arg;
+}
+
+/**
+ * Given a list of recvfn_t, create and return a new dtbl_entry_t mapping
+ * to each of those functions.
+ **/
+static dtbl_entry_t *
+dtbl_entry_from_lst(smartlist_t *receivers)
+{
+ if (!receivers)
+ return NULL;
+
+ size_t n_recv = smartlist_len(receivers);
+ dtbl_entry_t *ent;
+ ent = tor_malloc_zero(offsetof(dtbl_entry_t, rcv) +
+ sizeof(dispatch_rcv_t) * n_recv);
+
+ ent->n_fns = n_recv;
+
+ SMARTLIST_FOREACH_BEGIN(receivers, const dispatch_rcv_t *, rcv) {
+ memcpy(&ent->rcv[rcv_sl_idx], rcv, sizeof(*rcv));
+ if (rcv->enabled) {
+ ++ent->n_enabled;
+ }
+ } SMARTLIST_FOREACH_END(rcv);
+
+ return ent;
+}
+
+/** Create and return a new dispatcher from a given dispatch_cfg_t. */
+dispatch_t *
+dispatch_new(const dispatch_cfg_t *cfg)
+{
+ dispatch_t *d = tor_malloc_zero(sizeof(dispatch_t));
+
+ /* Any message that has a type or a receiver counts towards our messages */
+ const size_t n_msgs = MAX(smartlist_len(cfg->type_by_msg),
+ smartlist_len(cfg->recv_by_msg)) + 1;
+
+ /* Any channel that any message has counts towards the number of channels. */
+ const size_t n_chans = (size_t)
+ MAX(1, max_in_u16_sl(cfg->chan_by_msg,0)) + 1;
+
+ /* Any type that a message has, or that has functions, counts towards
+ * the number of types. */
+ const size_t n_types = (size_t) MAX(max_in_u16_sl(cfg->type_by_msg,0),
+ smartlist_len(cfg->fns_by_type)) + 1;
+
+ d->n_msgs = n_msgs;
+ d->n_queues = n_chans;
+ d->n_types = n_types;
+
+ /* Initialize the array of type-functions. */
+ d->typefns = tor_calloc(n_types, sizeof(dispatch_typefns_t));
+ for (size_t i = 0; i < n_types; ++i) {
+ /* Default to no-op for everything... */
+ memcpy(&d->typefns[i], &nop_typefns, sizeof(dispatch_typefns_t));
+ }
+ SMARTLIST_FOREACH_BEGIN(cfg->fns_by_type, dispatch_typefns_t *, fns) {
+ /* Set the functions if they are provided. */
+ if (fns) {
+ if (fns->free_fn)
+ d->typefns[fns_sl_idx].free_fn = fns->free_fn;
+ if (fns->fmt_fn)
+ d->typefns[fns_sl_idx].fmt_fn = fns->fmt_fn;
+ }
+ } SMARTLIST_FOREACH_END(fns);
+
+ /* Initialize the message queues: one for each channel. */
+ d->queues = tor_calloc(d->n_queues, sizeof(dqueue_t));
+ for (size_t i = 0; i < d->n_queues; ++i) {
+ TOR_SIMPLEQ_INIT(&d->queues[i].queue);
+ d->queues[i].alert_fn = alert_fn_nop;
+ }
+
+ /* Build the dispatch tables mapping message IDs to receivers. */
+ d->table = tor_calloc(d->n_msgs, sizeof(dtbl_entry_t *));
+ SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, rcv) {
+ d->table[rcv_sl_idx] = dtbl_entry_from_lst(rcv);
+ } SMARTLIST_FOREACH_END(rcv);
+
+ /* Fill in the empty entries in the dispatch tables:
+ * types and channels for each message. */
+ SMARTLIST_FOREACH_BEGIN(cfg->type_by_msg, msg_type_id_t *, type) {
+ if (d->table[type_sl_idx])
+ d->table[type_sl_idx]->type = *type;
+ } SMARTLIST_FOREACH_END(type);
+
+ SMARTLIST_FOREACH_BEGIN(cfg->chan_by_msg, channel_id_t *, chan) {
+ if (d->table[chan_sl_idx])
+ d->table[chan_sl_idx]->channel = *chan;
+ } SMARTLIST_FOREACH_END(chan);
+
+ return d;
+}
diff --git a/src/lib/dispatch/dispatch_st.h b/src/lib/dispatch/dispatch_st.h
new file mode 100644
index 0000000000..ee42518b5a
--- /dev/null
+++ b/src/lib/dispatch/dispatch_st.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file dispatch_st.h
+ *
+ * \brief private structures used for the dispatcher module
+ */
+
+#ifndef TOR_DISPATCH_ST_H
+#define TOR_DISPATCH_ST_H
+
+#ifdef DISPATCH_PRIVATE
+
+#include "lib/container/smartlist.h"
+
+/**
+ * Information about the recipient of a message.
+ **/
+typedef struct dispatch_rcv_t {
+ /** The subsystem receiving a message. */
+ subsys_id_t sys;
+ /** True iff this recipient is enabled. */
+ bool enabled;
+ /** The function that will handle the message. */
+ recv_fn_t fn;
+} dispatch_rcv_t;
+
+/**
+ * Information used by a dispatcher to handle and dispatch a single message
+ * ID. It maps that message ID to its type, channel, and list of receiver
+ * functions.
+ *
+ * This structure is used when the dispatcher is running.
+ **/
+typedef struct dtbl_entry_t {
+ /** The number of enabled non-stub subscribers for this message.
+ *
+ * Note that for now, this will be the same as <b>n_fns</b>, since there is
+ * no way to turn these subscribers on an off yet. */
+ uint16_t n_enabled;
+ /** The channel that handles this message. */
+ channel_id_t channel;
+ /** The associated C type for this message. */
+ msg_type_id_t type;
+ /**
+ * The number of functions pointers for subscribers that receive this
+ * message, in rcv. */
+ uint16_t n_fns;
+ /**
+ * The recipients for this message.
+ */
+ dispatch_rcv_t rcv[FLEXIBLE_ARRAY_MEMBER];
+} dtbl_entry_t;
+
+/**
+ * A queue of messages for a given channel, used by a live dispatcher.
+ */
+typedef struct dqueue_t {
+ /** The queue of messages itself. */
+ TOR_SIMPLEQ_HEAD( , msg_t) queue;
+ /** A function to be called when the queue becomes nonempty. */
+ dispatch_alertfn_t alert_fn;
+ /** An argument for the alert_fn. */
+ void *alert_fn_arg;
+} dqueue_t ;
+
+/**
+ * A single dispatcher for cross-module messages.
+ */
+struct dispatch_t {
+ /**
+ * The length of <b>table</b>: the number of message IDs that this
+ * dispatcher can handle.
+ */
+ size_t n_msgs;
+ /**
+ * The length of <b>queues</b>: the number of channels that this dispatcher
+ * has configured.
+ */
+ size_t n_queues;
+ /**
+ * The length of <b>typefns</b>: the number of C type IDs that this
+ * dispatcher has configured.
+ */
+ size_t n_types;
+ /**
+ * An array of message queues, indexed by channel ID.
+ */
+ dqueue_t *queues;
+ /**
+ * An array of entries about how to handle particular message types, indexed
+ * by message ID.
+ */
+ dtbl_entry_t **table;
+ /**
+ * An array of function tables for manipulating types, index by message
+ * type ID.
+ **/
+ dispatch_typefns_t *typefns;
+};
+
+#endif /* defined(DISPATCH_PRIVATE) */
+
+#endif /* !defined(TOR_DISPATCH_ST_H) */
diff --git a/src/lib/dispatch/include.am b/src/lib/dispatch/include.am
new file mode 100644
index 0000000000..4a0e0dfd90
--- /dev/null
+++ b/src/lib/dispatch/include.am
@@ -0,0 +1,27 @@
+
+noinst_LIBRARIES += src/lib/libtor-dispatch.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-dispatch-testing.a
+endif
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+src_lib_libtor_dispatch_a_SOURCES = \
+ src/lib/dispatch/dispatch_cfg.c \
+ src/lib/dispatch/dispatch_core.c \
+ src/lib/dispatch/dispatch_naming.c \
+ src/lib/dispatch/dispatch_new.c
+
+src_lib_libtor_dispatch_testing_a_SOURCES = \
+ $(src_lib_libtor_dispatch_a_SOURCES)
+src_lib_libtor_dispatch_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_dispatch_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/lib/dispatch/dispatch.h \
+ src/lib/dispatch/dispatch_cfg.h \
+ src/lib/dispatch/dispatch_cfg_st.h \
+ src/lib/dispatch/dispatch_naming.h \
+ src/lib/dispatch/dispatch_st.h \
+ src/lib/dispatch/msgtypes.h
diff --git a/src/lib/dispatch/msgtypes.h b/src/lib/dispatch/msgtypes.h
new file mode 100644
index 0000000000..b4c4a10248
--- /dev/null
+++ b/src/lib/dispatch/msgtypes.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file msgtypes.h
+ * \brief Types used for messages in the dispatcher code.
+ **/
+
+#ifndef TOR_DISPATCH_MSGTYPES_H
+#define TOR_DISPATCH_MSGTYPES_H
+
+#include <stdint.h>
+
+#include "ext/tor_queue.h"
+
+/**
+ * These types are aliases for subsystems, channels, and message IDs.
+ **/
+typedef uint16_t subsys_id_t;
+typedef uint16_t channel_id_t;
+typedef uint16_t message_id_t;
+
+/**
+ * This identifies a C type that can be sent along with a message.
+ **/
+typedef uint16_t msg_type_id_t;
+
+/**
+ * An ID value returned for *_type_t when none exists.
+ */
+#define ERROR_ID 65535
+
+/**
+ * Auxiliary (untyped) data sent along with a message.
+ *
+ * We define this as a union of a pointer and a u64, so that the integer
+ * types will have the same range across platforms.
+ **/
+typedef union {
+ void *ptr;
+ uint64_t u64;
+} msg_aux_data_t;
+
+/**
+ * Structure of a received message.
+ **/
+typedef struct msg_t {
+ TOR_SIMPLEQ_ENTRY(msg_t) next;
+ subsys_id_t sender;
+ channel_id_t channel;
+ message_id_t msg;
+ /** We could omit this field, since it is implicit in the message type, but
+ * IMO let's leave it in for safety. */
+ msg_type_id_t type;
+ /** Untyped auxiliary data. You shouldn't have to mess with this
+ * directly. */
+ msg_aux_data_t aux_data__;
+} msg_t;
+
+/**
+ * A function that a subscriber uses to receive a message.
+ **/
+typedef void (*recv_fn_t)(const msg_t *m);
+
+/**
+ * Table of functions to use for a given C type. Any omitted (NULL) functions
+ * will be treated as no-ops.
+ **/
+typedef struct dispatch_typefns_t {
+ /** Release storage held for the auxiliary data of this type. */
+ void (*free_fn)(msg_aux_data_t);
+ /** Format and return a newly allocated string describing the contents
+ * of this data element. */
+ char *(*fmt_fn)(msg_aux_data_t);
+} dispatch_typefns_t;
+
+#endif /* !defined(TOR_DISPATCH_MSGTYPES_H) */
diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c
index de4d1648bb..fc64e014e7 100644
--- a/src/lib/encoding/binascii.c
+++ b/src/lib/encoding/binascii.c
@@ -84,7 +84,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
}
/** Implements base32 decoding as in RFC 4648.
- * Returns 0 if successful, -1 otherwise.
+ * Return the number of bytes decoded if successful; -1 otherwise.
*/
int
base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
@@ -147,7 +147,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
memset(tmp, 0, srclen); /* on the heap, this should be safe */
tor_free(tmp);
tmp = NULL;
- return 0;
+ return i;
}
#define BASE64_OPENSSL_LINELEN 64
@@ -321,8 +321,10 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
return (int) enclen;
}
-/** As base64_encode, but do not add any internal spaces or external padding
- * to the output stream. */
+/** As base64_encode, but do not add any internal spaces, and remove external
+ * padding from the output stream.
+ * dest must be at least base64_encode_size(srclen, 0), including space for
+ * the removed external padding. */
int
base64_encode_nopad(char *dest, size_t destlen,
const uint8_t *src, size_t srclen)
diff --git a/src/lib/encoding/binascii.h b/src/lib/encoding/binascii.h
index 44998bb85b..40c5593b11 100644
--- a/src/lib/encoding/binascii.h
+++ b/src/lib/encoding/binascii.h
@@ -58,4 +58,4 @@ size_t base32_encoded_size(size_t srclen);
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);
-#endif /* !defined(TOR_UTIL_FORMAT_H) */
+#endif /* !defined(TOR_BINASCII_H) */
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index 8110f3dd9c..fdb575e03f 100644
--- a/src/lib/encoding/confline.c
+++ b/src/lib/encoding/confline.c
@@ -82,6 +82,19 @@ config_line_find(const config_line_t *lines,
return NULL;
}
+/** As config_line_find(), but perform a case-insensitive comparison. */
+const config_line_t *
+config_line_find_case(const config_line_t *lines,
+ const char *key)
+{
+ const config_line_t *cl;
+ for (cl = lines; cl; cl = cl->next) {
+ if (!strcasecmp(cl->key, key))
+ return cl;
+ }
+ return NULL;
+}
+
/** Auxiliary function that does all the work of config_get_lines.
* <b>recursion_level</b> is the count of how many nested %includes we have.
* <b>opened_lst</b> will have a list of opened files if provided.
diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h
index 3d9ae8a662..56ea36bf61 100644
--- a/src/lib/encoding/confline.h
+++ b/src/lib/encoding/confline.h
@@ -48,6 +48,8 @@ config_line_t *config_lines_dup_and_filter(const config_line_t *inp,
const char *key);
const config_line_t *config_line_find(const config_line_t *lines,
const char *key);
+const config_line_t *config_line_find_case(const config_line_t *lines,
+ const char *key);
int config_lines_eq(config_line_t *a, config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
void config_free_lines_(config_line_t *front);
diff --git a/src/lib/encoding/include.am b/src/lib/encoding/include.am
index 83e9211b6f..48d0120bfc 100644
--- a/src/lib/encoding/include.am
+++ b/src/lib/encoding/include.am
@@ -4,6 +4,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-encoding-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_encoding_a_SOURCES = \
src/lib/encoding/binascii.c \
src/lib/encoding/confline.c \
@@ -11,6 +12,7 @@ src_lib_libtor_encoding_a_SOURCES = \
src/lib/encoding/keyval.c \
src/lib/encoding/kvline.c \
src/lib/encoding/pem.c \
+ src/lib/encoding/qstring.c \
src/lib/encoding/time_fmt.c
src_lib_libtor_encoding_testing_a_SOURCES = \
@@ -18,6 +20,7 @@ src_lib_libtor_encoding_testing_a_SOURCES = \
src_lib_libtor_encoding_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_encoding_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/encoding/binascii.h \
src/lib/encoding/confline.h \
@@ -25,4 +28,5 @@ noinst_HEADERS += \
src/lib/encoding/keyval.h \
src/lib/encoding/kvline.h \
src/lib/encoding/pem.h \
+ src/lib/encoding/qstring.h \
src/lib/encoding/time_fmt.h
diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h
index cd327b7a82..dcddfa3396 100644
--- a/src/lib/encoding/keyval.h
+++ b/src/lib/encoding/keyval.h
@@ -14,4 +14,4 @@
int string_is_key_value(int severity, const char *string);
-#endif
+#endif /* !defined(TOR_KEYVAL_H) */
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index 307adc3f12..d4a8f510ba 100644
--- a/src/lib/encoding/kvline.c
+++ b/src/lib/encoding/kvline.c
@@ -16,6 +16,7 @@
#include "lib/encoding/confline.h"
#include "lib/encoding/cstring.h"
#include "lib/encoding/kvline.h"
+#include "lib/encoding/qstring.h"
#include "lib/malloc/malloc.h"
#include "lib/string/compat_ctype.h"
#include "lib/string/printf.h"
@@ -54,6 +55,15 @@ line_has_no_key(const config_line_t *line)
}
/**
+ * Return true iff the value in <b>line</b> is not set.
+ **/
+static bool
+line_has_no_val(const config_line_t *line)
+{
+ return line->value == NULL || strlen(line->value) == 0;
+}
+
+/**
* Return true iff the all the lines in <b>line</b> can be encoded
* using <b>flags</b>.
**/
@@ -98,14 +108,25 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
* If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are
* allowed, and are encoded as 'Value'. Otherwise, such pairs are not
* allowed.
+ *
+ * If KV_OMIT_VALS is set in <b>flags</b>, then an empty value is
+ * encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with
+ * KV_OMIT_KEYS.
+ *
+ * KV_QUOTED_QSTRING is not supported.
*/
char *
kvline_encode(const config_line_t *line,
unsigned flags)
{
+ tor_assert(! (flags & KV_QUOTED_QSTRING));
+
if (!kvline_can_encode_lines(line, flags))
return NULL;
+ tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
+ (KV_OMIT_KEYS|KV_OMIT_VALS));
+
smartlist_t *elements = smartlist_new();
for (; line; line = line->next) {
@@ -126,7 +147,10 @@ kvline_encode(const config_line_t *line,
}
}
- if (esc) {
+ if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
+ eq = "";
+ v = "";
+ } else if (esc) {
tmp = esc_for_log(line->value);
v = tmp;
} else {
@@ -151,17 +175,30 @@ kvline_encode(const config_line_t *line,
* allocated list of pairs on success, or NULL on failure.
*
* If KV_QUOTED is set in <b>flags</b>, then (double-)quoted values are
- * allowed. Otherwise, such values are not allowed.
+ * allowed and handled as C strings. Otherwise, such values are not allowed.
*
* If KV_OMIT_KEYS is set in <b>flags</b>, then values without keys are
* allowed. Otherwise, such values are not allowed.
+ *
+ * If KV_OMIT_VALS is set in <b>flags</b>, then keys without values are
+ * allowed. Otherwise, such keys are not allowed. Mutually exclusive with
+ * KV_OMIT_KEYS.
+ *
+ * If KV_QUOTED_QSTRING is set in <b>flags</b>, then double-quoted values
+ * are allowed and handled as QuotedStrings per qstring.c. Do not add
+ * new users of this flag.
*/
config_line_t *
kvline_parse(const char *line, unsigned flags)
{
+ tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
+ (KV_OMIT_KEYS|KV_OMIT_VALS));
+
const char *cp = line, *cplast = NULL;
- bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
- bool quoted = (flags & KV_QUOTED) != 0;
+ const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
+ const bool omit_vals = (flags & KV_OMIT_VALS) != 0;
+ const bool quoted = (flags & (KV_QUOTED|KV_QUOTED_QSTRING)) != 0;
+ const bool c_quoted = (flags & (KV_QUOTED)) != 0;
config_line_t *result = NULL;
config_line_t **next_line = &result;
@@ -171,27 +208,33 @@ kvline_parse(const char *line, unsigned flags)
while (*cp) {
key = val = NULL;
+ /* skip all spaces */
{
size_t idx = strspn(cp, " \t\r\v\n");
cp += idx;
}
if (BUG(cp == cplast)) {
- /* If we didn't parse anything, this code is broken. */
+ /* If we didn't parse anything since the last loop, this code is
+ * broken. */
goto err; // LCOV_EXCL_LINE
}
cplast = cp;
if (! *cp)
break; /* End of string; we're done. */
- /* Possible formats are K=V, K="V", V, and "V", depending on flags. */
+ /* Possible formats are K=V, K="V", K, V, and "V", depending on flags. */
- /* Find the key. */
+ /* Find where the key ends */
if (*cp != '\"') {
size_t idx = strcspn(cp, " \t\r\v\n=");
if (cp[idx] == '=') {
key = tor_memdup_nulterm(cp, idx);
cp += idx + 1;
+ } else if (omit_vals) {
+ key = tor_memdup_nulterm(cp, idx);
+ cp += idx;
+ goto commit;
} else {
if (!omit_keys)
goto err;
@@ -203,7 +246,11 @@ kvline_parse(const char *line, unsigned flags)
if (!quoted)
goto err;
size_t len=0;
- cp = unescape_string(cp, &val, &len);
+ if (c_quoted) {
+ cp = unescape_string(cp, &val, &len);
+ } else {
+ cp = decode_qstring(cp, strlen(cp), &val, &len);
+ }
if (cp == NULL || len != strlen(val)) {
// The string contains a NUL or is badly coded.
goto err;
@@ -214,6 +261,7 @@ kvline_parse(const char *line, unsigned flags)
cp += idx;
}
+ commit:
if (key && strlen(key) == 0) {
/* We don't allow empty keys. */
goto err;
@@ -221,13 +269,15 @@ kvline_parse(const char *line, unsigned flags)
*next_line = tor_malloc_zero(sizeof(config_line_t));
(*next_line)->key = key ? key : tor_strdup("");
- (*next_line)->value = val;
+ (*next_line)->value = val ? val : tor_strdup("");
next_line = &(*next_line)->next;
key = val = NULL;
}
- if (!kvline_can_encode_lines(result, flags)) {
- goto err;
+ if (! (flags & KV_QUOTED_QSTRING)) {
+ if (!kvline_can_encode_lines(result, flags)) {
+ goto err;
+ }
}
return result;
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index 4eed30a223..dea2ce1809 100644
--- a/src/lib/encoding/kvline.h
+++ b/src/lib/encoding/kvline.h
@@ -17,6 +17,8 @@ struct config_line_t;
#define KV_QUOTED (1u<<0)
#define KV_OMIT_KEYS (1u<<1)
+#define KV_OMIT_VALS (1u<<2)
+#define KV_QUOTED_QSTRING (1u<<3)
struct config_line_t *kvline_parse(const char *line, unsigned flags);
char *kvline_encode(const struct config_line_t *line, unsigned flags);
diff --git a/src/lib/encoding/pem.h b/src/lib/encoding/pem.h
index 0bbb06a794..6b20350aa8 100644
--- a/src/lib/encoding/pem.h
+++ b/src/lib/encoding/pem.h
@@ -23,4 +23,4 @@ int pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen,
int pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen,
const char *objtype);
-#endif
+#endif /* !defined(TOR_PEM_H) */
diff --git a/src/lib/encoding/qstring.c b/src/lib/encoding/qstring.c
new file mode 100644
index 0000000000..a92d28c706
--- /dev/null
+++ b/src/lib/encoding/qstring.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file qstring.c
+ * \brief Implement QuotedString parsing.
+ *
+ * Note that this is only used for controller authentication; do not
+ * create new users for this. Instead, prefer the cstring.c functions.
+ **/
+
+#include "orconfig.h"
+#include "lib/encoding/qstring.h"
+#include "lib/malloc/malloc.h"
+#include "lib/log/util_bug.h"
+
+/** If the first <b>in_len_max</b> characters in <b>start</b> contain a
+ * QuotedString, return the length of that
+ * string (as encoded, including quotes). Otherwise return -1. */
+static inline int
+get_qstring_length(const char *start, size_t in_len_max,
+ int *chars_out)
+{
+ const char *cp, *end;
+ int chars = 0;
+
+ if (*start != '\"')
+ return -1;
+
+ cp = start+1;
+ end = start+in_len_max;
+
+ /* Calculate length. */
+ while (1) {
+ if (cp >= end) {
+ return -1; /* Too long. */
+ } else if (*cp == '\\') {
+ if (++cp == end)
+ return -1; /* Can't escape EOS. */
+ ++cp;
+ ++chars;
+ } else if (*cp == '\"') {
+ break;
+ } else {
+ ++cp;
+ ++chars;
+ }
+ }
+ if (chars_out)
+ *chars_out = chars;
+ return (int)(cp - start+1);
+}
+
+/** Given a pointer to a string starting at <b>start</b> containing
+ * <b>in_len_max</b> characters, decode a string beginning with one double
+ * quote, containing any number of non-quote characters or characters escaped
+ * with a backslash, and ending with a final double quote. Place the resulting
+ * string (unquoted, unescaped) into a newly allocated string in *<b>out</b>;
+ * store its length in <b>out_len</b>. On success, return a pointer to the
+ * character immediately following the escaped string. On failure, return
+ * NULL. */
+const char *
+decode_qstring(const char *start, size_t in_len_max,
+ char **out, size_t *out_len)
+{
+ const char *cp, *end;
+ char *outp;
+ int len, n_chars = 0;
+
+ len = get_qstring_length(start, in_len_max, &n_chars);
+ if (len<0)
+ return NULL;
+
+ end = start+len-1; /* Index of last quote. */
+ tor_assert(*end == '\"');
+ outp = *out = tor_malloc(len+1);
+ *out_len = n_chars;
+
+ cp = start+1;
+ while (cp < end) {
+ if (*cp == '\\')
+ ++cp;
+ *outp++ = *cp++;
+ }
+ *outp = '\0';
+ tor_assert((outp - *out) == (int)*out_len);
+
+ return end+1;
+}
diff --git a/src/lib/encoding/qstring.h b/src/lib/encoding/qstring.h
new file mode 100644
index 0000000000..840e1044ce
--- /dev/null
+++ b/src/lib/encoding/qstring.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file qstring.h
+ * \brief Header for qstring.c
+ */
+
+#ifndef TOR_ENCODING_QSTRING_H
+#define TOR_ENCODING_QSTRING_H
+
+#include <stddef.h>
+
+const char *decode_qstring(const char *start, size_t in_len_max,
+ char **out, size_t *out_len);
+
+#endif /* !defined(TOR_ENCODING_QSTRING_H) */
diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h
index 0ddeca57fc..d14bc1f902 100644
--- a/src/lib/encoding/time_fmt.h
+++ b/src/lib/encoding/time_fmt.h
@@ -41,4 +41,4 @@ int parse_iso_time_nospace(const char *cp, time_t *t);
int parse_http_time(const char *buf, struct tm *tm);
int format_time_interval(char *out, size_t out_len, long interval);
-#endif
+#endif /* !defined(TOR_TIME_FMT_H) */
diff --git a/src/lib/err/.may_include b/src/lib/err/.may_include
index daa1b6e4ca..314424545e 100644
--- a/src/lib/err/.may_include
+++ b/src/lib/err/.may_include
@@ -1,5 +1,6 @@
orconfig.h
lib/cc/*.h
+lib/defs/*.h
lib/err/*.h
lib/subsys/*.h
-lib/version/*.h \ No newline at end of file
+lib/version/*.h
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c
index 8606f42177..8bc7e6965c 100644
--- a/src/lib/err/backtrace.c
+++ b/src/lib/err/backtrace.c
@@ -57,7 +57,8 @@
#include "lib/err/torerr.h"
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
- defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
+ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) && \
+ defined(HAVE_PTHREAD_H)
#define USE_BACKTRACE
#endif
@@ -115,7 +116,7 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx)
* that with a backtrace log. Send messages via the tor_log function at
* logger". */
void
-log_backtrace_impl(int severity, int domain, const char *msg,
+log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
tor_log_fn logger)
{
size_t depth;
@@ -172,7 +173,7 @@ crash_handler(int sig, siginfo_t *si, void *ctx_)
for (i=0; i < n_fds; ++i)
backtrace_symbols_fd(cb_buf, (int)depth, fds[i]);
- abort();
+ tor_raw_abort_();
}
/** Write a backtrace to all of the emergency-error fds. */
@@ -190,13 +191,15 @@ dump_stack_symbols_to_error_fds(void)
backtrace_symbols_fd(cb_buf, (int)depth, fds[i]);
}
+/* The signals that we want our backtrace handler to trap */
+static int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
+ SIGIO, -1 };
+
/** Install signal handlers as needed so that when we crash, we produce a
* useful stack trace. Return 0 on success, -errno on failure. */
static int
install_bt_handler(void)
{
- int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
- SIGIO, -1 };
int i, rv=0;
struct sigaction sa;
@@ -232,12 +235,29 @@ install_bt_handler(void)
static void
remove_bt_handler(void)
{
+ int i;
+
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigfillset(&sa.sa_mask);
+
+ for (i = 0; trap_signals[i] >= 0; ++i) {
+ /* remove_bt_handler() is called on shutdown, from low-level code.
+ * It's not a fatal error, so we just ignore it. */
+ (void)sigaction(trap_signals[i], &sa, NULL);
+ }
+
+ /* cb_buf_mutex is statically initialised, so we can not destroy it.
+ * If we destroy it, and then re-initialise tor, all our backtraces will
+ * fail. */
}
#endif /* defined(USE_BACKTRACE) */
#ifdef NO_BACKTRACE_IMPL
void
-log_backtrace_impl(int severity, int domain, const char *msg,
+log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
tor_log_fn logger)
{
logger(severity, domain, "%s: %s. (Stack trace not available)",
diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h
index 48b41fca02..7e09a0a5a7 100644
--- a/src/lib/err/backtrace.h
+++ b/src/lib/err/backtrace.h
@@ -12,11 +12,14 @@
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
+#include "lib/cc/torint.h"
+#include "lib/defs/logging_types.h"
-typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...)
+typedef void (*tor_log_fn)(int, log_domain_mask_t, const char *fmt, ...)
CHECK_PRINTF(3,4);
-void log_backtrace_impl(int severity, int domain, const char *msg,
+void log_backtrace_impl(int severity, log_domain_mask_t domain,
+ const char *msg,
tor_log_fn logger);
int configure_backtrace_handler(const char *tor_version);
void clean_up_backtrace_handler(void);
diff --git a/src/lib/err/include.am b/src/lib/err/include.am
index 43adcd2694..883ac91511 100644
--- a/src/lib/err/include.am
+++ b/src/lib/err/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-err-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_err_a_SOURCES = \
src/lib/err/backtrace.c \
src/lib/err/torerr.c \
@@ -15,6 +16,7 @@ src_lib_libtor_err_testing_a_SOURCES = \
src_lib_libtor_err_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_err_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/err/backtrace.h \
src/lib/err/torerr.h \
diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c
index 1a246e995c..b7e32a3e20 100644
--- a/src/lib/err/torerr.c
+++ b/src/lib/err/torerr.c
@@ -110,6 +110,14 @@ tor_log_get_sigsafe_err_fds(const int **out)
* Update the list of fds that get errors from inside a signal handler or
* other emergency condition. Ignore any beyond the first
* TOR_SIGSAFE_LOG_MAX_FDS.
+ *
+ * These fds must remain open even after the log module has shut down. (And
+ * they should remain open even while logs are being reconfigured.) Therefore,
+ * any fds closed by the log module should be dup()ed, and the duplicate fd
+ * should be given to the err module in fds. In particular, the log module
+ * closes the file log fds, but does not close the stdio log fds.
+ *
+ * If fds is NULL or n is 0, clears the list of error fds.
*/
void
tor_log_set_sigsafe_err_fds(const int *fds, int n)
@@ -118,8 +126,18 @@ tor_log_set_sigsafe_err_fds(const int *fds, int n)
n = TOR_SIGSAFE_LOG_MAX_FDS;
}
- memcpy(sigsafe_log_fds, fds, n * sizeof(int));
- n_sigsafe_log_fds = n;
+ /* Clear the entire array. This code mitigates against some race conditions,
+ * but there are still some races here:
+ * - err logs are disabled while the array is cleared, and
+ * - a thread can read the old value of n_sigsafe_log_fds, then read a
+ * partially written array.
+ * We could fix these races using atomics, but atomics use the err module. */
+ n_sigsafe_log_fds = 0;
+ memset(sigsafe_log_fds, 0, sizeof(sigsafe_log_fds));
+ if (fds && n > 0) {
+ memcpy(sigsafe_log_fds, fds, n * sizeof(int));
+ n_sigsafe_log_fds = n;
+ }
}
/**
@@ -133,6 +151,32 @@ tor_log_reset_sigsafe_err_fds(void)
}
/**
+ * Close the list of fds that get errors from inside a signal handler or
+ * other emergency condition. These fds are shared with the logging code:
+ * closing them flushes the log buffers, and prevents any further logging.
+ *
+ * This function closes stderr, so it should only be called immediately before
+ * process shutdown.
+ */
+void
+tor_log_close_sigsafe_err_fds(void)
+{
+ int n_fds, i;
+ const int *fds = NULL;
+
+ n_fds = tor_log_get_sigsafe_err_fds(&fds);
+ for (i = 0; i < n_fds; ++i) {
+ /* tor_log_close_sigsafe_err_fds_on_error() is called on error and on
+ * shutdown, so we can't log or take any useful action if close()
+ * fails. */
+ (void)close(fds[i]);
+ }
+
+ /* Don't even try logging, we've closed all the log fds. */
+ tor_log_set_sigsafe_err_fds(NULL, 0);
+}
+
+/**
* Set the granularity (in ms) to use when reporting fatal errors outside
* the logging system.
*/
@@ -171,6 +215,18 @@ tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr,
tor_log_err_sigsafe_write("\n");
}
+/**
+ * Call the abort() function to kill the current process with a fatal
+ * error. But first, close the raw error file descriptors, so error messages
+ * are written before process termination.
+ **/
+void
+tor_raw_abort_(void)
+{
+ tor_log_close_sigsafe_err_fds();
+ abort();
+}
+
/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument
* in range 2..16 inclusive. */
static int
@@ -205,7 +261,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len,
unsigned digit = (unsigned) (x % radix);
if (cp <= buf) {
/* Not tor_assert(); see above. */
- abort();
+ tor_raw_abort_();
}
--cp;
*cp = "0123456789ABCDEF"[digit];
@@ -214,7 +270,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len,
/* NOT tor_assert; see above. */
if (cp != buf) {
- abort(); // LCOV_EXCL_LINE
+ tor_raw_abort_(); // LCOV_EXCL_LINE
}
return len;
diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h
index 0badaf7c6d..0e839cb1ba 100644
--- a/src/lib/err/torerr.h
+++ b/src/lib/err/torerr.h
@@ -20,13 +20,13 @@
#define raw_assert(expr) STMT_BEGIN \
if (!(expr)) { \
tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \
- abort(); \
+ tor_raw_abort_(); \
} \
STMT_END
#define raw_assert_unreached(expr) raw_assert(0)
#define raw_assert_unreached_msg(msg) STMT_BEGIN \
tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \
- abort(); \
+ tor_raw_abort_(); \
STMT_END
void tor_raw_assertion_failed_msg_(const char *file, int line,
@@ -40,9 +40,12 @@ void tor_log_err_sigsafe(const char *m, ...);
int tor_log_get_sigsafe_err_fds(const int **out);
void tor_log_set_sigsafe_err_fds(const int *fds, int n);
void tor_log_reset_sigsafe_err_fds(void);
+void tor_log_close_sigsafe_err_fds(void);
void tor_log_sigsafe_err_set_granularity(int ms);
+void tor_raw_abort_(void) ATTR_NORETURN;
+
int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len);
int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len);
-#endif /* !defined(TOR_TORLOG_H) */
+#endif /* !defined(TOR_TORERR_H) */
diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c
index 3ab1b3c4e1..a14c46f945 100644
--- a/src/lib/err/torerr_sys.c
+++ b/src/lib/err/torerr_sys.c
@@ -27,8 +27,11 @@ subsys_torerr_initialize(void)
static void
subsys_torerr_shutdown(void)
{
- tor_log_reset_sigsafe_err_fds();
+ /* Stop handling signals with backtraces, then close the logs. */
clean_up_backtrace_handler();
+ /* We can't log any log messages after this point: we've closed all the log
+ * fds, including stdio. */
+ tor_log_close_sigsafe_err_fds();
}
const subsys_fns_t sys_torerr = {
diff --git a/src/lib/evloop/include.am b/src/lib/evloop/include.am
index 6b0076272a..6595b3a34b 100644
--- a/src/lib/evloop/include.am
+++ b/src/lib/evloop/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-evloop-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_evloop_a_SOURCES = \
src/lib/evloop/compat_libevent.c \
src/lib/evloop/procmon.c \
@@ -12,12 +13,12 @@ src_lib_libtor_evloop_a_SOURCES = \
src/lib/evloop/token_bucket.c \
src/lib/evloop/workqueue.c
-
src_lib_libtor_evloop_testing_a_SOURCES = \
$(src_lib_libtor_evloop_a_SOURCES)
src_lib_libtor_evloop_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_evloop_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/evloop/compat_libevent.h \
src/lib/evloop/procmon.h \
diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h
index 9398d2baa3..1ce6f1bf94 100644
--- a/src/lib/evloop/token_bucket.h
+++ b/src/lib/evloop/token_bucket.h
@@ -112,6 +112,6 @@ token_bucket_rw_get_write(const token_bucket_rw_t *bucket)
STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate);
-#endif
+#endif /* defined(TOKEN_BUCKET_PRIVATE) */
-#endif /* TOR_TOKEN_BUCKET_H */
+#endif /* !defined(TOR_TOKEN_BUCKET_H) */
diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
index b36a02da5e..015b694290 100644
--- a/src/lib/evloop/workqueue.c
+++ b/src/lib/evloop/workqueue.c
@@ -59,9 +59,6 @@ struct threadpool_s {
* <b>p</b> is work[p]. */
work_tailq_t work[WORKQUEUE_N_PRIORITIES];
- /** Weak RNG, used to decide when to ignore priority. */
- tor_weak_rng_t weak_rng;
-
/** The current 'update generation' of the threadpool. Any thread that is
* at an earlier generation needs to run the update function. */
unsigned generation;
@@ -238,7 +235,7 @@ worker_thread_extract_next_work(workerthread_t *thread)
this_queue = &pool->work[i];
if (!TOR_TAILQ_EMPTY(this_queue)) {
queue = this_queue;
- if (! tor_weak_random_one_in_n(&pool->weak_rng,
+ if (! crypto_fast_rng_one_in_n(get_thread_fast_rng(),
thread->lower_priority_chance)) {
/* Usually we'll just break now, so that we can get out of the loop
* and use the queue where we found work. But with a small
@@ -555,11 +552,6 @@ threadpool_new(int n_threads,
for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) {
TOR_TAILQ_INIT(&pool->work[i]);
}
- {
- unsigned seed;
- crypto_rand((void*)&seed, sizeof(seed));
- tor_init_weak_random(&pool->weak_rng, seed);
- }
pool->new_thread_state_fn = new_thread_state_fn;
pool->new_thread_state_arg = arg;
diff --git a/src/lib/fdio/include.am b/src/lib/fdio/include.am
index 6c18f00a0d..545bbc929e 100644
--- a/src/lib/fdio/include.am
+++ b/src/lib/fdio/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-fdio-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_fdio_a_SOURCES = \
src/lib/fdio/fdio.c
@@ -13,5 +14,6 @@ src_lib_libtor_fdio_testing_a_SOURCES = \
src_lib_libtor_fdio_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_fdio_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/fdio/fdio.h
diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h
index 7af9119dbb..29115e1085 100644
--- a/src/lib/fs/conffile.h
+++ b/src/lib/fs/conffile.h
@@ -20,4 +20,4 @@ int config_get_lines_include(const char *string, struct config_line_t **result,
int extended, int *has_include,
struct smartlist_t *opened_lst);
-#endif /* !defined(TOR_CONFLINE_H) */
+#endif /* !defined(TOR_CONFFILE_H) */
diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h
index 826bc2dfc5..9ff81faa42 100644
--- a/src/lib/fs/dir.h
+++ b/src/lib/fs/dir.h
@@ -30,4 +30,4 @@ MOCK_DECL(int, check_private_dir, (const char *dirname, cpd_check_t check,
MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname));
-#endif
+#endif /* !defined(TOR_DIR_H) */
diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h
index 52c94c914f..81dba8c140 100644
--- a/src/lib/fs/files.h
+++ b/src/lib/fs/files.h
@@ -27,7 +27,7 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
-#endif
+#endif /* defined(_WIN32) */
#ifndef O_BINARY
#define O_BINARY 0
@@ -108,7 +108,7 @@ char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
* Tor is built for unit tests, or when Tor is built on an operating system
* without its own getdelim(). */
ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream);
-#endif
+#endif /* !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS) */
#ifdef HAVE_GETDELIM
/**
@@ -123,10 +123,10 @@ ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream);
*/
#define tor_getdelim(lineptr, n, delim, stream) \
getdelim((lineptr), (n), (delim), (stream))
-#else
+#else /* !(defined(HAVE_GETDELIM)) */
#define tor_getdelim(lineptr, n, delim, stream) \
compat_getdelim_((lineptr), (n), (delim), (stream))
-#endif
+#endif /* defined(HAVE_GETDELIM) */
#ifdef HAVE_GETLINE
/**
@@ -137,9 +137,9 @@ ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream);
*/
#define tor_getline(lineptr, n, stream) \
getline((lineptr), (n), (stream))
-#else
+#else /* !(defined(HAVE_GETLINE)) */
#define tor_getline(lineptr, n, stream) \
tor_getdelim((lineptr), (n), '\n', (stream))
-#endif
+#endif /* defined(HAVE_GETLINE) */
-#endif
+#endif /* !defined(TOR_FS_H) */
diff --git a/src/lib/fs/include.am b/src/lib/fs/include.am
index f33e4d6430..493db8f044 100644
--- a/src/lib/fs/include.am
+++ b/src/lib/fs/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-fs-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_fs_a_SOURCES = \
src/lib/fs/conffile.c \
src/lib/fs/dir.c \
@@ -25,6 +26,7 @@ src_lib_libtor_fs_testing_a_SOURCES = \
src_lib_libtor_fs_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_fs_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/fs/conffile.h \
src/lib/fs/dir.h \
diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h
index 8aeee4cc7f..fc0281e253 100644
--- a/src/lib/fs/lockfile.h
+++ b/src/lib/fs/lockfile.h
@@ -17,4 +17,4 @@ tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking,
int *locked_out);
void tor_lockfile_unlock(tor_lockfile_t *lockfile);
-#endif
+#endif /* !defined(TOR_LOCKFILE_H) */
diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c
index daaee1f9b1..f71c0cff7a 100644
--- a/src/lib/fs/mmap.c
+++ b/src/lib/fs/mmap.c
@@ -237,4 +237,4 @@ tor_munmap_file(tor_mmap_t *handle)
}
#else
#error "cannot implement tor_mmap_file"
-#endif /* defined(HAVE_MMAP) || ... || ... */
+#endif /* defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) || ... */
diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h
index 18fb18a13c..61aad544b2 100644
--- a/src/lib/fs/mmap.h
+++ b/src/lib/fs/mmap.h
@@ -38,4 +38,4 @@ typedef struct tor_mmap_t {
tor_mmap_t *tor_mmap_file(const char *filename);
int tor_munmap_file(tor_mmap_t *handle);
-#endif
+#endif /* !defined(TOR_MMAP_H) */
diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h
index 4675ac84e8..28a1838b88 100644
--- a/src/lib/fs/path.h
+++ b/src/lib/fs/path.h
@@ -27,4 +27,4 @@ void clean_fname_for_stat(char *name);
int get_parent_directory(char *fname);
char *make_path_absolute(char *fname);
-#endif
+#endif /* !defined(TOR_PATH_H) */
diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h
index 5c39794873..5e5ddb89a3 100644
--- a/src/lib/fs/userdb.h
+++ b/src/lib/fs/userdb.h
@@ -21,6 +21,6 @@ struct passwd;
const struct passwd *tor_getpwnam(const char *username);
const struct passwd *tor_getpwuid(uid_t uid);
char *get_user_homedir(const char *username);
-#endif
+#endif /* !defined(_WIN32) */
-#endif
+#endif /* !defined(TOR_USERDB_H) */
diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h
index 64a22439e5..7237226c76 100644
--- a/src/lib/fs/winlib.h
+++ b/src/lib/fs/winlib.h
@@ -17,6 +17,6 @@
#include <tchar.h>
HANDLE load_windows_system_library(const TCHAR *library_name);
-#endif
+#endif /* defined(_WIN32) */
-#endif
+#endif /* !defined(TOR_WINLIB_H) */
diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h
index 9a8911d494..a24a1c4c0d 100644
--- a/src/lib/geoip/country.h
+++ b/src/lib/geoip/country.h
@@ -13,4 +13,4 @@ typedef int16_t country_t;
#define COUNTRY_MAX INT16_MAX
-#endif
+#endif /* !defined(TOR_COUNTRY_H) */
diff --git a/src/lib/geoip/include.am b/src/lib/geoip/include.am
index 9710d75ac7..ea426d14bc 100644
--- a/src/lib/geoip/include.am
+++ b/src/lib/geoip/include.am
@@ -4,6 +4,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-geoip-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_geoip_a_SOURCES = \
src/lib/geoip/geoip.c
@@ -12,6 +13,7 @@ src_lib_libtor_geoip_testing_a_SOURCES = \
src_lib_libtor_geoip_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_geoip_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/geoip/geoip.h \
src/lib/geoip/country.h
diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h
index 83efa82919..3f745d457d 100644
--- a/src/lib/intmath/addsub.h
+++ b/src/lib/intmath/addsub.h
@@ -16,4 +16,4 @@
uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b);
-#endif /* !defined(TOR_INTMATH_MULDIV_H) */
+#endif /* !defined(TOR_INTMATH_ADDSUB_H) */
diff --git a/src/lib/intmath/include.am b/src/lib/intmath/include.am
index 45ee3bd53b..155ffa145a 100644
--- a/src/lib/intmath/include.am
+++ b/src/lib/intmath/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-intmath-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_intmath_a_SOURCES = \
src/lib/intmath/addsub.c \
src/lib/intmath/bits.c \
@@ -16,6 +17,7 @@ src_lib_libtor_intmath_testing_a_SOURCES = \
src_lib_libtor_intmath_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_intmath_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/intmath/addsub.h \
src/lib/intmath/cmp.h \
diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h
index a4cecd69cc..b2f77462e1 100644
--- a/src/lib/intmath/logic.h
+++ b/src/lib/intmath/logic.h
@@ -17,4 +17,4 @@
/** Macro: true if two values have different boolean values. */
#define bool_neq(a,b) (!(a)!=!(b))
-#endif
+#endif /* !defined(HAVE_TOR_LOGIC_H) */
diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h
index e26bf58cbb..40941e59b2 100644
--- a/src/lib/intmath/weakrng.h
+++ b/src/lib/intmath/weakrng.h
@@ -28,4 +28,4 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
* <b>n</b> */
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
-#endif
+#endif /* !defined(TOR_WEAKRNG_H) */
diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c
index 4ad5929715..670bd0174c 100644
--- a/src/lib/lock/compat_mutex.c
+++ b/src/lib/lock/compat_mutex.c
@@ -29,7 +29,15 @@ tor_mutex_new_nonrecursive(void)
tor_mutex_init_nonrecursive(m);
return m;
}
-/** Release all storage and system resources held by <b>m</b>. */
+/** Release all storage and system resources held by <b>m</b>.
+ *
+ * Destroying a locked mutex is undefined behaviour. Global mutexes may be
+ * locked when they are passed to this function, because multiple threads can
+ * still access them. So we can either:
+ * - destroy on shutdown, and re-initialise when tor re-initialises, or
+ * - skip destroying and re-initialisation, using a sentinel variable.
+ * See #31735 for details.
+ */
void
tor_mutex_free_(tor_mutex_t *m)
{
diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h
index b63ce24024..e0c3d7cb78 100644
--- a/src/lib/lock/compat_mutex.h
+++ b/src/lib/lock/compat_mutex.h
@@ -48,7 +48,7 @@ typedef struct tor_mutex_t {
#else
/** No-threads only: Dummy variable so that tor_mutex_t takes up space. */
int _unused;
-#endif /* defined(USE_WIN32_MUTEX) || ... */
+#endif /* defined(USE_WIN32_THREADS) || ... */
} tor_mutex_t;
tor_mutex_t *tor_mutex_new(void);
diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c
index ee5f520cd0..f82ad9f0e8 100644
--- a/src/lib/lock/compat_mutex_pthreads.c
+++ b/src/lib/lock/compat_mutex_pthreads.c
@@ -88,12 +88,26 @@ tor_mutex_release(tor_mutex_t *m)
}
/** Clean up the mutex <b>m</b> so that it no longer uses any system
* resources. Does not free <b>m</b>. This function must only be called on
- * mutexes from tor_mutex_init(). */
+ * mutexes from tor_mutex_init().
+ *
+ * Destroying a locked mutex is undefined behaviour. Global mutexes may be
+ * locked when they are passed to this function, because multiple threads can
+ * still access them. So we can either:
+ * - destroy on shutdown, and re-initialise when tor re-initialises, or
+ * - skip destroying and re-initialisation, using a sentinel variable.
+ * See #31735 for details.
+ */
void
tor_mutex_uninit(tor_mutex_t *m)
{
int err;
raw_assert(m);
+ /* If the mutex is already locked, wait until after it is unlocked to destroy
+ * it. Locking and releasing the mutex makes undefined behaviour less likely,
+ * but does not prevent it. Another thread can lock the mutex between release
+ * and destroy. */
+ tor_mutex_acquire(m);
+ tor_mutex_release(m);
err = pthread_mutex_destroy(&m->mutex);
if (PREDICT_UNLIKELY(err)) {
// LCOV_EXCL_START
diff --git a/src/lib/lock/include.am b/src/lib/lock/include.am
index 4e6f444347..1475b9911b 100644
--- a/src/lib/lock/include.am
+++ b/src/lib/lock/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-lock-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_lock_a_SOURCES = \
src/lib/lock/compat_mutex.c
@@ -20,5 +21,6 @@ src_lib_libtor_lock_testing_a_SOURCES = \
src_lib_libtor_lock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/lock/compat_mutex.h
diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include
index 11c87f0a0d..54d96324db 100644
--- a/src/lib/log/.may_include
+++ b/src/lib/log/.may_include
@@ -1,6 +1,7 @@
orconfig.h
lib/cc/*.h
+lib/defs/*.h
lib/smartlist_core/*.h
lib/err/*.h
lib/fdio/*.h
diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h
index 2f726186c5..0b9fc3406b 100644
--- a/src/lib/log/escape.h
+++ b/src/lib/log/escape.h
@@ -20,4 +20,4 @@ char *esc_for_log(const char *string) ATTR_MALLOC;
char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
const char *escaped(const char *string);
-#endif /* !defined(TOR_TORLOG_H) */
+#endif /* !defined(TOR_ESCAPE_H) */
diff --git a/src/lib/log/include.am b/src/lib/log/include.am
index 9d3dbe3104..5b9f7113ba 100644
--- a/src/lib/log/include.am
+++ b/src/lib/log/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-log-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_log_a_SOURCES = \
src/lib/log/escape.c \
src/lib/log/ratelim.c \
@@ -21,6 +22,7 @@ src_lib_libtor_log_testing_a_SOURCES = \
src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/log/escape.h \
src/lib/log/ratelim.h \
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index d21d8d1d41..ec7c2fa24e 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -49,6 +49,7 @@
#include "lib/wallclock/approx_time.h"
#include "lib/wallclock/time_to_tm.h"
#include "lib/fdio/fdio.h"
+#include "lib/cc/ctassert.h"
#ifdef HAVE_ANDROID_LOG_H
#include <android/log.h>
@@ -154,7 +155,7 @@ severity_to_android_log_priority(int severity)
// LCOV_EXCL_STOP
}
}
-#endif // HAVE_ANDROID_LOG_H.
+#endif /* defined(HAVE_ANDROID_LOG_H) */
/** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex;
@@ -224,6 +225,7 @@ int log_global_min_severity_ = LOG_NOTICE;
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
+static void close_log_sigsafe(logfile_t *victim);
static char *domain_to_string(log_domain_mask_t domain,
char *buf, size_t buflen);
@@ -664,13 +666,24 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf;
int found_real_stderr = 0;
- int fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ /* log_fds and err_fds contain matching entries: log_fds are the fds used by
+ * the log module, and err_fds are the fds used by the err module.
+ * For stdio logs, the log_fd and err_fd values are identical,
+ * and the err module closes the fd on shutdown.
+ * For file logs, the err_fd is a dup() of the log_fd,
+ * and the log and err modules both close their respective fds on shutdown.
+ * (Once all fds representing a file are closed, the underlying file is
+ * closed.)
+ */
+ int log_fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ int err_fds[TOR_SIGSAFE_LOG_MAX_FDS];
int n_fds;
LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize,
- * we dup2 /dev/null to stderr, */
- fds[0] = STDERR_FILENO;
+ * we dup2 /dev/null to stderr.
+ * For stderr, log_fds and err_fds are the same. */
+ log_fds[0] = err_fds[0] = STDERR_FILENO;
n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) {
@@ -684,25 +697,39 @@ tor_log_update_sigsafe_err_fds(void)
(LD_BUG|LD_GENERAL)) {
if (lf->fd == STDERR_FILENO)
found_real_stderr = 1;
- /* Avoid duplicates */
- if (int_array_contains(fds, n_fds, lf->fd))
+ /* Avoid duplicates by checking the log module fd against log_fds */
+ if (int_array_contains(log_fds, n_fds, lf->fd))
continue;
- fds[n_fds++] = lf->fd;
+ /* Update log_fds using the log module's fd */
+ log_fds[n_fds] = lf->fd;
+ if (lf->needs_close) {
+ /* File log fds are duplicated, because close_log() closes the log
+ * module's fd, and tor_log_close_sigsafe_err_fds() closes the err
+ * module's fd. Both refer to the same file. */
+ err_fds[n_fds] = dup(lf->fd);
+ } else {
+ /* stdio log fds are not closed by the log module.
+ * tor_log_close_sigsafe_err_fds() closes stdio logs. */
+ err_fds[n_fds] = lf->fd;
+ }
+ n_fds++;
if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break;
}
}
if (!found_real_stderr &&
- int_array_contains(fds, n_fds, STDOUT_FILENO)) {
+ int_array_contains(log_fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout. */
raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
- fds[0] = fds[--n_fds];
+ --n_fds;
+ log_fds[0] = log_fds[n_fds];
+ err_fds[0] = err_fds[n_fds];
}
UNLOCK_LOGS();
- tor_log_set_sigsafe_err_fds(fds, n_fds);
+ tor_log_set_sigsafe_err_fds(err_fds, n_fds);
}
/** Add to <b>out</b> a copy of every currently configured log file name. Used
@@ -805,7 +832,34 @@ logs_free_all(void)
}
/* We _could_ destroy the log mutex here, but that would screw up any logs
- * that happened between here and the end of execution. */
+ * that happened between here and the end of execution.
+ * If tor is re-initialized, log_mutex_initialized will still be 1. So we
+ * won't trigger any undefined behaviour by trying to re-initialize the
+ * log mutex. */
+}
+
+/** Close signal-safe log files.
+ * Closing the log files makes the process and OS flush log buffers.
+ *
+ * This function is safe to call from a signal handler. It should only be
+ * called when shutting down the log or err modules. It is currenly called
+ * by the err module, when terminating the process on an abnormal condition.
+ */
+void
+logs_close_sigsafe(void)
+{
+ logfile_t *victim, *next;
+ /* We can't LOCK_LOGS() in a signal handler, because it may call
+ * signal-unsafe functions. And we can't deallocate memory, either. */
+ next = logfiles;
+ logfiles = NULL;
+ while (next) {
+ victim = next;
+ next = next->next;
+ if (victim->needs_close) {
+ close_log_sigsafe(victim);
+ }
+ }
}
/** Remove and free the log entry <b>victim</b> from the linked-list
@@ -834,13 +888,26 @@ delete_log(logfile_t *victim)
}
/** Helper: release system resources (but not memory) held by a single
- * logfile_t. */
+ * signal-safe logfile_t. If the log's resources can not be released in
+ * a signal handler, does nothing. */
static void
-close_log(logfile_t *victim)
+close_log_sigsafe(logfile_t *victim)
{
if (victim->needs_close && victim->fd >= 0) {
+ /* We can't do anything useful here if close() fails: we're shutting
+ * down logging, and the err module only does fatal errors. */
close(victim->fd);
victim->fd = -1;
+ }
+}
+
+/** Helper: release system resources (but not memory) held by a single
+ * logfile_t. */
+static void
+close_log(logfile_t *victim)
+{
+ if (victim->needs_close) {
+ close_log_sigsafe(victim);
} else if (victim->is_syslog) {
#ifdef HAVE_SYSLOG_H
if (--syslog_count == 0) {
@@ -1021,7 +1088,7 @@ flush_pending_log_callbacks(void)
do {
SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) {
const int severity = msg->severity;
- const int domain = msg->domain;
+ const log_domain_mask_t domain = msg->domain;
for (lf = logfiles; lf; lf = lf->next) {
if (! lf->callback || lf->seems_dead ||
! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
@@ -1232,7 +1299,7 @@ add_android_log(const log_severity_list_t *severity,
UNLOCK_LOGS();
return 0;
}
-#endif // HAVE_ANDROID_LOG_H.
+#endif /* defined(HAVE_ANDROID_LOG_H) */
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
@@ -1268,9 +1335,14 @@ static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
- "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", NULL
+ "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", "MESG",
+ NULL
};
+CTASSERT(ARRAY_LENGTH(domain_list) == N_LOGGING_DOMAINS + 1);
+
+CTASSERT((UINT64_C(1)<<(N_LOGGING_DOMAINS-1)) < LOWEST_RESERVED_LD_FLAG_);
+
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
* or 0 if there is no such name. */
static log_domain_mask_t
@@ -1371,7 +1443,7 @@ parse_log_severity_config(const char **cfg_ptr,
if (!strcmp(domain, "*")) {
domains = ~0u;
} else {
- int d;
+ log_domain_mask_t d;
int negate=0;
if (*domain == '~') {
negate = 1;
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index dbc1c47021..4291418eb6 100644
--- a/src/lib/log/log.h
+++ b/src/lib/log/log.h
@@ -11,10 +11,12 @@
**/
#ifndef TOR_TORLOG_H
+#define TOR_TORLOG_H
#include <stdarg.h>
#include "lib/cc/torint.h"
#include "lib/cc/compat_compiler.h"
+#include "lib/defs/logging_types.h"
#include "lib/testsupport/testsupport.h"
#ifdef HAVE_SYSLOG_H
@@ -55,81 +57,81 @@
/* Logging domains */
/** Catch-all for miscellaneous events and fatal errors. */
-#define LD_GENERAL (1u<<0)
+#define LD_GENERAL (UINT64_C(1)<<0)
/** The cryptography subsystem. */
-#define LD_CRYPTO (1u<<1)
+#define LD_CRYPTO (UINT64_C(1)<<1)
/** Networking. */
-#define LD_NET (1u<<2)
+#define LD_NET (UINT64_C(1)<<2)
/** Parsing and acting on our configuration. */
-#define LD_CONFIG (1u<<3)
+#define LD_CONFIG (UINT64_C(1)<<3)
/** Reading and writing from the filesystem. */
-#define LD_FS (1u<<4)
+#define LD_FS (UINT64_C(1)<<4)
/** Other servers' (non)compliance with the Tor protocol. */
-#define LD_PROTOCOL (1u<<5)
+#define LD_PROTOCOL (UINT64_C(1)<<5)
/** Memory management. */
-#define LD_MM (1u<<6)
+#define LD_MM (UINT64_C(1)<<6)
/** HTTP implementation. */
-#define LD_HTTP (1u<<7)
+#define LD_HTTP (UINT64_C(1)<<7)
/** Application (socks) requests. */
-#define LD_APP (1u<<8)
+#define LD_APP (UINT64_C(1)<<8)
/** Communication via the controller protocol. */
-#define LD_CONTROL (1u<<9)
+#define LD_CONTROL (UINT64_C(1)<<9)
/** Building, using, and managing circuits. */
-#define LD_CIRC (1u<<10)
+#define LD_CIRC (UINT64_C(1)<<10)
/** Hidden services. */
-#define LD_REND (1u<<11)
+#define LD_REND (UINT64_C(1)<<11)
/** Internal errors in this Tor process. */
-#define LD_BUG (1u<<12)
+#define LD_BUG (UINT64_C(1)<<12)
/** Learning and using information about Tor servers. */
-#define LD_DIR (1u<<13)
+#define LD_DIR (UINT64_C(1)<<13)
/** Learning and using information about Tor servers. */
-#define LD_DIRSERV (1u<<14)
+#define LD_DIRSERV (UINT64_C(1)<<14)
/** Onion routing protocol. */
-#define LD_OR (1u<<15)
+#define LD_OR (UINT64_C(1)<<15)
/** Generic edge-connection functionality. */
-#define LD_EDGE (1u<<16)
+#define LD_EDGE (UINT64_C(1)<<16)
#define LD_EXIT LD_EDGE
/** Bandwidth accounting. */
-#define LD_ACCT (1u<<17)
+#define LD_ACCT (UINT64_C(1)<<17)
/** Router history */
-#define LD_HIST (1u<<18)
+#define LD_HIST (UINT64_C(1)<<18)
/** OR handshaking */
-#define LD_HANDSHAKE (1u<<19)
+#define LD_HANDSHAKE (UINT64_C(1)<<19)
/** Heartbeat messages */
-#define LD_HEARTBEAT (1u<<20)
+#define LD_HEARTBEAT (UINT64_C(1)<<20)
/** Abstract channel_t code */
-#define LD_CHANNEL (1u<<21)
+#define LD_CHANNEL (UINT64_C(1)<<21)
/** Scheduler */
-#define LD_SCHED (1u<<22)
+#define LD_SCHED (UINT64_C(1)<<22)
/** Guard nodes */
-#define LD_GUARD (1u<<23)
+#define LD_GUARD (UINT64_C(1)<<23)
/** Generation and application of consensus diffs. */
-#define LD_CONSDIFF (1u<<24)
+#define LD_CONSDIFF (UINT64_C(1)<<24)
/** Denial of Service mitigation. */
-#define LD_DOS (1u<<25)
+#define LD_DOS (UINT64_C(1)<<25)
/** Processes */
-#define LD_PROCESS (1u<<26)
+#define LD_PROCESS (UINT64_C(1)<<26)
/** Pluggable Transports. */
-#define LD_PT (1u<<27)
+#define LD_PT (UINT64_C(1)<<27)
/** Bootstrap tracker. */
-#define LD_BTRACK (1u<<28)
-/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 29
-
-/** This log message is not safe to send to a callback-based logger
- * immediately. Used as a flag, not a log domain. */
-#define LD_NOCB (1u<<31)
-/** This log message should not include a function name, even if it otherwise
- * would. Used as a flag, not a log domain. */
-#define LD_NOFUNCNAME (1u<<30)
+#define LD_BTRACK (UINT64_C(1)<<28)
+/** Message-passing backend. */
+#define LD_MESG (UINT64_C(1)<<29)
+#define N_LOGGING_DOMAINS 30
+/** First bit that is reserved in log_domain_mask_t for non-domain flags. */
+#define LOWEST_RESERVED_LD_FLAG_ (UINT64_C(1)<<61)
#ifdef TOR_UNIT_TESTS
/** This log message should not be intercepted by mock_saving_logv */
-#define LD_NO_MOCK (1u<<29)
+#define LD_NO_MOCK (UINT64_C(1)<<61)
#endif
-/** Mask of zero or more log domains, OR'd together. */
-typedef uint32_t log_domain_mask_t;
+/** This log message is not safe to send to a callback-based logger
+ * immediately. Used as a flag, not a log domain. */
+#define LD_NOCB (UINT64_C(1)<<62)
+/** This log message should not include a function name, even if it otherwise
+ * would. Used as a flag, not a log domain. */
+#define LD_NOFUNCNAME (UINT64_C(1)<<63)
/** Configures which severities are logged for each logging domain for a given
* log target. */
@@ -140,7 +142,8 @@ typedef struct log_severity_list_t {
} log_severity_list_t;
/** Callback type used for add_callback_log. */
-typedef void (*log_callback)(int severity, uint32_t domain, const char *msg);
+typedef void (*log_callback)(int severity, log_domain_mask_t domain,
+ const char *msg);
void init_logging(int disable_startup_queue);
int parse_log_level(const char *level);
@@ -170,6 +173,7 @@ void logs_set_domain_logging(int enabled);
int get_min_log_level(void);
void switch_logs_debug(void);
void logs_free_all(void);
+void logs_close_sigsafe(void);
void add_temp_log(int min_severity);
void close_temp_logs(void);
void rollback_log_changes(void);
@@ -192,6 +196,21 @@ void tor_log_get_logfile_names(struct smartlist_t *out);
extern int log_global_min_severity_;
+#ifdef TOR_COVERAGE
+/* For coverage builds, we try to avoid our log_debug optimization, since it
+ * can have weird effects on internal macro coverage. */
+#define debug_logging_enabled() (1)
+#else
+static inline bool debug_logging_enabled(void);
+/**
+ * Return true iff debug logging is enabled for at least one domain.
+ */
+static inline bool debug_logging_enabled(void)
+{
+ return PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG);
+}
+#endif /* defined(TOR_COVERAGE) */
+
void log_fn_(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5);
@@ -221,8 +240,8 @@ void tor_log_string(int severity, log_domain_mask_t domain,
log_fn_ratelim_(ratelim, severity, domain, __FUNCTION__, args)
#define log_debug(domain, args...) \
STMT_BEGIN \
- if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
- log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \
+ if (debug_logging_enabled()) \
+ log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \
STMT_END
#define log_info(domain, args...) \
log_fn_(LOG_INFO, domain, __FUNCTION__, args)
@@ -239,8 +258,8 @@ void tor_log_string(int severity, log_domain_mask_t domain,
#define log_debug(domain, args, ...) \
STMT_BEGIN \
- if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
- log_fn_(LOG_DEBUG, domain, __FUNCTION__, args, ##__VA_ARGS__); \
+ if (debug_logging_enabled()) \
+ log_fn_(LOG_DEBUG, domain, __FUNCTION__, args, ##__VA_ARGS__); \
STMT_END
#define log_info(domain, args,...) \
log_fn_(LOG_INFO, domain, __FUNCTION__, args, ##__VA_ARGS__)
@@ -278,5 +297,4 @@ MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
va_list ap) CHECK_PRINTF(5,0));
#endif
-# define TOR_TORLOG_H
#endif /* !defined(TOR_TORLOG_H) */
diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h
index 48edd7c849..1db54ba726 100644
--- a/src/lib/log/ratelim.h
+++ b/src/lib/log/ratelim.h
@@ -50,4 +50,4 @@ typedef struct ratelim_t {
char *rate_limit_log(ratelim_t *lim, time_t now);
-#endif
+#endif /* !defined(TOR_RATELIM_H) */
diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c
index c65a91ae9e..0e99be35a4 100644
--- a/src/lib/log/util_bug.c
+++ b/src/lib/log/util_bug.c
@@ -11,6 +11,7 @@
#include "lib/log/util_bug.h"
#include "lib/log/log.h"
#include "lib/err/backtrace.h"
+#include "lib/err/torerr.h"
#ifdef TOR_UNIT_TESTS
#include "lib/smartlist_core/smartlist_core.h"
#include "lib/smartlist_core/smartlist_foreach.h"
@@ -70,25 +71,45 @@ tor_set_failed_assertion_callback(void (*fn)(void))
/** Helper for tor_assert: report the assertion failure. */
void
+CHECK_PRINTF(5, 6)
tor_assertion_failed_(const char *fname, unsigned int line,
- const char *func, const char *expr)
+ const char *func, const char *expr,
+ const char *fmt, ...)
{
- char buf[256];
+ char *buf = NULL;
+ char *extra = NULL;
+ va_list ap;
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+#endif
+ if (fmt) {
+ va_start(ap,fmt);
+ tor_vasprintf(&extra, fmt, ap);
+ va_end(ap);
+ }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
fname, line, func, expr);
- tor_snprintf(buf, sizeof(buf),
- "Assertion %s failed in %s at %s:%u",
- expr, func, fname, line);
+ tor_asprintf(&buf, "Assertion %s failed in %s at %s:%u: %s",
+ expr, func, fname, line, extra ? extra : "");
+ tor_free(extra);
log_backtrace(LOG_ERR, LD_BUG, buf);
+ tor_free(buf);
}
/** Helper for tor_assert_nonfatal: report the assertion failure. */
void
+CHECK_PRINTF(6, 7)
tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
- int once)
+ int once, const char *fmt, ...)
{
- char buf[256];
+ char *buf = NULL;
const char *once_str = once ?
" (Future instances of this warning will be silenced.)": "";
if (! expr) {
@@ -98,7 +119,7 @@ tor_bug_occurred_(const char *fname, unsigned int line,
}
log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s",
fname, line, func, once_str);
- tor_snprintf(buf, sizeof(buf),
+ tor_asprintf(&buf,
"Line unexpectedly reached at %s at %s:%u",
func, fname, line);
} else {
@@ -106,13 +127,32 @@ tor_bug_occurred_(const char *fname, unsigned int line,
add_captured_bug(expr);
return;
}
+
+ va_list ap;
+ char *extra = NULL;
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+#endif
+ if (fmt) {
+ va_start(ap,fmt);
+ tor_vasprintf(&extra, fmt, ap);
+ va_end(ap);
+ }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s",
fname, line, func, expr, once_str);
- tor_snprintf(buf, sizeof(buf),
- "Non-fatal assertion %s failed in %s at %s:%u",
- expr, func, fname, line);
+ tor_asprintf(&buf, "Non-fatal assertion %s failed in %s at %s:%u%s%s",
+ expr, func, fname, line, fmt ? " : " : "",
+ extra ? extra : "");
+ tor_free(extra);
}
log_backtrace(LOG_WARN, LD_BUG, buf);
+ tor_free(buf);
#ifdef TOR_UNIT_TESTS
if (failed_assertion_cb) {
@@ -122,16 +162,18 @@ tor_bug_occurred_(const char *fname, unsigned int line,
}
/**
- * Call the abort() function to kill the current process with a fatal
- * error.
+ * Call the tor_raw_abort_() function to close raw logs, then kill the current
+ * process with a fatal error. But first, close the file-based log file
+ * descriptors, so error messages are written before process termination.
*
* (This is a separate function so that we declare it in util_bug.h without
- * including stdlib in all the users of util_bug.h)
+ * including torerr.h in all the users of util_bug.h)
**/
void
tor_abort_(void)
{
- abort();
+ logs_close_sigsafe();
+ tor_raw_abort_();
}
#ifdef _WIN32
diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h
index 2a4d68127e..546ae1e3ef 100644
--- a/src/lib/log/util_bug.h
+++ b/src/lib/log/util_bug.h
@@ -80,10 +80,10 @@
tor__assert_tmp_value__; \
} )
#define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e)
-#else
+#else /* !(defined(TOR_UNIT_TESTS) && defined(__GNUC__)) */
#define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e)
#define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e)
-#endif
+#endif /* defined(TOR_UNIT_TESTS) && defined(__GNUC__) */
/* Sometimes we don't want to use assertions during branch coverage tests; it
* leads to tons of unreached branches which in reality are only assertions we
@@ -92,21 +92,28 @@
#define tor_assert(a) STMT_BEGIN \
(void)(a); \
STMT_END
-#else
+#define tor_assertf(a, fmt, ...) STMT_BEGIN \
+ (void)(a); \
+ (void)(fmt); \
+ STMT_END
+#else /* !(defined(TOR_UNIT_TESTS) && ... */
/** Like assert(3), but send assertion failures to the log as well as to
* stderr. */
-#define tor_assert(expr) STMT_BEGIN \
+#define tor_assert(expr) tor_assertf(expr, NULL)
+
+#define tor_assertf(expr, fmt, ...) STMT_BEGIN \
if (ASSERT_PREDICT_LIKELY_(expr)) { \
} else { \
- tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \
- tor_abort_(); \
+ tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr, \
+ fmt, ##__VA_ARGS__); \
+ tor_abort_(); \
} STMT_END
#endif /* defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) */
#define tor_assert_unreached() \
STMT_BEGIN { \
tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, \
- "line should be unreached"); \
+ "line should be unreached", NULL); \
tor_abort_(); \
} STMT_END
@@ -136,34 +143,47 @@
#ifdef ALL_BUGS_ARE_FATAL
#define tor_assert_nonfatal_unreached() tor_assert(0)
#define tor_assert_nonfatal(cond) tor_assert((cond))
+#define tor_assertf_nonfatal(cond, fmt, ...) \
+ tor_assertf(cond, fmt, ##__VA_ARGS__)
#define tor_assert_nonfatal_unreached_once() tor_assert(0)
#define tor_assert_nonfatal_once(cond) tor_assert((cond))
#define BUG(cond) \
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
- (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")"), \
+ (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
tor_abort_(), 1) \
: 0)
#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert_nonfatal_unreached() STMT_NIL
#define tor_assert_nonfatal(cond) ((void)(cond))
+#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
+ (void)cond; \
+ (void)fmt; \
+ STMT_END
#define tor_assert_nonfatal_unreached_once() STMT_NIL
#define tor_assert_nonfatal_once(cond) ((void)(cond))
#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
#define tor_assert_nonfatal_unreached() STMT_BEGIN \
- tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0); \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
STMT_END
#define tor_assert_nonfatal(cond) STMT_BEGIN \
if (ASSERT_PREDICT_LIKELY_(cond)) { \
} else { \
- tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0); \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, NULL);\
+ } \
+ STMT_END
+#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
+ if (ASSERT_PREDICT_UNLIKELY_(cond)) { \
+ } else { \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, \
+ fmt, ##__VA_ARGS__); \
} \
STMT_END
#define tor_assert_nonfatal_unreached_once() STMT_BEGIN \
static int warning_logged__ = 0; \
if (!warning_logged__) { \
warning_logged__ = 1; \
- tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1); \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \
} \
STMT_END
#define tor_assert_nonfatal_once(cond) STMT_BEGIN \
@@ -171,12 +191,12 @@
if (ASSERT_PREDICT_LIKELY_(cond)) { \
} else if (!warning_logged__) { \
warning_logged__ = 1; \
- tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\
} \
STMT_END
#define BUG(cond) \
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
- (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0), 1) \
+ (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",1,NULL),1) \
: 0)
#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
@@ -188,7 +208,7 @@
if (bool_result && !var) { \
var = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1); \
+ "!("#cond")", 1, NULL); \
} \
bool_result; } ))
#else /* !(defined(__GNUC__)) */
@@ -198,7 +218,7 @@
(var ? 1 : \
(var=1, \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1), \
+ "!("#cond")", 1, NULL), \
1)) \
: 0)
#endif /* defined(__GNUC__) */
@@ -221,10 +241,11 @@
#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
void tor_assertion_failed_(const char *fname, unsigned int line,
- const char *func, const char *expr);
+ const char *func, const char *expr,
+ const char *fmt, ...);
void tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
- int once);
+ int once, const char *fmt, ...);
void tor_abort_(void) ATTR_NORETURN;
diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h
index 33413dfd15..ecfa88792d 100644
--- a/src/lib/log/win32err.h
+++ b/src/lib/log/win32err.h
@@ -19,4 +19,4 @@
char *format_win32_error(DWORD err);
#endif
-#endif
+#endif /* !defined(TOR_WIN32ERR_H) */
diff --git a/src/lib/malloc/include.am b/src/lib/malloc/include.am
index 95d96168e1..b74292bc6e 100644
--- a/src/lib/malloc/include.am
+++ b/src/lib/malloc/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-malloc-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_malloc_a_SOURCES = \
src/lib/malloc/malloc.c \
src/lib/malloc/map_anon.c
@@ -18,6 +19,7 @@ src_lib_libtor_malloc_testing_a_SOURCES = \
src_lib_libtor_malloc_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_malloc_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/malloc/malloc.h \
src/lib/malloc/map_anon.h
diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h
index ef6b509ca4..8c81d30dd5 100644
--- a/src/lib/malloc/malloc.h
+++ b/src/lib/malloc/malloc.h
@@ -48,12 +48,12 @@ void tor_free_(void *mem);
raw_free(*tor_free__tmpvar); \
*tor_free__tmpvar=NULL; \
STMT_END
-#else
+#else /* !(defined(__GNUC__)) */
#define tor_free(p) STMT_BEGIN \
raw_free(p); \
(p)=NULL; \
STMT_END
-#endif
+#endif /* defined(__GNUC__) */
#define tor_malloc(size) tor_malloc_(size)
#define tor_malloc_zero(size) tor_malloc_zero_(size)
diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c
index 2430f7ad11..ae4edff769 100644
--- a/src/lib/malloc/map_anon.c
+++ b/src/lib/malloc/map_anon.c
@@ -27,6 +27,9 @@
#include <windows.h>
#endif
+#include <string.h>
+#include <errno.h>
+
/**
* Macro to get the high bytes of a size_t, if there are high bytes.
* Windows needs this; other operating systems define a size_t that does
@@ -59,7 +62,7 @@
#define FLAG_NOINHERIT VM_INHERIT_NONE
#elif defined(MAP_INHERIT_NONE)
#define FLAG_NOINHERIT MAP_INHERIT_NONE
-#endif
+#endif /* defined(INHERIT_NONE) || ... */
#elif defined(HAVE_MADVISE)
@@ -72,6 +75,11 @@
#define FLAG_NOINHERIT MADV_DONTFORK
#endif
+#endif /* defined(HAVE_MINHERIT) || ... */
+
+#if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT)
+#warn "minherit() is defined, but we couldn't find the right flag for it."
+#warn "This is probably a bug in Tor's support for this platform."
#endif
/**
@@ -91,7 +99,7 @@ lock_mem(void *mem, size_t sz)
(void) sz;
return 0;
-#endif
+#endif /* defined(_WIN32) || ... */
}
/**
@@ -103,12 +111,22 @@ static int
nodump_mem(void *mem, size_t sz)
{
#if defined(MADV_DONTDUMP)
- return madvise(mem, sz, MADV_DONTDUMP);
+ int rv = madvise(mem, sz, MADV_DONTDUMP);
+ if (rv == 0) {
+ return 0;
+ } else if (errno == ENOSYS || errno == EINVAL) {
+ return 0; // syscall not supported, or flag not supported.
+ } else {
+ tor_log_err_sigsafe("Unexpected error from madvise: ",
+ strerror(errno),
+ NULL);
+ return -1;
+ }
#else
(void) mem;
(void) sz;
return 0;
-#endif
+#endif /* defined(MADV_DONTDUMP) */
}
/**
@@ -117,18 +135,43 @@ nodump_mem(void *mem, size_t sz)
* fork, and if that doesn't work, by having them unmapped after a fork.
* Return 0 on success or if the facility is not available on this OS; return
* -1 on failure.
+ *
+ * If we successfully make the memory uninheritable, adjust the value of
+ * *<b>inherit_result_out</b>.
*/
static int
-noinherit_mem(void *mem, size_t sz)
+noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out)
{
#ifdef FLAG_ZERO
int r = MINHERIT(mem, sz, FLAG_ZERO);
- if (r == 0)
+ if (r == 0) {
+ *inherit_result_out = INHERIT_RES_ZERO;
return 0;
-#endif
+ }
+#endif /* defined(FLAG_ZERO) */
+
#ifdef FLAG_NOINHERIT
- return MINHERIT(mem, sz, FLAG_NOINHERIT);
+ int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT);
+ if (r2 == 0) {
+ *inherit_result_out = INHERIT_RES_DROP;
+ return 0;
+ }
+#endif /* defined(FLAG_NOINHERIT) */
+
+#if defined(FLAG_ZERO) || defined(FLAG_NOINHERIT)
+ /* At least one operation was tried, and neither succeeded. */
+
+ if (errno == ENOSYS || errno == EINVAL) {
+ /* Syscall not supported, or flag not supported. */
+ return 0;
+ } else {
+ tor_log_err_sigsafe("Unexpected error from minherit: ",
+ strerror(errno),
+ NULL);
+ return -1;
+ }
#else
+ (void)inherit_result_out;
(void)mem;
(void)sz;
return 0;
@@ -148,14 +191,25 @@ noinherit_mem(void *mem, size_t sz)
* Memory returned from this function must be released with
* tor_munmap_anonymous().
*
+ * If <b>inherit_result_out</b> is non-NULL, set it to one of
+ * INHERIT_RES_KEEP, INHERIT_RES_DROP, or INHERIT_RES_ZERO, depending on the
+ * properties of the returned memory.
+ *
* [Note: OS people use the word "anonymous" here to mean that the memory
* isn't associated with any file. This has *nothing* to do with the kind of
* anonymity that Tor is trying to provide.]
*/
void *
-tor_mmap_anonymous(size_t sz, unsigned flags)
+tor_mmap_anonymous(size_t sz, unsigned flags,
+ inherit_res_t *inherit_result_out)
{
void *ptr;
+ inherit_res_t itmp=0;
+ if (inherit_result_out == NULL) {
+ inherit_result_out = &itmp;
+ }
+ *inherit_result_out = INHERIT_RES_KEEP;
+
#if defined(_WIN32)
HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL, /*attributes*/
@@ -178,7 +232,7 @@ tor_mmap_anonymous(size_t sz, unsigned flags)
raw_assert(ptr != NULL);
#else
ptr = tor_malloc_zero(sz);
-#endif
+#endif /* defined(_WIN32) || ... */
if (flags & ANONMAP_PRIVATE) {
int lock_result = lock_mem(ptr, sz);
@@ -188,7 +242,7 @@ tor_mmap_anonymous(size_t sz, unsigned flags)
}
if (flags & ANONMAP_NOINHERIT) {
- int noinherit_result = noinherit_mem(ptr, sz);
+ int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out);
raw_assert(noinherit_result == 0);
}
@@ -213,5 +267,5 @@ tor_munmap_anonymous(void *mapping, size_t sz)
#else
(void)sz;
tor_free(mapping);
-#endif
+#endif /* defined(_WIN32) || ... */
}
diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h
index cc5797e4ec..4c4690e12f 100644
--- a/src/lib/malloc/map_anon.h
+++ b/src/lib/malloc/map_anon.h
@@ -31,7 +31,41 @@
*/
#define ANONMAP_NOINHERIT (1u<<1)
-void *tor_mmap_anonymous(size_t sz, unsigned flags);
+typedef enum {
+ /** Possible value for inherit_result_out: the memory will be kept
+ * by any child process. */
+ INHERIT_RES_KEEP=0,
+ /** Possible value for inherit_result_out: the memory will be dropped in the
+ * child process. Attempting to access it will likely cause a segfault. */
+ INHERIT_RES_DROP,
+ /** Possible value for inherit_result_out: the memory will be cleared in
+ * the child process. */
+ INHERIT_RES_ZERO
+} inherit_res_t;
+
+/* Here we define the NOINHERIT_CAN_FAIL macro if and only if
+ * it's possible that ANONMAP_NOINHERIT might yield inheritable memory.
+ */
+#ifdef _WIN32
+/* Windows can't fork, so NOINHERIT is never needed. */
+#elif defined(HAVE_MINHERIT)
+/* minherit() will always have a working MAP_INHERIT_NONE or MAP_INHERIT_ZERO.
+ * NOINHERIT should always work.
+ */
+#elif defined(HAVE_MADVISE)
+/* madvise() sometimes has neither MADV_DONTFORK and MADV_WIPEONFORK.
+ * We need to be ready for the possibility it failed.
+ *
+ * (Linux added DONTFORK in 2.6.16 and WIPEONFORK in 4.14. If we someday
+ * require 2.6.16 or later, we can assume that DONTFORK will work.)
+ */
+#define NOINHERIT_CAN_FAIL
+#else
+#define NOINHERIT_CAN_FAIL
+#endif /* defined(_WIN32) || ... */
+
+void *tor_mmap_anonymous(size_t sz, unsigned flags,
+ inherit_res_t *inherit_result_out);
void tor_munmap_anonymous(void *mapping, size_t sz);
#endif /* !defined(TOR_MAP_ANON_H) */
diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h
index cb24649e6c..a73789c945 100644
--- a/src/lib/math/fp.h
+++ b/src/lib/math/fp.h
@@ -21,4 +21,4 @@ int64_t tor_llround(double d) ATTR_CONST;
int64_t clamp_double_to_int64(double number);
int tor_isinf(double x);
-#endif
+#endif /* !defined(TOR_FP_H) */
diff --git a/src/lib/math/include.am b/src/lib/math/include.am
index 6d65ce90a7..b2ca280f47 100644
--- a/src/lib/math/include.am
+++ b/src/lib/math/include.am
@@ -5,17 +5,18 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-math-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_math_a_SOURCES = \
src/lib/math/fp.c \
src/lib/math/laplace.c \
src/lib/math/prob_distr.c
-
src_lib_libtor_math_testing_a_SOURCES = \
$(src_lib_libtor_math_a_SOURCES)
src_lib_libtor_math_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/math/fp.h \
src/lib/math/laplace.h \
diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h
index e8651e5197..02b0e890f0 100644
--- a/src/lib/math/laplace.h
+++ b/src/lib/math/laplace.h
@@ -19,4 +19,4 @@ int64_t sample_laplace_distribution(double mu, double b, double p);
int64_t add_laplace_noise(int64_t signal, double random, double delta_f,
double epsilon);
-#endif
+#endif /* !defined(TOR_LAPLACE_H) */
diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index c952dadc06..d44dc28265 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -46,26 +46,27 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/cc/ctassert.h"
+#include "lib/log/util_bug.h"
#include <float.h>
#include <math.h>
#include <stddef.h>
-/** Validators for downcasting macros below */
-#define validate_container_of(PTR, TYPE, FIELD) \
- (0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) - \
- offsetof(TYPE, FIELD)))->FIELD))
-#define validate_const_container_of(PTR, TYPE, FIELD) \
- (0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) - \
- offsetof(TYPE, FIELD)))->FIELD))
-/** Downcasting macro */
-#define container_of(PTR, TYPE, FIELD) \
- ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD)) \
- + validate_container_of(PTR, TYPE, FIELD))
-/** Constified downcasting macro */
-#define const_container_of(PTR, TYPE, FIELD) \
- ((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD)) \
- + validate_const_container_of(PTR, TYPE, FIELD))
+/** Declare a function that downcasts from a generic dist struct to the actual
+ * subtype probablity distribution it represents. */
+#define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \
+ static inline \
+ const struct name * \
+ dist_to_const_##name(const struct dist *obj) { \
+ tor_assert(obj->ops == &name##_ops); \
+ return SUBTYPE_P(obj, struct name, base); \
+ }
+DECLARE_PROB_DISTR_DOWNCAST_FN(uniform)
+DECLARE_PROB_DISTR_DOWNCAST_FN(geometric)
+DECLARE_PROB_DISTR_DOWNCAST_FN(logistic)
+DECLARE_PROB_DISTR_DOWNCAST_FN(log_logistic)
+DECLARE_PROB_DISTR_DOWNCAST_FN(genpareto)
+DECLARE_PROB_DISTR_DOWNCAST_FN(weibull)
/**
* Count number of one bits in 32-bit word.
@@ -458,7 +459,7 @@ random_uniform_01(void)
* system is broken.
*/
z = 0;
- while ((x = crypto_rand_u32()) == 0) {
+ while ((x = crypto_fast_rng_get_u32(get_thread_fast_rng())) == 0) {
if (z >= 1088)
/* Your bit sampler is broken. Go home. */
return 0;
@@ -472,8 +473,8 @@ random_uniform_01(void)
* occur only with measure zero in the uniform distribution on
* [0, 1].
*/
- hi = crypto_rand_u32() | UINT32_C(0x80000000);
- lo = crypto_rand_u32() | UINT32_C(0x00000001);
+ hi = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x80000000);
+ lo = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x00000001);
/* Round to nearest scaled significand in [2^63, 2^64]. */
s = hi*(double)4294967296 + lo;
@@ -1315,40 +1316,48 @@ sample_geometric(uint32_t s, double p0, double p)
/** Public API for probability distributions:
*
- * For each probability distribution we define each public functions
- * (sample/cdf/sf/icdf/isf) as part of its dist_ops structure.
+ * These are wrapper functions on top of the various probability distribution
+ * operations using the generic <b>dist</b> structure.
+
+ * These are the functions that should be used by consumers of this API.
*/
+/** Returns the name of the distribution in <b>dist</b>. */
const char *
dist_name(const struct dist *dist)
{
return dist->ops->name;
}
+/* Sample a value from <b>dist</b> and return it. */
double
dist_sample(const struct dist *dist)
{
return dist->ops->sample(dist);
}
+/** Compute the CDF of <b>dist</b> at <b>x</b>. */
double
dist_cdf(const struct dist *dist, double x)
{
return dist->ops->cdf(dist, x);
}
+/** Compute the SF (Survival function) of <b>dist</b> at <b>x</b>. */
double
dist_sf(const struct dist *dist, double x)
{
return dist->ops->sf(dist, x);
}
+/** Compute the iCDF (Inverse CDF) of <b>dist</b> at <b>x</b>. */
double
dist_icdf(const struct dist *dist, double p)
{
return dist->ops->icdf(dist, p);
}
+/** Compute the iSF (Inverse Survival function) of <b>dist</b> at <b>x</b>. */
double
dist_isf(const struct dist *dist, double p)
{
@@ -1360,8 +1369,7 @@ dist_isf(const struct dist *dist, double p)
static double
uniform_sample(const struct dist *dist)
{
- const struct uniform *U = const_container_of(dist, struct uniform,
- base);
+ const struct uniform *U = dist_to_const_uniform(dist);
double p0 = random_uniform_01();
return sample_uniform_interval(p0, U->a, U->b);
@@ -1370,9 +1378,7 @@ uniform_sample(const struct dist *dist)
static double
uniform_cdf(const struct dist *dist, double x)
{
- const struct uniform *U = const_container_of(dist, struct uniform,
- base);
-
+ const struct uniform *U = dist_to_const_uniform(dist);
if (x < U->a)
return 0;
else if (x < U->b)
@@ -1384,8 +1390,7 @@ uniform_cdf(const struct dist *dist, double x)
static double
uniform_sf(const struct dist *dist, double x)
{
- const struct uniform *U = const_container_of(dist, struct uniform,
- base);
+ const struct uniform *U = dist_to_const_uniform(dist);
if (x > U->b)
return 0;
@@ -1398,8 +1403,7 @@ uniform_sf(const struct dist *dist, double x)
static double
uniform_icdf(const struct dist *dist, double p)
{
- const struct uniform *U = const_container_of(dist, struct uniform,
- base);
+ const struct uniform *U = dist_to_const_uniform(dist);
double w = U->b - U->a;
return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p)));
@@ -1408,8 +1412,7 @@ uniform_icdf(const struct dist *dist, double p)
static double
uniform_isf(const struct dist *dist, double p)
{
- const struct uniform *U = const_container_of(dist, struct uniform,
- base);
+ const struct uniform *U = dist_to_const_uniform(dist);
double w = U->b - U->a;
return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p)));
@@ -1424,14 +1427,17 @@ const struct dist_ops uniform_ops = {
.isf = uniform_isf,
};
+/*******************************************************************/
+
+/** Private functions for each probability distribution. */
+
/** Functions for logistic distribution: */
static double
logistic_sample(const struct dist *dist)
{
- const struct logistic *L = const_container_of(dist, struct logistic,
- base);
- uint32_t s = crypto_rand_u32();
+ const struct logistic *L = dist_to_const_logistic(dist);
+ uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double t = random_uniform_01();
double p0 = random_uniform_01();
@@ -1441,36 +1447,28 @@ logistic_sample(const struct dist *dist)
static double
logistic_cdf(const struct dist *dist, double x)
{
- const struct logistic *L = const_container_of(dist, struct logistic,
- base);
-
+ const struct logistic *L = dist_to_const_logistic(dist);
return cdf_logistic(x, L->mu, L->sigma);
}
static double
logistic_sf(const struct dist *dist, double x)
{
- const struct logistic *L = const_container_of(dist, struct logistic,
- base);
-
+ const struct logistic *L = dist_to_const_logistic(dist);
return sf_logistic(x, L->mu, L->sigma);
}
static double
logistic_icdf(const struct dist *dist, double p)
{
- const struct logistic *L = const_container_of(dist, struct logistic,
- base);
-
+ const struct logistic *L = dist_to_const_logistic(dist);
return icdf_logistic(p, L->mu, L->sigma);
}
static double
logistic_isf(const struct dist *dist, double p)
{
- const struct logistic *L = const_container_of(dist, struct logistic,
- base);
-
+ const struct logistic *L = dist_to_const_logistic(dist);
return isf_logistic(p, L->mu, L->sigma);
}
@@ -1488,9 +1486,8 @@ const struct dist_ops logistic_ops = {
static double
log_logistic_sample(const struct dist *dist)
{
- const struct log_logistic *LL = const_container_of(dist, struct
- log_logistic, base);
- uint32_t s = crypto_rand_u32();
+ const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta);
@@ -1499,36 +1496,28 @@ log_logistic_sample(const struct dist *dist)
static double
log_logistic_cdf(const struct dist *dist, double x)
{
- const struct log_logistic *LL = const_container_of(dist,
- struct log_logistic, base);
-
+ const struct log_logistic *LL = dist_to_const_log_logistic(dist);
return cdf_log_logistic(x, LL->alpha, LL->beta);
}
static double
log_logistic_sf(const struct dist *dist, double x)
{
- const struct log_logistic *LL = const_container_of(dist,
- struct log_logistic, base);
-
+ const struct log_logistic *LL = dist_to_const_log_logistic(dist);
return sf_log_logistic(x, LL->alpha, LL->beta);
}
static double
log_logistic_icdf(const struct dist *dist, double p)
{
- const struct log_logistic *LL = const_container_of(dist,
- struct log_logistic, base);
-
+ const struct log_logistic *LL = dist_to_const_log_logistic(dist);
return icdf_log_logistic(p, LL->alpha, LL->beta);
}
static double
log_logistic_isf(const struct dist *dist, double p)
{
- const struct log_logistic *LL = const_container_of(dist,
- struct log_logistic, base);
-
+ const struct log_logistic *LL = dist_to_const_log_logistic(dist);
return isf_log_logistic(p, LL->alpha, LL->beta);
}
@@ -1546,9 +1535,8 @@ const struct dist_ops log_logistic_ops = {
static double
weibull_sample(const struct dist *dist)
{
- const struct weibull *W = const_container_of(dist, struct weibull,
- base);
- uint32_t s = crypto_rand_u32();
+ const struct weibull *W = dist_to_const_weibull(dist);
+ uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
return sample_weibull(s, p0, W->lambda, W->k);
@@ -1557,36 +1545,28 @@ weibull_sample(const struct dist *dist)
static double
weibull_cdf(const struct dist *dist, double x)
{
- const struct weibull *W = const_container_of(dist, struct weibull,
- base);
-
+ const struct weibull *W = dist_to_const_weibull(dist);
return cdf_weibull(x, W->lambda, W->k);
}
static double
weibull_sf(const struct dist *dist, double x)
{
- const struct weibull *W = const_container_of(dist, struct weibull,
- base);
-
+ const struct weibull *W = dist_to_const_weibull(dist);
return sf_weibull(x, W->lambda, W->k);
}
static double
weibull_icdf(const struct dist *dist, double p)
{
- const struct weibull *W = const_container_of(dist, struct weibull,
- base);
-
+ const struct weibull *W = dist_to_const_weibull(dist);
return icdf_weibull(p, W->lambda, W->k);
}
static double
weibull_isf(const struct dist *dist, double p)
{
- const struct weibull *W = const_container_of(dist, struct weibull,
- base);
-
+ const struct weibull *W = dist_to_const_weibull(dist);
return isf_weibull(p, W->lambda, W->k);
}
@@ -1604,9 +1584,8 @@ const struct dist_ops weibull_ops = {
static double
genpareto_sample(const struct dist *dist)
{
- const struct genpareto *GP = const_container_of(dist, struct genpareto,
- base);
- uint32_t s = crypto_rand_u32();
+ const struct genpareto *GP = dist_to_const_genpareto(dist);
+ uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi);
@@ -1615,36 +1594,28 @@ genpareto_sample(const struct dist *dist)
static double
genpareto_cdf(const struct dist *dist, double x)
{
- const struct genpareto *GP = const_container_of(dist, struct genpareto,
- base);
-
+ const struct genpareto *GP = dist_to_const_genpareto(dist);
return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi);
}
static double
genpareto_sf(const struct dist *dist, double x)
{
- const struct genpareto *GP = const_container_of(dist, struct genpareto,
- base);
-
+ const struct genpareto *GP = dist_to_const_genpareto(dist);
return sf_genpareto(x, GP->mu, GP->sigma, GP->xi);
}
static double
genpareto_icdf(const struct dist *dist, double p)
{
- const struct genpareto *GP = const_container_of(dist, struct genpareto,
- base);
-
+ const struct genpareto *GP = dist_to_const_genpareto(dist);
return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi);
}
static double
genpareto_isf(const struct dist *dist, double p)
{
- const struct genpareto *GP = const_container_of(dist, struct genpareto,
- base);
-
+ const struct genpareto *GP = dist_to_const_genpareto(dist);
return isf_genpareto(p, GP->mu, GP->sigma, GP->xi);
}
@@ -1662,8 +1633,8 @@ const struct dist_ops genpareto_ops = {
static double
geometric_sample(const struct dist *dist)
{
- const struct geometric *G = const_container_of(dist, struct geometric, base);
- uint32_t s = crypto_rand_u32();
+ const struct geometric *G = dist_to_const_geometric(dist);
+ uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
return sample_geometric(s, p0, G->p);
@@ -1672,7 +1643,7 @@ geometric_sample(const struct dist *dist)
static double
geometric_cdf(const struct dist *dist, double x)
{
- const struct geometric *G = const_container_of(dist, struct geometric, base);
+ const struct geometric *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1683,7 +1654,7 @@ geometric_cdf(const struct dist *dist, double x)
static double
geometric_sf(const struct dist *dist, double x)
{
- const struct geometric *G = const_container_of(dist, struct geometric, base);
+ const struct geometric *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1694,7 +1665,7 @@ geometric_sf(const struct dist *dist, double x)
static double
geometric_icdf(const struct dist *dist, double p)
{
- const struct geometric *G = const_container_of(dist, struct geometric, base);
+ const struct geometric *G = dist_to_const_geometric(dist);
return log1p(-p)/log1p(-G->p);
}
@@ -1702,7 +1673,7 @@ geometric_icdf(const struct dist *dist, double p)
static double
geometric_isf(const struct dist *dist, double p)
{
- const struct geometric *G = const_container_of(dist, struct geometric, base);
+ const struct geometric *G = dist_to_const_geometric(dist);
return log(p)/log1p(-G->p);
}
diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h
index 66acb796fd..7254dc8623 100644
--- a/src/lib/math/prob_distr.h
+++ b/src/lib/math/prob_distr.h
@@ -19,10 +19,100 @@ struct dist {
const struct dist_ops *ops;
};
+/**
+ * Untyped initializer element for struct dist using the specified
+ * struct dist_ops pointer. Don't actually use this directly -- use
+ * the type-specific macro built out of DIST_BASE_TYPED below -- but if
+ * you did use this directly, it would be something like:
+ *
+ * struct weibull mydist = {
+ * DIST_BASE(&weibull_ops),
+ * .lambda = ...,
+ * .k = ...,
+ * };
+ *
+ * Note there is NO COMPILER FEEDBACK if you accidentally do something
+ * like
+ *
+ * struct geometric mydist = {
+ * DIST_BASE(&weibull_ops),
+ * ...
+ * };
+ */
#define DIST_BASE(OPS) { .ops = (OPS) }
+
+/** A compile-time type-checking macro for use with DIST_BASE_TYPED.
+ *
+ * This macro works by checking that &OBJ is a pointer type that is the same
+ * type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint
+ * violation (which requires a diagnostic) if two pointers are different types
+ * and are subtracted. The sizeof() forces compile-time evaluation, and the
+ * multiplication by zero is to discard the result of the sizeof() from the
+ * expression.
+ *
+ * We define this conditionally to suppress false positives from
+ * Coverity, which gets confused by the sizeof business.
+ */
+#ifdef __COVERITY__
+#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0
+#else
+#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \
+ (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
+#endif /* defined(__COVERITY__) */
+
+/**
+* Typed initializer element for struct dist using the specified struct
+* dist_ops pointer. Don't actually use this directly -- use a
+* type-specific macro built out of it -- but if you did use this
+* directly, it would be something like:
+*
+* struct weibull mydist = {
+* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull),
+* .lambda = ...,
+* .k = ...,
+* };
+*
+* If you want to define a distribution type, define a canonical set of
+* operations and define a type-specific initializer element like so:
+*
+* struct foo {
+* struct dist base;
+* int omega;
+* double tau;
+* double phi;
+* };
+*
+* struct dist_ops foo_ops = ...;
+*
+* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo)
+*
+* Then users can do:
+*
+* struct foo mydist = {
+* FOO(mydist),
+* .omega = ...,
+* .tau = ...,
+* .phi = ...,
+* };
+*
+* If you accidentally write
+*
+* struct bar mydist = {
+* FOO(mydist),
+* ...
+* };
+*
+* then the compiler will report a type mismatch in the sizeof
+* expression, which otherwise evaporates at runtime.
+*/
#define DIST_BASE_TYPED(OPS, OBJ, TYPE) \
- DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
+ DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE))
+/**
+ * Generic operations on distributions. These simply defer to the
+ * corresponding dist_ops function. In the parlance of C++, these call
+ * virtual member functions.
+ */
const char *dist_name(const struct dist *);
double dist_sample(const struct dist *);
double dist_cdf(const struct dist *, double x);
@@ -30,6 +120,11 @@ double dist_sf(const struct dist *, double x);
double dist_icdf(const struct dist *, double p);
double dist_isf(const struct dist *, double p);
+/**
+ * Set of operations on a potentially parametric family of
+ * distributions. In the parlance of C++, this would be called a
+ * `vtable' and the members are virtual member functions.
+ */
struct dist_ops {
const char *name;
double (*sample)(const struct dist *);
@@ -153,6 +248,6 @@ STATIC double icdf_genpareto(double p, double mu, double sigma, double xi);
STATIC double isf_genpareto(double p, double mu, double sigma, double xi);
STATIC double sample_genpareto(uint32_t s, double p0, double xi);
-#endif
+#endif /* defined(PROB_DISTR_PRIVATE) */
-#endif
+#endif /* !defined(TOR_PROB_DISTR_H) */
diff --git a/src/lib/memarea/include.am b/src/lib/memarea/include.am
index 94343dcead..83fb99ec73 100644
--- a/src/lib/memarea/include.am
+++ b/src/lib/memarea/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-memarea-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_memarea_a_SOURCES = \
src/lib/memarea/memarea.c
@@ -13,5 +14,6 @@ src_lib_libtor_memarea_testing_a_SOURCES = \
src_lib_libtor_memarea_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_memarea_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/memarea/memarea.h
diff --git a/src/lib/meminfo/include.am b/src/lib/meminfo/include.am
index d1fdde6313..12c1bff72d 100644
--- a/src/lib/meminfo/include.am
+++ b/src/lib/meminfo/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-meminfo-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_meminfo_a_SOURCES = \
src/lib/meminfo/meminfo.c
@@ -13,5 +14,6 @@ src_lib_libtor_meminfo_testing_a_SOURCES = \
src_lib_libtor_meminfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_meminfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/meminfo/meminfo.h
diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h
index 2d64e1ab06..9580640f4d 100644
--- a/src/lib/meminfo/meminfo.h
+++ b/src/lib/meminfo/meminfo.h
@@ -18,4 +18,4 @@
void tor_log_mallinfo(int severity);
MOCK_DECL(int, get_total_system_memory, (size_t *mem_out));
-#endif
+#endif /* !defined(TOR_MEMINFO_H) */
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 214d8aa3eb..546af800a9 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -339,7 +339,7 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
break;
case AF_INET6:
/* Shortest addr [ :: ] + \0 */
- if (len < (3 + (decorate ? 2 : 0)))
+ if (len < (3u + (decorate ? 2 : 0)))
return NULL;
if (decorate)
@@ -2027,8 +2027,12 @@ string_is_valid_nonrfc_hostname(const char *string)
smartlist_split_string(components,string,".",0,0);
- if (BUG(smartlist_len(components) == 0))
- return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks.
+ if (BUG(smartlist_len(components) == 0)) {
+ // LCOV_EXCL_START should be impossible given the earlier checks.
+ smartlist_free(components);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
/* Allow a single terminating '.' used rarely to indicate domains
* are FQDNs rather than relative. */
diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h
index c45f42be81..4d0d0dd57c 100644
--- a/src/lib/net/alertsock.h
+++ b/src/lib/net/alertsock.h
@@ -42,4 +42,4 @@ typedef struct alert_sockets_t {
int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags);
void alert_sockets_close(alert_sockets_t *socks);
-#endif
+#endif /* !defined(TOR_ALERTSOCK_H) */
diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h
index a3a90172a1..5058dd0a26 100644
--- a/src/lib/net/buffers_net.h
+++ b/src/lib/net/buffers_net.h
@@ -31,4 +31,4 @@ int buf_read_from_pipe(struct buf_t *buf, int fd, size_t at_most,
int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz,
size_t *buf_flushlen);
-#endif /* !defined(TOR_BUFFERS_H) */
+#endif /* !defined(TOR_BUFFERS_NET_H) */
diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h
index 69b0528bc0..b3b77b0589 100644
--- a/src/lib/net/gethostname.h
+++ b/src/lib/net/gethostname.h
@@ -16,4 +16,4 @@
MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen));
-#endif
+#endif /* !defined(TOR_GETHOSTNAME_H) */
diff --git a/src/lib/net/inaddr.h b/src/lib/net/inaddr.h
index 36352b65ea..602573944c 100644
--- a/src/lib/net/inaddr.h
+++ b/src/lib/net/inaddr.h
@@ -24,4 +24,4 @@ int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
int tor_inet_pton(int af, const char *src, void *dst);
-#endif
+#endif /* !defined(TOR_INADDR_H) */
diff --git a/src/lib/net/inaddr_st.h b/src/lib/net/inaddr_st.h
index 806f2c096a..230f29a63a 100644
--- a/src/lib/net/inaddr_st.h
+++ b/src/lib/net/inaddr_st.h
@@ -104,4 +104,4 @@ struct sockaddr_in6 {
};
#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */
-#endif /* TOR_INADDR_ST_H */
+#endif /* !defined(TOR_INADDR_ST_H) */
diff --git a/src/lib/net/include.am b/src/lib/net/include.am
index 8a88f0f2ae..485019f4b7 100644
--- a/src/lib/net/include.am
+++ b/src/lib/net/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-net-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_net_a_SOURCES = \
src/lib/net/address.c \
src/lib/net/alertsock.c \
@@ -21,6 +22,7 @@ src_lib_libtor_net_testing_a_SOURCES = \
src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/net/address.h \
src/lib/net/alertsock.h \
diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h
index 6209bbe18a..0eb352c657 100644
--- a/src/lib/net/nettypes.h
+++ b/src/lib/net/nettypes.h
@@ -41,4 +41,4 @@ typedef int socklen_t;
#define TOR_INVALID_SOCKET (-1)
#endif /* defined(_WIN32) */
-#endif
+#endif /* !defined(TOR_NET_TYPES_H) */
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
index 49c263faa2..2dda491d14 100644
--- a/src/lib/net/resolve.c
+++ b/src/lib/net/resolve.c
@@ -421,7 +421,7 @@ tor_make_getaddrinfo_cache_active(void)
{
sandbox_getaddrinfo_is_active = 1;
}
-#else
+#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */
void
sandbox_disable_getaddrinfo_cache(void)
{
@@ -430,4 +430,4 @@ void
tor_make_getaddrinfo_cache_active(void)
{
}
-#endif
+#endif /* defined(USE_SANDBOX_GETADDRINFO) */
diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h
index 0fb77f1661..d11c902a91 100644
--- a/src/lib/net/resolve.h
+++ b/src/lib/net/resolve.h
@@ -55,4 +55,4 @@ void tor_free_getaddrinfo_cache(void);
void sandbox_disable_getaddrinfo_cache(void);
void tor_make_getaddrinfo_cache_active(void);
-#endif
+#endif /* !defined(TOR_RESOLVE_H) */
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
index f978deeab8..e824a05045 100644
--- a/src/lib/net/socket.c
+++ b/src/lib/net/socket.c
@@ -84,9 +84,9 @@ check_network_configuration(bool server_mode)
"so your relay makes it harder to figure out how busy it is.");
}
}
-#else
+#else /* !(defined(__FreeBSD__)) */
(void) server_mode;
-#endif
+#endif /* defined(__FreeBSD__) */
}
/* When set_max_file_sockets() is called, update this with the max file
@@ -487,11 +487,11 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
r = socketpair(family, type, protocol, fd);
if (r < 0)
return -errno;
-#else
+#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */
r = tor_ersatz_socketpair(family, type, protocol, fd);
if (r < 0)
return -r;
-#endif
+#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
#if defined(FD_CLOEXEC)
if (SOCKET_OK(fd[0])) {
diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h
index 86ae336dfb..193ad91e4c 100644
--- a/src/lib/net/socket.h
+++ b/src/lib/net/socket.h
@@ -116,4 +116,4 @@ const char *tor_socket_strerror(int e);
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b
#endif
-#endif
+#endif /* !defined(TOR_SOCKET_H) */
diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c
index 15c706bec7..3be7b26f7f 100644
--- a/src/lib/net/socketpair.c
+++ b/src/lib/net/socketpair.c
@@ -22,11 +22,11 @@
#include <windows.h>
#define socket_errno() (WSAGetLastError())
#define SOCKET_EPROTONOSUPPORT WSAEPROTONOSUPPORT
-#else
+#else /* !(defined(_WIN32)) */
#define closesocket(x) close(x)
#define socket_errno() (errno)
#define SOCKET_EPROTONOSUPPORT EPROTONOSUPPORT
-#endif
+#endif /* defined(_WIN32) */
#ifdef NEED_ERSATZ_SOCKETPAIR
diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h
index 6be0803881..5820606973 100644
--- a/src/lib/net/socketpair.h
+++ b/src/lib/net/socketpair.h
@@ -16,4 +16,4 @@ int tor_ersatz_socketpair(int family, int type, int protocol,
tor_socket_t fd[2]);
#endif
-#endif
+#endif /* !defined(TOR_SOCKETPAIR_H) */
diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h
index e55242ce66..e55119e0b0 100644
--- a/src/lib/net/socks5_status.h
+++ b/src/lib/net/socks5_status.h
@@ -29,4 +29,4 @@ typedef enum {
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
} socks5_reply_status_t;
-#endif
+#endif /* !defined(TOR_SOCKS5_STATUS_H) */
diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am
index 16c5812604..84bd7feb00 100644
--- a/src/lib/osinfo/include.am
+++ b/src/lib/osinfo/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-osinfo-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_osinfo_a_SOURCES = \
src/lib/osinfo/uname.c
@@ -13,5 +14,6 @@ src_lib_libtor_osinfo_testing_a_SOURCES = \
src_lib_libtor_osinfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/osinfo/uname.h
diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h
index fcce629074..443a30d358 100644
--- a/src/lib/osinfo/uname.h
+++ b/src/lib/osinfo/uname.h
@@ -15,4 +15,4 @@
MOCK_DECL(const char *, get_uname,(void));
-#endif
+#endif /* !defined(HAVE_TOR_UNAME_H) */
diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h
index 20920e0aae..423c498837 100644
--- a/src/lib/process/daemon.h
+++ b/src/lib/process/daemon.h
@@ -18,4 +18,4 @@ int finish_daemon(const char *desired_cwd);
bool start_daemon_has_been_called(void);
-#endif
+#endif /* !defined(TOR_DAEMON_H) */
diff --git a/src/lib/process/env.h b/src/lib/process/env.h
index 15d59351e0..19c2235970 100644
--- a/src/lib/process/env.h
+++ b/src/lib/process/env.h
@@ -38,4 +38,4 @@ void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
const char *new_var,
void (*free_old)(void*),
int free_p);
-#endif
+#endif /* !defined(TOR_ENV_H) */
diff --git a/src/lib/process/include.am b/src/lib/process/include.am
index 83b67bf029..af5f99617b 100644
--- a/src/lib/process/include.am
+++ b/src/lib/process/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-process-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_process_a_SOURCES = \
src/lib/process/daemon.c \
src/lib/process/env.c \
@@ -23,6 +24,7 @@ src_lib_libtor_process_testing_a_SOURCES = \
src_lib_libtor_process_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_process_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/process/daemon.h \
src/lib/process/env.h \
diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h
index dfeb39e046..af59041f80 100644
--- a/src/lib/process/pidfile.h
+++ b/src/lib/process/pidfile.h
@@ -13,4 +13,4 @@
int write_pidfile(const char *filename);
-#endif
+#endif /* !defined(TOR_PIDFILE_H) */
diff --git a/src/lib/process/process.c b/src/lib/process/process.c
index 422942dc83..631c7169f1 100644
--- a/src/lib/process/process.c
+++ b/src/lib/process/process.c
@@ -83,7 +83,7 @@ struct process_t {
#else
/** Our Win32 process handle. */
process_win32_t *win32_process;
-#endif
+#endif /* !defined(_WIN32) */
};
/** Convert a given process status in <b>status</b> to its string
@@ -205,7 +205,7 @@ process_new(const char *command)
#else
/* Prepare our Win32 process handle. */
process->win32_process = process_win32_new();
-#endif
+#endif /* !defined(_WIN32) */
smartlist_add(processes, process);
@@ -240,7 +240,7 @@ process_free_(process_t *process)
#else
/* Cleanup our Win32 process handle. */
process_win32_free(process->win32_process);
-#endif
+#endif /* !defined(_WIN32) */
smartlist_remove(processes, process);
@@ -513,7 +513,7 @@ process_get_unix_process(const process_t *process)
tor_assert(process->unix_process);
return process->unix_process;
}
-#else
+#else /* !(!defined(_WIN32)) */
/** Get the internal handle for Windows backend. */
process_win32_t *
process_get_win32_process(const process_t *process)
@@ -522,7 +522,7 @@ process_get_win32_process(const process_t *process)
tor_assert(process->win32_process);
return process->win32_process;
}
-#endif
+#endif /* !defined(_WIN32) */
/** Write <b>size</b> bytes of <b>data</b> to the given process's standard
* input. */
diff --git a/src/lib/process/process.h b/src/lib/process/process.h
index 14069923a0..05c091a5bf 100644
--- a/src/lib/process/process.h
+++ b/src/lib/process/process.h
@@ -111,7 +111,7 @@ struct process_unix_t *process_get_unix_process(const process_t *process);
#else
struct process_win32_t;
struct process_win32_t *process_get_win32_process(const process_t *process);
-#endif
+#endif /* !defined(_WIN32) */
void process_write(process_t *process,
const uint8_t *data, size_t size);
@@ -140,6 +140,6 @@ STATIC void process_read_buffer(process_t *process,
STATIC void process_read_lines(process_t *process,
buf_t *buffer,
process_read_callback_t callback);
-#endif /* defined(PROCESS_PRIVATE). */
+#endif /* defined(PROCESS_PRIVATE) */
-#endif /* defined(TOR_PROCESS_H). */
+#endif /* !defined(TOR_PROCESS_H) */
diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c
index b102afff44..ef81ec9bf9 100644
--- a/src/lib/process/process_unix.c
+++ b/src/lib/process/process_unix.c
@@ -695,4 +695,4 @@ process_unix_close_file_descriptors(process_unix_t *unix_process)
return success;
}
-#endif /* defined(_WIN32). */
+#endif /* !defined(_WIN32) */
diff --git a/src/lib/process/process_unix.h b/src/lib/process/process_unix.h
index a1d8f72993..da40b3e567 100644
--- a/src/lib/process/process_unix.h
+++ b/src/lib/process/process_unix.h
@@ -61,8 +61,8 @@ STATIC int process_unix_read_handle(process_t *,
process_unix_handle_t *,
buf_t *);
STATIC bool process_unix_close_file_descriptors(process_unix_t *);
-#endif /* defined(PROCESS_UNIX_PRIVATE). */
+#endif /* defined(PROCESS_UNIX_PRIVATE) */
-#endif /* defined(_WIN32). */
+#endif /* !defined(_WIN32) */
-#endif /* defined(TOR_PROCESS_UNIX_H). */
+#endif /* !defined(TOR_PROCESS_UNIX_H) */
diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c
index 1b1de6ad55..7e4082ad13 100644
--- a/src/lib/process/process_win32.c
+++ b/src/lib/process/process_win32.c
@@ -759,7 +759,7 @@ process_win32_cleanup_handle(process_win32_handle_t *handle)
format_win32_error(error_code));
}
}
-#endif
+#endif /* 0 */
/* Close our handle. */
if (handle->pipe != INVALID_HANDLE_VALUE) {
@@ -1102,4 +1102,4 @@ tor_join_win_cmdline(const char *argv[])
return joined_argv;
}
-#endif /* ! defined(_WIN32). */
+#endif /* defined(_WIN32) */
diff --git a/src/lib/process/process_win32.h b/src/lib/process/process_win32.h
index d79dde157e..a50d86df5b 100644
--- a/src/lib/process/process_win32.h
+++ b/src/lib/process/process_win32.h
@@ -90,8 +90,8 @@ STATIC bool process_win32_handle_read_completion(process_win32_handle_t *,
STATIC char *format_win_cmdline_argument(const char *arg);
STATIC char *tor_join_win_cmdline(const char *argv[]);
-#endif /* defined(PROCESS_WIN32_PRIVATE). */
+#endif /* defined(PROCESS_WIN32_PRIVATE) */
-#endif /* ! defined(_WIN32). */
+#endif /* defined(_WIN32) */
-#endif /* defined(TOR_PROCESS_WIN32_H). */
+#endif /* !defined(TOR_PROCESS_WIN32_H) */
diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h
index 7d03e1f025..a2125d2d06 100644
--- a/src/lib/process/setuid.h
+++ b/src/lib/process/setuid.h
@@ -19,4 +19,4 @@ int have_capability_support(void);
#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1)
int switch_id(const char *user, unsigned flags);
-#endif
+#endif /* !defined(TOR_SETUID_H) */
diff --git a/src/lib/process/winprocess_sys.c b/src/lib/process/winprocess_sys.c
index 1266babca8..48c0888658 100644
--- a/src/lib/process/winprocess_sys.c
+++ b/src/lib/process/winprocess_sys.c
@@ -51,7 +51,7 @@ subsys_winprocess_initialize(void)
return 0;
}
-#else /* !defined(_WIN32) */
+#else /* !(defined(_WIN32)) */
#define WINPROCESS_SYS_ENABLED false
#define subsys_winprocess_initialize NULL
#endif /* defined(_WIN32) */
diff --git a/src/lib/pubsub/.may_include b/src/lib/pubsub/.may_include
new file mode 100644
index 0000000000..5623492f00
--- /dev/null
+++ b/src/lib/pubsub/.may_include
@@ -0,0 +1,10 @@
+orconfig.h
+
+lib/cc/*.h
+lib/container/*.h
+lib/dispatch/*.h
+lib/intmath/*.h
+lib/log/*.h
+lib/malloc/*.h
+lib/pubsub/*.h
+lib/string/*.h
diff --git a/src/lib/pubsub/include.am b/src/lib/pubsub/include.am
new file mode 100644
index 0000000000..e2abebcd40
--- /dev/null
+++ b/src/lib/pubsub/include.am
@@ -0,0 +1,28 @@
+
+noinst_LIBRARIES += src/lib/libtor-pubsub.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-pubsub-testing.a
+endif
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+src_lib_libtor_pubsub_a_SOURCES = \
+ src/lib/pubsub/pubsub_build.c \
+ src/lib/pubsub/pubsub_check.c \
+ src/lib/pubsub/pubsub_publish.c
+
+src_lib_libtor_pubsub_testing_a_SOURCES = \
+ $(src_lib_libtor_pubsub_a_SOURCES)
+src_lib_libtor_pubsub_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_pubsub_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/lib/pubsub/pub_binding_st.h \
+ src/lib/pubsub/pubsub.h \
+ src/lib/pubsub/pubsub_build.h \
+ src/lib/pubsub/pubsub_builder_st.h \
+ src/lib/pubsub/pubsub_connect.h \
+ src/lib/pubsub/pubsub_flags.h \
+ src/lib/pubsub/pubsub_macros.h \
+ src/lib/pubsub/pubsub_publish.h
diff --git a/src/lib/pubsub/pub_binding_st.h b/src/lib/pubsub/pub_binding_st.h
new file mode 100644
index 0000000000..d841bf3f54
--- /dev/null
+++ b/src/lib/pubsub/pub_binding_st.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pub_binding_st.h
+ * @brief Declaration of pub_binding_t.
+ *
+ * This is an internal type for the pubsub implementation.
+ */
+
+#ifndef TOR_PUB_BINDING_ST_H
+#define TOR_PUB_BINDING_ST_H
+
+#include "lib/dispatch/msgtypes.h"
+struct dispatch_t;
+
+/**
+ * A pub_binding_t is an opaque object that subsystems use to publish
+ * messages. The DISPATCH_ADD_PUB*() macros set it up.
+ **/
+typedef struct pub_binding_t {
+ /**
+ * A pointer to a configured dispatch_t object. This is filled in
+ * when the dispatch_t is finally constructed.
+ **/
+ struct dispatch_t *dispatch_ptr;
+ /**
+ * A template for the msg_t fields that are filled in for this message.
+ * This is copied into outgoing messages, ensuring that their fields are set
+ * corretly.
+ **/
+ msg_t msg_template;
+} pub_binding_t;
+
+#endif /* !defined(TOR_PUB_BINDING_ST_H) */
diff --git a/src/lib/pubsub/pubsub.h b/src/lib/pubsub/pubsub.h
new file mode 100644
index 0000000000..5346b07517
--- /dev/null
+++ b/src/lib/pubsub/pubsub.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub.h
+ * @brief Header for OO publish-subscribe functionality.
+ *
+ * This module provides a wrapper around the "dispatch" module,
+ * ensuring type-safety and allowing us to do static analysis on
+ * publication and subscriptions.
+ *
+ * With this module, we enforce:
+ * <ul>
+ * <li>that every message has (potential) publishers and subscribers;
+ * <li>that every message is published and subscribed from the correct
+ * channels, with the correct type ID, every time it is published.
+ * <li>that type IDs correspond to a single C type, and that the C types are
+ * used correctly.
+ * <li>that when a message is published or subscribed, it is done with
+ * a correct subsystem identifier
+ * </ul>
+ *
+ * We do this by making "publication requests" and "subscription requests"
+ * into objects, and doing some computation on them before we create
+ * a dispatch_t with them.
+ *
+ * Rather than using the dispatch module directly, a publishing module
+ * receives a "binding" object that it uses to send messages with the right
+ * settings.
+ *
+ * Most users of this module will want to use this header, and the
+ * pubsub_macros.h header for convenience.
+ */
+
+/*
+ *
+ * Overview: Messages are sent over channels. Before sending a message on a
+ * channel, or receiving a message on a channel, a subsystem needs to register
+ * that it publishes, or subscribes, to that message, on that channel.
+ *
+ * Messages, channels, and subsystems are represented internally as short
+ * integers, though they are associated with human-readable strings for
+ * initialization and debugging.
+ *
+ * When registering for a message, a subsystem must say whether it is an
+ * exclusive publisher/subscriber to that message type, or whether other
+ * subsystems may also publish/subscribe to it.
+ *
+ * All messages and their publishers/subscribers must be registered early in
+ * the initialization process.
+ *
+ * By default, it is an error for a message type to have publishers and no
+ * subscribers on a channel, or subscribers and no publishers on a channel.
+ *
+ * A subsystem may register for a message with a note that delivery or
+ * production is disabled -- for example, because the subsystem is
+ * disabled at compile-time. It is not an error for a message type to
+ * have all of its publishers or subscribers disabled.
+ *
+ * After a message is sent, it is delivered to every recipient. This
+ * delivery happens from the top level of the event loop; it may be
+ * interleaved with network events, timers, etc.
+ *
+ * Messages may have associated data. This data is typed, and is owned
+ * by the message. Strings, byte-arrays, and integers have built-in
+ * support. Other types may be added. If objects are to be sent,
+ * they should be identified by handle. If an object requires cleanup,
+ * it should be declared with an associated free function.
+ *
+ * Semantically, if two subsystems communicate only by this kind of
+ * message passing, neither is considered to depend on the other, though
+ * both are considered to have a dependency on the message and on any
+ * types it contains.
+ *
+ * (Or generational index?)
+ */
+#ifndef TOR_PUBSUB_PUBSUB_H
+#define TOR_PUBSUB_PUBSUB_H
+
+#include "lib/pubsub/pub_binding_st.h"
+#include "lib/pubsub/pubsub_connect.h"
+#include "lib/pubsub/pubsub_flags.h"
+#include "lib/pubsub/pubsub_macros.h"
+#include "lib/pubsub/pubsub_publish.h"
+
+#endif /* !defined(TOR_PUBSUB_PUBSUB_H) */
diff --git a/src/lib/pubsub/pubsub_build.c b/src/lib/pubsub/pubsub_build.c
new file mode 100644
index 0000000000..e44b7d76ec
--- /dev/null
+++ b/src/lib/pubsub/pubsub_build.c
@@ -0,0 +1,307 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_build.c
+ * @brief Construct a dispatch_t in safer, more OO way.
+ **/
+
+#define PUBSUB_PRIVATE
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_cfg.h"
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/dispatch/msgtypes.h"
+#include "lib/pubsub/pubsub_flags.h"
+#include "lib/pubsub/pub_binding_st.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_builder_st.h"
+#include "lib/pubsub/pubsub_connect.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+
+ #include <string.h>
+
+/** Construct and return a new empty pubsub_items_t. */
+static pubsub_items_t *
+pubsub_items_new(void)
+{
+ pubsub_items_t *cfg = tor_malloc_zero(sizeof(*cfg));
+ cfg->items = smartlist_new();
+ cfg->type_items = smartlist_new();
+ return cfg;
+}
+
+/** Release all storage held in a pubsub_items_t. */
+void
+pubsub_items_free_(pubsub_items_t *cfg)
+{
+ if (! cfg)
+ return;
+ SMARTLIST_FOREACH(cfg->items, pubsub_cfg_t *, item, tor_free(item));
+ SMARTLIST_FOREACH(cfg->type_items,
+ pubsub_type_cfg_t *, item, tor_free(item));
+ smartlist_free(cfg->items);
+ smartlist_free(cfg->type_items);
+ tor_free(cfg);
+}
+
+/** Construct and return a new pubsub_builder_t. */
+pubsub_builder_t *
+pubsub_builder_new(void)
+{
+ dispatch_naming_init();
+
+ pubsub_builder_t *pb = tor_malloc_zero(sizeof(*pb));
+ pb->cfg = dcfg_new();
+ pb->items = pubsub_items_new();
+ return pb;
+}
+
+/**
+ * Release all storage held by a pubsub_builder_t.
+ *
+ * You'll (mostly) only want to call this function on an error case: if you're
+ * constructing a dispatch_t instead, you should call
+ * pubsub_builder_finalize() to consume the pubsub_builder_t.
+ */
+void
+pubsub_builder_free_(pubsub_builder_t *pb)
+{
+ if (pb == NULL)
+ return;
+ pubsub_items_free(pb->items);
+ dcfg_free(pb->cfg);
+ tor_free(pb);
+}
+
+/**
+ * Create and return a pubsub_connector_t for the subsystem with ID
+ * <b>subsys</b> to use in adding publications, subscriptions, and types to
+ * <b>builder</b>.
+ **/
+pubsub_connector_t *
+pubsub_connector_for_subsystem(pubsub_builder_t *builder,
+ subsys_id_t subsys)
+{
+ tor_assert(builder);
+ ++builder->n_connectors;
+
+ pubsub_connector_t *con = tor_malloc_zero(sizeof(*con));
+
+ con->builder = builder;
+ con->subsys_id = subsys;
+
+ return con;
+}
+
+/**
+ * Release all storage held by a pubsub_connector_t.
+ **/
+void
+pubsub_connector_free_(pubsub_connector_t *con)
+{
+ if (!con)
+ return;
+
+ if (con->builder) {
+ --con->builder->n_connectors;
+ tor_assert(con->builder->n_connectors >= 0);
+ }
+ tor_free(con);
+}
+
+/**
+ * Use <b>con</b> to add a request for being able to publish messages of type
+ * <b>msg</b> with auxiliary data of <b>type</b> on <b>channel</b>.
+ **/
+int
+pubsub_add_pub_(pubsub_connector_t *con,
+ pub_binding_t *out,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ unsigned flags,
+ const char *file,
+ unsigned line)
+{
+ pubsub_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg));
+
+ memset(out, 0, sizeof(*out));
+ cfg->is_publish = true;
+
+ out->msg_template.sender = cfg->subsys = con->subsys_id;
+ out->msg_template.channel = cfg->channel = channel;
+ out->msg_template.msg = cfg->msg = msg;
+ out->msg_template.type = cfg->type = type;
+
+ cfg->flags = flags;
+ cfg->added_by_file = file;
+ cfg->added_by_line = line;
+
+ /* We're grabbing a pointer to the pub_binding_t so we can tell it about
+ * the dispatcher later on.
+ */
+ cfg->pub_binding = out;
+
+ smartlist_add(con->builder->items->items, cfg);
+
+ if (dcfg_msg_set_type(con->builder->cfg, msg, type) < 0)
+ goto err;
+ if (dcfg_msg_set_chan(con->builder->cfg, msg, channel) < 0)
+ goto err;
+
+ return 0;
+ err:
+ ++con->builder->n_errors;
+ return -1;
+}
+
+/**
+ * Use <b>con</b> to add a request for being able to publish messages of type
+ * <b>msg</b> with auxiliary data of <b>type</b> on <b>channel</b>,
+ * passing them to the callback in <b>recv_fn</b>.
+ **/
+int
+pubsub_add_sub_(pubsub_connector_t *con,
+ recv_fn_t recv_fn,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ unsigned flags,
+ const char *file,
+ unsigned line)
+{
+ pubsub_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg));
+
+ cfg->is_publish = false;
+ cfg->subsys = con->subsys_id;
+ cfg->channel = channel;
+ cfg->msg = msg;
+ cfg->type = type;
+ cfg->flags = flags;
+ cfg->added_by_file = file;
+ cfg->added_by_line = line;
+
+ cfg->recv_fn = recv_fn;
+
+ smartlist_add(con->builder->items->items, cfg);
+
+ if (dcfg_msg_set_type(con->builder->cfg, msg, type) < 0)
+ goto err;
+ if (dcfg_msg_set_chan(con->builder->cfg, msg, channel) < 0)
+ goto err;
+ if (! (flags & DISP_FLAG_STUB)) {
+ if (dcfg_add_recv(con->builder->cfg, msg, cfg->subsys, recv_fn) < 0)
+ goto err;
+ }
+
+ return 0;
+ err:
+ ++con->builder->n_errors;
+ return -1;
+}
+
+/**
+ * Use <b>con</b> to define the functions to use for manipulating the type
+ * <b>type</b>. Any function pointers left as NULL will be implemented as
+ * no-ops.
+ **/
+int
+pubsub_connector_register_type_(pubsub_connector_t *con,
+ msg_type_id_t type,
+ dispatch_typefns_t *fns,
+ const char *file,
+ unsigned line)
+{
+ pubsub_type_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg));
+ cfg->type = type;
+ memcpy(&cfg->fns, fns, sizeof(*fns));
+ cfg->subsys = con->subsys_id;
+ cfg->added_by_file = file;
+ cfg->added_by_line = line;
+
+ smartlist_add(con->builder->items->type_items, cfg);
+
+ if (dcfg_type_set_fns(con->builder->cfg, type, fns) < 0)
+ goto err;
+
+ return 0;
+ err:
+ ++con->builder->n_errors;
+ return -1;
+}
+
+/**
+ * Initialize the dispatch_ptr field in every relevant publish binding
+ * for <b>d</b>.
+ */
+static void
+pubsub_items_install_bindings(pubsub_items_t *items,
+ dispatch_t *d)
+{
+ SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, cfg) {
+ if (cfg->pub_binding) {
+ // XXXX we could skip this for STUB publishers, and for any publishers
+ // XXXX where all subscribers are STUB.
+ cfg->pub_binding->dispatch_ptr = d;
+ }
+ } SMARTLIST_FOREACH_END(cfg);
+}
+
+/**
+ * Remove the dispatch_ptr fields for all the relevant publish bindings
+ * in <b>items</b>. The prevents subsequent dispatch_pub_() calls from
+ * sending messages to a dispatcher that has been freed.
+ **/
+void
+pubsub_items_clear_bindings(pubsub_items_t *items)
+{
+ SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, cfg) {
+ if (cfg->pub_binding) {
+ cfg->pub_binding->dispatch_ptr = NULL;
+ }
+ } SMARTLIST_FOREACH_END(cfg);
+}
+
+/**
+ * Create a new dispatcher as configured in a pubsub_builder_t.
+ *
+ * Consumes and frees its input.
+ **/
+dispatch_t *
+pubsub_builder_finalize(pubsub_builder_t *builder,
+ pubsub_items_t **items_out)
+{
+ dispatch_t *dispatcher = NULL;
+ tor_assert_nonfatal(builder->n_connectors == 0);
+
+ if (pubsub_builder_check(builder) < 0)
+ goto err;
+
+ if (builder->n_errors) {
+ log_warn(LD_GENERAL, "At least one error occurred previously when "
+ "configuring the dispatcher.");
+ goto err;
+ }
+
+ dispatcher = dispatch_new(builder->cfg);
+
+ if (!dispatcher)
+ goto err;
+
+ pubsub_items_install_bindings(builder->items, dispatcher);
+ if (items_out) {
+ *items_out = builder->items;
+ builder->items = NULL; /* Prevent free */
+ }
+
+ err:
+ pubsub_builder_free(builder);
+ return dispatcher;
+}
diff --git a/src/lib/pubsub/pubsub_build.h b/src/lib/pubsub/pubsub_build.h
new file mode 100644
index 0000000000..5a0c5f5bd3
--- /dev/null
+++ b/src/lib/pubsub/pubsub_build.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_build.h
+ * @brief Header used for constructing the OO publish-subscribe facility.
+ *
+ * (See pubsub.h for more general information on this API.)
+ **/
+
+#ifndef TOR_PUBSUB_BUILD_H
+#define TOR_PUBSUB_BUILD_H
+
+#include "lib/dispatch/msgtypes.h"
+
+struct dispatch_t;
+struct pubsub_connector_t;
+
+/**
+ * A "dispatch builder" is an incomplete dispatcher, used when
+ * registering messages. It does not have the same integrity guarantees
+ * as a dispatcher. It cannot actually handle messages itself: once all
+ * subsystems have registered, it is converted into a dispatch_t.
+ **/
+typedef struct pubsub_builder_t pubsub_builder_t;
+
+/**
+ * A "pubsub items" holds the configuration items used to configure a
+ * pubsub_builder. After the builder is finalized, this field is extracted,
+ * and used later to tear down pointers that enable publishing.
+ **/
+typedef struct pubsub_items_t pubsub_items_t;
+
+/**
+ * Create a new pubsub_builder. This should only happen in the
+ * main-init code.
+ */
+pubsub_builder_t *pubsub_builder_new(void);
+
+/** DOCDOC */
+int pubsub_builder_check(pubsub_builder_t *);
+
+/**
+ * Free a pubsub builder. This should only happen on error paths, where
+ * we have decided not to construct a dispatcher for some reason.
+ */
+#define pubsub_builder_free(db) \
+ FREE_AND_NULL(pubsub_builder_t, pubsub_builder_free_, (db))
+
+/** Internal implementation of pubsub_builder_free(). */
+void pubsub_builder_free_(pubsub_builder_t *);
+
+/**
+ * Create a pubsub connector that a single subsystem will use to
+ * register its messages. The main-init code does this during susbsystem
+ * initialization.
+ */
+struct pubsub_connector_t *pubsub_connector_for_subsystem(pubsub_builder_t *,
+ subsys_id_t);
+
+/**
+ * The main-init code does this after subsystem initialization.
+ */
+#define pubsub_connector_free(c) \
+ FREE_AND_NULL(struct pubsub_connector_t, pubsub_connector_free_, (c))
+
+void pubsub_connector_free_(struct pubsub_connector_t *);
+
+/**
+ * Constructs a dispatcher from a dispatch_builder, after checking that the
+ * invariances on the messages, channels, and connections have been
+ * respected.
+ *
+ * This should happen after every subsystem has initialized, and before
+ * entering the mainloop.
+ */
+struct dispatch_t *pubsub_builder_finalize(pubsub_builder_t *,
+ pubsub_items_t **items_out);
+
+/**
+ * Clear all pub_binding_t backpointers in <b>items</b>.
+ **/
+void pubsub_items_clear_bindings(pubsub_items_t *items);
+
+#define pubsub_items_free(cfg) \
+ FREE_AND_NULL(pubsub_items_t, pubsub_items_free_, (cfg))
+void pubsub_items_free_(pubsub_items_t *cfg);
+
+#endif /* !defined(TOR_PUBSUB_BUILD_H) */
diff --git a/src/lib/pubsub/pubsub_builder_st.h b/src/lib/pubsub/pubsub_builder_st.h
new file mode 100644
index 0000000000..545aa3f3ef
--- /dev/null
+++ b/src/lib/pubsub/pubsub_builder_st.h
@@ -0,0 +1,161 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_builder_st.h
+ *
+ * @brief private structures used for configuring dispatchers and messages.
+ */
+
+#ifndef TOR_PUBSUB_BUILDER_ST_H
+#define TOR_PUBSUB_BUILDER_ST_H
+
+#ifdef PUBSUB_PRIVATE
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct dispatch_cfg_t;
+struct smartlist_t;
+struct pub_binding_t;
+
+/**
+ * Configuration for a single publication or subscription request.
+ *
+ * These can be stored while the dispatcher is in use, but are only used for
+ * setup, teardown, and debugging.
+ *
+ * There are various fields in this request describing the message; all of
+ * them must match other descriptions of the message, or a bug has occurred.
+ **/
+typedef struct pubsub_cfg_t {
+ /** True if this is a publishing request; false for a subscribing request. */
+ bool is_publish;
+ /** The system making this request. */
+ subsys_id_t subsys;
+ /** The channel on which the message is to be sent. */
+ channel_id_t channel;
+ /** The message ID to be sent or received. */
+ message_id_t msg;
+ /** The C type associated with the message. */
+ msg_type_id_t type;
+ /** One or more DISP_FLAGS_* items, combined with bitwise OR. */
+ unsigned flags;
+
+ /**
+ * Publishing only: a pub_binding object that will receive the binding for
+ * this request. We will finish filling this in when the dispatcher is
+ * constructed, so that the subsystem can publish then and not before.
+ */
+ struct pub_binding_t *pub_binding;
+
+ /**
+ * Subscribing only: a function to receive message objects for this request.
+ */
+ recv_fn_t recv_fn;
+
+ /** The file from which this message was configured */
+ const char *added_by_file;
+ /** The line at which this message was configured */
+ unsigned added_by_line;
+} pubsub_cfg_t;
+
+/**
+ * Configuration request for a single C type.
+ *
+ * These are stored while the dispatcher is in use, but are only used for
+ * setup, teardown, and debugging.
+ **/
+typedef struct pubsub_type_cfg_t {
+ /**
+ * The identifier for this type.
+ */
+ msg_type_id_t type;
+ /**
+ * Functions to use when manipulating the type.
+ */
+ dispatch_typefns_t fns;
+
+ /** The subsystem that configured this type. */
+ subsys_id_t subsys;
+ /** The file from which this type was configured */
+ const char *added_by_file;
+ /** The line at which this type was configured */
+ unsigned added_by_line;
+} pubsub_type_cfg_t;
+
+/**
+ * The set of configuration requests for a dispatcher, as made by various
+ * subsystems.
+ **/
+struct pubsub_items_t {
+ /** List of pubsub_cfg_t. */
+ struct smartlist_t *items;
+ /** List of pubsub_type_cfg_t. */
+ struct smartlist_t *type_items;
+};
+
+/**
+ * Type used to construct a dispatcher. We use this type to build up the
+ * configuration for a dispatcher, and then pass ownership of that
+ * configuration to the newly constructed dispatcher.
+ **/
+struct pubsub_builder_t {
+ /** Number of outstanding pubsub_connector_t objects pointing to this
+ * pubsub_builder_t. */
+ int n_connectors;
+ /** Number of errors encountered while constructing this object so far. */
+ int n_errors;
+ /** In-progress configuration that we're constructing, as a list of the
+ * requests that have been made. */
+ struct pubsub_items_t *items;
+ /** In-progress configuration that we're constructing, in a form that can
+ * be converted to a dispatch_t. */
+ struct dispatch_cfg_t *cfg;
+};
+
+/**
+ * Type given to a subsystem when adding connections to a pubsub_builder_t.
+ * We use this type to force each subsystem to get blamed for the
+ * publications, subscriptions, and types that it adds.
+ **/
+struct pubsub_connector_t {
+ /** The pubsub_builder that this connector refers to. */
+ struct pubsub_builder_t *builder;
+ /** The subsystem that has been given this connector. */
+ subsys_id_t subsys_id;
+};
+
+/**
+ * Helper structure used when constructing a dispatcher that sorts the
+ * pubsub_cfg_t objects in various ways.
+ **/
+typedef struct pubsub_adjmap_t {
+ /* XXXX The next three fields are currently constructed but not yet
+ * XXXX used. I believe we'll want them in the future, though. -nickm
+ */
+ /** Number of subsystems; length of the *_by_subsys arrays. */
+ size_t n_subsystems;
+ /** Array of lists of publisher pubsub_cfg_t objects, indexed by
+ * subsystem. */
+ struct smartlist_t **pub_by_subsys;
+ /** Array of lists of subscriber pubsub_cfg_t objects, indexed by
+ * subsystem. */
+ struct smartlist_t **sub_by_subsys;
+
+ /** Number of message IDs; length of the *_by_msg arrays. */
+ size_t n_msgs;
+ /** Array of lists of publisher pubsub_cfg_t objects, indexed by
+ * message ID. */
+ struct smartlist_t **pub_by_msg;
+ /** Array of lists of subscriber pubsub_cfg_t objects, indexed by
+ * message ID. */
+ struct smartlist_t **sub_by_msg;
+} pubsub_adjmap_t;
+
+#endif /* defined(PUBSUB_PRIVATE) */
+
+#endif /* !defined(TOR_PUBSUB_BUILDER_ST_H) */
diff --git a/src/lib/pubsub/pubsub_check.c b/src/lib/pubsub/pubsub_check.c
new file mode 100644
index 0000000000..a3c22d4f25
--- /dev/null
+++ b/src/lib/pubsub/pubsub_check.c
@@ -0,0 +1,428 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_check.c
+ * @brief Enforce various requirements on a pubsub_builder.
+ **/
+
+#define PUBSUB_PRIVATE
+
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/dispatch/msgtypes.h"
+#include "lib/pubsub/pubsub_flags.h"
+#include "lib/pubsub/pubsub_builder_st.h"
+#include "lib/pubsub/pubsub_build.h"
+
+#include "lib/container/bitarray.h"
+#include "lib/container/smartlist.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/compat_string.h"
+
+#include <string.h>
+
+static void pubsub_adjmap_add(pubsub_adjmap_t *map,
+ const pubsub_cfg_t *item);
+
+/**
+ * Helper: contruct and return a new pubsub_adjacency_map from <b>cfg</b>.
+ * Return NULL on error.
+ **/
+static pubsub_adjmap_t *
+pubsub_build_adjacency_map(const pubsub_items_t *cfg)
+{
+ pubsub_adjmap_t *map = tor_malloc_zero(sizeof(*map));
+ const size_t n_subsystems = get_num_subsys_ids();
+ const size_t n_msgs = get_num_message_ids();
+
+ map->n_subsystems = n_subsystems;
+ map->n_msgs = n_msgs;
+
+ map->pub_by_subsys = tor_calloc(n_subsystems, sizeof(smartlist_t*));
+ map->sub_by_subsys = tor_calloc(n_subsystems, sizeof(smartlist_t*));
+ map->pub_by_msg = tor_calloc(n_msgs, sizeof(smartlist_t*));
+ map->sub_by_msg = tor_calloc(n_msgs, sizeof(smartlist_t*));
+
+ SMARTLIST_FOREACH_BEGIN(cfg->items, const pubsub_cfg_t *, item) {
+ pubsub_adjmap_add(map, item);
+ } SMARTLIST_FOREACH_END(item);
+
+ return map;
+}
+
+/**
+ * Helper: add a single pubsub_cfg_t to an adjacency map.
+ **/
+static void
+pubsub_adjmap_add(pubsub_adjmap_t *map,
+ const pubsub_cfg_t *item)
+{
+ smartlist_t **by_subsys;
+ smartlist_t **by_msg;
+
+ tor_assert(item->subsys < map->n_subsystems);
+ tor_assert(item->msg < map->n_msgs);
+
+ if (item->is_publish) {
+ by_subsys = &map->pub_by_subsys[item->subsys];
+ by_msg = &map->pub_by_msg[item->msg];
+ } else {
+ by_subsys = &map->sub_by_subsys[item->subsys];
+ by_msg = &map->sub_by_msg[item->msg];
+ }
+
+ if (! *by_subsys)
+ *by_subsys = smartlist_new();
+ if (! *by_msg)
+ *by_msg = smartlist_new();
+ smartlist_add(*by_subsys, (void*) item);
+ smartlist_add(*by_msg, (void *) item);
+}
+
+/**
+ * Release all storage held by m and set m to NULL.
+ **/
+#define pubsub_adjmap_free(m) \
+ FREE_AND_NULL(pubsub_adjmap_t, pubsub_adjmap_free_, m)
+
+/**
+ * Free every element of an <b>n</b>-element array of smartlists, then
+ * free the array itself.
+ **/
+static void
+pubsub_adjmap_free_helper(smartlist_t **lsts, size_t n)
+{
+ if (!lsts)
+ return;
+
+ for (unsigned i = 0; i < n; ++i) {
+ smartlist_free(lsts[i]);
+ }
+ tor_free(lsts);
+}
+
+/**
+ * Release all storage held by <b>map</b>.
+ **/
+static void
+pubsub_adjmap_free_(pubsub_adjmap_t *map)
+{
+ if (!map)
+ return;
+ pubsub_adjmap_free_helper(map->pub_by_subsys, map->n_subsystems);
+ pubsub_adjmap_free_helper(map->sub_by_subsys, map->n_subsystems);
+ pubsub_adjmap_free_helper(map->pub_by_msg, map->n_msgs);
+ pubsub_adjmap_free_helper(map->sub_by_msg, map->n_msgs);
+ tor_free(map);
+}
+
+/**
+ * Helper: return the length of <b>sl</b>, or 0 if sl is NULL.
+ **/
+static int
+smartlist_len_opt(const smartlist_t *sl)
+{
+ if (sl)
+ return smartlist_len(sl);
+ else
+ return 0;
+}
+
+/** Return a pointer to a statically allocated string encoding the
+ * dispatcher flags in <b>flags</b>. */
+static const char *
+format_flags(unsigned flags)
+{
+ static char buf[32];
+ buf[0] = 0;
+ if (flags & DISP_FLAG_EXCL) {
+ strlcat(buf, " EXCL", sizeof(buf));
+ }
+ if (flags & DISP_FLAG_STUB) {
+ strlcat(buf, " STUB", sizeof(buf));
+ }
+ return buf[0] ? buf+1 : buf;
+}
+
+/**
+ * Log a message containing a description of <b>cfg</b> at severity, prefixed
+ * by the string <b>prefix</b>.
+ */
+static void
+pubsub_cfg_dump(const pubsub_cfg_t *cfg, int severity, const char *prefix)
+{
+ tor_assert(prefix);
+
+ tor_log(severity, LD_MESG,
+ "%s%s %s: %s{%s} on %s (%s) <%u %u %u %u %x> [%s:%d]",
+ prefix,
+ get_subsys_id_name(cfg->subsys),
+ cfg->is_publish ? "PUB" : "SUB",
+ get_message_id_name(cfg->msg),
+ get_msg_type_id_name(cfg->type),
+ get_channel_id_name(cfg->channel),
+ format_flags(cfg->flags),
+ cfg->subsys, cfg->msg, cfg->type, cfg->channel, cfg->flags,
+ cfg->added_by_file, cfg->added_by_line);
+}
+
+/**
+ * Helper: fill a bitarray <b>out</b> with entries corresponding to the
+ * subsystems listed in <b>items</b>. If any subsystem is listed more than
+ * once, log a warning. Return 0 on success, -1 on failure.
+ **/
+static int
+get_message_bitarray(const pubsub_adjmap_t *map,
+ message_id_t msg,
+ const smartlist_t *items,
+ const char *operation,
+ bitarray_t **out)
+{
+ bool ok = true;
+ *out = bitarray_init_zero((unsigned)map->n_subsystems);
+ if (! items)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(items, const pubsub_cfg_t *, cfg) {
+ if (bitarray_is_set(*out, cfg->subsys)) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" is configured to be %s by subsystem "
+ "\"%s\" more than once.",
+ get_message_id_name(msg), operation,
+ get_subsys_id_name(cfg->subsys));
+ ok = false;
+ }
+ bitarray_set(*out, cfg->subsys);
+ } SMARTLIST_FOREACH_END(cfg);
+
+ return ok ? 0 : -1;
+}
+
+/**
+ * Helper for lint_message: check that all the pubsub_cfg_t items in the two
+ * respective smartlists obey our local graph topology rules.
+ *
+ * (Right now this is just a matter of "each subsystem only
+ * publishes/subscribes once; no subsystem is a publisher and subscriber for
+ * the same message.")
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+static int
+lint_message_graph(const pubsub_adjmap_t *map,
+ message_id_t msg,
+ const smartlist_t *pub,
+ const smartlist_t *sub)
+{
+ bitarray_t *published_by = NULL;
+ bitarray_t *subscribed_by = NULL;
+ bool ok = true;
+
+ if (get_message_bitarray(map, msg, pub, "published", &published_by) < 0)
+ ok = false;
+ if (get_message_bitarray(map, msg, sub, "subscribed", &subscribed_by) < 0)
+ ok = false;
+
+ /* Check whether any subsystem is publishing and subscribing the same
+ * message. [??]
+ */
+ for (unsigned i = 0; i < map->n_subsystems; ++i) {
+ if (bitarray_is_set(published_by, i) &&
+ bitarray_is_set(subscribed_by, i)) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" is published and subscribed by the same "
+ "subsystem \"%s\".",
+ get_message_id_name(msg),
+ get_subsys_id_name(i));
+ ok = false;
+ }
+ }
+
+ bitarray_free(published_by);
+ bitarray_free(subscribed_by);
+
+ return ok ? 0 : -1;
+}
+
+/**
+ * Helper for lint_message: check that all the pubsub_cfg_t items in the two
+ * respective smartlists have compatible flags, channels, and types.
+ **/
+static int
+lint_message_consistency(message_id_t msg,
+ const smartlist_t *pub,
+ const smartlist_t *sub)
+{
+ if (!smartlist_len_opt(pub) && !smartlist_len_opt(sub))
+ return 0; // LCOV_EXCL_LINE -- this was already checked.
+
+ /* The 'all' list has the publishers and the subscribers. */
+ smartlist_t *all = smartlist_new();
+ if (pub)
+ smartlist_add_all(all, pub);
+ if (sub)
+ smartlist_add_all(all, sub);
+
+ const pubsub_cfg_t *item0 = smartlist_get(all, 0);
+
+ /* Indicates which subsystems we've found publishing/subscribing here. */
+ bool pub_excl = false, sub_excl = false, chan_same = true, type_same = true;
+
+ /* Simple message consistency properties across messages.
+ */
+ SMARTLIST_FOREACH_BEGIN(all, const pubsub_cfg_t *, cfg) {
+ chan_same &= (cfg->channel == item0->channel);
+ type_same &= (cfg->type == item0->type);
+ if (cfg->is_publish)
+ pub_excl |= (cfg->flags & DISP_FLAG_EXCL) != 0;
+ else
+ sub_excl |= (cfg->flags & DISP_FLAG_EXCL) != 0;
+ } SMARTLIST_FOREACH_END(cfg);
+
+ bool ok = true;
+
+ if (! chan_same) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" is associated with multiple inconsistent "
+ "channels.",
+ get_message_id_name(msg));
+ ok = false;
+ }
+ if (! type_same) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" is associated with multiple inconsistent "
+ "message types.",
+ get_message_id_name(msg));
+ ok = false;
+ }
+
+ /* Enforce exclusive-ness for publishers and subscribers that have asked for
+ * it.
+ */
+ if (pub_excl && smartlist_len_opt(pub) > 1) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" has multiple publishers, but at least one is "
+ "marked as exclusive.",
+ get_message_id_name(msg));
+ ok = false;
+ }
+ if (sub_excl && smartlist_len_opt(sub) > 1) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" has multiple subscribers, but at least one is "
+ "marked as exclusive.",
+ get_message_id_name(msg));
+ ok = false;
+ }
+
+ smartlist_free(all);
+
+ return ok ? 0 : -1;
+}
+
+/**
+ * Check whether there are any errors or inconsistencies for the message
+ * described by <b>msg</b> in <b>map</b>. If there are problems, log about
+ * them, and return -1. Otherwise return 0.
+ **/
+static int
+lint_message(const pubsub_adjmap_t *map, message_id_t msg)
+{
+ /* NOTE: Some of the checks in this function are maybe over-zealous, and we
+ * might not want to have them forever. I've marked them with [?] below.
+ */
+ if (BUG(msg >= map->n_msgs))
+ return 0; // LCOV_EXCL_LINE
+
+ const smartlist_t *pub = map->pub_by_msg[msg];
+ const smartlist_t *sub = map->sub_by_msg[msg];
+
+ const size_t n_pub = smartlist_len_opt(pub);
+ const size_t n_sub = smartlist_len_opt(sub);
+
+ if (n_pub == 0 && n_sub == 0) {
+ log_info(LD_MESG, "Nobody is publishing or subscribing to message "
+ "\"%s\".",
+ get_message_id_name(msg));
+ return 0; // No publishers or subscribers: nothing to do.
+ }
+ /* We'll set this to false if there are any problems. */
+ bool ok = true;
+
+ /* First make sure that if there are publishers, there are subscribers. */
+ if (n_pub == 0) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" has subscribers, but no publishers.",
+ get_message_id_name(msg));
+ ok = false;
+ } else if (n_sub == 0) {
+ log_warn(LD_MESG|LD_BUG,
+ "Message \"%s\" has publishers, but no subscribers.",
+ get_message_id_name(msg));
+ ok = false;
+ }
+
+ /* Check the message graph topology. */
+ if (lint_message_graph(map, msg, pub, sub) < 0)
+ ok = false;
+
+ /* Check whether the messages have the same fields set on them. */
+ if (lint_message_consistency(msg, pub, sub) < 0)
+ ok = false;
+
+ if (!ok) {
+ /* There was a problem -- let's log all the publishers and subscribers on
+ * this message */
+ if (pub) {
+ SMARTLIST_FOREACH(pub, pubsub_cfg_t *, cfg,
+ pubsub_cfg_dump(cfg, LOG_WARN, " "));
+ }
+ if (sub) {
+ SMARTLIST_FOREACH(sub, pubsub_cfg_t *, cfg,
+ pubsub_cfg_dump(cfg, LOG_WARN, " "));
+ }
+ }
+
+ return ok ? 0 : -1;
+}
+
+/**
+ * Check all the messages in <b>map</b> for consistency. Return 0 on success,
+ * -1 on problems.
+ **/
+static int
+pubsub_adjmap_check(const pubsub_adjmap_t *map)
+{
+ bool all_ok = true;
+ for (unsigned i = 0; i < map->n_msgs; ++i) {
+ if (lint_message(map, i) < 0) {
+ all_ok = false;
+ }
+ }
+ return all_ok ? 0 : -1;
+}
+
+/**
+ * Check builder for consistency and various constraints. Return 0 on success,
+ * -1 on failure.
+ **/
+int
+pubsub_builder_check(pubsub_builder_t *builder)
+{
+ pubsub_adjmap_t *map = pubsub_build_adjacency_map(builder->items);
+ int rv = -1;
+
+ if (!map)
+ goto err; // should be impossible
+
+ if (pubsub_adjmap_check(map) < 0)
+ goto err;
+
+ rv = 0;
+ err:
+ pubsub_adjmap_free(map);
+ return rv;
+}
diff --git a/src/lib/pubsub/pubsub_connect.h b/src/lib/pubsub/pubsub_connect.h
new file mode 100644
index 0000000000..0ad106044e
--- /dev/null
+++ b/src/lib/pubsub/pubsub_connect.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_connect.h
+ * @brief Header for functions that add relationships to a pubsub builder.
+ *
+ * These functions are used by modules that need to add publication and
+ * subscription requests. Most users will want to call these functions
+ * indirectly, via the macros in pubsub_macros.h.
+ **/
+
+#ifndef TOR_PUBSUB_CONNECT_H
+#define TOR_PUBSUB_CONNECT_H
+
+#include "lib/dispatch/msgtypes.h"
+
+struct pub_binding_t;
+/**
+ * A "dispatch connector" is a view of the dispatcher that a subsystem
+ * uses while initializing itself. It is specific to the subsystem, and
+ * ensures that each subsystem doesn't need to identify itself
+ * repeatedly while registering its messages.
+ **/
+typedef struct pubsub_connector_t pubsub_connector_t;
+
+int pubsub_add_pub_(struct pubsub_connector_t *con,
+ struct pub_binding_t *out,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ unsigned flags,
+ const char *file,
+ unsigned line);
+
+int pubsub_add_sub_(struct pubsub_connector_t *con,
+ recv_fn_t recv_fn,
+ channel_id_t channel,
+ message_id_t msg,
+ msg_type_id_t type,
+ unsigned flags,
+ const char *file,
+ unsigned line);
+
+int pubsub_connector_register_type_(struct pubsub_connector_t *,
+ msg_type_id_t,
+ dispatch_typefns_t *,
+ const char *file,
+ unsigned line);
+
+#endif /* !defined(TOR_PUBSUB_CONNECT_H) */
diff --git a/src/lib/pubsub/pubsub_flags.h b/src/lib/pubsub/pubsub_flags.h
new file mode 100644
index 0000000000..53c6e49565
--- /dev/null
+++ b/src/lib/pubsub/pubsub_flags.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_flags.h
+ * @brief Flags that can be set on publish/subscribe messages.
+ **/
+
+#ifndef TOR_PUBSUB_FLAGS_H
+#define TOR_PUBSUB_FLAGS_H
+
+/**
+ * Flag for registering a message: declare that no other module is allowed to
+ * publish this message if we are publishing it, or subscribe to it if we are
+ * subscribing to it.
+ */
+#define DISP_FLAG_EXCL (1u<<0)
+
+/**
+ * Flag for registering a message: declare that this message is a stub, and we
+ * will not actually publish/subscribe it, but that the dispatcher should
+ * treat us as if we did when typechecking.
+ *
+ * We use this so that messages aren't treated as "dangling" if they are
+ * potentially used by some other build of Tor.
+ */
+#define DISP_FLAG_STUB (1u<<1)
+
+#endif /* !defined(TOR_PUBSUB_FLAGS_H) */
diff --git a/src/lib/pubsub/pubsub_macros.h b/src/lib/pubsub/pubsub_macros.h
new file mode 100644
index 0000000000..357e59fd54
--- /dev/null
+++ b/src/lib/pubsub/pubsub_macros.h
@@ -0,0 +1,373 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file pubsub_macros.h
+ * \brief Macros to help with the publish/subscribe dispatch API.
+ *
+ * The dispatch API allows different subsystems of Tor to communicate with
+ * another asynchronously via a shared "message" system. Some subsystems
+ * declare that they publish a given message, and others declare that they
+ * subscribe to it. Both subsystems depend on the message, but not upon one
+ * another.
+ *
+ * To declare a message, use DECLARE_MESSAGE() (for messages that take their
+ * data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their
+ * data as an integer. For example, you might say
+ *
+ * DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *);
+ * or
+ * DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool);
+ *
+ * Every message has a unique name, a "type name" that the dispatch system
+ * uses to manage associated data, and a C type name. You'll want to put
+ * these declarations in a header, to be included by all publishers and all
+ * subscribers.
+ *
+ * When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at
+ * file scope to create necessary static functions. Then, in its subsystem
+ * initialization (in the "bind to dispatcher" callback) (TODO: name this
+ * properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its
+ * intent to publish. When it actually wants to publish, it uses the
+ * PUBLISH() macro. For example:
+ *
+ * // At file scope
+ * DECLARE_PUBLISH(shutdown_requested);
+ *
+ * static void bind_to_dispatcher(pubsub_connector_t *con)
+ * {
+ * DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested);
+ * }
+ *
+ * // somewhere in a function
+ * {
+ * PUBLISH(shutdown_requested, true);
+ * }
+ *
+ * When a subsystem wants to subscribe to a message, it uses
+ * DECLARE_SUBSCRIBE() at file scope to declare static functions. It must
+ * declare a hook function that receives the message type. Then, in its "bind
+ * to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the
+ * dispatcher about its intent to subscribe. When another module publishes
+ * the message, the dispatcher will call the provided hook function.
+ *
+ * // At file scope. The first argument is the message that you're
+ * // subscribing to; the second argument is the hook function to declare.
+ * DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb);
+ *
+ * // You need to declare this function.
+ * static void on_shutdown_req_cb(const msg_t *msg,
+ * bool value)
+ * {
+ * // (do something here.)
+ * }
+ *
+ * static void bind_to_dispatcher(pubsub_connector_t *con)
+ * {
+ * DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested);
+ * }
+ *
+ * Where did these types come from? Somewhere in the code, you need to call
+ * DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the
+ * message auxiliary data. It associates a vtbl-like structure with the
+ * type name, so that the dispatcher knows how to manipulate the type you're
+ * giving it.
+ *
+ * For example, the "boolean" type we're using above could be defined as:
+ *
+ * static char *boolean_fmt(msg_aux_data_t d)
+ * {
+ * // This is used for debugging and dumping messages.
+ * if (d.u64)
+ * return tor_strdup("true");
+ * else
+ * return tor_strdup("false");
+ * }
+ *
+ * static void boolean_free(msg_aux_data_t d)
+ * {
+ * // We don't actually need to do anything to free a boolean.
+ * // We could use "NULL" instead of this function, but I'm including
+ * // it as an example.
+ * }
+ *
+ * static void bind_to_dispatcher(pubsub_connector_t *con)
+ * {
+ * dispatch_typefns_t boolean_fns = {
+ * .fmt_fn = boolean_fmt,
+ * .free_fn = boolean_free,
+ * };
+ * DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns);
+ * }
+ *
+ *
+ *
+ * So, how does this all work? (You can stop reading here, unless you're
+ * debugging something.)
+ *
+ * When you declare a message in a header with DECLARE_MESSAGE() or
+ * DECLARE_MESSAGE_INT(), it creates five things:
+ *
+ * * two typedefs for the message argument (constant and non-constant
+ * variants).
+ * * a constant string to hold the declared message type name
+ * * two inline functions, to coerce the message argument type to and from
+ * a "msg_aux_data_t" union.
+ *
+ * All of these declarations have names based on the message name.
+ *
+ * Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the
+ * elements defined by DECLARE_MESSAGE() to make sure that the publish
+ * function takes the correct argument type, and that the subscription hook is
+ * declared with the right argument type.
+ **/
+
+#ifndef TOR_DISPATCH_MSG_H
+#define TOR_DISPATCH_MSG_H
+
+#include "lib/cc/compat_compiler.h"
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/pubsub/pub_binding_st.h"
+#include "lib/pubsub/pubsub_connect.h"
+#include "lib/pubsub/pubsub_flags.h"
+#include "lib/pubsub/pubsub_publish.h"
+
+/* Implemenation notes:
+ *
+ * For a messagename "foo", the DECLARE_MESSAGE*() macros must declare:
+ *
+ * msg_arg_type__foo -- a typedef for the argument type of the foo message.
+ * msg_arg_consttype__foo -- a typedef for the const argument type of the
+ * foo message.
+ * msg_arg_name__foo[] -- a static string constant holding the unique
+ * identifier for the type of the foo message.
+ * msg_arg_get__foo() -- an inline function taking a msg_aux_data_t and
+ * returning the C data type.
+ * msg_arg_set__foo() -- an inline function taking a msg_aux_data_t and
+ * the C type, setting the msg_aux_data_t to hold the C type.
+ *
+ * For a messagename "foo", the DECLARE_PUBLISH() macro must declare:
+ *
+ * pub_binding__foo -- A static pub_binding_t object used to send messages
+ * from this module.
+ * publish_fn__foo -- A function taking an argument of the appropriate
+ * C type, to be invoked by PUBLISH().
+ *
+ * For a messagename "foo", the DECLARE_SUBSCRIBE() macro must declare:
+ *
+ * hookfn -- A user-provided function name, with the correct signature.
+ * recv_fn__foo -- A wrapper callback that takes a msg_t *, and calls
+ * hookfn with the appropriate arguments.
+ */
+
+/* Macro to declare common elements shared by DECLARE_MESSAGE and
+ * DECLARE_MESSAGE_INT. Don't call this directly.
+ *
+ * Note that the "msg_arg_name" string constant is defined in each
+ * translation unit. This might be undesirable; we can tweak it in the
+ * future if need be.
+ */
+#define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \
+ typedef c_type msg_arg_type__ ##messagename; \
+ typedef const c_type msg_arg_consttype__ ##messagename; \
+ ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename;
+
+/**
+ * Use this macro in a header to declare the existence of a given message,
+ * taking a pointer as auxiliary data.
+ *
+ * "messagename" is a unique identifier for the message; it must be a valid
+ * C identifier.
+ *
+ * "typename" is a unique identifier for the type of the auxiliary data.
+ * It needs to be defined somewhere in Tor, using
+ * "DISPATCH_REGISTER_TYPE."
+ *
+ * "c_ptr_type" is a C pointer type (like "char *" or "struct foo *").
+ * The "*" needs to be included.
+ */
+#define DECLARE_MESSAGE(messagename, typename, c_ptr_type) \
+ DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type) \
+ ATTR_UNUSED static inline c_ptr_type \
+ msg_arg_get__ ##messagename(msg_aux_data_t m) \
+ { \
+ return m.ptr; \
+ } \
+ ATTR_UNUSED static inline void \
+ msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v) \
+ { \
+ m->ptr = v; \
+ } \
+ EAT_SEMICOLON
+
+/**
+ * Use this macro in a header to declare the existence of a given message,
+ * taking an integer as auxiliary data.
+ *
+ * "messagename" is a unique identifier for the message; it must be a valid
+ * C identifier.
+ *
+ * "typename" is a unique identifier for the type of the auxiliary data. It
+ * needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE."
+ *
+ * "c_type" is a C integer type, like "int" or "bool". It needs to fit inside
+ * a uint64_t.
+ */
+#define DECLARE_MESSAGE_INT(messagename, typename, c_type) \
+ DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \
+ ATTR_UNUSED static inline c_type \
+ msg_arg_get__ ##messagename(msg_aux_data_t m) \
+ { \
+ return (c_type)m.u64; \
+ } \
+ ATTR_UNUSED static inline void \
+ msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v) \
+ { \
+ m->u64 = (uint64_t)v; \
+ } \
+ EAT_SEMICOLON
+
+/**
+ * Use this macro inside a C module declare that we'll be publishing a given
+ * message type from within this module.
+ *
+ * It creates necessary functions and wrappers to publish a message whose
+ * unique identifier is "messagename".
+ *
+ * Before you use this, you need to include the header where DECLARE_MESSAGE*()
+ * was used for this message.
+ *
+ * You can only use this once per message in each subsystem.
+ */
+#define DECLARE_PUBLISH(messagename) \
+ static pub_binding_t pub_binding__ ##messagename; \
+ static void \
+ publish_fn__ ##messagename(msg_arg_type__ ##messagename arg) \
+ { \
+ msg_aux_data_t data; \
+ msg_arg_set__ ##messagename(&data, arg); \
+ pubsub_pub_(&pub_binding__ ##messagename, data); \
+ } \
+ EAT_SEMICOLON
+
+/**
+ * Use this macro inside a C file to declare that we're subscribing to a
+ * given message and associating it with a given "hook function". It
+ * declares the hook function static, and helps with strong typing.
+ *
+ * Before you use this, you need to include the header where
+ * DECLARE_MESSAGE*() was used for the message whose unique identifier is
+ * "messagename".
+ *
+ * You will need to define a function with the name that you provide for
+ * "hookfn". The type of this function will be:
+ * static void hookfn(const msg_t *, const c_type)
+ * where c_type is the c type that you declared in the header.
+ *
+ * You can only use this once per message in each subsystem.
+ */
+#define DECLARE_SUBSCRIBE(messagename, hookfn) \
+ static void hookfn(const msg_t *, \
+ const msg_arg_consttype__ ##messagename); \
+ static void recv_fn__ ## messagename(const msg_t *m) \
+ { \
+ msg_arg_type__ ## messagename arg; \
+ arg = msg_arg_get__ ##messagename(m->aux_data__); \
+ hookfn(m, arg); \
+ } \
+ EAT_SEMICOLON
+
+/**
+ * Add a fake use of the publish function for 'messagename', so that
+ * the compiler does not call it unused.
+ */
+#define DISPATCH__FAKE_USE_OF_PUBFN_(messagename) \
+ ( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \
+ : 1)
+
+/*
+ * This macro is for internal use. It backs DISPATCH_ADD_PUB*()
+ */
+#define DISPATCH_ADD_PUB_(connector, channel, messagename, flags) \
+ ( \
+ DISPATCH__FAKE_USE_OF_PUBFN_(messagename), \
+ pubsub_add_pub_((connector), \
+ &pub_binding__ ##messagename, \
+ get_channel_id(# channel), \
+ get_message_id(# messagename), \
+ get_msg_type_id(msg_arg_name__ ## messagename), \
+ (flags), \
+ __FILE__, \
+ __LINE__) \
+ )
+
+/**
+ * Use a given connector and channel name to declare that this subsystem will
+ * publish a given message type.
+ *
+ * Call this macro from within the add_subscriptions() function of a module.
+ */
+#define DISPATCH_ADD_PUB(connector, channel, messagename) \
+ DISPATCH_ADD_PUB_(connector, channel, messagename, 0)
+
+/**
+ * Use a given connector and channel name to declare that this subsystem will
+ * publish a given message type, and that no other subsystem is allowed to.
+ *
+ * Call this macro from within the add_subscriptions() function of a module.
+ */
+#define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename) \
+ DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL)
+
+/*
+ * This macro is for internal use. It backs DISPATCH_ADD_SUB*()
+ */
+#define DISPATCH_ADD_SUB_(connector, channel, messagename, flags) \
+ pubsub_add_sub_((connector), \
+ recv_fn__ ##messagename, \
+ get_channel_id(#channel), \
+ get_message_id(# messagename), \
+ get_msg_type_id(msg_arg_name__ ##messagename), \
+ (flags), \
+ __FILE__, \
+ __LINE__)
+/*
+ * Use a given connector and channel name to declare that this subsystem will
+ * receive a given message type.
+ *
+ * Call this macro from within the add_subscriptions() function of a module.
+ */
+#define DISPATCH_ADD_SUB(connector, channel, messagename) \
+ DISPATCH_ADD_SUB_(connector, channel, messagename, 0)
+/**
+ * Use a given connector and channel name to declare that this subsystem will
+ * receive a given message type, and that no other subsystem is allowed to do
+ * so.
+ *
+ * Call this macro from within the add_subscriptions() function of a module.
+ */
+#define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename) \
+ DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL)
+
+/**
+ * Publish a given message with a given argument. (Takes ownership of the
+ * argument if it is a pointer.)
+ */
+#define PUBLISH(messagename, arg) \
+ publish_fn__ ##messagename(arg)
+
+/**
+ * Use a given connector to declare that the functions to be used to manipuate
+ * a certain C type.
+ **/
+#define DISPATCH_REGISTER_TYPE(con, type, fns) \
+ pubsub_connector_register_type_((con), \
+ get_msg_type_id(#type), \
+ (fns), \
+ __FILE__, \
+ __LINE__)
+
+#endif /* !defined(TOR_DISPATCH_MSG_H) */
diff --git a/src/lib/pubsub/pubsub_publish.c b/src/lib/pubsub/pubsub_publish.c
new file mode 100644
index 0000000000..454a335a78
--- /dev/null
+++ b/src/lib/pubsub/pubsub_publish.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file pubsub_publish.c
+ * @brief Header for functions to publish using a pub_binding_t.
+ **/
+
+#define PUBSUB_PRIVATE
+#define DISPATCH_PRIVATE
+#include "orconfig.h"
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_st.h"
+
+#include "lib/pubsub/pub_binding_st.h"
+#include "lib/pubsub/pubsub_publish.h"
+
+#include "lib/malloc/malloc.h"
+#include "lib/log/util_bug.h"
+
+#include <string.h>
+
+/**
+ * Publish a message from the publication binding <b>pub</b> using the
+ * auxiliary data <b>auxdata</b>.
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+int
+pubsub_pub_(const pub_binding_t *pub, msg_aux_data_t auxdata)
+{
+ dispatch_t *d = pub->dispatch_ptr;
+ if (BUG(! d)) {
+ /* Tried to publish a message before the dispatcher was configured. */
+ /* (Without a dispatcher, we don't know how to free auxdata.) */
+ return -1;
+ }
+
+ if (BUG(pub->msg_template.type >= d->n_types)) {
+ /* The type associated with this message is not known to the dispatcher. */
+ /* (Without a correct type, we don't know how to free auxdata.) */
+ return -1;
+ }
+
+ if (BUG(pub->msg_template.msg >= d->n_msgs) ||
+ BUG(pub->msg_template.channel >= d->n_queues)) {
+ /* The message ID or channel ID was out of bounds. */
+ // LCOV_EXCL_START
+ d->typefns[pub->msg_template.type].free_fn(auxdata);
+ return -1;
+ // LCOV_EXCL_STOP
+ }
+
+ if (! d->table[pub->msg_template.msg]) {
+ /* Fast path: nobody wants this data. */
+
+ // XXXX Faster path: we could store this in the pub_binding_t.
+ d->typefns[pub->msg_template.type].free_fn(auxdata);
+ return 0;
+ }
+
+ /* Construct the message object */
+ msg_t *m = tor_malloc(sizeof(msg_t));
+ memcpy(m, &pub->msg_template, sizeof(msg_t));
+ m->aux_data__ = auxdata;
+
+ return dispatch_send_msg_unchecked(d, m);
+}
diff --git a/src/lib/pubsub/pubsub_publish.h b/src/lib/pubsub/pubsub_publish.h
new file mode 100644
index 0000000000..0686a465de
--- /dev/null
+++ b/src/lib/pubsub/pubsub_publish.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_PUBSUB_PUBLISH_H
+#define TOR_PUBSUB_PUBLISH_H
+
+#include "lib/dispatch/msgtypes.h"
+struct pub_binding_t;
+
+int pubsub_pub_(const struct pub_binding_t *pub, msg_aux_data_t auxdata);
+
+#endif /* !defined(TOR_PUBSUB_PUBLISH_H) */
diff --git a/src/lib/sandbox/include.am b/src/lib/sandbox/include.am
index adfda6bde5..e81f14b55f 100644
--- a/src/lib/sandbox/include.am
+++ b/src/lib/sandbox/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-sandbox-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_sandbox_a_SOURCES = \
src/lib/sandbox/sandbox.c
@@ -13,6 +14,7 @@ src_lib_libtor_sandbox_testing_a_SOURCES = \
src_lib_libtor_sandbox_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_sandbox_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/sandbox/linux_syscalls.inc \
src/lib/sandbox/sandbox.h
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index dfb41a0965..de37989fad 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -143,6 +143,7 @@ static int filter_nopar_gen[] = {
SCMP_SYS(clock_gettime),
SCMP_SYS(close),
SCMP_SYS(clone),
+ SCMP_SYS(dup),
SCMP_SYS(epoll_create),
SCMP_SYS(epoll_wait),
#ifdef __NR_epoll_pwait
@@ -294,6 +295,7 @@ sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
unsigned i;
int rc;
int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD,
+ SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, SIGIO,
#ifdef SIGXFSZ
SIGXFSZ
#endif
diff --git a/src/lib/smartlist_core/include.am b/src/lib/smartlist_core/include.am
index 99d65f0b23..548179bc4f 100644
--- a/src/lib/smartlist_core/include.am
+++ b/src/lib/smartlist_core/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-smartlist-core-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_smartlist_core_a_SOURCES = \
src/lib/smartlist_core/smartlist_core.c \
src/lib/smartlist_core/smartlist_split.c
@@ -15,6 +16,7 @@ src_lib_libtor_smartlist_core_testing_a_CPPFLAGS = \
$(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_smartlist_core_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/smartlist_core/smartlist_core.h \
src/lib/smartlist_core/smartlist_foreach.h \
diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c
index ac85a6cc84..6b0a305a93 100644
--- a/src/lib/smartlist_core/smartlist_core.c
+++ b/src/lib/smartlist_core/smartlist_core.c
@@ -88,6 +88,30 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size)
#undef MAX_CAPACITY
}
+/** Expand <b>sl</b> so that its length is at least <b>new_size</b>,
+ * filling in previously unused entries with NULL>
+ *
+ * Do nothing if <b>sl</b> already had at least <b>new_size</b> elements.
+ */
+void
+smartlist_grow(smartlist_t *sl, size_t new_size)
+{
+ smartlist_ensure_capacity(sl, new_size);
+
+ if (new_size > (size_t)sl->num_used) {
+ /* This memset() should be a no-op: everything else in the smartlist code
+ * tries to make sure that unused entries are always NULL. Still, that is
+ * meant as a safety mechanism, so let's clear the memory here.
+ */
+ memset(sl->list + sl->num_used, 0,
+ sizeof(void *) * (new_size - sl->num_used));
+
+ /* This cast is safe, since we already asserted that we were below
+ * MAX_CAPACITY in smartlist_ensure_capacity(). */
+ sl->num_used = (int)new_size;
+ }
+}
+
/** Append element to the end of the list. */
void
smartlist_add(smartlist_t *sl, void *element)
@@ -153,6 +177,8 @@ smartlist_remove_keeporder(smartlist_t *sl, const void *element)
sl->list[i++] = sl->list[j];
}
}
+ memset(sl->list + sl->num_used, 0,
+ sizeof(void *) * (num_used_orig - sl->num_used));
}
/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise,
diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h
index a7fbaa099b..795741c447 100644
--- a/src/lib/smartlist_core/smartlist_core.h
+++ b/src/lib/smartlist_core/smartlist_core.h
@@ -43,6 +43,7 @@ void smartlist_clear(smartlist_t *sl);
void smartlist_add(smartlist_t *sl, void *element);
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
void smartlist_add_strdup(struct smartlist_t *sl, const char *string);
+void smartlist_grow(smartlist_t *sl, size_t new_size);
void smartlist_remove(smartlist_t *sl, const void *element);
void smartlist_remove_keeporder(smartlist_t *sl, const void *element);
@@ -97,4 +98,4 @@ void smartlist_del(smartlist_t *sl, int idx);
void smartlist_del_keeporder(smartlist_t *sl, int idx);
void smartlist_insert(smartlist_t *sl, int idx, void *val);
-#endif /* !defined(TOR_CONTAINER_H) */
+#endif /* !defined(TOR_SMARTLIST_CORE_H) */
diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h
index 4f72376125..e2cc7245b7 100644
--- a/src/lib/smartlist_core/smartlist_split.h
+++ b/src/lib/smartlist_core/smartlist_split.h
@@ -17,4 +17,4 @@
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
int flags, int max);
-#endif
+#endif /* !defined(TOR_SMARTLIST_SPLIT_H) */
diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h
index a0e37bb6dc..4f30bf5392 100644
--- a/src/lib/string/compat_string.h
+++ b/src/lib/string/compat_string.h
@@ -25,14 +25,14 @@ static inline int strncasecmp(const char *a, const char *b, size_t n);
static inline int strncasecmp(const char *a, const char *b, size_t n) {
return _strnicmp(a,b,n);
}
-#endif
+#endif /* !defined(HAVE_STRNCASECMP) */
#ifndef HAVE_STRCASECMP
static inline int strcasecmp(const char *a, const char *b);
static inline int strcasecmp(const char *a, const char *b) {
return _stricmp(a,b);
}
-#endif
-#endif
+#endif /* !defined(HAVE_STRCASECMP) */
+#endif /* defined(_WIN32) */
#if defined __APPLE__
/* On OSX 10.9 and later, the overlap-checking code for strlcat would
@@ -59,4 +59,4 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts)
#endif
-#endif
+#endif /* !defined(TOR_COMPAT_STRING_H) */
diff --git a/src/lib/string/include.am b/src/lib/string/include.am
index edd74b8a3e..82d35cc5af 100644
--- a/src/lib/string/include.am
+++ b/src/lib/string/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-string-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_string_a_SOURCES = \
src/lib/string/compat_ctype.c \
src/lib/string/compat_string.c \
@@ -18,6 +19,7 @@ src_lib_libtor_string_testing_a_SOURCES = \
src_lib_libtor_string_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_string_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/string/compat_ctype.h \
src/lib/string/compat_string.h \
diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h
index 925547942e..50d48b44c5 100644
--- a/src/lib/string/parse_int.h
+++ b/src/lib/string/parse_int.h
@@ -22,4 +22,4 @@ double tor_parse_double(const char *s, double min, double max, int *ok,
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
uint64_t max, int *ok, char **next);
-#endif
+#endif /* !defined(TOR_PARSE_INT_H) */
diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c
index a5cb71ce09..26203932e4 100644
--- a/src/lib/string/printf.c
+++ b/src/lib/string/printf.c
@@ -117,8 +117,8 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
*strp = NULL;
return -1;
}
- strp_tmp = tor_malloc(len + 1);
- r = _vsnprintf(strp_tmp, len+1, fmt, args);
+ strp_tmp = tor_malloc((size_t)len + 1);
+ r = _vsnprintf(strp_tmp, (size_t)len+1, fmt, args);
if (r != len) {
tor_free(strp_tmp);
*strp = NULL;
@@ -153,9 +153,9 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
*strp = tor_strdup(buf);
return len;
}
- strp_tmp = tor_malloc(len+1);
+ strp_tmp = tor_malloc((size_t)len+1);
/* use of tor_vsnprintf() will ensure string is null terminated */
- r = tor_vsnprintf(strp_tmp, len+1, fmt, args);
+ r = tor_vsnprintf(strp_tmp, (size_t)len+1, fmt, args);
if (r != len) {
tor_free(strp_tmp);
*strp = NULL;
diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h
index 2cc13d6bee..6e90770f81 100644
--- a/src/lib/string/printf.h
+++ b/src/lib/string/printf.h
@@ -27,4 +27,4 @@ int tor_asprintf(char **strp, const char *fmt, ...)
int tor_vasprintf(char **strp, const char *fmt, va_list args)
CHECK_PRINTF(2,0);
-#endif /* !defined(TOR_UTIL_STRING_H) */
+#endif /* !defined(TOR_UTIL_PRINTF_H) */
diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h
index 6673173de5..b642e242db 100644
--- a/src/lib/string/scanf.h
+++ b/src/lib/string/scanf.h
@@ -21,4 +21,4 @@ int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \
int tor_sscanf(const char *buf, const char *pattern, ...)
CHECK_SCANF(2, 3);
-#endif /* !defined(TOR_UTIL_STRING_H) */
+#endif /* !defined(TOR_UTIL_SCANF_H) */
diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c
index 0c4e399008..f5061a11d2 100644
--- a/src/lib/string/util_string.c
+++ b/src/lib/string/util_string.c
@@ -71,7 +71,7 @@ tor_memstr(const void *haystack, size_t hlen, const char *needle)
/** Return true iff the 'len' bytes at 'mem' are all zero. */
int
-tor_mem_is_zero(const char *mem, size_t len)
+fast_mem_is_zero(const char *mem, size_t len)
{
static const char ZERO[] = {
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
@@ -95,17 +95,14 @@ tor_mem_is_zero(const char *mem, size_t len)
int
tor_digest_is_zero(const char *digest)
{
- static const uint8_t ZERO_DIGEST[] = {
- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
- };
- return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN);
+ return safe_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);
+ return safe_mem_is_zero(digest, DIGEST256_LEN);
}
/** Remove from the string <b>s</b> every character which appears in
diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h
index da4fab159c..b3c6841d41 100644
--- a/src/lib/string/util_string.h
+++ b/src/lib/string/util_string.h
@@ -20,7 +20,10 @@ const void *tor_memmem(const void *haystack, size_t hlen, const void *needle,
size_t nlen);
const void *tor_memstr(const void *haystack, size_t hlen,
const char *needle);
-int tor_mem_is_zero(const char *mem, size_t len);
+int fast_mem_is_zero(const char *mem, size_t len);
+#define fast_digest_is_zero(d) fast_mem_is_zero((d), DIGEST_LEN)
+#define fast_digetst256_is_zero(d) fast_mem_is_zero((d), DIGEST256_LEN)
+
int tor_digest_is_zero(const char *digest);
int tor_digest256_is_zero(const char *digest);
diff --git a/src/lib/subsys/include.am b/src/lib/subsys/include.am
index 4741126b14..c9ab54ca73 100644
--- a/src/lib/subsys/include.am
+++ b/src/lib/subsys/include.am
@@ -1,3 +1,4 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/subsys/subsys.h
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index 241ad7829c..21f984f32d 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -8,7 +8,7 @@
#include <stdbool.h>
-struct dispatch_connector_t;
+struct pubsub_connector_t;
/**
* A subsystem is a part of Tor that is initialized, shut down, configured,
@@ -58,7 +58,7 @@ typedef struct subsys_fns_t {
/**
* Connect a subsystem to the message dispatch system.
**/
- int (*add_pubsub)(struct dispatch_connector_t *);
+ int (*add_pubsub)(struct pubsub_connector_t *);
/**
* Perform any necessary pre-fork cleanup. This function may not fail.
@@ -92,4 +92,4 @@ typedef struct subsys_fns_t {
* less than this value. */
#define SUBSYS_LEVEL_LIBS -10
-#endif
+#endif /* !defined(TOR_SUBSYS_T) */
diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h
index a9c146ea8f..aa597ec423 100644
--- a/src/lib/term/getpass.h
+++ b/src/lib/term/getpass.h
@@ -15,4 +15,4 @@
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
-#endif
+#endif /* !defined(TOR_GETPASS_H) */
diff --git a/src/lib/term/include.am b/src/lib/term/include.am
index 55fe548ebc..a120bba0cb 100644
--- a/src/lib/term/include.am
+++ b/src/lib/term/include.am
@@ -11,6 +11,7 @@ else
readpassphrase_source=
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_term_a_SOURCES = \
src/lib/term/getpass.c \
$(readpassphrase_source)
@@ -20,5 +21,6 @@ src_lib_libtor_term_testing_a_SOURCES = \
src_lib_libtor_term_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_term_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/term/getpass.h
diff --git a/src/lib/testsupport/include.am b/src/lib/testsupport/include.am
index b2aa620985..a5ed46eb67 100644
--- a/src/lib/testsupport/include.am
+++ b/src/lib/testsupport/include.am
@@ -1,3 +1,4 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/testsupport/testsupport.h
diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h
index 9363a9ba66..631ec0228c 100644
--- a/src/lib/testsupport/testsupport.h
+++ b/src/lib/testsupport/testsupport.h
@@ -21,7 +21,7 @@
* tests. */
#define STATIC
#define EXTERN(type, name) extern type name;
-#else
+#else /* !(defined(TOR_UNIT_TESTS)) */
#define STATIC static
#define EXTERN(type, name)
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c
index 35cfeba64c..8cf1967e53 100644
--- a/src/lib/thread/compat_threads.c
+++ b/src/lib/thread/compat_threads.c
@@ -67,7 +67,15 @@ atomic_counter_init(atomic_counter_t *counter)
memset(counter, 0, sizeof(*counter));
tor_mutex_init_nonrecursive(&counter->mutex);
}
-/** Clean up all resources held by an atomic counter. */
+/** Clean up all resources held by an atomic counter.
+ *
+ * Destroying a locked mutex is undefined behaviour. Global mutexes may be
+ * locked when they are passed to this function, because multiple threads can
+ * still access them. So we can either:
+ * - destroy on shutdown, and re-initialise when tor re-initialises, or
+ * - skip destroying and re-initialisation, using a sentinel variable.
+ * See #31735 for details.
+ */
void
atomic_counter_destroy(atomic_counter_t *counter)
{
diff --git a/src/lib/thread/include.am b/src/lib/thread/include.am
index 695795a2c8..cd8016b5df 100644
--- a/src/lib/thread/include.am
+++ b/src/lib/thread/include.am
@@ -12,6 +12,7 @@ if THREADS_WIN32
threads_impl_source=src/lib/thread/compat_winthreads.c
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_thread_a_SOURCES = \
src/lib/thread/compat_threads.c \
src/lib/thread/numcpus.c \
@@ -22,6 +23,7 @@ src_lib_libtor_thread_testing_a_SOURCES = \
src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/thread/numcpus.h \
src/lib/thread/thread_sys.h \
diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h
index 3f0a29ce7c..2f1ea16eb9 100644
--- a/src/lib/thread/numcpus.h
+++ b/src/lib/thread/numcpus.h
@@ -13,4 +13,4 @@
int compute_num_cpus(void);
-#endif
+#endif /* !defined(TOR_NUMCPUS_H) */
diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h
index ecf60641b5..de3da6a585 100644
--- a/src/lib/thread/threads.h
+++ b/src/lib/thread/threads.h
@@ -131,7 +131,17 @@ atomic_counter_init(atomic_counter_t *counter)
{
atomic_init(&counter->val, 0);
}
-/** Clean up all resources held by an atomic counter. */
+/** Clean up all resources held by an atomic counter.
+ *
+ * This usage note applies to the compat_threads implementation of
+ * atomic_counter_destroy():
+ * Destroying a locked mutex is undefined behaviour. Global mutexes may be
+ * locked when they are passed to this function, because multiple threads can
+ * still access them. So we can either:
+ * - destroy on shutdown, and re-initialise when tor re-initialises, or
+ * - skip destroying and re-initialisation, using a sentinel variable.
+ * See #31735 for details.
+ */
static inline void
atomic_counter_destroy(atomic_counter_t *counter)
{
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
index a047d6c2cd..3f41500f3a 100644
--- a/src/lib/time/compat_time.c
+++ b/src/lib/time/compat_time.c
@@ -164,6 +164,8 @@ static int64_t last_tick_count = 0;
* to be monotonic; increments them as appropriate so that they actually
* _are_ monotonic.
*
+ * The returned time may be the same as the previous returned time.
+ *
* Caller must hold lock. */
STATIC int64_t
ratchet_performance_counter(int64_t count_raw)
@@ -202,6 +204,8 @@ static struct timeval timeofday_offset = { 0, 0 };
* supposed to be monotonic; increments them as appropriate so that they
* actually _are_ monotonic.
*
+ * The returned time may be the same as the previous returned time.
+ *
* Caller must hold lock. */
STATIC void
ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out)
@@ -270,7 +274,9 @@ monotime_init_internal(void)
}
/**
- * Set "out" to the most recent monotonic time value
+ * Set "out" to the most recent monotonic time value.
+ *
+ * The returned time may be the same as the previous returned time.
*/
void
monotime_get(monotime_t *out)
@@ -298,10 +304,12 @@ monotime_coarse_get(monotime_coarse_t *out)
#endif /* defined(TOR_UNIT_TESTS) */
out->abstime_ = mach_approximate_time();
}
-#endif
+#endif /* defined(HAVE_MACH_APPROXIMATE_TIME) */
/**
* Return the number of nanoseconds between <b>start</b> and <b>end</b>.
+ *
+ * The returned value may be equal to zero.
*/
int64_t
monotime_diff_nsec(const monotime_t *start,
@@ -759,7 +767,7 @@ monotime_coarse_zero(monotime_coarse_t *out)
{
memset(out, 0, sizeof(*out));
}
-#endif
+#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */
int64_t
monotime_diff_usec(const monotime_t *start,
@@ -825,7 +833,7 @@ monotime_coarse_absolute_msec(void)
{
return monotime_coarse_absolute_nsec() / ONE_MILLION;
}
-#else
+#else /* !(defined(MONOTIME_COARSE_FN_IS_DIFFERENT)) */
#define initialized_at_coarse initialized_at
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */
@@ -857,7 +865,7 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec)
mach_time_info.numer;
return abstime_val >> monotime_shift;
}
-#else
+#else /* !(defined(__APPLE__)) */
uint64_t
monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
{
@@ -868,4 +876,4 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec)
{
return (msec * STAMP_TICKS_PER_SECOND) / 1000;
}
-#endif
+#endif /* defined(__APPLE__) */
diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h
index 2cd4b3bee3..8c7661d7cb 100644
--- a/src/lib/time/compat_time.h
+++ b/src/lib/time/compat_time.h
@@ -15,11 +15,29 @@
* of tens of milliseconds.
*/
-/* Q: Should you use monotime or monotime_coarse as your source?
+/* Q: When should I use monotonic time?
+ *
+ * A: If you need a time that never decreases, use monotonic time. If you need
+ * to send a time to a user or another process, or store a time, use the
+ * wall-clock time.
+ *
+ * Q: Should you use monotime or monotime_coarse as your source?
*
* A: Generally, you get better precision with monotime, but better
* performance with monotime_coarse.
*
+ * Q: What is a "monotonic" time, exactly?
+ *
+ * A: Monotonic times are strictly non-decreasing. The difference between any
+ * previous monotonic time, and the current monotonic time, is always greater
+ * than *or equal to* zero.
+ * Zero deltas happen more often:
+ * - on Windows (due to an OS bug),
+ * - when using monotime_coarse, or on systems with low-resolution timers,
+ * - on platforms where we emulate monotonic time using wall-clock time, and
+ * - when using time units that are larger than nanoseconds (due to
+ * truncation on division).
+ *
* Q: Should you use monotime_t or monotime_coarse_t directly? Should you use
* usec? msec? "stamp units?"
*
@@ -95,7 +113,7 @@
* All, "timestamp units": Cheap everywhere: it never divides.
*
* Q: This is only somewhat related, but how much precision could I hope for
- * from a libevent time.?
+ * from a libevent time?
*
* A: Actually, it's _very_ related if you're timing in order to have a
* timeout happen.
@@ -182,26 +200,36 @@ void monotime_init(void);
void monotime_get(monotime_t *out);
/**
* Return the number of nanoseconds between <b>start</b> and <b>end</b>.
+ * The returned value may be equal to zero.
*/
int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end);
/**
* Return the number of microseconds between <b>start</b> and <b>end</b>.
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end);
/**
* Return the number of milliseconds between <b>start</b> and <b>end</b>.
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end);
/**
* Return the number of nanoseconds since the timer system was initialized.
+ * The returned value may be equal to zero.
*/
uint64_t monotime_absolute_nsec(void);
/**
* Return the number of microseconds since the timer system was initialized.
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
MOCK_DECL(uint64_t, monotime_absolute_usec,(void));
/**
* Return the number of milliseconds since the timer system was initialized.
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
uint64_t monotime_absolute_msec(void);
@@ -225,6 +253,9 @@ void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec);
* Set <b>out</b> to the current coarse time.
*/
void monotime_coarse_get(monotime_coarse_t *out);
+/**
+ * Like monotime_absolute_*(), but faster on some platforms.
+ */
uint64_t monotime_coarse_absolute_nsec(void);
uint64_t monotime_coarse_absolute_usec(void);
uint64_t monotime_coarse_absolute_msec(void);
@@ -248,18 +279,27 @@ uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t);
/**
* Convert a difference, expressed in the units of monotime_coarse_to_stamp,
* into an approximate number of milliseconds.
+ *
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units);
uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec);
uint32_t monotime_coarse_get_stamp(void);
#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)
+/**
+ * Like monotime_diff_*(), but faster on some platforms.
+ */
int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start,
const monotime_coarse_t *end);
+/**
+ * Like monotime_*(), but faster on some platforms.
+ */
void monotime_coarse_zero(monotime_coarse_t *out);
int monotime_coarse_is_zero(const monotime_coarse_t *val);
void monotime_coarse_add_msec(monotime_coarse_t *out,
@@ -278,6 +318,9 @@ void monotime_coarse_add_msec(monotime_coarse_t *out,
*
* Requires that the difference fit into an int32_t; not for use with
* large time differences.
+ *
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start,
const monotime_coarse_t *end);
@@ -287,6 +330,9 @@ int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start,
*
* Requires that the difference fit into an int32_t; not for use with
* large time differences.
+ *
+ * The returned value may be equal to zero.
+ * Fractional units are truncated, not rounded.
*/
static inline int32_t
monotime_coarse_diff_msec32(const monotime_coarse_t *start,
@@ -298,7 +344,7 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start,
#else
#define USING_32BIT_MSEC_HACK
return monotime_coarse_diff_msec32_(start, end);
-#endif
+#endif /* SIZEOF_VOID_P == 8 */
}
#ifdef TOR_UNIT_TESTS
diff --git a/src/lib/time/include.am b/src/lib/time/include.am
index dae16f49ac..dcb199b142 100644
--- a/src/lib/time/include.am
+++ b/src/lib/time/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-time-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_time_a_SOURCES = \
src/lib/time/compat_time.c \
src/lib/time/time_sys.c \
@@ -15,6 +16,7 @@ src_lib_libtor_time_testing_a_SOURCES = \
src_lib_libtor_time_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/time/compat_time.h \
src/lib/time/time_sys.h \
diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h
index 724af1528a..657cb99553 100644
--- a/src/lib/time/tvdiff.h
+++ b/src/lib/time/tvdiff.h
@@ -20,4 +20,4 @@ int64_t tv_to_msec(const struct timeval *tv);
time_t time_diff(const time_t from, const time_t to);
-#endif
+#endif /* !defined(TOR_TVDIFF_H) */
diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am
index 1817739eef..7e05ef4f8c 100644
--- a/src/lib/tls/include.am
+++ b/src/lib/tls/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-tls-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_tls_a_SOURCES = \
src/lib/tls/buffers_tls.c \
src/lib/tls/tortls.c \
@@ -29,6 +30,7 @@ src_lib_libtor_tls_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_tls_testing_a_CFLAGS = \
$(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/tls/ciphers.inc \
src/lib/tls/buffers_tls.h \
diff --git a/src/lib/tls/nss_countbytes.h b/src/lib/tls/nss_countbytes.h
index 8b31603923..47f220c4c1 100644
--- a/src/lib/tls/nss_countbytes.h
+++ b/src/lib/tls/nss_countbytes.h
@@ -22,4 +22,4 @@ int tor_get_prfiledesc_byte_counts(struct PRFileDesc *fd,
uint64_t *n_read_out,
uint64_t *n_written_out);
-#endif
+#endif /* !defined(TOR_NSS_COUNTBYTES_H) */
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index 8efc7a1c98..9e195c6af2 100644
--- a/src/lib/tls/tortls.h
+++ b/src/lib/tls/tortls.h
@@ -25,12 +25,12 @@ struct ssl_ctx_st;
struct ssl_session_st;
typedef struct ssl_ctx_st tor_tls_context_impl_t;
typedef struct ssl_st tor_tls_impl_t;
-#else
+#else /* !(defined(ENABLE_OPENSSL)) */
struct PRFileDesc;
typedef struct PRFileDesc tor_tls_context_impl_t;
typedef struct PRFileDesc tor_tls_impl_t;
-#endif
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
+#endif /* defined(TORTLS_PRIVATE) */
struct tor_x509_cert_t;
@@ -144,9 +144,9 @@ void check_no_tls_errors_(const char *fname, int line);
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
-#else
+#else /* !(defined(ENABLE_OPENSSL)) */
#define check_no_tls_errors() STMT_NIL
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
int tor_tls_get_my_certs(int server,
const struct tor_x509_cert_t **link_cert_out,
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index 071c506561..866483a94c 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -61,8 +61,8 @@ STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret,
void *arg);
STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m,
uint16_t cipher);
-#endif
-#endif
+#endif /* defined(TORTLS_OPENSSL_PRIVATE) */
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef TOR_UNIT_TESTS
extern int tor_tls_object_ex_data_index;
@@ -73,4 +73,4 @@ extern uint64_t total_bytes_written_over_tls;
extern uint64_t total_bytes_written_by_tls;
#endif /* defined(TOR_UNIT_TESTS) */
-#endif /* defined(TORTLS_INTERNAL_H) */
+#endif /* !defined(TORTLS_INTERNAL_H) */
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index b40f948a3b..86f0ac42cc 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -25,7 +25,7 @@
* <winsock.h> and mess things up, in at least some openssl versions. */
#include <winsock2.h>
#include <ws2tcpip.h>
-#endif
+#endif /* defined(_WIN32) */
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -318,7 +318,7 @@ tor_tls_init(void)
#else
SSL_library_init();
SSL_load_error_strings();
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
#if (SIZEOF_VOID_P >= 8 && \
OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
@@ -383,7 +383,7 @@ static const char SERVER_CIPHER_LIST[] =
* conclude that it has no valid ciphers if it's running with TLS1.3.
*/
TLS1_3_TXT_AES_128_GCM_SHA256 ":"
-#endif
+#endif /* defined(TLS1_3_TXT_AES_128_GCM_SHA256) */
TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA;
@@ -657,7 +657,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
if (r < 0)
goto error;
}
-#else
+#else /* !(defined(SSL_CTX_set1_groups_list) || ...) */
if (! is_client) {
int nid;
EC_KEY *ec_key;
@@ -673,7 +673,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_tmp_ecdh(result->ctx, ec_key);
EC_KEY_free(ec_key);
}
-#endif
+#endif /* defined(SSL_CTX_set1_groups_list) || ...) */
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
always_accept_verify_cb);
/* let us realloc bufs that we're writing from */
@@ -1062,7 +1062,7 @@ tor_tls_new(tor_socket_t sock, int isServer)
/* We can't actually use TLS 1.3 until this bug is fixed. */
SSL_set_max_proto_version(result->ssl, TLS1_2_VERSION);
}
-#endif
+#endif /* defined(SSL_CTRL_SET_MAX_PROTO_VERSION) */
if (!SSL_set_cipher_list(result->ssl,
isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
@@ -1728,7 +1728,7 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
else
return -1;
}
-#endif
+#endif /* defined(TLS1_3_VERSION) */
return (r == 1) ? 0 : -1;
}
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 3f7ea8ac6a..73f6e6ecca 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -64,7 +64,7 @@ struct tor_tls_t {
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
/** Argument to pass to negotiated_callback. */
void *callback_arg;
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#ifdef ENABLE_NSS
/** Last values retried from tor_get_prfiledesc_byte_counts(). */
uint64_t last_write_count;
@@ -72,4 +72,4 @@ struct tor_tls_t {
#endif
};
-#endif
+#endif /* !defined(TOR_TORTLS_ST_H) */
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index 5e6660de5c..0390a5464d 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -35,7 +35,7 @@ struct tor_x509_cert_t {
common_digests_t cert_digests;
common_digests_t pkey_digests;
};
-#endif
+#endif /* defined(TOR_X509_PRIVATE) */
void tor_tls_pick_certificate_lifetime(time_t now,
unsigned cert_lifetime,
@@ -47,7 +47,7 @@ tor_x509_cert_t *tor_x509_cert_replace_expiration(
const tor_x509_cert_t *inp,
time_t new_expiration_time,
crypto_pk_t *signing_key);
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert);
@@ -72,4 +72,4 @@ int tor_tls_cert_is_valid(int severity,
time_t now,
int check_rsa_1024);
-#endif
+#endif /* !defined(TOR_X509_H) */
diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h
index bf2bec9689..f858baae98 100644
--- a/src/lib/tls/x509_internal.h
+++ b/src/lib/tls/x509_internal.h
@@ -50,4 +50,4 @@ int tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert);
#define tor_x509_cert_set_cached_der_encoding(cert) (0)
#endif
-#endif
+#endif /* !defined(TOR_X509_INTERNAL_H) */
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
index fb4af54c52..e04afaf07b 100644
--- a/src/lib/tls/x509_nss.c
+++ b/src/lib/tls/x509_nss.c
@@ -120,13 +120,13 @@ tor_tls_create_certificate_internal(crypto_pk_t *rsa,
der.data, der.len,
(SECKEYPrivateKey *)signing_key,//const
&cert->signature);
-#else
+#else /* !(0) */
s = SEC_DerSignData(cert->arena,
&signed_der,
der.data, der.len,
(SECKEYPrivateKey *)signing_key,//const
SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION);
-#endif
+#endif /* 0 */
if (s != SECSuccess)
goto err;
@@ -145,7 +145,7 @@ tor_tls_create_certificate_internal(crypto_pk_t *rsa,
&result_cert->signatureWrap, issuer_pk, NULL);
tor_assert(cert_ok == SECSuccess);
}
-#endif
+#endif /* 1 */
err:
if (subject_spki)
@@ -455,4 +455,4 @@ tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp,
return newcert ? tor_x509_cert_new(newcert) : NULL;
}
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
index a344279c22..03f65049cf 100644
--- a/src/lib/tls/x509_openssl.c
+++ b/src/lib/tls/x509_openssl.c
@@ -59,12 +59,12 @@ ENABLE_GCC_WARNING(redundant-decls)
#define X509_get_notAfter(cert) \
X509_getm_notAfter(cert)
#endif
-#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
+#else /* !(defined(OPENSSL_1_1_API)) */
#define X509_get_notBefore_const(cert) \
((const ASN1_TIME*) X509_get_notBefore((X509 *)cert))
#define X509_get_notAfter_const(cert) \
((const ASN1_TIME*) X509_get_notAfter((X509 *)cert))
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
/** Return a newly allocated X509 name with commonName <b>cname</b>. */
static X509_NAME *
diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h
index e35616cf50..92bb95c883 100644
--- a/src/lib/trace/debug.h
+++ b/src/lib/trace/debug.h
@@ -27,4 +27,4 @@
"\"" XSTR(subsystem) "\" hit. " \
"(line "XSTR(__LINE__) ")")
-#endif /* TOR_TRACE_LOG_DEBUG_H */
+#endif /* !defined(TOR_TRACE_LOG_DEBUG_H) */
diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h
index 1e1e7b9d16..0674f7d501 100644
--- a/src/lib/trace/events.h
+++ b/src/lib/trace/events.h
@@ -34,12 +34,12 @@
#include "lib/trace/debug.h"
#endif
-#else /* TOR_EVENT_TRACING_ENABLED */
+#else /* !(defined(TOR_EVENT_TRACING_ENABLED)) */
/* Reaching this point, we NOP every event declaration because event tracing
* is not been enabled at compile time. */
#define tor_trace(subsystem, name, args...)
-#endif /* TOR_EVENT_TRACING_ENABLED */
+#endif /* defined(TOR_EVENT_TRACING_ENABLED) */
-#endif /* TOR_TRACE_EVENTS_H */
+#endif /* !defined(TOR_TRACE_EVENTS_H) */
diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am
index 6f10c98744..98098c87f4 100644
--- a/src/lib/trace/include.am
+++ b/src/lib/trace/include.am
@@ -2,6 +2,7 @@
noinst_LIBRARIES += \
src/lib/libtor-trace.a
+# ADD_C_FILE: INSERT HEADERS HERE.
TRACEHEADERS = \
src/lib/trace/trace.h \
src/lib/trace/events.h
@@ -11,7 +12,7 @@ TRACEHEADERS += \
src/lib/trace/debug.h
endif
-# Library source files.
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_trace_a_SOURCES = \
src/lib/trace/trace.c
diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h
index 606d435568..5001b28a1d 100644
--- a/src/lib/trace/trace.h
+++ b/src/lib/trace/trace.h
@@ -11,4 +11,4 @@
void tor_trace_init(void);
-#endif // TOR_TRACE_TRACE_H
+#endif /* !defined(TOR_TRACE_TRACE_H) */
diff --git a/src/lib/version/include.am b/src/lib/version/include.am
index 6944eb05e3..0ae31be1b2 100644
--- a/src/lib/version/include.am
+++ b/src/lib/version/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-version-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_version_a_SOURCES = \
src/lib/version/git_revision.c \
src/lib/version/version.c
@@ -20,6 +21,7 @@ src/lib/version/git_revision.$(OBJEXT) \
src/lib/version/src_lib_libtor_version_testing_a-git_revision.$(OBJEXT): \
micro-revision.i
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/version/git_revision.h \
src/lib/version/torversion.h
diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h
index e6b53f2c27..e7da160122 100644
--- a/src/lib/wallclock/approx_time.h
+++ b/src/lib/wallclock/approx_time.h
@@ -22,4 +22,4 @@ time_t approx_time(void);
void update_approx_time(time_t now);
#endif /* defined(TIME_IS_FAST) */
-#endif
+#endif /* !defined(TOR_APPROX_TIME_H) */
diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am
index 2351252e0c..2b50d6ccbb 100644
--- a/src/lib/wallclock/include.am
+++ b/src/lib/wallclock/include.am
@@ -5,6 +5,7 @@ if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-wallclock-testing.a
endif
+# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_wallclock_a_SOURCES = \
src/lib/wallclock/approx_time.c \
src/lib/wallclock/time_to_tm.c \
@@ -15,6 +16,7 @@ src_lib_libtor_wallclock_testing_a_SOURCES = \
src_lib_libtor_wallclock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/wallclock/approx_time.h \
src/lib/wallclock/timeval.h \
diff --git a/src/lib/wallclock/time_to_tm.h b/src/lib/wallclock/time_to_tm.h
index abe78c0efe..da27fcaba1 100644
--- a/src/lib/wallclock/time_to_tm.h
+++ b/src/lib/wallclock/time_to_tm.h
@@ -19,4 +19,4 @@ struct tm *tor_localtime_r_msg(const time_t *timep, struct tm *result,
struct tm *tor_gmtime_r_msg(const time_t *timep, struct tm *result,
char **err_out);
-#endif
+#endif /* !defined(TOR_WALLCLOCK_TIME_TO_TM_H) */
diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h
index 4967e939bf..e632d04a04 100644
--- a/src/lib/wallclock/timeval.h
+++ b/src/lib/wallclock/timeval.h
@@ -20,6 +20,27 @@
#include <sys/time.h>
#endif
+#ifdef TOR_COVERAGE
+/* For coverage builds, we use a slower definition of these macros without
+ * branches, to make coverage consistent. */
+#undef timeradd
+#undef timersub
+#define timeradd(tv1,tv2,tvout) \
+ do { \
+ (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \
+ (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \
+ (tvout)->tv_sec += (tvout)->tv_usec / 1000000; \
+ (tvout)->tv_usec %= 1000000; \
+ } while (0)
+#define timersub(tv1,tv2,tvout) \
+ do { \
+ (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec - 1; \
+ (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec + 1000000; \
+ (tvout)->tv_sec += (tvout)->tv_usec / 1000000; \
+ (tvout)->tv_usec %= 1000000; \
+ } while (0)
+#endif /* defined(TOR_COVERAGE) */
+
#ifndef timeradd
/** Replacement for timeradd on platforms that do not have it: sets tvout to
* the sum of tv1 and tv2. */
@@ -62,4 +83,4 @@
((tv1)->tv_sec op (tv2)->tv_sec))
#endif /* !defined(timercmp) */
-#endif
+#endif /* !defined(TOR_TIMEVAL_H) */
diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h
index c7fff9747a..6fec2fc893 100644
--- a/src/lib/wallclock/tor_gettimeofday.h
+++ b/src/lib/wallclock/tor_gettimeofday.h
@@ -17,4 +17,4 @@ struct timeval;
MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval));
-#endif
+#endif /* !defined(TOR_GETTIMEOFDAY_H) */