aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/arch/bytes.h21
-rw-r--r--src/lib/arch/lib_arch.md2
-rw-r--r--src/lib/buf/buffers.c3
-rw-r--r--src/lib/buf/lib_buf.md13
-rw-r--r--src/lib/cc/compat_compiler.h12
-rw-r--r--src/lib/cc/ctassert.h2
-rw-r--r--src/lib/cc/include.am1
-rw-r--r--src/lib/cc/lib_cc.md2
-rw-r--r--src/lib/cc/tokpaste.h30
-rw-r--r--src/lib/compress/lib_compress.md6
-rw-r--r--src/lib/conf/confdecl.h221
-rw-r--r--src/lib/conf/config.md126
-rw-r--r--src/lib/conf/confmacros.h7
-rw-r--r--src/lib/conf/conftesting.h15
-rw-r--r--src/lib/conf/conftypes.h183
-rw-r--r--src/lib/conf/include.am1
-rw-r--r--src/lib/conf/lib_conf.md3
-rw-r--r--src/lib/confmgt/.may_include1
-rw-r--r--src/lib/confmgt/confmgt.c (renamed from src/lib/confmgt/confparse.c)189
-rw-r--r--src/lib/confmgt/confmgt.h (renamed from src/lib/confmgt/confparse.h)132
-rw-r--r--src/lib/confmgt/include.am4
-rw-r--r--src/lib/confmgt/lib_confmgt.md7
-rw-r--r--src/lib/confmgt/structvar.c26
-rw-r--r--src/lib/confmgt/type_defs.c144
-rw-r--r--src/lib/confmgt/unitparse.c37
-rw-r--r--src/lib/container/handles.h23
-rw-r--r--src/lib/container/lib_container.md49
-rw-r--r--src/lib/container/map.h59
-rw-r--r--src/lib/container/namemap.c5
-rw-r--r--src/lib/container/namemap_st.h7
-rw-r--r--src/lib/container/smartlist.h2
-rw-r--r--src/lib/crypt_ops/.may_include3
-rw-r--r--src/lib/crypt_ops/aes.h2
-rw-r--r--src/lib/crypt_ops/aes_openssl.c3
-rw-r--r--src/lib/crypt_ops/certs.md30
-rw-r--r--src/lib/crypt_ops/crypto_cipher.h2
-rw-r--r--src/lib/crypt_ops/crypto_digest.c3
-rw-r--r--src/lib/crypt_ops/crypto_digest.h33
-rw-r--r--src/lib/crypt_ops/crypto_digest_nss.c7
-rw-r--r--src/lib/crypt_ops/crypto_digest_openssl.c5
-rw-r--r--src/lib/crypt_ops/crypto_init.c66
-rw-r--r--src/lib/crypt_ops/crypto_ope.c5
-rw-r--r--src/lib/crypt_ops/crypto_ope.h11
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.c38
-rw-r--r--src/lib/crypt_ops/crypto_options.inc19
-rw-r--r--src/lib/crypt_ops/crypto_options_st.h23
-rw-r--r--src/lib/crypt_ops/crypto_rand_fast.c11
-rw-r--r--src/lib/crypt_ops/crypto_s2k.c2
-rw-r--r--src/lib/crypt_ops/crypto_util.c2
-rw-r--r--src/lib/crypt_ops/include.am2
-rw-r--r--src/lib/crypt_ops/lib_crypt_ops.md137
-rw-r--r--src/lib/ctime/di_ops.c3
-rw-r--r--src/lib/ctime/di_ops.h23
-rw-r--r--src/lib/ctime/lib_ctime.md14
-rw-r--r--src/lib/defs/lib_defs.md2
-rw-r--r--src/lib/defs/time.h2
-rw-r--r--src/lib/defs/x25519_sizes.h8
-rw-r--r--src/lib/dispatch/dispatch_cfg.h5
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h12
-rw-r--r--src/lib/dispatch/dispatch_naming.c7
-rw-r--r--src/lib/dispatch/dispatch_naming.h5
-rw-r--r--src/lib/dispatch/lib_dispatch.md14
-rw-r--r--src/lib/encoding/kvline.c52
-rw-r--r--src/lib/encoding/kvline.h1
-rw-r--r--src/lib/encoding/lib_encoding.md6
-rw-r--r--src/lib/err/backtrace.c14
-rw-r--r--src/lib/err/backtrace.h4
-rw-r--r--src/lib/err/lib_err.md13
-rw-r--r--src/lib/evloop/compat_libevent.c12
-rw-r--r--src/lib/evloop/compat_libevent.h9
-rw-r--r--src/lib/evloop/lib_evloop.md7
-rw-r--r--src/lib/evloop/time_periodic.md76
-rw-r--r--src/lib/evloop/timers.c10
-rw-r--r--src/lib/evloop/workqueue.c20
-rw-r--r--src/lib/evloop/workqueue.h6
-rw-r--r--src/lib/fdio/fdio.c7
-rw-r--r--src/lib/fdio/lib_fdio.md5
-rw-r--r--src/lib/fs/lib_fs.md9
-rw-r--r--src/lib/fs/mmap.c16
-rw-r--r--src/lib/fs/mmap.h5
-rw-r--r--src/lib/fs/path.c5
-rw-r--r--src/lib/fs/path.h2
-rw-r--r--src/lib/fs/storagedir.h4
-rw-r--r--src/lib/geoip/country.h6
-rw-r--r--src/lib/geoip/geoip.c16
-rw-r--r--src/lib/geoip/geoip.h1
-rw-r--r--src/lib/geoip/lib_geoip.md3
-rw-r--r--src/lib/intmath/lib_intmath.md2
-rw-r--r--src/lib/intmath/muldiv.c14
-rw-r--r--src/lib/intmath/muldiv.h2
-rw-r--r--src/lib/intmath/weakrng.h3
-rw-r--r--src/lib/lib.md131
-rw-r--r--src/lib/lock/compat_mutex.h5
-rw-r--r--src/lib/lock/compat_mutex_pthreads.c6
-rw-r--r--src/lib/lock/lib_lock.md6
-rw-r--r--src/lib/log/lib_log.md10
-rw-r--r--src/lib/log/log.c31
-rw-r--r--src/lib/log/log.h20
-rw-r--r--src/lib/log/ratelim.h2
-rw-r--r--src/lib/log/util_bug.h15
-rw-r--r--src/lib/malloc/lib_malloc.md76
-rw-r--r--src/lib/malloc/map_anon.c4
-rw-r--r--src/lib/math/lib_math.md6
-rw-r--r--src/lib/math/prob_distr.c152
-rw-r--r--src/lib/math/prob_distr.h100
-rw-r--r--src/lib/memarea/lib_memarea.md28
-rw-r--r--src/lib/memarea/memarea.h3
-rw-r--r--src/lib/meminfo/lib_meminfo.md5
-rw-r--r--src/lib/net/address.c2
-rw-r--r--src/lib/net/inaddr.c4
-rw-r--r--src/lib/net/lib_net.md6
-rw-r--r--src/lib/net/socket.c1
-rw-r--r--src/lib/net/socketpair.c5
-rw-r--r--src/lib/net/socketpair.h5
-rw-r--r--src/lib/net/socks5_status.h10
-rw-r--r--src/lib/osinfo/lib_osinfo.md8
-rw-r--r--src/lib/process/env.c1
-rw-r--r--src/lib/process/lib_process.md2
-rw-r--r--src/lib/process/process.c1
-rw-r--r--src/lib/process/process_unix.c9
-rw-r--r--src/lib/process/process_win32.c18
-rw-r--r--src/lib/process/setuid.c4
-rw-r--r--src/lib/pubsub/lib_pubsub.md14
-rw-r--r--src/lib/pubsub/publish_subscribe.md144
-rw-r--r--src/lib/pubsub/pubsub_build.h5
-rw-r--r--src/lib/pubsub/pubsub_check.c2
-rw-r--r--src/lib/pubsub/pubsub_macros.h8
-rw-r--r--src/lib/pubsub/pubsub_publish.h5
-rw-r--r--src/lib/sandbox/lib_sandbox.md15
-rw-r--r--src/lib/sandbox/sandbox.c43
-rw-r--r--src/lib/sandbox/sandbox.h10
-rw-r--r--src/lib/smartlist_core/lib_smartlist_core.md10
-rw-r--r--src/lib/string/lib_string.md13
-rw-r--r--src/lib/string/parse_int.c5
-rw-r--r--src/lib/string/strings.md102
-rw-r--r--src/lib/subsys/initialization.md75
-rw-r--r--src/lib/subsys/lib_subsys.md32
-rw-r--r--src/lib/subsys/subsys.h120
-rw-r--r--src/lib/term/lib_term.md2
-rw-r--r--src/lib/testsupport/lib_testsupport.md2
-rw-r--r--src/lib/testsupport/testsupport.h53
-rw-r--r--src/lib/thread/lib_thread.md7
-rw-r--r--src/lib/thread/threading.md26
-rw-r--r--src/lib/thread/threads.h4
-rw-r--r--src/lib/time/lib_time.md9
-rw-r--r--src/lib/tls/lib_tls.md11
-rw-r--r--src/lib/tls/tortls.c5
-rw-r--r--src/lib/tls/tortls_internal.h5
-rw-r--r--src/lib/tls/tortls_openssl.c2
-rw-r--r--src/lib/tls/tortls_st.h8
-rw-r--r--src/lib/trace/lib_trace.md6
-rw-r--r--src/lib/version/git_revision.c15
-rw-r--r--src/lib/version/git_revision.h5
-rw-r--r--src/lib/version/lib_version.md2
-rw-r--r--src/lib/version/torversion.h5
-rw-r--r--src/lib/version/version.c9
-rw-r--r--src/lib/wallclock/approx_time.c6
-rw-r--r--src/lib/wallclock/lib_wallclock.md11
-rw-r--r--src/lib/wallclock/timeval.h2
159 files changed, 3054 insertions, 582 deletions
diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h
index 4756ca2beb..245dc94bbe 100644
--- a/src/lib/arch/bytes.h
+++ b/src/lib/arch/bytes.h
@@ -16,12 +16,17 @@
#include <string.h>
#include "lib/cc/torint.h"
-/* The uint8 variants are defined to make the code more uniform. */
+/**
+ * Read an 8-bit from <b>cp</b>.
+ */
static inline uint8_t
get_uint8(const void *cp)
{
return *(const uint8_t*)(cp);
}
+/**
+ * Store an 8-bit value from <b>v</b> to <b>cp</b>.
+ */
static inline void
set_uint8(void *cp, uint8_t v)
{
@@ -93,7 +98,7 @@ set_uint64(void *cp, uint64_t v)
memcpy(cp,&v,8);
}
-#ifdef WORDS_BIGENDIAN
+#if defined(WORDS_BIGENDIAN)
static inline uint16_t
tor_htons(uint32_t a)
{
@@ -130,6 +135,9 @@ tor_ntohll(uint64_t a)
return a;
}
#else /* !defined(WORDS_BIGENDIAN) */
+/**
+ * Convert a 16-bit value from host order to network order (big-endian).
+ **/
static inline uint16_t
tor_htons(uint16_t a)
{
@@ -139,12 +147,18 @@ tor_htons(uint16_t a)
((a & 0xff00) >> 8);
}
+/**
+ * Convert a 16-bit value from network order (big-endian) to host order.
+ **/
static inline uint16_t
tor_ntohs(uint16_t a)
{
return tor_htons(a);
}
+/**
+ * Convert a 32-bit value from host order to network order (big-endian).
+ **/
static inline uint32_t
tor_htonl(uint32_t a)
{
@@ -156,6 +170,9 @@ tor_htonl(uint32_t a)
((a & 0xff000000) >>24);
}
+/**
+ * Convert a 32-bit value from network order (big-endian) to host order.
+ **/
static inline uint32_t
tor_ntohl(uint32_t a)
{
diff --git a/src/lib/arch/lib_arch.md b/src/lib/arch/lib_arch.md
new file mode 100644
index 0000000000..9b8bccdf16
--- /dev/null
+++ b/src/lib/arch/lib_arch.md
@@ -0,0 +1,2 @@
+@dir /lib/arch
+@brief lib/arch: Compatibility code for handling different CPU architectures.
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index 4d026bd37d..4adc08fdbf 100644
--- a/src/lib/buf/buffers.c
+++ b/src/lib/buf/buffers.c
@@ -99,6 +99,7 @@
#define DBG_S(s) (void)0
#endif
+#ifndef COCCI
#ifdef DISABLE_MEMORY_SENTINELS
#define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL
#else
@@ -109,6 +110,7 @@
memset(a,0,SENTINEL_LEN); \
} while (0)
#endif /* defined(DISABLE_MEMORY_SENTINELS) */
+#endif /* !defined(COCCI) */
/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
* to free up space at the end. */
@@ -578,6 +580,7 @@ buf_add_vprintf(buf_t *buf, const char *format, va_list args)
/* XXXX Faster implementations are easy enough, but let's optimize later */
char *tmp;
tor_vasprintf(&tmp, format, args);
+ tor_assert(tmp != NULL);
buf_add(buf, tmp, strlen(tmp));
tor_free(tmp);
}
diff --git a/src/lib/buf/lib_buf.md b/src/lib/buf/lib_buf.md
new file mode 100644
index 0000000000..519ab50a2d
--- /dev/null
+++ b/src/lib/buf/lib_buf.md
@@ -0,0 +1,13 @@
+@dir /lib/buf
+@brief lib/buf: An efficient byte queue.
+
+This module defines the buf_t type, which is used throughout our networking
+code. The implementation is a singly-linked queue of buffer chunks, similar
+to the BSD kernel's
+["mbuf"](https://www.freebsd.org/cgi/man.cgi?query=mbuf&sektion=9) structure.
+
+The buf_t type is also reasonable for use in constructing long strings.
+
+See \refdir{lib/net} for networking code that uses buf_t, and
+\refdir{lib/tls} for cryptographic code that uses buf_t.
+
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index 3ef866ecce..9e7436ca14 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -194,8 +194,8 @@
/** Macro: yield a pointer to the field at position <b>off</b> within the
* structure <b>st</b>. Example:
* <pre>
- * struct a { int foo; int bar; } x;
- * ptrdiff_t bar_offset = offsetof(struct a, bar);
+ * struct a_t { int foo; int bar; } x;
+ * ptrdiff_t bar_offset = offsetof(struct a_t, bar);
* int *bar_p = STRUCT_VAR_P(&x, bar_offset);
* *bar_p = 3;
* </pre>
@@ -205,10 +205,10 @@
/** Macro: yield a pointer to an enclosing structure given a pointer to
* a substructure at offset <b>off</b>. Example:
* <pre>
- * struct base { ... };
- * struct subtype { int x; struct base b; } x;
- * struct base *bp = &x.base;
- * struct *sp = SUBTYPE_P(bp, struct subtype, b);
+ * struct base_t { ... };
+ * struct subtype_t { int x; struct base_t b; } x;
+ * struct base_t *bp = &x.base;
+ * struct *sp = SUBTYPE_P(bp, struct subtype_t, b);
* </pre>
*/
#define SUBTYPE_P(p, subtype, basemember) \
diff --git a/src/lib/cc/ctassert.h b/src/lib/cc/ctassert.h
index bedf0b83a6..d9d3aa40b0 100644
--- a/src/lib/cc/ctassert.h
+++ b/src/lib/cc/ctassert.h
@@ -46,7 +46,7 @@
#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
+ typedef char tor_ctassert_##a##_##b[(x) ? 1 : -1] ATTR_UNUSED; EAT_SEMICOLON
#endif /* __STDC_VERSION__ >= 201112L */
diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am
index 1aa722dd82..d2a415e956 100644
--- a/src/lib/cc/include.am
+++ b/src/lib/cc/include.am
@@ -3,4 +3,5 @@
noinst_HEADERS += \
src/lib/cc/compat_compiler.h \
src/lib/cc/ctassert.h \
+ src/lib/cc/tokpaste.h \
src/lib/cc/torint.h
diff --git a/src/lib/cc/lib_cc.md b/src/lib/cc/lib_cc.md
new file mode 100644
index 0000000000..bd49005ba2
--- /dev/null
+++ b/src/lib/cc/lib_cc.md
@@ -0,0 +1,2 @@
+@dir /lib/cc
+@brief lib/cc: Macros for managing the C compiler and language.
diff --git a/src/lib/cc/tokpaste.h b/src/lib/cc/tokpaste.h
new file mode 100644
index 0000000000..e7ddbffc6a
--- /dev/null
+++ b/src/lib/cc/tokpaste.h
@@ -0,0 +1,30 @@
+/* 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 tokpaste.h
+ * @brief Token-pasting macros.
+ **/
+
+#ifndef TOR_LIB_CC_TOKPASTE_H
+#define TOR_LIB_CC_TOKPASTE_H
+
+/**
+ * Concatenate `a` and `b` in a way that allows their result itself to be
+ * expanded by the preprocessor.
+ *
+ * Ordinarily you could just say `a ## b` in a macro definition. But doing so
+ * results in a symbol which the preprocessor will not then expand. If you
+ * wanted to use `a ## b` to create the name of a macro and have the
+ * preprocessor expand _that_ macro, you need to have another level of
+ * indirection, as this macro provides.
+ **/
+#define PASTE(a,b) PASTE__(a,b)
+
+/** Helper for PASTE(). */
+#define PASTE__(a,b) a ## b
+
+#endif /* !defined(TOR_LIB_CC_TOKPASTE_H) */
diff --git a/src/lib/compress/lib_compress.md b/src/lib/compress/lib_compress.md
new file mode 100644
index 0000000000..c43f223fe7
--- /dev/null
+++ b/src/lib/compress/lib_compress.md
@@ -0,0 +1,6 @@
+@dir /lib/compress
+@brief lib/compress: Wraps several compression libraries
+
+Currently supported are zlib (mandatory), zstd (optional), and lzma
+(optional).
+
diff --git a/src/lib/conf/confdecl.h b/src/lib/conf/confdecl.h
new file mode 100644
index 0000000000..723aea1878
--- /dev/null
+++ b/src/lib/conf/confdecl.h
@@ -0,0 +1,221 @@
+/* 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 confdecl.h
+ * @brief Macros for generating a configuration struct from a list
+ * of its individual fields.
+ *
+ * This header defines three important macros: BEGIN_CONF_STRUCT(),
+ * END_CONF_STRUCT(), and CONF_VAR(). They're meant to be used together to
+ * define a configuration structure and the means for encoding and decoding
+ * it.
+ *
+ * To use them, make a new header with a name like `MOD_options.inc`. Start
+ * it with a BEGIN_CONF_STRUCT(), then define your variables with CONF_VAR(),
+ * then end the header with END_CONF_STRUCT(), as in:
+ *
+ * BEGIN_CONF_STRUCT(module_options_t)
+ * CONF_VAR(ModuleIsActive, BOOLEAN, 0, "1")
+ * END_CONF_STRUCT(module_options_t)
+ *
+ * Once you've done that, you can use that header to define a configuration
+ * structure by saying:
+ *
+ * typedef struct module_options_t module_options_t;
+ * #define CONF_CONTEXT STRUCT
+ * #include "MOD_options.inc"
+ * #undef CONF_CONTEXT
+ *
+ * And you can define your field definition table by saying:
+ *
+ * #define CONF_CONTEXT TABLE
+ * #include "MOD_options.inc"
+ * #undef CONF_CONTEXT
+ *
+ * The two above snippets will define a structure called `module_options_t`
+ * with appropriate members, and a table of config_var_t objects called
+ * `module_options_t_vars[]`.
+ *
+ * For lower-level modules, you can say <tt>\#define CONF_TABLE LL_TABLE</tt>,
+ * and get a table definition suitable for use in modules that are at a lower
+ * level than lib/confmgt. Note that the types for these tables cannot
+ * include any extended types.
+ **/
+
+#ifndef TOR_LIB_CONF_CONFDECL_H
+#define TOR_LIB_CONF_CONFDECL_H
+
+#undef CONF_CONTEXT
+#include "lib/cc/tokpaste.h"
+#include "lib/cc/torint.h"
+
+/**
+ * Begin the definition of a configuration object called `name`.
+ **/
+#define BEGIN_CONF_STRUCT(name) \
+ PASTE(BEGIN_CONF_STRUCT__, CONF_CONTEXT)(name)
+/**
+ * End the definition of a configuration object called `name`.
+ **/
+#define END_CONF_STRUCT(name) \
+ PASTE(END_CONF_STRUCT__, CONF_CONTEXT)(name)
+/**
+ * Declare a single configuration field with name `varname`, type `vartype`,
+ * flags `varflags`, and initial value `initval`.
+ **/
+#define CONF_VAR(varname, vartype, varflags, initval) \
+ PASTE(CONF_VAR__, CONF_CONTEXT)(varname, vartype, varflags, initval)
+
+#ifndef COCCI
+/**
+ * @defgroup STRUCT_MACROS Internal macros: struct definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to STRUCT. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__STRUCT(name) \
+ struct name { \
+ uint32_t magic;
+#define END_CONF_STRUCT__STRUCT(name) \
+ };
+#define CONF_VAR__STRUCT(varname, vartype, varflags, initval) \
+ config_decl_ ## vartype varname;
+/** @} */
+
+/**
+ * @defgroup TABLE_MACROS Internal macros: table definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to TABLE. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__TABLE(structname) \
+ /* We use this typedef so we can refer to the config type */ \
+ /* without having its name as a macro argument to CONF_VAR. */ \
+ typedef struct structname config_var_reference__obj; \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_EXTENDED, \
+ .type_def = &vartype ## _type_defn, \
+ .offset=offsetof(config_var_reference__obj, varname), \
+ }, \
+ .flags = varflags, \
+ .initvalue = initval \
+ },
+/**@}*/
+
+/**
+ * @defgroup LL_TABLE_MACROS Internal macros: low-level table definitions.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to LL_TABLE. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__LL_TABLE(structname) \
+ /* We use this typedef so we can refer to the config type */ \
+ /* without having its name as a macro argument to CONF_VAR. */ \
+ typedef struct structname config_var_reference__obj; \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__LL_TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__LL_TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_ ## vartype, \
+ .offset=offsetof(config_var_reference__obj, varname), \
+ }, \
+ .flags = varflags, \
+ .initvalue = initval \
+ },
+/**@}*/
+
+/* @defgroup STUB_TABLE_MACROS Internal macros: stub table declarations,
+ * for use when a module is disabled.
+ * Implementation helpers: the regular confdecl macros expand to these
+ * when CONF_CONTEXT is defined to LL_TABLE. Don't use them directly.
+ * @{*/
+#define BEGIN_CONF_STRUCT__STUB_TABLE(structname) \
+ static const config_var_t structname##_vars[] = {
+#define END_CONF_STRUCT__STUB_TABLE(structname) \
+ { .member = { .name = NULL } } \
+ };
+#define CONF_VAR__STUB_TABLE(varname, vartype, varflags, initval) \
+ { \
+ .member = \
+ { .name = #varname, \
+ .type = CONFIG_TYPE_IGNORE, \
+ .offset = -1, \
+ }, \
+ .flags = CFLG_GROUP_DISABLED, \
+ },
+/**@}*/
+
+#endif /* !defined(COCCI) */
+
+/** Type aliases for the "commonly used" configuration types.
+ *
+ * Defining them in this way allows our CONF_VAR__STRUCT() macro to declare
+ * structure members corresponding to the configuration types. For example,
+ * when the macro sees us declare a configuration option "foo" of type STRING,
+ * it can emit `config_decl_STRING foo;`, which is an alias for `char *foo`.
+ */
+/**{*/
+typedef char *config_decl_STRING;
+typedef char *config_decl_FILENAME;
+/* Yes, "POSINT" is really an int, and not an unsigned int. For
+ * historical reasons, many configuration values are restricted
+ * to the range [0,INT_MAX], and stored in signed ints.
+ */
+typedef int config_decl_POSINT;
+typedef uint64_t config_decl_UINT64;
+typedef int config_decl_INT;
+typedef int config_decl_INTERVAL;
+typedef int config_decl_MSEC_INTERVAL;
+typedef uint64_t config_decl_MEMUNIT;
+typedef double config_decl_DOUBLE;
+typedef int config_decl_BOOL;
+typedef int config_decl_AUTOBOOL;
+typedef time_t config_decl_ISOTIME;
+typedef struct smartlist_t config_decl_CSV;
+typedef int config_decl_CSV_INTERVAL;
+typedef struct config_line_t *config_decl_LINELIST;
+typedef struct config_line_t *config_decl_LINELIST_V;
+typedef struct nonexistent_struct *config_decl_LINELIST_S;
+/**@}*/
+
+struct var_type_def_t;
+
+/* Forward declarations for configuration type definitions. These are used by
+ * the CONF_VAR__TABLE macro to set the definition of each variable type
+ * correctly.
+ */
+/**@{*/
+extern const struct var_type_def_t STRING_type_defn;
+extern const struct var_type_def_t FILENAME_type_defn;
+extern const struct var_type_def_t POSINT_type_defn;
+extern const struct var_type_def_t UINT64_type_defn;
+extern const struct var_type_def_t INT_type_defn;
+extern const struct var_type_def_t INTERVAL_type_defn;
+extern const struct var_type_def_t MSEC_INTERVAL_type_defn;
+extern const struct var_type_def_t MEMUNIT_type_defn;
+extern const struct var_type_def_t DOUBLE_type_defn;
+extern const struct var_type_def_t BOOL_type_defn;
+extern const struct var_type_def_t AUTOBOOL_type_defn;
+extern const struct var_type_def_t ISOTIME_type_defn;
+extern const struct var_type_def_t CSV_type_defn;
+extern const struct var_type_def_t CSV_INTERVAL_type_defn;
+extern const struct var_type_def_t LINELIST_type_defn;
+extern const struct var_type_def_t LINELIST_V_type_defn;
+extern const struct var_type_def_t LINELIST_S_type_defn;
+extern const struct var_type_def_t IGNORE_type_defn;
+extern const struct var_type_def_t OBSOLETE_type_defn;
+/**@}*/
+
+#endif /* !defined(TOR_LIB_CONF_CONFDECL_H) */
diff --git a/src/lib/conf/config.md b/src/lib/conf/config.md
new file mode 100644
index 0000000000..7741e21f42
--- /dev/null
+++ b/src/lib/conf/config.md
@@ -0,0 +1,126 @@
+
+@page configuration Configuration options and persistent state
+
+@tableofcontents
+
+## Introduction
+
+Tor uses a shared, table-driven mechanism to handle its
+configuration (torrc) files and its state files. Each module can
+declare a set of named fields for these files, and get notified
+whenever the configuration changes, or when the state is about to be
+flushed to disk.
+
+## Declaring options
+
+Most modules will only need to use the macros in confdecl.h to
+declare a configuration or state structure.
+
+You'll write something like this:
+
+ // my_module_config.inc
+ BEGIN_CONF_STRUCT(module_options_t)
+ CONF_VAR(FieldOne, INT, 0, "7")
+ CONF_VAR(FieldTwo, STRING, 0, NULL)
+ END_CONF_STRUCT(module_options_t)
+
+The above example will result in a structure called module_config_t
+with two fields: one an integer called FieldOne and one a string
+called FieldTwo. The integer gets a default value of 7; the
+string's default value is NULL.
+
+After making a definition file like that, you include it twice: once
+in a header, after saying \#define CONF_CONTEXT STRUCT, and once in
+a C file, after saying \#define CONF_CONTEXT TABLE. The first time
+defines a module_options_t structure, and the second time defines a
+table that tells the configuration manager how to use it.
+
+Using the table, you declare a `const` config_format_t, which
+associates the fields with a set of functions for validating and
+normalizing them, a list of abbreviations and deprecations, and
+other features.
+
+See confdecl.h and conftypes.h for more information. For example
+usage, see crypto_options.inc or mainloop_state.inc.
+
+## Getting notifications
+
+After using those macros, you must tell the subsystem management
+code about your module's configuration/state.
+
+If you're writing configuration code, you'll need a function that receives
+the configuration object, and acts upon it. This function needs to be safe
+to call multiple times, since Tor will reconfigure its subsystems whenever it
+re-reads the torrc, gets a configuration change from a controller, or
+restarts in process. This function goes in your subsystem's
+subsys_fns_t.set_options field.
+
+If you're writing state code, you'll need a function that receives
+state (subsys_fns_t.set_state), and a function that flushes the
+application state into a state object (subsys_fns_t.flush_state).
+The `set_state` function will be called once (@ref config_once_per
+"1") when Tor is starting, whereas the `flush_state` function will
+be called whenever Tor is about to save the state to disk.
+
+See subsys_fns_t for more information here, and \ref initialization
+for more information about initialization and subsystems in general.
+
+> @anchor config_once_per 1. Technically, state is set once _per startup_.
+> Remember that Tor can be stopped and started multiple times in
+> the same process. If this happens, then your set_state() function
+> is called once every time Tor starts.
+
+## How it works
+
+The common logic used to handle configuration and state files lives
+in @refdir{lib/confmgt}. At the highest level, a configuration
+manager object (config_mgr_t) maintains a list of each module's
+configuration objects, and a list of all their fields. When the
+user specifies a configuration value, the manager finds out how to
+parse it, where to store it, and which configuration object is
+affected.
+
+The top-level configuration module (config.c) and state module
+(statefile.c) use config_mgr_t to create, initialize, set, compare,
+and free a "top level configuration object". This object contains a
+list of sub-objects: one for each module that participates in the
+configuration/state system. This top-level code then invokes the
+subsystem manager code (subsysmgr.c) to pass the corresponding
+configuration or state objects to each module that has one.
+
+Note that the top level code does not have easy access to the
+configuration objects used by the sub-modules. This is by design. A
+module _may_ expose some or all of its configuration or state object via
+accessor functions, if it likes, but if it does not, that object should
+be considered module-local.
+
+## Adding new types
+
+Configuration and state fields each have a "type". These types
+specify how the fields' values are represented in C; how they are
+stored in files; and how they are encoded back and forth.
+
+There is a set of built-in types listed in conftypes.h, but
+higher-level code can define its own types. To do so, you make an
+instance of var_type_fns_t that describes how to manage your type,
+and an instance of var_type_def_t that wraps your var_type_fns_t
+with a name and optional parameters and flags.
+
+For an example of how a higher-level type is defined, see
+ROUTERSET_type_defn in routerset.c. Also see the typedef
+`config_decl_ROUTERSET`. Together, these let the routerset type be
+used with the macros in confdecl.h.
+
+## Legacy configuration and state
+
+As of this writing (November 2019), most of the configuration and state is
+still handled directly in config.c and statefile.c, and stored in the
+monolithic structures or_options_t and or_state_t respectively.
+
+These top-level structures are accessed with get_options() and
+get_state(), and used throughout much of the code, at the level of
+@refdir{core} and higher.
+
+With time we hope to refactor this configuration into more
+reasonable pieces, so that they are no longer (effectively) global
+variables used throughout the code.
diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h
index 68121891f1..10de1fbcee 100644
--- a/src/lib/conf/confmacros.h
+++ b/src/lib/conf/confmacros.h
@@ -15,11 +15,13 @@
#include "orconfig.h"
#include "lib/conf/conftesting.h"
+#ifndef COCCI
/**
* Used to indicate the end of an array of configuration variables.
**/
#define END_OF_CONFIG_VARS \
{ .member = { .name = NULL } DUMMY_CONF_TEST_MEMBERS }
+#endif /* !defined(COCCI) */
/**
* Declare a config_var_t as a member named <b>membername</b> of the structure
@@ -43,7 +45,7 @@
}
/**
- * As CONFIG_VAR_XTYPE, but declares a value using an extension type whose
+ * As CONFIG_VAR_ETYPE, but declares a value using an extension type whose
* type definition is <b>vartype</b>_type_defn.
**/
#define CONFIG_VAR_DEFN(structtype, varname, vartype, membername, \
@@ -59,6 +61,9 @@
CONF_TEST_MEMBERS(structtype, vartype, membername) \
}
+/**
+ * Declare an obsolete configuration variable with a given name.
+ **/
#define CONFIG_VAR_OBSOLETE(varname) \
{ .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE }, \
.flags = CFLG_GROUP_OBSOLETE \
diff --git a/src/lib/conf/conftesting.h b/src/lib/conf/conftesting.h
index f01f52d59e..7e12fe76db 100644
--- a/src/lib/conf/conftesting.h
+++ b/src/lib/conf/conftesting.h
@@ -12,10 +12,12 @@
#ifndef TOR_LIB_CONF_CONFTESTING_H
#define TOR_LIB_CONF_CONFTESTING_H
+#ifndef COCCI
#ifdef TOR_UNIT_TESTS
+#define USE_CONF_TESTING
/**
* Union used when building in test mode typechecking the members of a type
- * used with confparse.c. See CONF_CHECK_VAR_TYPE for a description of how
+ * used with confmgt.c. See CONF_CHECK_VAR_TYPE for a description of how
* it is used. */
typedef union {
char **STRING;
@@ -41,13 +43,11 @@ typedef union {
// XXXX this doesn't belong at this level of abstraction.
struct routerset_t **ROUTERSET;
} confparse_dummy_values_t;
-#endif /* defined(TOR_UNIT_TESTS) */
/* Macros to define extra members inside config_var_t fields, and at the
* end of a list of them.
*/
-#ifdef TOR_UNIT_TESTS
-/* This is a somewhat magic type-checking macro for users of confparse.c.
+/* This is a somewhat magic type-checking macro for users of confmgt.c.
* It initializes a union member "confparse_dummy_values_t.conftype" with
* the address of a static member "tp_dummy.member". This
* will give a compiler warning unless the member field is of the correct
@@ -72,15 +72,16 @@ typedef union {
#define DUMMY_CONF_TEST_MEMBERS , .var_ptr_dummy={ .INT=NULL }
#define DUMMY_TYPECHECK_INSTANCE(tp) \
static tp tp ## _dummy
+#endif /* defined(TOR_UNIT_TESTS) */
+#endif /* !defined(COCCI) */
-#else /* !defined(TOR_UNIT_TESTS) */
-
+#ifndef USE_CONF_TESTING
#define CONF_TEST_MEMBERS(tp, conftype, member)
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
#define DUMMY_TYPECHECK_INSTANCE(tp) \
struct tor_semicolon_eater
#define DUMMY_CONF_TEST_MEMBERS
-#endif /* defined(TOR_UNIT_TESTS) */
+#endif /* !defined(USE_CONF_TESTING) */
#endif /* !defined(TOR_LIB_CONF_CONFTESTING_H) */
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index 274065cff2..52f9fceb20 100644
--- a/src/lib/conf/conftypes.h
+++ b/src/lib/conf/conftypes.h
@@ -64,7 +64,18 @@ typedef enum config_type_t {
CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
* context-sensitive config lines when fetching.
*/
- CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
+ /** Ignored (obsolete) option. Uses no storage.
+ *
+ * Reported as "obsolete" when its type is queried.
+ */
+ CONFIG_TYPE_OBSOLETE,
+ /** Ignored option. Uses no storage.
+ *
+ * Reported as "ignored" when its type is queried. For use with options used
+ * by disabled modules.
+ **/
+ CONFIG_TYPE_IGNORE,
+
/**
* Extended type: definition appears in the <b>type_def</b> pointer
* of the corresponding struct_member_t.
@@ -120,6 +131,9 @@ typedef struct struct_member_t {
*
* These 'magic numbers' are 32-bit values used to tag objects to make sure
* that they have the correct type.
+ *
+ * If all fields in this structure are zero or 0, the magic-number check is
+ * not performed.
*/
typedef struct struct_magic_decl_t {
/** The name of the structure */
@@ -178,12 +192,35 @@ typedef struct struct_magic_decl_t {
* however, setting them appends to their old value.
*/
#define CFLG_NOREPLACE (1u<<5)
+/**
+ * Flag to indicate that an option or type cannot be changed while Tor is
+ * running.
+ **/
+#define CFLG_IMMUTABLE (1u<<6)
+/**
+ * Flag to indicate that we should warn that an option or type is obsolete
+ * whenever the user tries to use it.
+ **/
+#define CFLG_WARN_OBSOLETE (1u<<7)
+/**
+ * Flag to indicate that we should warn that an option applies only to
+ * a disabled module, whenever the user tries to use it.
+ **/
+#define CFLG_WARN_DISABLED (1u<<8)
/**
* A group of flags that should be set on all obsolete options and types.
**/
#define CFLG_GROUP_OBSOLETE \
- (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST)
+ (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST|\
+ CFLG_WARN_OBSOLETE)
+
+/**
+ * A group of fflags that should be set on all disabled options.
+ **/
+#define CFLG_GROUP_DISABLED \
+ (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST|\
+ CFLG_WARN_DISABLED)
/** A variable allowed in the configuration file or on the command line. */
typedef struct config_var_t {
@@ -199,4 +236,146 @@ typedef struct config_var_t {
#endif
} config_var_t;
+/**
+ * An abbreviation or alias for a configuration option.
+ **/
+typedef struct config_abbrev_t {
+ /** The option name as abbreviated. Not case-sensitive. */
+ const char *abbreviated;
+ /** The full name of the option. Not case-sensitive. */
+ const char *full;
+ /** True if this abbreviation should only be allowed on the command line. */
+ int commandline_only;
+ /** True if we should warn whenever this abbreviation is used. */
+ int warn;
+} config_abbrev_t;
+
+/**
+ * A note that a configuration option is deprecated, with an explanation why.
+ */
+typedef struct config_deprecation_t {
+ /** The option that is deprecated. */
+ const char *name;
+ /** A user-facing string explaining why the option is deprecated. */
+ const char *why_deprecated;
+} config_deprecation_t;
+
+/**
+ * Handy macro for declaring "In the config file or on the command line, you
+ * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
+ * config_abbrev_t.
+ *
+ * For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
+ * you can say PLURAL(NumCpu).
+ **/
+#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
+
+/**
+ * Validation function: verify whether a configuation object is well-formed
+ * and consistent.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*validate_fn_t)(const void *value, char **msg_out);
+/**
+ * Validation function: verify whether a configuration object (`value`) is an
+ * allowable value given the previous configuration value (`old_value`).
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*check_transition_fn_t)(const void *old_value, const void *value,
+ char **msg_out);
+/**
+ * Validation function: normalize members of `value`, and compute derived
+ * members.
+ *
+ * This function is called before any other validation of `value`, and must
+ * not assume that validate_fn or check_transition_fn has passed.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*pre_normalize_fn_t)(void *value, char **msg_out);
+/**
+ * Validation function: normalize members of `value`, and compute derived
+ * members.
+ *
+ * This function is called after validation of `value`, and may
+ * assume that validate_fn or check_transition_fn has passed.
+ *
+ * On success, return 0. On failure, set <b>msg_out</b> to a newly allocated
+ * string containing an error message, and return -1. */
+typedef int (*post_normalize_fn_t)(void *value, char **msg_out);
+
+/**
+ * Legacy function to validate whether a given configuration is
+ * well-formed and consistent.
+ *
+ * The configuration to validate is passed as <b>newval</b>. The previous
+ * configuration, if any, is provided in <b>oldval</b>.
+ *
+ * This API is deprecated, since it mixes the responsibilities of
+ * pre_normalize_fn_t, post_normalize_fn_t, validate_fn_t, and
+ * check_transition_fn_t. No new instances of this function type should
+ * be written.
+ *
+ * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated
+ * error message, and return -1.
+ */
+typedef int (*legacy_validate_fn_t)(const void *oldval,
+ void *newval,
+ char **msg_out);
+
+struct config_mgr_t;
+
+/**
+ * Callback to clear all non-managed fields of a configuration object.
+ *
+ * <b>obj</b> is the configuration object whose non-managed fields should be
+ * cleared.
+ *
+ * (Regular fields get cleared by config_reset(), but you might have fields
+ * in the object that do not correspond to configuration variables. If those
+ * fields need to be cleared or freed, this is where to do it.)
+ */
+typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);
+
+/** Information on the keys, value types, key-to-struct-member mappings,
+ * variable descriptions, validation functions, and abbreviations for a
+ * configuration or storage format. */
+typedef struct config_format_t {
+ size_t size; /**< Size of the struct that everything gets parsed into. */
+ struct_magic_decl_t magic; /**< Magic number info for this struct. */
+ const config_abbrev_t *abbrevs; /**< List of abbreviations that we expand
+ * when parsing this format. */
+ const config_deprecation_t *deprecations; /** List of deprecated options */
+ const config_var_t *vars; /**< List of variables we recognize, their default
+ * values, and where we stick them in the
+ * structure. */
+
+ /** Early-stage normalization callback. Invoked by config_validate(). */
+ pre_normalize_fn_t pre_normalize_fn;
+ /** Configuration validation function. Invoked by config_validate(). */
+ validate_fn_t validate_fn;
+ /** Legacy validation function. Invoked by config_validate(). */
+ legacy_validate_fn_t legacy_validate_fn;
+ /** Transition checking function. Invoked by config_validate(). */
+ check_transition_fn_t check_transition_fn;
+ /** Late-stage normalization callback. Invoked by config_validate(). */
+ post_normalize_fn_t post_normalize_fn;
+
+ clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
+ /** If present, extra denotes a LINELIST variable for unrecognized
+ * lines. Otherwise, unrecognized lines are an error. */
+ const struct_member_t *extra;
+ /**
+ * If true, this format describes a top-level configuration, with
+ * a suite containing multiple sub-configuration objects.
+ */
+ bool has_config_suite;
+ /** The position of a config_suite_t pointer within the toplevel object.
+ * Ignored unless have_config_suite is true.
+ */
+ ptrdiff_t config_suite_offset;
+} config_format_t;
+
#endif /* !defined(TOR_SRC_LIB_CONF_CONFTYPES_H) */
diff --git a/src/lib/conf/include.am b/src/lib/conf/include.am
index cb7126184d..cb0b83fa64 100644
--- a/src/lib/conf/include.am
+++ b/src/lib/conf/include.am
@@ -1,6 +1,7 @@
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
+ src/lib/conf/confdecl.h \
src/lib/conf/conftesting.h \
src/lib/conf/conftypes.h \
src/lib/conf/confmacros.h
diff --git a/src/lib/conf/lib_conf.md b/src/lib/conf/lib_conf.md
new file mode 100644
index 0000000000..60dd04e99e
--- /dev/null
+++ b/src/lib/conf/lib_conf.md
@@ -0,0 +1,3 @@
+@dir /lib/conf
+@brief lib/conf: Types and macros for declaring configuration options.
+
diff --git a/src/lib/confmgt/.may_include b/src/lib/confmgt/.may_include
index 2564133917..5ff949f103 100644
--- a/src/lib/confmgt/.may_include
+++ b/src/lib/confmgt/.may_include
@@ -4,6 +4,7 @@ lib/conf/*.h
lib/confmgt/*.h
lib/container/*.h
lib/encoding/*.h
+lib/intmath/*.h
lib/log/*.h
lib/malloc/*.h
lib/string/*.h
diff --git a/src/lib/confmgt/confparse.c b/src/lib/confmgt/confmgt.c
index 08e562f654..eaa4468d55 100644
--- a/src/lib/confmgt/confparse.c
+++ b/src/lib/confmgt/confmgt.c
@@ -5,7 +5,7 @@
/* See LICENSE for licensing information */
/**
- * \file confparse.c
+ * \file confmgt.c
*
* \brief Back-end for parsing and generating key-value files, used to
* implement the torrc file format and the state file.
@@ -21,9 +21,9 @@
* specified, and a linked list of key-value pairs.
*/
-#define CONFPARSE_PRIVATE
+#define CONFMGT_PRIVATE
#include "orconfig.h"
-#include "lib/confmgt/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/confmgt/structvar.h"
#include "lib/confmgt/unitparse.h"
@@ -169,9 +169,14 @@ config_mgr_register_fmt(config_mgr_t *mgr,
"it had been frozen.");
if (object_idx != IDX_TOPLEVEL) {
- tor_assertf(fmt->config_suite_offset < 0,
+ tor_assertf(! fmt->has_config_suite,
"Tried to register a toplevel format in a non-toplevel position");
}
+ if (fmt->config_suite_offset) {
+ tor_assertf(fmt->has_config_suite,
+ "config_suite_offset was set, but has_config_suite was not.");
+ }
+
tor_assertf(fmt != mgr->toplevel &&
! smartlist_contains(mgr->subconfigs, fmt),
"Tried to register an already-registered format.");
@@ -223,7 +228,7 @@ config_mgr_add_format(config_mgr_t *mgr,
static inline config_suite_t **
config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
{
- if (mgr->toplevel->config_suite_offset < 0)
+ if (! mgr->toplevel->has_config_suite)
return NULL;
return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
}
@@ -237,7 +242,7 @@ config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
* to configuration objects for other modules. This function gets
* the sub-object for a particular module.
*/
-STATIC void *
+void *
config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
{
tor_assert(mgr);
@@ -256,7 +261,7 @@ config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
}
/** As config_mgr_get_obj_mutable(), but return a const pointer. */
-STATIC const void *
+const void *
config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
{
return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
@@ -334,6 +339,17 @@ config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
return result;
}
+/**
+ * Check the magic number on <b>object</b> to make sure it's a valid toplevel
+ * object, created with <b>mgr</b>. Exit with an assertion if it isn't.
+ **/
+void
+config_check_toplevel_magic(const config_mgr_t *mgr,
+ const void *object)
+{
+ struct_check_magic(object, &mgr->toplevel_magic);
+}
+
/** Assert that the magic fields in <b>options</b> and its subsidiary
* objects are all okay. */
static void
@@ -641,6 +657,14 @@ config_assign_value(const config_mgr_t *mgr, void *options,
tor_assert(!strcmp(c->key, var->cvar->member.name));
void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
+ if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) {
+ log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".",
+ var->cvar->member.name);
+ } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) {
+ log_warn(LD_GENERAL, "This copy of Tor was built without support for "
+ "the option \"%s\". Skipping.", var->cvar->member.name);
+ }
+
return struct_var_kvassign(object, c, msg, &var->cvar->member);
}
@@ -1142,6 +1166,146 @@ config_init(const config_mgr_t *mgr, void *options)
} SMARTLIST_FOREACH_END(mv);
}
+/**
+ * Helper for config_validate_single: see whether any immutable option
+ * has changed between old_options and new_options.
+ *
+ * On success return 0; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return -1.
+ */
+static int
+config_check_immutable_flags(const config_format_t *fmt,
+ const void *old_options,
+ const void *new_options,
+ char **msg_out)
+{
+ tor_assert(fmt);
+ tor_assert(new_options);
+ if (BUG(! old_options))
+ return 0;
+
+ unsigned i;
+ for (i = 0; fmt->vars[i].member.name; ++i) {
+ const config_var_t *v = &fmt->vars[i];
+ if (! config_var_has_flag(v, CFLG_IMMUTABLE))
+ continue;
+
+ if (! struct_var_eq(old_options, new_options, &v->member)) {
+ tor_asprintf(msg_out,
+ "While Tor is running, changing %s is not allowed",
+ v->member.name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Normalize and validate a single object `options` within a configuration
+ * suite, according to its format. `options` may be modified as appropriate
+ * in order to set ancillary data. If `old_options` is provided, make sure
+ * that the transition from `old_options` to `options` is permitted.
+ *
+ * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return a different validation_status_t
+ * to describe which step failed.
+ **/
+static validation_status_t
+config_validate_single(const config_format_t *fmt,
+ const void *old_options, void *options,
+ char **msg_out)
+{
+ tor_assert(fmt);
+ tor_assert(options);
+
+ if (fmt->pre_normalize_fn) {
+ if (fmt->pre_normalize_fn(options, msg_out) < 0) {
+ return VSTAT_PRE_NORMALIZE_ERR;
+ }
+ }
+
+ if (fmt->legacy_validate_fn) {
+ if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) {
+ return VSTAT_LEGACY_ERR;
+ }
+ }
+
+ if (fmt->validate_fn) {
+ if (fmt->validate_fn(options, msg_out) < 0) {
+ return VSTAT_VALIDATE_ERR;
+ }
+ }
+
+ if (old_options) {
+ if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) {
+ return VSTAT_TRANSITION_ERR;
+ }
+
+ if (fmt->check_transition_fn) {
+ if (fmt->check_transition_fn(old_options, options, msg_out) < 0) {
+ return VSTAT_TRANSITION_ERR;
+ }
+ }
+ }
+
+ if (fmt->post_normalize_fn) {
+ if (fmt->post_normalize_fn(options, msg_out) < 0) {
+ return VSTAT_POST_NORMALIZE_ERR;
+ }
+ }
+
+ return VSTAT_OK;
+}
+
+/**
+ * Normalize and validate all the options in configuration object `options`
+ * and its sub-objects. `options` may be modified as appropriate in order to
+ * set ancillary data. If `old_options` is provided, make sure that the
+ * transition from `old_options` to `options` is permitted.
+ *
+ * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
+ * string explaining what is wrong, and return a different validation_status_t
+ * to describe which step failed.
+ **/
+validation_status_t
+config_validate(const config_mgr_t *mgr,
+ const void *old_options, void *options,
+ char **msg_out)
+{
+ validation_status_t rv;
+ CONFIG_CHECK(mgr, options);
+ if (old_options) {
+ CONFIG_CHECK(mgr, old_options);
+ }
+
+ config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options);
+ config_suite_t **suitep_old = NULL;
+ if (old_options)
+ suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options);
+
+ /* Validate the sub-objects */
+ if (suitep_new) {
+ SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
+ void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx);
+ const void *obj_old=NULL;
+ if (suitep_old)
+ obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx);
+
+ rv = config_validate_single(fmt, obj_old, obj, msg_out);
+ if (rv < 0)
+ return rv;
+ } SMARTLIST_FOREACH_END(fmt);
+ }
+
+ /* Validate the top-level object. */
+ rv = config_validate_single(mgr->toplevel, old_options, options, msg_out);
+ if (rv < 0)
+ return rv;
+
+ return VSTAT_OK;
+}
+
/** Allocate and return a new string holding the written-out values of the vars
* in 'options'. If 'minimal', do not write out any default-valued vars.
* Else, if comment_defaults, write default values as comments.
@@ -1166,7 +1330,7 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
/* XXX use a 1 here so we don't add a new log line while dumping */
if (default_options == NULL) {
- if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
+ if (config_validate(mgr, NULL, defaults_tmp, &msg) < 0) {
// LCOV_EXCL_START
log_err(LD_BUG, "Failed to validate default config: %s", msg);
tor_free(msg);
@@ -1197,9 +1361,10 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
*/
continue;
}
- smartlist_add_asprintf(elements, "%s%s %s\n",
+ int value_exists = line->value && *(line->value);
+ smartlist_add_asprintf(elements, "%s%s%s%s\n",
comment_option ? "# " : "",
- line->key, line->value);
+ line->key, value_exists ? " " : "", line->value);
}
config_free_lines(assigned);
} SMARTLIST_FOREACH_END(mv);
@@ -1207,7 +1372,9 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
if (fmt->extra) {
line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
+ int value_exists = line->value && *(line->value);
+ smartlist_add_asprintf(elements, "%s%s%s\n",
+ line->key, value_exists ? " " : "", line->value);
}
}
diff --git a/src/lib/confmgt/confparse.h b/src/lib/confmgt/confmgt.h
index 2332f69790..11f0de03a1 100644
--- a/src/lib/confmgt/confparse.h
+++ b/src/lib/confmgt/confmgt.h
@@ -5,112 +5,19 @@
/* See LICENSE for licensing information */
/**
- * \file confparse.h
+ * \file confmgt.h
*
- * \brief Header for confparse.c.
+ * \brief Header for confmgt.c.
*/
-#ifndef TOR_CONFPARSE_H
-#define TOR_CONFPARSE_H
+#ifndef TOR_CONFMGT_H
+#define TOR_CONFMGT_H
#include "lib/conf/conftypes.h"
#include "lib/conf/confmacros.h"
#include "lib/testsupport/testsupport.h"
/**
- * An abbreviation or alias for a configuration option.
- **/
-typedef struct config_abbrev_t {
- /** The option name as abbreviated. Not case-sensitive. */
- const char *abbreviated;
- /** The full name of the option. Not case-sensitive. */
- const char *full;
- /** True if this abbreviation should only be allowed on the command line. */
- int commandline_only;
- /** True if we should warn whenever this abbreviation is used. */
- int warn;
-} config_abbrev_t;
-
-/**
- * A note that a configuration option is deprecated, with an explanation why.
- */
-typedef struct config_deprecation_t {
- /** The option that is deprecated. */
- const char *name;
- /** A user-facing string explaining why the option is deprecated. */
- const char *why_deprecated;
-} config_deprecation_t;
-
-/**
- * Handy macro for declaring "In the config file or on the command line, you
- * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
- * config_abbrev_t.
- *
- * For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
- * you can say PLURAL(NumCpu).
- **/
-#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
-
-/**
- * Type of a callback to validate whether a given configuration is
- * well-formed and consistent.
- *
- * The configuration to validate is passed as <b>newval</b>. The previous
- * configuration, if any, is provided in <b>oldval</b>. The
- * <b>default_val</b> argument receives a configuration object initialized
- * with default values for all its fields. The <b>from_setconf</b> argument
- * is true iff the input comes from a SETCONF controller command.
- *
- * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated
- * error message, and return -1.
- *
- * REFACTORING NOTE: Currently, this callback type is only used from inside
- * config_dump(); later in our refactoring, it will be cleaned up and used
- * more generally.
- */
-typedef int (*validate_fn_t)(void *oldval,
- void *newval,
- void *default_val,
- int from_setconf,
- char **msg_out);
-
-struct config_mgr_t;
-
-/**
- * Callback to clear all non-managed fields of a configuration object.
- *
- * <b>obj</b> is the configuration object whose non-managed fields should be
- * cleared.
- *
- * (Regular fields get cleared by config_reset(), but you might have fields
- * in the object that do not correspond to configuration variables. If those
- * fields need to be cleared or freed, this is where to do it.)
- */
-typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);
-
-/** Information on the keys, value types, key-to-struct-member mappings,
- * variable descriptions, validation functions, and abbreviations for a
- * configuration or storage format. */
-typedef struct config_format_t {
- size_t size; /**< Size of the struct that everything gets parsed into. */
- struct_magic_decl_t magic; /**< Magic number info for this struct. */
- const config_abbrev_t *abbrevs; /**< List of abbreviations that we expand
- * when parsing this format. */
- const config_deprecation_t *deprecations; /** List of deprecated options */
- const config_var_t *vars; /**< List of variables we recognize, their default
- * values, and where we stick them in the
- * structure. */
- validate_fn_t validate_fn; /**< Function to validate config. */
- clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
- /** If present, extra denotes a LINELIST variable for unrecognized
- * lines. Otherwise, unrecognized lines are an error. */
- const struct_member_t *extra;
- /** The position of a config_suite_t pointer within the toplevel object,
- * or -1 if there is no such pointer. */
- ptrdiff_t config_suite_offset;
-} config_format_t;
-
-/**
* A collection of config_format_t objects to describe several objects
* that are all configured with the same configuration file.
*
@@ -171,10 +78,26 @@ int config_is_same(const config_mgr_t *fmt,
struct config_line_t *config_get_changes(const config_mgr_t *mgr,
const void *options1, const void *options2);
void config_init(const config_mgr_t *mgr, void *options);
+
+/** An enumeration to report which validation step failed. */
+typedef enum {
+ VSTAT_PRE_NORMALIZE_ERR = -5,
+ VSTAT_VALIDATE_ERR = -4,
+ VSTAT_LEGACY_ERR = -3,
+ VSTAT_TRANSITION_ERR = -2,
+ VSTAT_POST_NORMALIZE_ERR = -1,
+ VSTAT_OK = 0,
+} validation_status_t;
+
+validation_status_t config_validate(const config_mgr_t *mgr,
+ const void *old_options, void *options,
+ char **msg_out);
void *config_dup(const config_mgr_t *mgr, const void *old);
char *config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults);
+void config_check_toplevel_magic(const config_mgr_t *mgr,
+ const void *object);
bool config_check_ok(const config_mgr_t *mgr, const void *options,
int severity);
int config_assign(const config_mgr_t *mgr, void *options,
@@ -200,13 +123,14 @@ bool config_var_is_listable(const config_var_t *var);
#define CFG_EQ_LINELIST(a,b,opt) config_lines_eq((a)->opt, (b)->opt)
#define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)
-#ifdef CONFPARSE_PRIVATE
+void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
+ void *toplevel, int idx);
+const void *config_mgr_get_obj(const config_mgr_t *mgr,
+ const void *toplevel, int idx);
+
+#ifdef CONFMGT_PRIVATE
STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults);
-STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
- void *toplevel, int idx);
-STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr,
- const void *toplevel, int idx);
-#endif /* defined(CONFPARSE_PRIVATE) */
+#endif /* defined(CONFMGT_PRIVATE) */
-#endif /* !defined(TOR_CONFPARSE_H) */
+#endif /* !defined(TOR_CONFMGT_H) */
diff --git a/src/lib/confmgt/include.am b/src/lib/confmgt/include.am
index 81cd868e5e..d3a7a7cd69 100644
--- a/src/lib/confmgt/include.am
+++ b/src/lib/confmgt/include.am
@@ -6,7 +6,7 @@ endif
# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_confmgt_a_SOURCES = \
- src/lib/confmgt/confparse.c \
+ src/lib/confmgt/confmgt.c \
src/lib/confmgt/structvar.c \
src/lib/confmgt/type_defs.c \
src/lib/confmgt/typedvar.c \
@@ -19,7 +19,7 @@ src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
- src/lib/confmgt/confparse.h \
+ src/lib/confmgt/confmgt.h \
src/lib/confmgt/structvar.h \
src/lib/confmgt/type_defs.h \
src/lib/confmgt/typedvar.h \
diff --git a/src/lib/confmgt/lib_confmgt.md b/src/lib/confmgt/lib_confmgt.md
new file mode 100644
index 0000000000..861e720f64
--- /dev/null
+++ b/src/lib/confmgt/lib_confmgt.md
@@ -0,0 +1,7 @@
+@dir /lib/confmgt
+@brief lib/confmgt: Parse, encode, manipulate configuration files.
+
+This logic is used in common by our state files (statefile.c) and
+configuration files (config.c) to manage a set of named, typed fields,
+reading and writing them to disk and to the controller.
+
diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c
index de678d18c8..ce8e426cda 100644
--- a/src/lib/confmgt/structvar.c
+++ b/src/lib/confmgt/structvar.c
@@ -30,13 +30,28 @@
#include <stddef.h>
/**
+ * Return true iff all fields on <b>decl</b> are NULL or 0, indicating that
+ * there is no object or no magic number to check.
+ **/
+static inline bool
+magic_is_null(const struct_magic_decl_t *decl)
+{
+ return decl->typename == NULL &&
+ decl->magic_offset == 0 &&
+ decl->magic_val == 0;
+}
+
+/**
* Set the 'magic number' on <b>object</b> to correspond to decl.
**/
void
struct_set_magic(void *object, const struct_magic_decl_t *decl)
{
- tor_assert(object);
tor_assert(decl);
+ if (magic_is_null(decl))
+ return;
+
+ tor_assert(object);
uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
*ptr = decl->magic_val;
}
@@ -47,14 +62,17 @@ struct_set_magic(void *object, const struct_magic_decl_t *decl)
void
struct_check_magic(const void *object, const struct_magic_decl_t *decl)
{
- tor_assert(object);
tor_assert(decl);
+ if (magic_is_null(decl))
+ return;
+
+ tor_assert(object);
const uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
tor_assertf(*ptr == decl->magic_val,
"Bad magic number on purported %s object. "
- "Expected %"PRIu32"x but got "PRIu32"x.",
- decl->magic_val, *ptr);
+ "Expected %"PRIu32"x but got %"PRIu32"x.",
+ decl->typename, decl->magic_val, *ptr);
}
/**
diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c
index ed930fb02a..00932511ab 100644
--- a/src/lib/confmgt/type_defs.c
+++ b/src/lib/confmgt/type_defs.c
@@ -17,12 +17,12 @@
#include "orconfig.h"
#include "lib/conf/conftypes.h"
+#include "lib/conf/confdecl.h"
#include "lib/confmgt/typedvar.h"
#include "lib/confmgt/type_defs.h"
#include "lib/confmgt/unitparse.h"
#include "lib/cc/compat_compiler.h"
-#include "lib/conf/conftypes.h"
#include "lib/container/smartlist.h"
#include "lib/encoding/confline.h"
#include "lib/encoding/time_fmt.h"
@@ -90,9 +90,12 @@ static const var_type_fns_t string_fns = {
// These types are implemented as int, possibly with a restricted range.
/////
+/**
+ * Parameters for parsing an integer type.
+ **/
typedef struct int_type_params_t {
- int minval;
- int maxval;
+ int minval; /**< Lowest allowed value */
+ int maxval; /**< Highest allowed value */
} int_parse_params_t;
static const int_parse_params_t INT_PARSE_UNRESTRICTED = {
@@ -678,17 +681,13 @@ static const var_type_fns_t linelist_s_fns = {
/////
// CONFIG_TYPE_ROUTERSET
//
-// XXXX This type is not implemented here, since routerset_t is not available
// XXXX to this module.
/////
/////
-// CONFIG_TYPE_OBSOLETE
-//
-// Used to indicate an obsolete option.
+// CONFIG_TYPE_IGNORE
//
-// XXXX This is not a type, and should be handled at a higher level of
-// XXXX abstraction.
+// Used to indicate an option that cannot be stored or encoded.
/////
static int
@@ -699,8 +698,6 @@ ignore_parse(void *target, const char *value, char **errmsg,
(void)value;
(void)errmsg;
(void)params;
- // XXXX move this to a higher level, once such a level exists.
- log_warn(LD_GENERAL, "Skipping obsolete configuration option.");
return 0;
}
@@ -717,50 +714,91 @@ static const var_type_fns_t ignore_fns = {
.encode = ignore_encode,
};
+const var_type_def_t STRING_type_defn = {
+ .name="String", .fns=&string_fns };
+const var_type_def_t FILENAME_type_defn = {
+ .name="Filename", .fns=&string_fns };
+const var_type_def_t INT_type_defn = {
+ .name="SignedInteger", .fns=&int_fns,
+ .params=&INT_PARSE_UNRESTRICTED };
+const var_type_def_t POSINT_type_defn = {
+ .name="Integer", .fns=&int_fns,
+ .params=&INT_PARSE_POSINT };
+const var_type_def_t UINT64_type_defn = {
+ .name="Integer", .fns=&uint64_fns, };
+const var_type_def_t MEMUNIT_type_defn = {
+ .name="DataSize", .fns=&memunit_fns,
+ .params=&memory_units };
+const var_type_def_t INTERVAL_type_defn = {
+ .name="TimeInterval", .fns=&interval_fns,
+ .params=&time_units };
+const var_type_def_t MSEC_INTERVAL_type_defn = {
+ .name="TimeMsecInterval",
+ .fns=&interval_fns,
+ .params=&time_msec_units };
+const var_type_def_t DOUBLE_type_defn = {
+ .name="Float", .fns=&double_fns, };
+const var_type_def_t BOOL_type_defn = {
+ .name="Boolean", .fns=&enum_fns,
+ .params=&enum_table_bool };
+const var_type_def_t AUTOBOOL_type_defn = {
+ .name="Boolean+Auto", .fns=&enum_fns,
+ .params=&enum_table_autobool };
+const var_type_def_t ISOTIME_type_defn = {
+ .name="Time", .fns=&time_fns, };
+const var_type_def_t CSV_type_defn = {
+ .name="CommaList", .fns=&csv_fns, };
+const var_type_def_t CSV_INTERVAL_type_defn = {
+ .name="TimeInterval",
+ .fns=&legacy_csv_interval_fns, };
+const var_type_def_t LINELIST_type_defn = {
+ .name="LineList", .fns=&linelist_fns,
+ .flags=CFLG_NOREPLACE };
+/*
+ * A "linelist_s" is a derived view of a linelist_v: inspecting
+ * it gets part of a linelist_v, and setting it adds to the linelist_v.
+ */
+const var_type_def_t LINELIST_S_type_defn = {
+ .name="Dependent", .fns=&linelist_s_fns,
+ .flags=CFLG_NOREPLACE|
+ /* The operations we disable here are
+ * handled by the linelist_v. */
+ CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP };
+const var_type_def_t LINELIST_V_type_defn = {
+ .name="Virtual", .fns=&linelist_v_fns,
+ .flags=CFLG_NOREPLACE|CFLG_NOSET };
+const var_type_def_t IGNORE_type_defn = {
+ .name="Ignored", .fns=&ignore_fns,
+ .flags=CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET,
+};
+const var_type_def_t OBSOLETE_type_defn = {
+ .name="Obsolete", .fns=&ignore_fns,
+ .flags=CFLG_GROUP_OBSOLETE,
+};
+
/**
* Table mapping conf_type_t values to var_type_def_t objects.
**/
-static const var_type_def_t type_definitions_table[] = {
- [CONFIG_TYPE_STRING] = { .name="String", .fns=&string_fns },
- [CONFIG_TYPE_FILENAME] = { .name="Filename", .fns=&string_fns },
- [CONFIG_TYPE_INT] = { .name="SignedInteger", .fns=&int_fns,
- .params=&INT_PARSE_UNRESTRICTED },
- [CONFIG_TYPE_POSINT] = { .name="Integer", .fns=&int_fns,
- .params=&INT_PARSE_POSINT },
- [CONFIG_TYPE_UINT64] = { .name="Integer", .fns=&uint64_fns, },
- [CONFIG_TYPE_MEMUNIT] = { .name="DataSize", .fns=&memunit_fns,
- .params=&memory_units },
- [CONFIG_TYPE_INTERVAL] = { .name="TimeInterval", .fns=&interval_fns,
- .params=&time_units },
- [CONFIG_TYPE_MSEC_INTERVAL] = { .name="TimeMsecInterval",
- .fns=&interval_fns,
- .params=&time_msec_units },
- [CONFIG_TYPE_DOUBLE] = { .name="Float", .fns=&double_fns, },
- [CONFIG_TYPE_BOOL] = { .name="Boolean", .fns=&enum_fns,
- .params=&enum_table_bool },
- [CONFIG_TYPE_AUTOBOOL] = { .name="Boolean+Auto", .fns=&enum_fns,
- .params=&enum_table_autobool },
- [CONFIG_TYPE_ISOTIME] = { .name="Time", .fns=&time_fns, },
- [CONFIG_TYPE_CSV] = { .name="CommaList", .fns=&csv_fns, },
- [CONFIG_TYPE_CSV_INTERVAL] = { .name="TimeInterval",
- .fns=&legacy_csv_interval_fns, },
- [CONFIG_TYPE_LINELIST] = { .name="LineList", .fns=&linelist_fns,
- .flags=CFLG_NOREPLACE },
- /*
- * A "linelist_s" is a derived view of a linelist_v: inspecting
- * it gets part of a linelist_v, and setting it adds to the linelist_v.
- */
- [CONFIG_TYPE_LINELIST_S] = { .name="Dependent", .fns=&linelist_s_fns,
- .flags=CFLG_NOREPLACE|
- /* The operations we disable here are
- * handled by the linelist_v. */
- CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP },
- [CONFIG_TYPE_LINELIST_V] = { .name="Virtual", .fns=&linelist_v_fns,
- .flags=CFLG_NOREPLACE|CFLG_NOSET },
- [CONFIG_TYPE_OBSOLETE] = {
- .name="Obsolete", .fns=&ignore_fns,
- .flags=CFLG_GROUP_OBSOLETE,
- }
+static const var_type_def_t *type_definitions_table[] = {
+ [CONFIG_TYPE_STRING] = &STRING_type_defn,
+ [CONFIG_TYPE_FILENAME] = &FILENAME_type_defn,
+ [CONFIG_TYPE_INT] = &INT_type_defn,
+ [CONFIG_TYPE_POSINT] = &POSINT_type_defn,
+ [CONFIG_TYPE_UINT64] = &UINT64_type_defn,
+ [CONFIG_TYPE_MEMUNIT] = &MEMUNIT_type_defn,
+ [CONFIG_TYPE_INTERVAL] = &INTERVAL_type_defn,
+ [CONFIG_TYPE_MSEC_INTERVAL] = &MSEC_INTERVAL_type_defn,
+ [CONFIG_TYPE_DOUBLE] = &DOUBLE_type_defn,
+ [CONFIG_TYPE_BOOL] = &BOOL_type_defn,
+ [CONFIG_TYPE_AUTOBOOL] = &AUTOBOOL_type_defn,
+ [CONFIG_TYPE_ISOTIME] = &ISOTIME_type_defn,
+ [CONFIG_TYPE_CSV] = &CSV_type_defn,
+ [CONFIG_TYPE_CSV_INTERVAL] = &CSV_INTERVAL_type_defn,
+ [CONFIG_TYPE_LINELIST] = &LINELIST_type_defn,
+ [CONFIG_TYPE_LINELIST_S] = &LINELIST_S_type_defn,
+ [CONFIG_TYPE_LINELIST_V] = &LINELIST_V_type_defn,
+ [CONFIG_TYPE_IGNORE] = &IGNORE_type_defn,
+ [CONFIG_TYPE_OBSOLETE] = &OBSOLETE_type_defn,
};
/**
@@ -774,5 +812,5 @@ lookup_type_def(config_type_t type)
tor_assert(t >= 0);
if (t >= (int)ARRAY_LENGTH(type_definitions_table))
return NULL;
- return &type_definitions_table[t];
+ return type_definitions_table[t];
}
diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c
index c3ed8285a4..e8d9392ef6 100644
--- a/src/lib/confmgt/unitparse.c
+++ b/src/lib/confmgt/unitparse.c
@@ -15,6 +15,7 @@
#include "lib/log/util_bug.h"
#include "lib/string/parse_int.h"
#include "lib/string/util_string.h"
+#include "lib/intmath/muldiv.h"
#include <string.h>
@@ -109,6 +110,7 @@ const struct unit_table_t time_msec_units[] = {
* table <b>u</b>, then multiply the number by the unit multiplier.
* On success, set *<b>ok</b> to 1 and return this product.
* Otherwise, set *<b>ok</b> to 0.
+ * Warns user when overflow or a negative value is detected.
*/
uint64_t
config_parse_units(const char *val, const unit_table_t *u, int *ok)
@@ -142,10 +144,37 @@ config_parse_units(const char *val, const unit_table_t *u, int *ok)
for ( ;u->unit;++u) {
if (!strcasecmp(u->unit, cp)) {
- if (use_float)
- v = (uint64_t)(u->multiplier * d);
- else
- v *= u->multiplier;
+ if (use_float) {
+ d = u->multiplier * d;
+
+ if (d < 0) {
+ log_warn(LD_CONFIG, "Got a negative value while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+
+ // Some compilers may warn about casting a double to an unsigned type
+ // because they don't know if d is >= 0
+ if (d >= 0 && (d > (double)INT64_MAX || (uint64_t)d > INT64_MAX)) {
+ log_warn(LD_CONFIG, "Overflow detected while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+
+ v = (uint64_t) d;
+ } else {
+ v = tor_mul_u64_nowrap(v, u->multiplier);
+
+ if (v > INT64_MAX) {
+ log_warn(LD_CONFIG, "Overflow detected while parsing %s %s",
+ val, u->unit);
+ *ok = 0;
+ goto done;
+ }
+ }
+
*ok = 1;
goto done;
}
diff --git a/src/lib/container/handles.h b/src/lib/container/handles.h
index ca7c94559e..798c8a367c 100644
--- a/src/lib/container/handles.h
+++ b/src/lib/container/handles.h
@@ -16,33 +16,33 @@
* To enable a type to have handles, add a HANDLE_ENTRY() field in its
* definition, as in:
*
- * struct walrus {
- * HANDLE_ENTRY(wlr, walrus);
+ * struct walrus_t {
+ * HANDLE_ENTRY(wlr, walrus_t);
* // ...
* };
*
- * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle
+ * And invoke HANDLE_DECL(wlr, walrus_t, [static]) to declare the handle
* manipulation functions (typically in a header):
*
* // opaque handle to walrus.
* typedef struct wlr_handle_t wlr_handle_t;
*
* // make a new handle
- * struct wlr_handle_t *wlr_handle_new(struct walrus *);
+ * struct wlr_handle_t *wlr_handle_new(struct walrus_t *);
*
* // release a handle
* void wlr_handle_free(wlr_handle_t *);
*
* // return the pointed-to walrus, or NULL.
- * struct walrus *wlr_handle_get(wlr_handle_t *).
+ * struct walrus_t *wlr_handle_get(wlr_handle_t *).
*
* // call this function when you're about to free the walrus;
* // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE
* // DANGLING REFERENCES)
- * void wlr_handles_clear(struct walrus *);
+ * void wlr_handles_clear(struct walrus_t *);
*
* Finally, use HANDLE_IMPL() to define the above functions in some
- * appropriate C file: HANDLE_IMPL(wlr, walrus, [static])
+ * appropriate C file: HANDLE_IMPL(wlr, walrus_t, [static])
*
**/
@@ -57,12 +57,13 @@
#define HANDLE_ENTRY(name, structname) \
struct name ## _handle_head_t *handle_head
-#define HANDLE_DECL(name, structname, linkage) \
+#define HANDLE_DECL(name, structname_t, linkage) \
typedef struct name ## _handle_t name ## _handle_t; \
- linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
+ linkage name ## _handle_t *name ## _handle_new( \
+ struct structname_t *object); \
linkage void name ## _handle_free_(name ## _handle_t *); \
- linkage struct structname *name ## _handle_get(name ## _handle_t *); \
- linkage void name ## _handles_clear(struct structname *object);
+ linkage struct structname_t *name ## _handle_get(name ## _handle_t *); \
+ linkage void name ## _handles_clear(struct structname_t *object);
/*
* Implementation notes: there are lots of possible implementations here. We
diff --git a/src/lib/container/lib_container.md b/src/lib/container/lib_container.md
new file mode 100644
index 0000000000..f4902ca44a
--- /dev/null
+++ b/src/lib/container/lib_container.md
@@ -0,0 +1,49 @@
+@dir /lib/container
+@brief lib/container: Hash tables, dynamic arrays, bit arrays, etc.
+
+### Smartlists: Neither lists, nor especially smart.
+
+For historical reasons, we call our dynamic-allocated array type
+`smartlist_t`. It can grow or shrink as elements are added and removed.
+
+All smartlists hold an array of `void *`. Whenever you expose a smartlist
+in an API you *must* document which types its pointers actually hold.
+
+<!-- It would be neat to fix that, wouldn't it? -NM -->
+
+Smartlists are created empty with `smartlist_new()` and freed with
+`smartlist_free()`. See the `containers.h` header documentation for more
+information; there are many convenience functions for commonly needed
+operations.
+
+For low-level operations on smartlists, see also
+\refdir{lib/smartlist_core}.
+
+<!-- TODO: WRITE more about what you can do with smartlists. -->
+
+### Digest maps, string maps, and more.
+
+Tor makes frequent use of maps from 160-bit digests, 256-bit digests,
+or nul-terminated strings to `void *`. These types are `digestmap_t`,
+`digest256map_t`, and `strmap_t` respectively. See the containers.h
+module documentation for more information.
+
+### Intrusive lists and hashtables
+
+For performance-sensitive cases, we sometimes want to use "intrusive"
+collections: ones where the bookkeeping pointers are stuck inside the
+structures that belong to the collection. If you've used the
+BSD-style sys/queue.h macros, you'll be familiar with these.
+
+Unfortunately, the `sys/queue.h` macros vary significantly between the
+platforms that have them, so we provide our own variants in
+`ext/tor_queue.h`.
+
+We also provide an intrusive hashtable implementation in `ext/ht.h`.
+When you're using it, you'll need to define your own hash
+functions. If attacker-induced collisions are a worry here, use the
+cryptographic siphash24g function to extract hashes.
+
+<!-- TODO: WRITE about bloom filters, namemaps, bit-arrays, order functions.
+-->
+
diff --git a/src/lib/container/map.h b/src/lib/container/map.h
index 9da1d3072c..35378a299b 100644
--- a/src/lib/container/map.h
+++ b/src/lib/container/map.h
@@ -17,22 +17,23 @@
#include "ext/siphash.h"
-#define DECLARE_MAP_FNS(maptype, keytype, prefix) \
- typedef struct maptype maptype; \
+#define DECLARE_MAP_FNS(mapname_t, keytype, prefix) \
+ typedef struct mapname_t mapname_t; \
typedef struct prefix##entry_t *prefix##iter_t; \
- MOCK_DECL(maptype*, prefix##new, (void)); \
- void* prefix##set(maptype *map, keytype key, void *val); \
- void* prefix##get(const maptype *map, keytype key); \
- void* prefix##remove(maptype *map, keytype key); \
- MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \
- int prefix##isempty(const maptype *map); \
- int prefix##size(const maptype *map); \
- prefix##iter_t *prefix##iter_init(maptype *map); \
- prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \
- prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \
+ MOCK_DECL(mapname_t*, prefix##new, (void)); \
+ void* prefix##set(mapname_t *map, keytype key, void *val); \
+ void* prefix##get(const mapname_t *map, keytype key); \
+ void* prefix##remove(mapname_t *map, keytype key); \
+ MOCK_DECL(void, prefix##free_, (mapname_t *map, void (*free_val)(void*))); \
+ int prefix##isempty(const mapname_t *map); \
+ int prefix##size(const mapname_t *map); \
+ prefix##iter_t *prefix##iter_init(mapname_t *map); \
+ prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter); \
+ prefix##iter_t *prefix##iter_next_rmv(mapname_t *map, \
+ prefix##iter_t *iter); \
void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \
int prefix##iter_done(prefix##iter_t *iter); \
- void prefix##assert_ok(const maptype *map)
+ void prefix##assert_ok(const mapname_t *map)
/* Map from const char * to void *. Implemented with a hash table. */
DECLARE_MAP_FNS(strmap_t, const char *, strmap_);
@@ -42,9 +43,9 @@ DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
* table. */
DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
-#define MAP_FREE_AND_NULL(maptype, map, fn) \
+#define MAP_FREE_AND_NULL(mapname_t, map, fn) \
do { \
- maptype ## _free_((map), (fn)); \
+ mapname_t ## _free_((map), (fn)); \
(map) = NULL; \
} while (0)
@@ -183,62 +184,62 @@ void* strmap_set_lc(strmap_t *map, const char *key, void *val);
void* strmap_get_lc(const strmap_t *map, const char *key);
void* strmap_remove_lc(strmap_t *map, const char *key);
-#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \
- typedef struct maptype maptype; \
+#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, mapname_t, valtype) \
+ typedef struct mapname_t mapname_t; \
typedef struct prefix##iter_t *prefix##iter_t; \
- ATTR_UNUSED static inline maptype* \
+ ATTR_UNUSED static inline mapname_t* \
prefix##new(void) \
{ \
- return (maptype*)digestmap_new(); \
+ return (mapname_t*)digestmap_new(); \
} \
ATTR_UNUSED static inline digestmap_t* \
- prefix##to_digestmap(maptype *map) \
+ prefix##to_digestmap(mapname_t *map) \
{ \
return (digestmap_t*)map; \
} \
ATTR_UNUSED static inline valtype* \
- prefix##get(maptype *map, const char *key) \
+ prefix##get(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_get((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##set(maptype *map, const char *key, valtype *val) \
+ prefix##set(mapname_t *map, const char *key, valtype *val) \
{ \
return (valtype*)digestmap_set((digestmap_t*)map, key, val); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##remove(maptype *map, const char *key) \
+ prefix##remove(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline void \
- prefix##f##ree_(maptype *map, void (*free_val)(void*)) \
+ prefix##f##ree_(mapname_t *map, void (*free_val)(void*)) \
{ \
digestmap_free_((digestmap_t*)map, free_val); \
} \
ATTR_UNUSED static inline int \
- prefix##isempty(maptype *map) \
+ prefix##isempty(mapname_t *map) \
{ \
return digestmap_isempty((digestmap_t*)map); \
} \
ATTR_UNUSED static inline int \
- prefix##size(maptype *map) \
+ prefix##size(mapname_t *map) \
{ \
return digestmap_size((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_init(maptype *map) \
+ prefix##iter_t *prefix##iter_init(mapname_t *map) \
{ \
return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \
+ prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
ATTR_UNUSED static inline prefix##iter_t* \
- prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \
+ prefix##iter_next_rmv(mapname_t *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next_rmv( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c
index a90057b32c..909dcc9f03 100644
--- a/src/lib/container/namemap.c
+++ b/src/lib/container/namemap.c
@@ -3,6 +3,11 @@
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file namemap.c
+ * @brief Mappings between identifiers and 16-bit ints.
+ **/
+
#include "orconfig.h"
#include "lib/container/smartlist.h"
#include "lib/container/namemap.h"
diff --git a/src/lib/container/namemap_st.h b/src/lib/container/namemap_st.h
index 5008fd5855..20a8051918 100644
--- a/src/lib/container/namemap_st.h
+++ b/src/lib/container/namemap_st.h
@@ -6,6 +6,11 @@
#ifndef NAMEMAP_ST_H
#define NAMEMAP_ST_H
+/**
+ * @file namemap_st.h
+ * @brief Internal declarations for namemap structure.
+ **/
+
#include "lib/cc/compat_compiler.h"
#include "ext/ht.h"
@@ -28,7 +33,9 @@ struct namemap_t {
struct smartlist_t *names;
};
+#ifndef COCCI
/** Macro to initialize a namemap. */
#define NAMEMAP_INIT() { HT_INITIALIZER(), NULL }
+#endif
#endif /* !defined(NAMEMAP_ST_H) */
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index 25638e4b22..984cd2d293 100644
--- a/src/lib/container/smartlist.h
+++ b/src/lib/container/smartlist.h
@@ -92,6 +92,7 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
size_t join_len, int terminate, size_t *len_out)
ATTR_MALLOC;
+#ifndef COCCI
/* Helper: Given two lists of items, possibly of different types, such that
* both lists are sorted on some common field (as determined by a comparison
* expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no
@@ -165,5 +166,6 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \
} \
STMT_END
+#endif /* !defined(COCCI) */
#endif /* !defined(TOR_SMARTLIST_H) */
diff --git a/src/lib/crypt_ops/.may_include b/src/lib/crypt_ops/.may_include
index 0739699686..810e777271 100644
--- a/src/lib/crypt_ops/.may_include
+++ b/src/lib/crypt_ops/.may_include
@@ -1,6 +1,7 @@
orconfig.h
lib/arch/*.h
lib/cc/*.h
+lib/conf/*.h
lib/container/*.h
lib/crypt_ops/*.h
lib/ctime/*.h
@@ -17,6 +18,8 @@ lib/testsupport/*.h
lib/thread/*.h
lib/log/*.h
+lib/crypt_ops/*.inc
+
trunnel/pwbox.h
keccak-tiny/*.h
diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h
index 7c774062d9..e47294e9a8 100644
--- a/src/lib/crypt_ops/aes.h
+++ b/src/lib/crypt_ops/aes.h
@@ -16,7 +16,7 @@
#include "lib/cc/torint.h"
#include "lib/malloc/malloc.h"
-typedef struct aes_cnt_cipher aes_cnt_cipher_t;
+typedef struct aes_cnt_cipher_t aes_cnt_cipher_t;
aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv,
int key_bits);
diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c
index 64564892ad..f5cc97ff68 100644
--- a/src/lib/crypt_ops/aes_openssl.c
+++ b/src/lib/crypt_ops/aes_openssl.c
@@ -39,7 +39,6 @@ DISABLE_GCC_WARNING(redundant-decls)
ENABLE_GCC_WARNING(redundant-decls)
-#include "lib/crypt_ops/aes.h"
#include "lib/log/log.h"
#include "lib/ctime/di_ops.h"
@@ -154,7 +153,7 @@ evaluate_ctr_for_aes(void)
/* Interface to AES code, and counter implementation */
/** Implements an AES counter-mode cipher. */
-struct aes_cnt_cipher {
+struct aes_cnt_cipher_t {
/** This next element (however it's defined) is the AES key. */
union {
EVP_CIPHER_CTX evp;
diff --git a/src/lib/crypt_ops/certs.md b/src/lib/crypt_ops/certs.md
new file mode 100644
index 0000000000..2768548b2a
--- /dev/null
+++ b/src/lib/crypt_ops/certs.md
@@ -0,0 +1,30 @@
+
+@page certificates Certificates in Tor.
+
+We have, alas, several certificate types in Tor.
+
+The tor_x509_cert_t type represents an X.509 certificate. This document
+won't explain X.509 to you -- possibly, no document can. (OTOH, Peter
+Gutmann's "x.509 style guide", though severely dated, does a good job of
+explaining how awful x.509 can be.) Do not introduce any new usages of
+X.509. Right now we only use it in places where TLS forces us to do so.
+See x509.c for more information about using this type.
+
+
+The authority_cert_t type is used only for directory authority keys. It
+has a medium-term signing key (which the authorities actually keep
+online) signed by a long-term identity key (which the authority operator
+had really better be keeping offline). Don't use it for any new kind of
+certificate.
+
+For new places where you need a certificate, consider tor_cert_t: it
+represents a typed and dated _something_ signed by an Ed25519 key. The
+format is described in tor-spec. Unlike x.509, you can write it on a
+napkin. The torcert.c file is used for manipulating these certificates and
+their associated keys.
+
+(Additionally, the Tor directory design uses a fairly wide variety of
+documents that include keys and which are signed by keys. You can
+consider these documents to be an additional kind of certificate if you
+want.)
+
diff --git a/src/lib/crypt_ops/crypto_cipher.h b/src/lib/crypt_ops/crypto_cipher.h
index 88d63c1df2..af00104010 100644
--- a/src/lib/crypt_ops/crypto_cipher.h
+++ b/src/lib/crypt_ops/crypto_cipher.h
@@ -25,7 +25,7 @@
/** Length of our symmetric cipher's keys of 256-bit. */
#define CIPHER256_KEY_LEN 32
-typedef struct aes_cnt_cipher crypto_cipher_t;
+typedef struct aes_cnt_cipher_t crypto_cipher_t;
/* environment setup */
crypto_cipher_t *crypto_cipher_new(const char *key);
diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c
index ba226f8756..d14a40f321 100644
--- a/src/lib/crypt_ops/crypto_digest.c
+++ b/src/lib/crypt_ops/crypto_digest.c
@@ -150,6 +150,9 @@ struct crypto_xof_t {
*/
EVP_MD_CTX *ctx;
#else /* !defined(OPENSSL_HAS_SHAKE3_EVP) */
+ /**
+ * State of the Keccak sponge for the SHAKE-256 computation.
+ **/
keccak_state s;
#endif /* defined(OPENSSL_HAS_SHAKE3_EVP) */
};
diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h
index 5869db7800..fb819b12e7 100644
--- a/src/lib/crypt_ops/crypto_digest.h
+++ b/src/lib/crypt_ops/crypto_digest.h
@@ -38,6 +38,9 @@
/** Length of hex encoding of SHA512 digest, not including final NUL. */
#define HEX_DIGEST512_LEN 128
+/**
+ * An identifier for a cryptographic digest algorithm.
+ **/
typedef enum {
DIGEST_SHA1 = 0,
DIGEST_SHA256 = 1,
@@ -45,16 +48,31 @@ typedef enum {
DIGEST_SHA3_256 = 3,
DIGEST_SHA3_512 = 4,
} digest_algorithm_t;
+/** Number of digest algorithms that we know */
#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
+/** Number of digest algorithms to compute when computing "all the
+ * commonly used digests."
+ *
+ * (This is used in common_digests_t and related functions.)
+ */
#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+/**
+ * Bytes of storage needed to record the state of an in-progress SHA-1 digest.
+ *
+ * This is a deliberate overestimate.
+ **/
#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512)
+
/** Structure used to temporarily save the a digest object. Only implemented
* for SHA1 digest for now. */
typedef struct crypto_digest_checkpoint_t {
#ifdef ENABLE_NSS
+ /** The number of bytes used in <b>mem</b>. */
unsigned int bytes_used;
#endif
+ /** A buffer to store the SHA1 state. Its contents are unspecified, and
+ * are managed by the underlying crypto library.*/
uint8_t mem[DIGEST_CHECKPOINT_BYTES];
} crypto_digest_checkpoint_t;
@@ -67,10 +85,19 @@ typedef struct crypto_digest_checkpoint_t {
* once.
**/
typedef struct {
+ /** An array of digest outputs, one for each "common" digest algorithm. */
char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
} common_digests_t;
+/**
+ * State for computing a digest over a stream of data.
+ **/
typedef struct crypto_digest_t crypto_digest_t;
+
+/**
+ * State for computing an "extendable-output function" (like SHAKE) over a
+ * stream of data, and/or streaming the output.
+ **/
typedef struct crypto_xof_t crypto_xof_t;
struct smartlist_t;
@@ -97,6 +124,9 @@ crypto_digest_t *crypto_digest_new(void);
crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
void crypto_digest_free_(crypto_digest_t *digest);
+/**
+ * Release all storage held in <b>d</b>, and set it to NULL.
+ **/
#define crypto_digest_free(d) \
FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
@@ -122,6 +152,9 @@ crypto_xof_t *crypto_xof_new(void);
void 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);
void crypto_xof_free_(crypto_xof_t *xof);
+/**
+ * Release all storage held in <b>xof</b>, and set it to NULL.
+ **/
#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,
diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c
index b73f0736fd..54fb714436 100644
--- a/src/lib/crypt_ops/crypto_digest_nss.c
+++ b/src/lib/crypt_ops/crypto_digest_nss.c
@@ -44,7 +44,11 @@ digest_alg_to_nss_oid(digest_algorithm_t alg)
}
}
-/* Helper: get an unkeyed digest via pk11wrap */
+/** Helper: Compute an unkeyed digest of the <b>msg_len</b> bytes at
+ * <b>msg</b>, using the digest algorithm specified by <b>alg</b>.
+ * Store the result in the <b>len_out</b>-byte buffer at <b>digest</b>.
+ * Return the number of bytes written on success, and -1 on failure.
+ **/
static int
digest_nss_internal(SECOidTag alg,
char *digest, unsigned len_out,
@@ -557,4 +561,3 @@ crypto_hmac_sha256(char *hmac_out,
tor_assert(ok);
}
-
diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c
index b0d8b6aee9..319714f868 100644
--- a/src/lib/crypt_ops/crypto_digest_openssl.c
+++ b/src/lib/crypt_ops/crypto_digest_openssl.c
@@ -147,9 +147,9 @@ crypto_digest_get_algorithm(crypto_digest_t *digest)
static size_t
crypto_digest_alloc_bytes(digest_algorithm_t alg)
{
- /* Helper: returns the number of bytes in the 'f' field of 'st' */
+ /** 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' */
+ /** 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) {
@@ -519,4 +519,3 @@ crypto_hmac_sha256(char *hmac_out,
(unsigned char*)hmac_out, NULL);
tor_assert(rv);
}
-
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index a16bf4e11a..fbd4da4704 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -23,6 +23,9 @@
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_sys.h"
+#include "lib/crypt_ops/crypto_options_st.h"
+#include "lib/conf/conftypes.h"
+#include "lib/log/util_bug.h"
#include "lib/subsys/subsys.h"
@@ -252,6 +255,66 @@ subsys_crypto_thread_cleanup(void)
crypto_thread_cleanup();
}
+/** Magic number for crypto_options_t. */
+#define CRYPTO_OPTIONS_MAGIC 0x68757368
+
+/**
+ * Return 0 if <b>arg</b> is a valid crypto_options_t. Otherwise return -1
+ * and set *<b>msg_out</b> to a freshly allocated error string.
+ **/
+static int
+crypto_options_validate(const void *arg, char **msg_out)
+{
+ const crypto_options_t *opt = arg;
+ tor_assert(opt->magic == CRYPTO_OPTIONS_MAGIC);
+ tor_assert(msg_out);
+
+ if (opt->AccelDir && !opt->AccelName) {
+ *msg_out = tor_strdup("Can't use hardware crypto accelerator dir "
+ "without engine name.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Declare the options field table for crypto_options */
+#define CONF_CONTEXT LL_TABLE
+#include "lib/crypt_ops/crypto_options.inc"
+#undef CONF_CONTEXT
+
+/**
+ * Declares the configuration options for this module.
+ **/
+static const config_format_t crypto_options_fmt = {
+ .size = sizeof(crypto_options_t),
+ .magic = { "crypto_options_t",
+ CRYPTO_OPTIONS_MAGIC,
+ offsetof(crypto_options_t, magic) },
+ .vars = crypto_options_t_vars,
+ .validate_fn = crypto_options_validate,
+};
+
+/**
+ * Invoked from subsysmgr.c when a new set of options arrives.
+ **/
+static int
+crypto_set_options(void *arg)
+{
+ const crypto_options_t *options = arg;
+ const bool hardware_accel = options->HardwareAccel || options->AccelName;
+
+ // This call already checks for crypto_global_initialized_, so it
+ // will only initialize the subsystem the first time it's called.
+ if (crypto_global_init(hardware_accel,
+ options->AccelName,
+ options->AccelDir)) {
+ log_err(LD_BUG, "Unable to initialize the crypto subsystem. Exiting.");
+ return -1;
+ }
+ return 0;
+}
+
const struct subsys_fns_t sys_crypto = {
.name = "crypto",
.supported = true,
@@ -261,4 +324,7 @@ const struct subsys_fns_t sys_crypto = {
.prefork = subsys_crypto_prefork,
.postfork = subsys_crypto_postfork,
.thread_cleanup = subsys_crypto_thread_cleanup,
+
+ .options_format = &crypto_options_fmt,
+ .set_options = crypto_set_options,
};
diff --git a/src/lib/crypt_ops/crypto_ope.c b/src/lib/crypt_ops/crypto_ope.c
index ed832d852e..e4fef319e9 100644
--- a/src/lib/crypt_ops/crypto_ope.c
+++ b/src/lib/crypt_ops/crypto_ope.c
@@ -2,7 +2,8 @@
/* See LICENSE for licensing information */
/**
- * A rudimentary order-preserving encryption scheme.
+ * @file crypto_ope.c
+ * @brief A rudimentary order-preserving encryption scheme.
*
* To compute the encryption of N, this scheme uses an AES-CTR stream to
* generate M-byte values, and adds the first N of them together. (+1 each to
@@ -143,7 +144,7 @@ crypto_ope_new(const uint8_t *key)
return ope;
}
-/** Free all storage held in <>ope</b>. */
+/** Free all storage held in <b>ope</b>. */
void
crypto_ope_free_(crypto_ope_t *ope)
{
diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h
index 9778dfe0f0..fcac60427d 100644
--- a/src/lib/crypt_ops/crypto_ope.h
+++ b/src/lib/crypt_ops/crypto_ope.h
@@ -1,6 +1,11 @@
/* Copyright (c) 2018-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file crypto_ope.h
+ * @brief header for crypto_ope.c
+ **/
+
#ifndef CRYPTO_OPE_H
#define CRYPTO_OPE_H
@@ -37,10 +42,10 @@ void crypto_ope_free_(crypto_ope_t *ope);
uint64_t crypto_ope_encrypt(const crypto_ope_t *ope, int plaintext);
#ifdef CRYPTO_OPE_PRIVATE
-struct aes_cnt_cipher;
-STATIC struct aes_cnt_cipher *ope_get_cipher(const crypto_ope_t *ope,
+struct aes_cnt_cipher_t;
+STATIC struct aes_cnt_cipher_t *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);
+STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher_t *c, size_t n);
#endif /* defined(CRYPTO_OPE_PRIVATE) */
#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 f51309219a..cf0e499ee4 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.c
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.c
@@ -121,10 +121,12 @@ crypto_openssl_get_header_version_str(void)
return crypto_openssl_header_version_str;
}
+#ifndef COCCI
#ifndef OPENSSL_THREADS
-#error OpenSSL has been built without thread support. Tor requires an \
- OpenSSL library with thread support enabled.
+#error "OpenSSL has been built without thread support. Tor requires an \
+ OpenSSL library with thread support enabled."
#endif
+#endif /* !defined(COCCI) */
#ifndef NEW_THREAD_API
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
@@ -273,8 +275,14 @@ log_engine(const char *fn, ENGINE *e)
}
#endif /* !defined(DISABLE_ENGINES) */
-/** Initialize engines for openssl (if enabled). */
-static void
+/** Initialize engines for openssl (if enabled). Load all the built-in
+ * engines, along with the one called <b>accelName</b> (which may be NULL).
+ * If <b>accelName</b> is prefixed with "!", then it is required: return -1
+ * if it can't be loaded. Otherwise return 0.
+ *
+ * If <b>accelDir</b> is not NULL, it is the path from which the engine should
+ * be loaded. */
+static int
crypto_openssl_init_engines(const char *accelName,
const char *accelDir)
{
@@ -282,7 +290,13 @@ crypto_openssl_init_engines(const char *accelName,
(void)accelName;
(void)accelDir;
log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled.");
-#else
+ if (accelName && accelName[0] == '!') {
+ log_warn(LD_CRYPTO, "Unable to load required dynamic OpenSSL engine "
+ "\"%s\".", accelName+1);
+ return -1;
+ }
+ return 0;
+#else /* !defined(DISABLE_ENGINES) */
ENGINE *e = NULL;
log_info(LD_CRYPTO, "Initializing OpenSSL engine support.");
@@ -290,6 +304,9 @@ crypto_openssl_init_engines(const char *accelName,
ENGINE_register_all_complete();
if (accelName) {
+ const bool required = accelName[0] == '!';
+ if (required)
+ ++accelName;
if (accelDir) {
log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\""
" via path \"%s\".", accelName, accelDir);
@@ -300,8 +317,11 @@ crypto_openssl_init_engines(const char *accelName,
e = ENGINE_by_id(accelName);
}
if (!e) {
- log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".",
+ log_warn(LD_CRYPTO, "Unable to load %sdynamic OpenSSL engine \"%s\".",
+ required?"required ":"",
accelName);
+ if (required)
+ return -1;
} else {
log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".",
accelName);
@@ -338,6 +358,7 @@ crypto_openssl_init_engines(const char *accelName,
#ifdef NID_aes_256_gcm
log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm));
#endif
+ return 0;
#endif /* defined(DISABLE_ENGINES) */
}
@@ -348,7 +369,8 @@ crypto_openssl_late_init(int useAccel, const char *accelName,
const char *accelDir)
{
if (useAccel > 0) {
- crypto_openssl_init_engines(accelName, accelDir);
+ if (crypto_openssl_init_engines(accelName, accelDir) < 0)
+ return -1;
} else {
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
@@ -377,7 +399,7 @@ crypto_openssl_thread_cleanup(void)
void
crypto_openssl_global_cleanup(void)
{
- #ifndef OPENSSL_1_1_API
+#ifndef OPENSSL_1_1_API
EVP_cleanup();
#endif
#ifndef NEW_THREAD_API
diff --git a/src/lib/crypt_ops/crypto_options.inc b/src/lib/crypt_ops/crypto_options.inc
new file mode 100644
index 0000000000..5bee0daacd
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_options.inc
@@ -0,0 +1,19 @@
+
+/**
+ * @file crypto_options.inc
+ * @brief Declare configuration options for the crypto_ops module.
+ **/
+
+/** Holds configuration about our cryptography options. */
+BEGIN_CONF_STRUCT(crypto_options_t)
+
+/** Should we enable extra OpenSSL hardware acceleration (where available)? */
+CONF_VAR(HardwareAccel, BOOL, CFLG_IMMUTABLE, "0")
+
+/** Optional OpenSSL hardware-acceleration engine name */
+CONF_VAR(AccelName, STRING, CFLG_IMMUTABLE, NULL)
+
+/** Optional OpenSSL hardware-acceleration engine search directory. */
+CONF_VAR(AccelDir, FILENAME, CFLG_IMMUTABLE, NULL)
+
+END_CONF_STRUCT(crypto_options_t)
diff --git a/src/lib/crypt_ops/crypto_options_st.h b/src/lib/crypt_ops/crypto_options_st.h
new file mode 100644
index 0000000000..8127b41eec
--- /dev/null
+++ b/src/lib/crypt_ops/crypto_options_st.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 crypto_options_st.h
+ * @brief Header for lib/crypt_ops/crypto_options_st.c
+ **/
+
+#ifndef TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H
+#define TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H
+
+#include "lib/conf/confdecl.h"
+
+#define CONF_CONTEXT STRUCT
+#include "lib/crypt_ops/crypto_options.inc"
+#undef CONF_CONTEXT
+
+typedef struct crypto_options_t crypto_options_t;
+
+#endif /* !defined(TOR_LIB_CRYPT_OPS_CRYPTO_OPTIONS_ST_H) */
diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c
index e6ceb42ccb..166c67c87b 100644
--- a/src/lib/crypt_ops/crypto_rand_fast.c
+++ b/src/lib/crypt_ops/crypto_rand_fast.c
@@ -32,7 +32,6 @@
* request.
*/
-#define CRYPTO_RAND_FAST_PRIVATE
#define CRYPTO_PRIVATE
#include "lib/crypt_ops/crypto_rand.h"
@@ -102,16 +101,16 @@ struct crypto_fast_rng_t {
* crypto_strongest_rand().
*/
int16_t n_till_reseed;
- /** How many bytes are remaining in cbuf.bytes? */
+ /** How many bytes are remaining in cbuf_t.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 {
+ struct cbuf_t {
/** The seed (key and IV) that we will use the next time that we refill
- * cbuf. */
+ * cbuf_t. */
uint8_t seed[SEED_LEN];
/**
* Bytes that we are yielding to the user. The next byte to be
@@ -122,9 +121,9 @@ struct crypto_fast_rng_t {
} buf;
};
-/* alignof(uint8_t) should be 1, so there shouldn't be any padding in cbuf.
+/* alignof(uint8_t) should be 1, so there shouldn't be any padding in cbuf_t.
*/
-CTASSERT(sizeof(struct cbuf) == BUFLEN+SEED_LEN);
+CTASSERT(sizeof(struct cbuf_t) == BUFLEN+SEED_LEN);
/* We're trying to fit all of the RNG state into a nice mmapable chunk.
*/
CTASSERT(sizeof(crypto_fast_rng_t) <= MAPLEN);
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index 361db18927..0ee3bf601d 100644
--- a/src/lib/crypt_ops/crypto_s2k.c
+++ b/src/lib/crypt_ops/crypto_s2k.c
@@ -380,7 +380,7 @@ secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
#ifndef HAVE_SCRYPT
if (type == S2K_TYPE_SCRYPT)
return S2K_NO_SCRYPT_SUPPORT;
- #endif
+#endif
if (! legacy_format) {
++spec;
diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c
index 5e3f4a87a1..beb45792ad 100644
--- a/src/lib/crypt_ops/crypto_util.c
+++ b/src/lib/crypt_ops/crypto_util.c
@@ -10,8 +10,6 @@
* \brief Common cryptographic utilities.
**/
-#define CRYPTO_UTIL_PRIVATE
-
#include "lib/crypt_ops/crypto_util.h"
#include "lib/cc/compat_compiler.h"
diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am
index 1f58a33d38..7644cab412 100644
--- a/src/lib/crypt_ops/include.am
+++ b/src/lib/crypt_ops/include.am
@@ -68,6 +68,8 @@ noinst_HEADERS += \
src/lib/crypt_ops/crypto_nss_mgt.h \
src/lib/crypt_ops/crypto_openssl_mgt.h \
src/lib/crypt_ops/crypto_ope.h \
+ src/lib/crypt_ops/crypto_options.inc \
+ src/lib/crypt_ops/crypto_options_st.h \
src/lib/crypt_ops/crypto_pwbox.h \
src/lib/crypt_ops/crypto_rand.h \
src/lib/crypt_ops/crypto_rsa.h \
diff --git a/src/lib/crypt_ops/lib_crypt_ops.md b/src/lib/crypt_ops/lib_crypt_ops.md
new file mode 100644
index 0000000000..4e675e4871
--- /dev/null
+++ b/src/lib/crypt_ops/lib_crypt_ops.md
@@ -0,0 +1,137 @@
+@dir /lib/crypt_ops
+@brief lib/crypt_ops: Cryptographic operations.
+
+This module contains wrappers around the cryptographic libraries that we
+support, and implementations for some higher-level cryptographic
+constructions that we use.
+
+It wraps our two major cryptographic backends (OpenSSL or NSS, as configured
+by the user), and also wraps other cryptographic code in src/ext.
+
+Generally speaking, Tor code shouldn't be calling OpenSSL or NSS
+(or any other crypto library) directly. Instead, we should indirect through
+one of the functions in this directory, or through \refdir{lib/tls}.
+
+Cryptography functionality that's available is described below.
+
+### RNG facilities ###
+
+The most basic RNG capability in Tor is the crypto_rand() family of
+functions. These currently use OpenSSL's RAND_() backend, but may use
+something faster in the future.
+
+In addition to crypto_rand(), which fills in a buffer with random
+bytes, we also have functions to produce random integers in certain
+ranges; to produce random hostnames; to produce random doubles, etc.
+
+When you're creating a long-term cryptographic secret, you might want
+to use crypto_strongest_rand() instead of crypto_rand(). It takes the
+operating system's entropy source and combines it with output from
+crypto_rand(). This is a pure paranoia measure, but it might help us
+someday.
+
+You can use smartlist_choose() to pick a random element from a smartlist
+and smartlist_shuffle() to randomize the order of a smartlist. Both are
+potentially a bit slow.
+
+### Cryptographic digests and related functions ###
+
+We treat digests as separate types based on the length of their
+outputs. We support one 160-bit digest (SHA1), two 256-bit digests
+(SHA256 and SHA3-256), and two 512-bit digests (SHA512 and SHA3-512).
+
+You should not use SHA1 for anything new.
+
+The crypto_digest\*() family of functions manipulates digests. You
+can either compute a digest of a chunk of memory all at once using
+crypto_digest(), crypto_digest256(), or crypto_digest512(). Or you
+can create a crypto_digest_t object with
+crypto_digest{,256,512}_new(), feed information to it in chunks using
+crypto_digest_add_bytes(), and then extract the final digest using
+crypto_digest_get_digest(). You can copy the state of one of these
+objects using crypto_digest_dup() or crypto_digest_assign().
+
+We support the HMAC hash-based message authentication code
+instantiated using SHA256. See crypto_hmac_sha256. (You should not
+add any HMAC users with SHA1, and HMAC is not necessary with SHA3.)
+
+We also support the SHA3 cousins, SHAKE128 and SHAKE256. Unlike
+digests, these are extendable output functions (or XOFs) where you can
+get any amount of output. Use the crypto_xof_\*() functions to access
+these.
+
+We have several ways to derive keys from cryptographically strong secret
+inputs (like diffie-hellman outputs). The old
+crypto_expand_key_material_TAP() performs an ad-hoc KDF based on SHA1 -- you
+shouldn't use it for implementing anything but old versions of the Tor
+protocol. You can use HKDF-SHA256 (as defined in RFC5869) for more modern
+protocols. Also consider SHAKE256.
+
+If your input is potentially weak, like a password or passphrase, use a salt
+along with the secret_to_key() functions as defined in crypto_s2k.c. Prefer
+scrypt over other hashing methods when possible. If you're using a password
+to encrypt something, see the "boxed file storage" section below.
+
+Finally, in order to store objects in hash tables, Tor includes the
+randomized SipHash 2-4 function. Call it via the siphash24g() function in
+src/ext/siphash.h whenever you're creating a hashtable whose keys may be
+manipulated by an attacker in order to DoS you with collisions.
+
+
+### Stream ciphers ###
+
+You can create instances of a stream cipher using crypto_cipher_new().
+These are stateful objects of type crypto_cipher_t. Note that these
+objects only support AES-128 right now; a future version should add
+support for AES-128 and/or ChaCha20.
+
+You can encrypt/decrypt with crypto_cipher_encrypt or
+crypto_cipher_decrypt. The crypto_cipher_crypt_inplace function performs
+an encryption without a copy.
+
+Note that sensible people should not use raw stream ciphers; they should
+probably be using some kind of AEAD. Sorry.
+
+### Public key functionality ###
+
+We support four public key algorithms: DH1024, RSA, Curve25519, and
+Ed25519.
+
+We support DH1024 over two prime groups. You access these via the
+crypto_dh_\*() family of functions.
+
+We support RSA in many bit sizes for signing and encryption. You access
+it via the crypto_pk_*() family of functions. Note that a crypto_pk_t
+may or may not include a private key. See the crypto_pk_* functions in
+crypto.c for a full list of functions here.
+
+For Curve25519 functionality, see the functions and types in
+crypto_curve25519.c. Curve25519 is generally suitable for when you need
+a secure fast elliptic-curve diffie hellman implementation. When
+designing new protocols, prefer it over DH in Z_p.
+
+For Ed25519 functionality, see the functions and types in
+crypto_ed25519.c. Ed25519 is a generally suitable as a secure fast
+elliptic curve signature method. For new protocols, prefer it over RSA
+signatures.
+
+### Metaformats for storage ###
+
+When OpenSSL manages the storage of some object, we use whatever format
+OpenSSL provides -- typically, some kind of PEM-wrapped base 64 encoding
+that starts with "----- BEGIN CRYPTOGRAPHIC OBJECT ----".
+
+When we manage the storage of some cryptographic object, we prefix the
+object with 32-byte NUL-padded prefix in order to avoid accidental
+object confusion; see the crypto_read_tagged_contents_from_file() and
+crypto_write_tagged_contents_to_file() functions for manipulating
+these. The prefix is "== type: tag ==", where type describes the object
+and its encoding, and tag indicates which one it is.
+
+### Boxed-file storage ###
+
+When managing keys, you frequently want to have some way to write a
+secret object to disk, encrypted with a passphrase. The crypto_pwbox
+and crypto_unpwbox functions do so in a way that's likely to be
+readable by future versions of Tor.
+
diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c
index 89e0837ae9..a96a888b02 100644
--- a/src/lib/ctime/di_ops.c
+++ b/src/lib/ctime/di_ops.c
@@ -145,8 +145,11 @@ tor_memeq(const void *a, const void *b, size_t sz)
/* Implement di_digest256_map_t as a linked list of entries. */
struct di_digest256_map_t {
+ /** Pointer to the next entry in the list. */
struct di_digest256_map_t *next;
+ /** Key for this entry. */
uint8_t key[32];
+ /** Value for this entry. */
void *val;
};
diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h
index 264b56a8c1..fea8f93e37 100644
--- a/src/lib/ctime/di_ops.h
+++ b/src/lib/ctime/di_ops.h
@@ -16,6 +16,8 @@
int tor_memcmp(const void *a, const void *b, size_t sz);
int tor_memeq(const void *a, const void *b, size_t sz);
+/** Perform a constant-time comparison of the <b>sz</b> bytes at <b>a</b> and
+ * <b>b</b>, yielding true if they are different, and false otherwise. */
#define tor_memneq(a,b,sz) (!tor_memeq((a),(b),(sz)))
/** Alias for the platform's memcmp() function. This function is
@@ -24,7 +26,19 @@ int tor_memeq(const void *a, const void *b, size_t sz);
* implementation.
*/
#define fast_memcmp(a,b,c) (memcmp((a),(b),(c)))
+/** Alias for the platform's memcmp() function, for use in testing equality.
+ *
+ * This function is <em>not</em> data-independent: we define this alias so
+ * that we can mark cases where we are deliberately using a data-dependent
+ * memcmp() implementation.
+ */
#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c)))
+/** Alias for the platform's memcmp() function, for use in testing inequality.
+ *
+ * This function is <em>not</em> data-independent: we define this alias so
+ * that we can mark cases where we are deliberately using a data-dependent
+ * memcmp() implementation.
+ */
#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c)))
int safe_mem_is_zero(const void *mem, size_t sz);
@@ -35,9 +49,17 @@ int safe_mem_is_zero(const void *mem, size_t sz);
*
* Not efficient for large maps! */
typedef struct di_digest256_map_t di_digest256_map_t;
+/**
+ * Type for a function used to free members of a di_digest256_map_t.
+ **/
typedef void (*dimap_free_fn)(void *);
void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn);
+/**
+ * @copydoc dimap_free_
+ *
+ * Additionally, set the pointer <b>map</b> to NULL.
+ **/
#define dimap_free(map, free_fn) \
do { \
dimap_free_((map), (free_fn)); \
@@ -52,4 +74,3 @@ int select_array_member_cumulative_timei(const uint64_t *entries,
uint64_t total, uint64_t rand_val);
#endif /* !defined(TOR_DI_OPS_H) */
-
diff --git a/src/lib/ctime/lib_ctime.md b/src/lib/ctime/lib_ctime.md
new file mode 100644
index 0000000000..913199f6a5
--- /dev/null
+++ b/src/lib/ctime/lib_ctime.md
@@ -0,0 +1,14 @@
+@dir /lib/ctime
+@brief lib/ctime: Constant-time code to avoid side-channels.
+
+This module contains constant-time implementations of various
+data comparison and table lookup functions. We use these in preference to
+memcmp() and so forth, since memcmp() can leak information about its inputs
+based on how fast it returns. In general, your code should call tor_memeq()
+and tor_memneq(), not memcmp().
+
+We also define some _non_-constant-time wrappers for memcmp() here: Since we
+consider calls to memcmp() to be in error, we require that code that actually
+doesn't need to be constant-time to use the fast_memeq() / fast_memneq() /
+fast_memcmp() aliases instead.
+
diff --git a/src/lib/defs/lib_defs.md b/src/lib/defs/lib_defs.md
new file mode 100644
index 0000000000..5762e4550b
--- /dev/null
+++ b/src/lib/defs/lib_defs.md
@@ -0,0 +1,2 @@
+@dir /lib/defs
+@brief lib/defs: Lowest-level constants, used in many places.
diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h
index 459afbf42d..1609702706 100644
--- a/src/lib/defs/time.h
+++ b/src/lib/defs/time.h
@@ -17,7 +17,7 @@
#define TOR_USEC_PER_SEC (1000000)
/** How many nanoseconds per microsecond */
#define TOR_NSEC_PER_USEC (1000)
-/* How many nanoseconds per millisecond */
+/** How many nanoseconds per millisecond */
#define TOR_NSEC_PER_MSEC (1000*1000)
#endif /* !defined(TOR_TIME_DEFS_H) */
diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h
index 6431f0a2dd..080bb4282a 100644
--- a/src/lib/defs/x25519_sizes.h
+++ b/src/lib/defs/x25519_sizes.h
@@ -23,14 +23,22 @@
/** Length of the result of a curve25519 handshake. */
#define CURVE25519_OUTPUT_LEN 32
+/** Length of an Ed25519 public key */
#define ED25519_PUBKEY_LEN 32
+/** Length of an Ed25519 secret key */
#define ED25519_SECKEY_LEN 64
+/** Length of the seed that is ordinarily expanded to an Ed25519 secret
+ * key. */
#define ED25519_SECKEY_SEED_LEN 32
+/** Length of an Ed25519 signature. */
#define ED25519_SIG_LEN 64
+/** Length of a Curve25519 key when encoded in base 64, with padding. */
#define CURVE25519_BASE64_PADDED_LEN 44
+/** Length of a Ed25519 key when encoded in base 64, without padding. */
#define ED25519_BASE64_LEN 43
+/** Length of a Ed25519 signature when encoded in base 64, without padding. */
#define ED25519_SIG_BASE64_LEN 86
#endif /* !defined(TOR_X25519_SIZES_H) */
diff --git a/src/lib/dispatch/dispatch_cfg.h b/src/lib/dispatch/dispatch_cfg.h
index 348dce8d40..929ec54215 100644
--- a/src/lib/dispatch/dispatch_cfg.h
+++ b/src/lib/dispatch/dispatch_cfg.h
@@ -7,6 +7,11 @@
#ifndef TOR_DISPATCH_CFG_H
#define TOR_DISPATCH_CFG_H
+/**
+ * @file dispatch_cfg.h
+ * @brief Header for distpach_cfg.c
+ **/
+
#include "lib/dispatch/msgtypes.h"
#include "lib/testsupport/testsupport.h"
diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h
index 57b6f0347f..f64fc2b321 100644
--- a/src/lib/dispatch/dispatch_cfg_st.h
+++ b/src/lib/dispatch/dispatch_cfg_st.h
@@ -4,13 +4,21 @@
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_cfg_st.h
+ * @brief Declarations for dispatch-configuration types.
+ **/
+
#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. */
+/** Information needed to create a dispatcher, but in a less efficient, more
+ * mutable format.
+ *
+ * Nearly everybody should use the \refdir{lib/pubsub} module to configure
+ * dispatchers, instead of using this. */
struct dispatch_cfg_t {
/** A list of msg_type_id_t (cast to void*), indexed by msg_t. */
struct smartlist_t *type_by_msg;
diff --git a/src/lib/dispatch/dispatch_naming.c b/src/lib/dispatch/dispatch_naming.c
index 83d9a2d604..c501aa34bd 100644
--- a/src/lib/dispatch/dispatch_naming.c
+++ b/src/lib/dispatch/dispatch_naming.c
@@ -4,6 +4,11 @@
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_naming.c
+ * @brief Name-to-ID maps for our message dispatch system.
+ **/
+
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
@@ -33,6 +38,7 @@ dispatch_naming_init(void)
{
}
+#ifndef COCCI
/* Helper macro: declare functions to map IDs to and from names for a given
* type in a namemap_t.
*/
@@ -56,6 +62,7 @@ dispatch_naming_init(void)
return namemap_get_size(&type##_id_map); \
} \
EAT_SEMICOLON
+#endif /* !defined(COCCI) */
DECLARE_ID_MAP_FNS(message);
DECLARE_ID_MAP_FNS(channel);
diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h
index fd6c83cc12..d36851bce9 100644
--- a/src/lib/dispatch/dispatch_naming.h
+++ b/src/lib/dispatch/dispatch_naming.h
@@ -4,6 +4,11 @@
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dispatch_naming.h
+ * @brief Header for dispatch_naming.c
+ **/
+
#ifndef TOR_DISPATCH_NAMING_H
#define TOR_DISPATCH_NAMING_H
diff --git a/src/lib/dispatch/lib_dispatch.md b/src/lib/dispatch/lib_dispatch.md
new file mode 100644
index 0000000000..153ca50080
--- /dev/null
+++ b/src/lib/dispatch/lib_dispatch.md
@@ -0,0 +1,14 @@
+@dir /lib/dispatch
+@brief lib/dispatch: In-process message delivery.
+
+This module provides a general in-process "message dispatch" system in which
+typed messages are sent on channels. The dispatch.h header has far more
+information.
+
+It is used by by \refdir{lib/pubsub} to implement our general
+inter-module publish/subscribe system.
+
+This is not a fancy multi-threaded many-to-many dispatcher as you may be used
+to from more sophisticated architectures: this dispatcher is intended only
+for use in improving Tor's architecture.
+
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index d4a8f510ba..f55e3d966f 100644
--- a/src/lib/encoding/kvline.c
+++ b/src/lib/encoding/kvline.c
@@ -29,12 +29,20 @@
#include <string.h>
/** Return true iff we need to quote and escape the string <b>s</b> to encode
- * it. */
+ * it.
+ *
+ * kvline_can_encode_lines() also uses this (with
+ * <b>as_keyless_val</b> true) to check whether a key would require
+ * quoting.
+ */
static bool
needs_escape(const char *s, bool as_keyless_val)
{
if (as_keyless_val && *s == 0)
return true;
+ /* Keyless values containing '=' need to be escaped. */
+ if (as_keyless_val && strchr(s, '='))
+ return true;
for (; *s; ++s) {
if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
@@ -72,23 +80,17 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
{
for ( ; line; line = line->next) {
const bool keyless = line_has_no_key(line);
- if (keyless) {
- if (! (flags & KV_OMIT_KEYS)) {
- /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
- return false;
- }
- if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
- /* We can't have a keyless value with = without quoting it. */
- return false;
- }
+ if (keyless && ! (flags & KV_OMIT_KEYS)) {
+ /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
+ return false;
}
- if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
- /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
+ if (needs_escape(line->value, keyless) && ! (flags & (KV_QUOTED|KV_RAW))) {
+ /* If both KV_QUOTED and KV_RAW are false, we can't encode a
+ value that needs quotes. */
return false;
}
- if (line->key && strlen(line->key) &&
- (needs_escape(line->key, false) || strchr(line->key, '='))) {
+ if (!keyless && needs_escape(line->key, true)) {
/* We can't handle keys that need quoting. */
return false;
}
@@ -103,7 +105,7 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
*
* If KV_QUOTED is set in <b>flags</b>, then all values that contain
* spaces or unusual characters are escaped and quoted. Otherwise, such
- * values are not allowed.
+ * values are not allowed. Mutually exclusive with KV_RAW.
*
* 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
@@ -113,6 +115,11 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
* encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with
* KV_OMIT_KEYS.
*
+ * If KV_RAW is set in <b>flags</b>, then don't apply any quoting to
+ * the value, and assume that the caller has adequately quoted it.
+ * (The control protocol has some quirks that make this necessary.)
+ * Mutually exclusive with KV_QUOTED.
+ *
* KV_QUOTED_QSTRING is not supported.
*/
char *
@@ -121,11 +128,12 @@ kvline_encode(const config_line_t *line,
{
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));
+ tor_assert((flags & (KV_QUOTED|KV_RAW)) != (KV_QUOTED|KV_RAW));
+
+ if (!kvline_can_encode_lines(line, flags))
+ return NULL;
smartlist_t *elements = smartlist_new();
@@ -142,15 +150,12 @@ kvline_encode(const config_line_t *line,
k = line->key;
} else {
eq = "";
- if (strchr(line->value, '=')) {
- esc = true;
- }
}
if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
eq = "";
v = "";
- } else if (esc) {
+ } else if (!(flags & KV_RAW) && esc) {
tmp = esc_for_log(line->value);
v = tmp;
} else {
@@ -187,12 +192,15 @@ kvline_encode(const config_line_t *line,
* 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.
+ *
+ * KV_RAW is not supported.
*/
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));
+ tor_assert(!(flags & KV_RAW));
const char *cp = line, *cplast = NULL;
const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index dea2ce1809..9d36902ad1 100644
--- a/src/lib/encoding/kvline.h
+++ b/src/lib/encoding/kvline.h
@@ -19,6 +19,7 @@ struct config_line_t;
#define KV_OMIT_KEYS (1u<<1)
#define KV_OMIT_VALS (1u<<2)
#define KV_QUOTED_QSTRING (1u<<3)
+#define KV_RAW (1u<<4)
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/lib_encoding.md b/src/lib/encoding/lib_encoding.md
new file mode 100644
index 0000000000..66dd9d8caf
--- /dev/null
+++ b/src/lib/encoding/lib_encoding.md
@@ -0,0 +1,6 @@
+@dir /lib/encoding
+@brief lib/encoding: Encoding data in various forms, types, and transformations
+
+Here we have time formats (timefmt.c), quoted strings (qstring.c), C strings
+(string.c) base-16/32/64 (binascii.c), and more.
+
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c
index bc3ca286ec..62088c1f46 100644
--- a/src/lib/err/backtrace.c
+++ b/src/lib/err/backtrace.c
@@ -54,7 +54,7 @@
#include "lib/cc/ctassert.h"
-#define EXPOSE_CLEAN_BACKTRACE
+#define BACKTRACE_PRIVATE
#include "lib/err/backtrace.h"
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
@@ -85,7 +85,7 @@ static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
/** Lock and return a static stack pointer buffer that can hold up to
* MAX_DEPTH function pointers. */
-static void *
+static void **
lock_cb_buf(void)
{
/* Lock the mutex first, before even declaring the buffer. */
@@ -102,7 +102,7 @@ lock_cb_buf(void)
/** Unlock the static stack pointer buffer. */
static void
-unlock_cb_buf(void *cb_buf)
+unlock_cb_buf(void **cb_buf)
{
memset(cb_buf, 0, SIZEOF_CB_BUF);
pthread_mutex_unlock(&cb_buf_mutex);
@@ -149,7 +149,7 @@ log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
char **symbols;
size_t i;
- void *cb_buf = lock_cb_buf();
+ void **cb_buf = lock_cb_buf();
depth = backtrace(cb_buf, MAX_DEPTH);
symbols = backtrace_symbols(cb_buf, (int)depth);
@@ -183,7 +183,7 @@ crash_handler(int sig, siginfo_t *si, void *ctx_)
int n_fds, i;
const int *fds = NULL;
- void *cb_buf = lock_cb_buf();
+ void **cb_buf = lock_cb_buf();
(void) si;
@@ -214,7 +214,7 @@ dump_stack_symbols_to_error_fds(void)
const int *fds = NULL;
size_t depth;
- void *cb_buf = lock_cb_buf();
+ void **cb_buf = lock_cb_buf();
depth = backtrace(cb_buf, MAX_DEPTH);
@@ -256,7 +256,7 @@ install_bt_handler(void)
* libc has pre-loaded the symbols we need to dump things, so that later
* reads won't be denied by the sandbox code */
char **symbols;
- void *cb_buf = lock_cb_buf();
+ void **cb_buf = lock_cb_buf();
size_t depth = backtrace(cb_buf, MAX_DEPTH);
symbols = backtrace_symbols(cb_buf, (int) depth);
if (symbols)
diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h
index 7e09a0a5a7..21303105e2 100644
--- a/src/lib/err/backtrace.h
+++ b/src/lib/err/backtrace.h
@@ -29,11 +29,11 @@ const char *get_tor_backtrace_version(void);
#define log_backtrace(sev, dom, msg) \
log_backtrace_impl((sev), (dom), (msg), tor_log)
-#ifdef EXPOSE_CLEAN_BACKTRACE
+#ifdef BACKTRACE_PRIVATE
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx);
#endif
-#endif /* defined(EXPOSE_CLEAN_BACKTRACE) */
+#endif /* defined(BACKTRACE_PRIVATE) */
#endif /* !defined(TOR_BACKTRACE_H) */
diff --git a/src/lib/err/lib_err.md b/src/lib/err/lib_err.md
new file mode 100644
index 0000000000..cb4eba2e0d
--- /dev/null
+++ b/src/lib/err/lib_err.md
@@ -0,0 +1,13 @@
+@dir /lib/err
+@brief lib/err: Lowest-level error handling code.
+
+This module is responsible for generating stack traces, handling raw
+assertion failures, and otherwise reporting problems that might not be
+safe to report via the regular logging module.
+
+There are three kinds of users for the functions in this module:
+ * Code that needs a way to assert(), but which cannot use the regular
+ `tor_assert()` macros in logging module.
+ * Code that needs signal-safe error reporting.
+ * Higher-level error handling code.
+
diff --git a/src/lib/evloop/compat_libevent.c b/src/lib/evloop/compat_libevent.c
index 500c74831c..aad82fc9aa 100644
--- a/src/lib/evloop/compat_libevent.c
+++ b/src/lib/evloop/compat_libevent.c
@@ -130,7 +130,7 @@ rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg)
/** Initialize the Libevent library and set up the event base. */
void
-tor_libevent_initialize(tor_libevent_cfg *torcfg)
+tor_libevent_initialize(tor_libevent_cfg_t *torcfg)
{
tor_assert(the_event_base == NULL);
/* some paths below don't use torcfg, so avoid unused variable warnings */
@@ -181,6 +181,16 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
event_get_version(), tor_libevent_get_method());
}
+/**
+ * Return true iff the libevent module has been successfully initialized,
+ * and not subsequently shut down.
+ **/
+bool
+tor_libevent_is_initialized(void)
+{
+ return the_event_base != NULL;
+}
+
/** Return the current Libevent event base that we're set up to use. */
MOCK_IMPL(struct event_base *,
tor_libevent_get_base, (void))
diff --git a/src/lib/evloop/compat_libevent.h b/src/lib/evloop/compat_libevent.h
index afe887a013..f563d292f4 100644
--- a/src/lib/evloop/compat_libevent.h
+++ b/src/lib/evloop/compat_libevent.h
@@ -13,6 +13,8 @@
#include "lib/testsupport/testsupport.h"
#include "lib/malloc/malloc.h"
+#include <stdbool.h>
+
void configure_libevent_logging(void);
void suppress_libevent_log_msg(const char *msg);
@@ -59,15 +61,16 @@ void mainloop_event_free_(mainloop_event_t *event);
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
-typedef struct tor_libevent_cfg {
+typedef struct tor_libevent_cfg_t {
/** How many CPUs should we use (not currently useful). */
int num_cpus;
/** How many milliseconds should we allow between updating bandwidth limits?
* (Not currently useful). */
int msec_per_tick;
-} tor_libevent_cfg;
+} tor_libevent_cfg_t;
-void tor_libevent_initialize(tor_libevent_cfg *cfg);
+void tor_libevent_initialize(tor_libevent_cfg_t *cfg);
+bool tor_libevent_is_initialized(void);
MOCK_DECL(struct event_base *, tor_libevent_get_base, (void));
const char *tor_libevent_get_method(void);
void tor_check_libevent_header_compatibility(void);
diff --git a/src/lib/evloop/lib_evloop.md b/src/lib/evloop/lib_evloop.md
new file mode 100644
index 0000000000..830be88148
--- /dev/null
+++ b/src/lib/evloop/lib_evloop.md
@@ -0,0 +1,7 @@
+@dir /lib/evloop
+@brief lib/evloop: Low-level event loop.
+
+This modules has tools to manage the [libevent](https://libevent.org/) event
+loop and related functionality, in order to implement asynchronous
+networking, timers, periodic events, and other scheduling tasks.
+
diff --git a/src/lib/evloop/time_periodic.md b/src/lib/evloop/time_periodic.md
new file mode 100644
index 0000000000..8b3589d9db
--- /dev/null
+++ b/src/lib/evloop/time_periodic.md
@@ -0,0 +1,76 @@
+
+@page time_periodic Time and periodic events in Tor
+
+### What time is it? ###
+
+We have several notions of the current time in Tor.
+
+The *wallclock time* is available from time(NULL) with
+second-granularity and tor_gettimeofday() with microsecond
+granularity. It corresponds most closely to "the current time and date".
+
+The *monotonic time* is available with the set of monotime_\*
+functions declared in compat_time.h. Unlike the wallclock time, it
+can only move forward. It does not necessarily correspond to a real
+world time, and it is not portable between systems.
+
+The *coarse monotonic time* is available from the set of
+monotime_coarse_\* functions in compat_time.h. It is the same as
+monotime_\* on some platforms. On others, it gives a monotonic timer
+with less precision, but which it's more efficient to access.
+
+### Cached views of time. ###
+
+On some systems (like Linux), many time functions use a VDSO to avoid
+the overhead of a system call. But on other systems, gettimeofday()
+and time() can be costly enough that you wouldn't want to call them
+tens of thousands of times. To get a recent, but not especially
+accurate, view of the current time, see approx_time() and
+tor_gettimeofday_cached().
+
+
+### Parsing and encoding time values ###
+
+Tor has functions to parse and format time in these formats:
+
+ - RFC1123 format. ("Fri, 29 Sep 2006 15:54:20 GMT"). For this,
+ use format_rfc1123_time() and parse_rfc1123_time.
+
+ - ISO8601 format. ("2006-10-29 10:57:20") For this, use
+ format_local_iso_time() and format_iso_time(). We also support the
+ variant format "2006-10-29T10:57:20" with format_iso_time_nospace(), and
+ "2006-10-29T10:57:20.123456" with format_iso_time_nospace_usec().
+
+ - HTTP format collections (preferably "Mon, 25 Jul 2016 04:01:11
+ GMT" or possibly "Wed Jun 30 21:49:08 1993" or even "25-Jul-16
+ 04:01:11 GMT"). For this, use parse_http_time(). Don't generate anything
+ but the first format.
+
+Some of these functions use struct tm. You can use the standard
+tor_localtime_r() and tor_gmtime_r() to wrap these in a safe way. We
+also have a tor_timegm() function.
+
+### Scheduling events ###
+
+The main way to schedule a not-too-frequent periodic event with
+respect to the Tor mainloop is via the mechanism in periodic.c.
+There's a big table of periodic_events in mainloop.c, each of which gets
+invoked on its own schedule. You should not expect more than about
+one second of accuracy with these timers.
+
+You can create an independent timer using libevent directly, or using
+the periodic_timer_new() function. But you should avoid doing this
+for per-connection or per-circuit timers: Libevent's internal timer
+implementation uses a min-heap, and those tend to start scaling poorly
+once you have a few thousand entries.
+
+If you need to create a large number of fine-grained timers for some
+purpose, you should consider the mechanism in src/common/timers.c,
+which is optimized for the case where you have a large number of
+timers with not-too-long duration, many of which will be deleted
+before they actually expire. These timers should be reasonably
+accurate within a handful of milliseconds -- possibly better on some
+platforms. (The timers.c module uses William Ahern's timeout.c
+implementation as its backend, which is based on a hierarchical timing
+wheel algorithm. It's cool stuff; check it out.)
+
diff --git a/src/lib/evloop/timers.c b/src/lib/evloop/timers.c
index 4b2a96ef7d..496434d4ac 100644
--- a/src/lib/evloop/timers.c
+++ b/src/lib/evloop/timers.c
@@ -48,7 +48,7 @@
#include <winsock2.h>
#endif
-struct timeout_cb {
+struct timeout_cb_t {
timer_cb_fn_t cb;
void *arg;
};
@@ -56,19 +56,21 @@ struct timeout_cb {
/*
* These definitions are for timeouts.c and timeouts.h.
*/
-#ifdef __GNUC__
+#ifdef COCCI
+#define TIMEOUT_PUBLIC
+#elif defined(__GNUC__)
/* We're not exposing any of the functions outside this file. */
#define TIMEOUT_PUBLIC __attribute__((__unused__)) static
#else
/* We're not exposing any of the functions outside this file. */
#define TIMEOUT_PUBLIC static
-#endif /* defined(__GNUC__) */
+#endif /* defined(COCCI) || ... */
/* We're not using periodic events. */
#define TIMEOUT_DISABLE_INTERVALS
/* We always know the global_timeouts object, so we don't need each timeout
* to keep a pointer to it. */
#define TIMEOUT_DISABLE_RELATIVE_ACCESS
-/* We're providing our own struct timeout_cb. */
+/* We're providing our own struct timeout_cb_t. */
#define TIMEOUT_CB_OVERRIDE
/* We're going to support timers that are pretty far out in advance. Making
* this big can be inefficient, but having a significant number of timers
diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
index 015b694290..603dddd5a3 100644
--- a/src/lib/evloop/workqueue.c
+++ b/src/lib/evloop/workqueue.c
@@ -44,13 +44,13 @@
#define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW
#define WORKQUEUE_N_PRIORITIES (((int) WORKQUEUE_PRIORITY_LAST)+1)
-TOR_TAILQ_HEAD(work_tailq_t, workqueue_entry_s);
+TOR_TAILQ_HEAD(work_tailq_t, workqueue_entry_t);
typedef struct work_tailq_t work_tailq_t;
-struct threadpool_s {
+struct threadpool_t {
/** An array of pointers to workerthread_t: one for each running worker
* thread. */
- struct workerthread_s **threads;
+ struct workerthread_t **threads;
/** Condition variable that we wait on when we have no work, and which
* gets signaled when our queue becomes nonempty. */
@@ -92,14 +92,14 @@ struct threadpool_s {
/** Number of bits needed to hold all legal values of workqueue_priority_t */
#define WORKQUEUE_PRIORITY_BITS 2
-struct workqueue_entry_s {
+struct workqueue_entry_t {
/** The next workqueue_entry_t that's pending on the same thread or
* reply queue. */
- TOR_TAILQ_ENTRY(workqueue_entry_s) next_work;
+ TOR_TAILQ_ENTRY(workqueue_entry_t) next_work;
/** The threadpool to which this workqueue_entry_t was assigned. This field
* is set when the workqueue_entry_t is created, and won't be cleared until
* after it's handled in the main thread. */
- struct threadpool_s *on_pool;
+ struct threadpool_t *on_pool;
/** True iff this entry is waiting for a worker to start processing it. */
uint8_t pending;
/** Priority of this entry. */
@@ -112,22 +112,22 @@ struct workqueue_entry_s {
void *arg;
};
-struct replyqueue_s {
+struct replyqueue_t {
/** Mutex to protect the answers field */
tor_mutex_t lock;
/** Doubly-linked list of answers that the reply queue needs to handle. */
- TOR_TAILQ_HEAD(, workqueue_entry_s) answers;
+ TOR_TAILQ_HEAD(, workqueue_entry_t) answers;
/** Mechanism to wake up the main thread when it is receiving answers. */
alert_sockets_t alert;
};
/** A worker thread represents a single thread in a thread pool. */
-typedef struct workerthread_s {
+typedef struct workerthread_t {
/** Which thread it this? In range 0..in_pool->n_threads-1 */
int index;
/** The pool this thread is a part of. */
- struct threadpool_s *in_pool;
+ struct threadpool_t *in_pool;
/** User-supplied state field that we pass to the worker functions of each
* work item. */
void *state;
diff --git a/src/lib/evloop/workqueue.h b/src/lib/evloop/workqueue.h
index d0ee8f2be2..ae07eeafaa 100644
--- a/src/lib/evloop/workqueue.h
+++ b/src/lib/evloop/workqueue.h
@@ -13,12 +13,12 @@
/** A replyqueue is used to tell the main thread about the outcome of
* work that we queued for the workers. */
-typedef struct replyqueue_s replyqueue_t;
+typedef struct replyqueue_t replyqueue_t;
/** A thread-pool manages starting threads and passing work to them. */
-typedef struct threadpool_s threadpool_t;
+typedef struct threadpool_t threadpool_t;
/** A workqueue entry represents a request that has been passed to a thread
* pool. */
-typedef struct workqueue_entry_s workqueue_entry_t;
+typedef struct workqueue_entry_t workqueue_entry_t;
/** Possible return value from a work function: */
typedef enum workqueue_reply_t {
diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c
index 078af6a9ba..bfda26a430 100644
--- a/src/lib/fdio/fdio.c
+++ b/src/lib/fdio/fdio.c
@@ -28,9 +28,10 @@
#include <stdlib.h>
#include <stdio.h>
-/** @{ */
-/** Some old versions of Unix didn't define constants for these values,
+/* Some old versions of Unix didn't define constants for these values,
* and instead expect you to say 0, 1, or 2. */
+
+/** @cond */
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
@@ -40,7 +41,7 @@
#ifndef SEEK_END
#define SEEK_END 2
#endif
-/** @} */
+/** @endcond */
/** Return the position of <b>fd</b> with respect to the start of the file. */
off_t
diff --git a/src/lib/fdio/lib_fdio.md b/src/lib/fdio/lib_fdio.md
new file mode 100644
index 0000000000..9fe4b4d2be
--- /dev/null
+++ b/src/lib/fdio/lib_fdio.md
@@ -0,0 +1,5 @@
+@dir /lib/fdio
+@brief lib/fdio: Code to read/write on file descriptors.
+
+(This module also handles sockets, on platforms where a socket is not a kind
+of fd.)
diff --git a/src/lib/fs/lib_fs.md b/src/lib/fs/lib_fs.md
new file mode 100644
index 0000000000..3b5b0ac7d5
--- /dev/null
+++ b/src/lib/fs/lib_fs.md
@@ -0,0 +1,9 @@
+@dir /lib/fs
+@brief lib/fs: Files, filenames, directories, etc.
+
+This module is mostly a set of compatibility wrappers around
+operating-system-specific filesystem access.
+
+It also contains a set of convenience functions for safely writing to files,
+creating directories, and so on.
+
diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c
index f71c0cff7a..9d50a476bd 100644
--- a/src/lib/fs/mmap.c
+++ b/src/lib/fs/mmap.c
@@ -42,8 +42,8 @@
* failure, return NULL. Sets errno properly, using ERANGE to mean
* "empty file". Must only be called on trusted Tor-owned files, as changing
* the underlying file's size causes unspecified behavior. */
-tor_mmap_t *
-tor_mmap_file(const char *filename)
+MOCK_IMPL(tor_mmap_t *,
+tor_mmap_file,(const char *filename))
{
int fd; /* router file */
char *string;
@@ -111,8 +111,8 @@ tor_mmap_file(const char *filename)
}
/** Release storage held for a memory mapping; returns 0 on success,
* or -1 on failure (and logs a warning). */
-int
-tor_munmap_file(tor_mmap_t *handle)
+MOCK_IMPL(int,
+tor_munmap_file,(tor_mmap_t *handle))
{
int res;
@@ -132,8 +132,8 @@ tor_munmap_file(tor_mmap_t *handle)
return res;
}
#elif defined(_WIN32)
-tor_mmap_t *
-tor_mmap_file(const char *filename)
+MOCK_IMPL(tor_mmap_t *,
+tor_mmap_file,(const char *filename))
{
TCHAR tfilename[MAX_PATH]= {0};
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
@@ -213,8 +213,8 @@ tor_mmap_file(const char *filename)
}
/* Unmap the file, and return 0 for success or -1 for failure */
-int
-tor_munmap_file(tor_mmap_t *handle)
+MOCK_IMPL(int,
+tor_munmap_file,(tor_mmap_t *handle))
{
if (handle == NULL)
return 0;
diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h
index 61aad544b2..beb0535109 100644
--- a/src/lib/fs/mmap.h
+++ b/src/lib/fs/mmap.h
@@ -13,6 +13,7 @@
#define TOR_MMAP_H
#include "lib/cc/compat_compiler.h"
+#include "lib/testsupport/testsupport.h"
#include <stddef.h>
#ifdef _WIN32
@@ -35,7 +36,7 @@ typedef struct tor_mmap_t {
} tor_mmap_t;
-tor_mmap_t *tor_mmap_file(const char *filename);
-int tor_munmap_file(tor_mmap_t *handle);
+MOCK_DECL(tor_mmap_t *, tor_mmap_file, (const char *filename));
+MOCK_DECL(int, tor_munmap_file, (tor_mmap_t *handle));
#endif /* !defined(TOR_MMAP_H) */
diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c
index 28dde62aea..9f297d98e8 100644
--- a/src/lib/fs/path.c
+++ b/src/lib/fs/path.c
@@ -255,9 +255,10 @@ alloc_getcwd(void)
#endif /* !defined(_WIN32) */
/** Expand possibly relative path <b>fname</b> to an absolute path.
- * Return a newly allocated string, possibly equal to <b>fname</b>. */
+ * Return a newly allocated string, which may be a duplicate of <b>fname</b>.
+ */
char *
-make_path_absolute(char *fname)
+make_path_absolute(const char *fname)
{
#ifdef _WIN32
char *absfname_malloced = _fullpath(NULL, fname, 1);
diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h
index 28a1838b88..0c2a574941 100644
--- a/src/lib/fs/path.h
+++ b/src/lib/fs/path.h
@@ -25,6 +25,6 @@ char *expand_filename(const char *filename);
int path_is_relative(const char *filename);
void clean_fname_for_stat(char *name);
int get_parent_directory(char *fname);
-char *make_path_absolute(char *fname);
+char *make_path_absolute(const char *fname);
#endif /* !defined(TOR_PATH_H) */
diff --git a/src/lib/fs/storagedir.h b/src/lib/fs/storagedir.h
index 7e6633a0bb..f28d13ddb7 100644
--- a/src/lib/fs/storagedir.h
+++ b/src/lib/fs/storagedir.h
@@ -15,7 +15,7 @@
typedef struct storage_dir_t storage_dir_t;
struct config_line_t;
-struct sandbox_cfg_elem;
+struct sandbox_cfg_elem_t;
struct tor_mmap_t;
struct smartlist_t;
@@ -25,7 +25,7 @@ void storage_dir_free_(storage_dir_t *d);
FREE_AND_NULL(storage_dir_t, storage_dir_free_, (d))
int storage_dir_register_with_sandbox(storage_dir_t *d,
- struct sandbox_cfg_elem **cfg);
+ struct sandbox_cfg_elem_t **cfg);
const struct smartlist_t *storage_dir_list(storage_dir_t *d);
uint64_t storage_dir_get_usage(storage_dir_t *d);
struct tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname);
diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h
index a24a1c4c0d..e6d7d77e7e 100644
--- a/src/lib/geoip/country.h
+++ b/src/lib/geoip/country.h
@@ -4,6 +4,11 @@
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file country.h
+ * @brief Country type for geoip.
+ **/
+
#ifndef TOR_COUNTRY_H
#define TOR_COUNTRY_H
@@ -11,6 +16,7 @@
/** A signed integer representing a country code. */
typedef int16_t country_t;
+/** Maximum value for country_t. */
#define COUNTRY_MAX INT16_MAX
#endif /* !defined(TOR_COUNTRY_H) */
diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c
index 70b1c2dc8c..2e0be13c04 100644
--- a/src/lib/geoip/geoip.c
+++ b/src/lib/geoip/geoip.c
@@ -70,12 +70,18 @@ static smartlist_t *geoip_countries = NULL;
* The index is encoded in the pointer, and 1 is added so that NULL can mean
* not found. */
static strmap_t *country_idxplus1_by_lc_code = NULL;
-/** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted
- * by their respective ip_low. */
-static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL;
-
-/** SHA1 digest of the GeoIP files to include in extra-info descriptors. */
+/** List of all known geoip_ipv4_entry_t sorted
+ * by their respective ip_low values. */
+static smartlist_t *geoip_ipv4_entries = NULL;
+/** List of all known geoip_ipv6_entry_t, sorted by their respective
+ * ip_low values. */
+static smartlist_t *geoip_ipv6_entries = NULL;
+
+/** SHA1 digest of the IPv4 GeoIP file to include in extra-info
+ * descriptors. */
static char geoip_digest[DIGEST_LEN];
+/** SHA1 digest of the IPv6 GeoIP file to include in extra-info
+ * descriptors. */
static char geoip6_digest[DIGEST_LEN];
/** Return a list of geoip_country_t for all known countries. */
diff --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h
index f872ebd25f..1407d0a1ea 100644
--- a/src/lib/geoip/geoip.h
+++ b/src/lib/geoip/geoip.h
@@ -31,6 +31,7 @@ int geoip_get_country_by_ipv6(const struct in6_addr *addr);
/** A per-country GeoIP record. */
typedef struct geoip_country_t {
+ /** A nul-terminated two-letter country-code. */
char countrycode[3];
} geoip_country_t;
diff --git a/src/lib/geoip/lib_geoip.md b/src/lib/geoip/lib_geoip.md
new file mode 100644
index 0000000000..a3ee39d574
--- /dev/null
+++ b/src/lib/geoip/lib_geoip.md
@@ -0,0 +1,3 @@
+@dir /lib/geoip
+@brief lib/geoip: IP-to-country mapping
+
diff --git a/src/lib/intmath/lib_intmath.md b/src/lib/intmath/lib_intmath.md
new file mode 100644
index 0000000000..4446b715cb
--- /dev/null
+++ b/src/lib/intmath/lib_intmath.md
@@ -0,0 +1,2 @@
+@dir /lib/intmath
+@brief lib/intmath: Integer mathematics.
diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c
index 6a292db7ba..bde1567cb3 100644
--- a/src/lib/intmath/muldiv.c
+++ b/src/lib/intmath/muldiv.c
@@ -69,6 +69,20 @@ gcd64(uint64_t a, uint64_t b)
return a;
}
+/** Return the unsigned integer product of <b>a</b> and <b>b</b>. If overflow
+ * is detected, return UINT64_MAX instead. */
+uint64_t
+tor_mul_u64_nowrap(uint64_t a, uint64_t b)
+{
+ if (a == 0 || b == 0) {
+ return 0;
+ } else if (PREDICT_UNLIKELY(UINT64_MAX / a < b)) {
+ return UINT64_MAX;
+ } else {
+ return a*b;
+ }
+}
+
/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it.
* Requires that the denominator is greater than 0. */
void
diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h
index 64500b6dce..7aa0f9b235 100644
--- a/src/lib/intmath/muldiv.h
+++ b/src/lib/intmath/muldiv.h
@@ -18,6 +18,8 @@ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
+uint64_t tor_mul_u64_nowrap(uint64_t a, uint64_t b);
+
void simplify_fraction64(uint64_t *numer, uint64_t *denom);
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b>
diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h
index 40941e59b2..d583c8f79b 100644
--- a/src/lib/intmath/weakrng.h
+++ b/src/lib/intmath/weakrng.h
@@ -19,8 +19,11 @@ typedef struct tor_weak_rng_t {
uint32_t state;
} tor_weak_rng_t;
+#ifndef COCCI
#define TOR_WEAK_RNG_INIT {383745623}
+#endif
#define TOR_WEAK_RANDOM_MAX (INT_MAX)
+
void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed);
int32_t tor_weak_random(tor_weak_rng_t *weak_rng);
int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
diff --git a/src/lib/lib.md b/src/lib/lib.md
new file mode 100644
index 0000000000..4f77a4c1d0
--- /dev/null
+++ b/src/lib/lib.md
@@ -0,0 +1,131 @@
+@dir /lib
+@brief lib: low-level functionality.
+
+The "lib" directory contains low-level functionality. In general, this
+code is not necessarily Tor-specific, but is instead possibly useful for
+other applications.
+
+The modules in `lib` are currently well-factored: each one depends
+only on lower-level modules. You can see an up-to-date list of the
+modules, sorted from lowest to highest level, by running
+`./scripts/maint/practracker/includes.py --toposort`.
+
+As of this writing, the library modules are (from lowest to highest
+level):
+
+ - \refdir{lib/cc} -- Macros for managing the C compiler and
+ language.
+
+ - \refdir{lib/version} -- Holds the current version of Tor.
+
+ - \refdir{lib/testsupport} -- Helpers for making
+ test-only code, and test mocking support.
+
+ - \refdir{lib/defs} -- Lowest-level constants.
+
+ - \refdir{lib/subsys} -- Types used for declaring a
+ "subsystem". (_A subsystem is a module with support for initialization,
+ shutdown, configuration, and so on._)
+
+ - \refdir{lib/conf} -- For declaring configuration options.
+
+ - \refdir{lib/arch} -- For handling differences in CPU
+ architecture.
+
+ - \refdir{lib/err} -- Lowest-level error handling code.
+
+ - \refdir{lib/malloc} -- Memory management.
+ management.
+
+ - \refdir{lib/intmath} -- Integer mathematics.
+
+ - \refdir{lib/fdio} -- For
+ reading and writing n file descriptors.
+
+ - \refdir{lib/lock} -- Simple locking support.
+ (_Lower-level than the rest of the threading code._)
+
+ - \refdir{lib/ctime} -- Constant-time code to avoid
+ side-channels.
+
+ - \refdir{lib/string} -- Low-level string manipulation.
+
+ - \refdir{lib/wallclock} --
+ For inspecting and manipulating the current (UTC) time.
+
+ - \refdir{lib/osinfo} -- For inspecting the OS version
+ and capabilities.
+
+ - \refdir{lib/smartlist_core} -- The bare-bones
+ pieces of our dynamic array ("smartlist") implementation.
+
+ - \refdir{lib/log} -- Log messages to files, syslogs, etc.
+
+ - \refdir{lib/container} -- General purpose containers,
+ including dynamic arrays ("smartlists"), hashtables, bit arrays,
+ etc.
+
+ - \refdir{lib/trace} -- A general-purpose API
+ function-tracing functionality Tor. (_Currently not much used._)
+
+ - \refdir{lib/thread} -- Mid-level Threading.
+
+ - \refdir{lib/term} -- Terminal manipulation
+ (like reading a password from the user).
+
+ - \refdir{lib/memarea} -- A fast
+ "arena" style allocator, where the data is freed all at once.
+
+ - \refdir{lib/encoding} -- Encoding
+ data in various formats, datatypes, and transformations.
+
+ - \refdir{lib/dispatch} -- A general-purpose in-process
+ message delivery system.
+
+ - \refdir{lib/sandbox} -- Our Linux seccomp2 sandbox
+ implementation.
+
+ - \refdir{lib/pubsub} -- A publish/subscribe message passing system.
+
+ - \refdir{lib/fs} -- Files, filenames, directories, etc.
+
+ - \refdir{lib/confmgt} -- Parse, encode, and manipulate onfiguration files.
+
+ - \refdir{lib/crypt_ops} -- Cryptographic operations.
+
+ - \refdir{lib/meminfo} -- Functions for inspecting our
+ memory usage, if the malloc implementation exposes that to us.
+
+ - \refdir{lib/time} -- Higher level time functions, including
+ fine-gained and monotonic timers.
+
+ - \refdir{lib/math} -- Floating-point mathematical utilities.
+
+ - \refdir{lib/buf} -- An efficient byte queue.
+
+ - \refdir{lib/net} -- Networking code, including address
+ manipulation, compatibility wrappers, etc.
+
+ - \refdir{lib/compress} -- Wraps several compression libraries.
+
+ - \refdir{lib/geoip} -- IP-to-country mapping.
+
+ - \refdir{lib/tls} -- TLS library wrappers.
+
+ - \refdir{lib/evloop} -- Low-level event-loop.
+
+ - \refdir{lib/process} -- Launch and manage subprocesses.
+
+### What belongs in lib?
+
+In general, if you can imagine some program wanting the functionality
+you're writing, even if that program had nothing to do with Tor, your
+functionality belongs in lib.
+
+If it falls into one of the existing "lib" categories, your
+functionality belongs in lib.
+
+If you are using platform-specific `ifdef`s to manage compatibility
+issues among platforms, you should probably consider whether you can
+put your code into lib.
+
diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h
index e0c3d7cb78..6fd4c1eb08 100644
--- a/src/lib/lock/compat_mutex.h
+++ b/src/lib/lock/compat_mutex.h
@@ -58,6 +58,11 @@ void tor_mutex_init_nonrecursive(tor_mutex_t *m);
void tor_mutex_acquire(tor_mutex_t *m);
void tor_mutex_release(tor_mutex_t *m);
void tor_mutex_free_(tor_mutex_t *m);
+/**
+ * @copydoc tor_mutex_free_
+ *
+ * Additionally, set the pointer <b>m</b> to NULL.
+ **/
#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m))
void tor_mutex_uninit(tor_mutex_t *m);
diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c
index f82ad9f0e8..a7f5986ecb 100644
--- a/src/lib/lock/compat_mutex_pthreads.c
+++ b/src/lib/lock/compat_mutex_pthreads.c
@@ -17,8 +17,14 @@
* "recursive" mutexes (i.e., once we can re-lock if we're already holding
* them.) */
static pthread_mutexattr_t attr_recursive;
+/**
+ * True iff <b>attr_recursive</b> has been initialized.
+ **/
static int attr_initialized = 0;
+/**
+ * Initialize the locking module, if it is not already initialized.
+ **/
void
tor_locking_init(void)
{
diff --git a/src/lib/lock/lib_lock.md b/src/lib/lock/lib_lock.md
new file mode 100644
index 0000000000..6f6727bfc2
--- /dev/null
+++ b/src/lib/lock/lib_lock.md
@@ -0,0 +1,6 @@
+@dir /lib/lock
+@brief lib/lock: Simple locking support.
+
+This module is more low-level than the rest of the threading code, since it
+is needed by more intermediate-level modules.
+
diff --git a/src/lib/log/lib_log.md b/src/lib/log/lib_log.md
new file mode 100644
index 0000000000..8740d6a02f
--- /dev/null
+++ b/src/lib/log/lib_log.md
@@ -0,0 +1,10 @@
+@dir /lib/log
+@brief lib/log: Log messages to files, syslogs, etc.
+
+You can think of this as the logical "midpoint" of the
+\refdir{lib} code": much of the higher-level code is higher-level
+_because_ it uses the logging module, and much of the lower-level code is
+specifically written to avoid having to log, because the logging module
+depends on it.
+
+
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index 83f04a3467..cb92ef07ef 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -276,8 +276,8 @@ static int log_time_granularity = 1;
/** Define log time granularity for all logs to be <b>granularity_msec</b>
* milliseconds. */
-void
-set_log_time_granularity(int granularity_msec)
+MOCK_IMPL(void,
+set_log_time_granularity,(int granularity_msec))
{
log_time_granularity = granularity_msec;
tor_log_sigsafe_err_set_granularity(granularity_msec);
@@ -523,7 +523,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
* pass them, and some very old ones do not detect overflow so well.
* Regrettably, they call their maximum line length MAXLINE. */
#if MAXLINE < 64
-#warn "MAXLINE is a very low number; it might not be from syslog.h after all"
+#warning "MAXLINE is a very low number; it might not be from syslog.h."
#endif
char *m = msg_after_prefix;
if (msg_len >= MAXLINE)
@@ -937,9 +937,9 @@ set_log_severity_config(int loglevelMin, int loglevelMax,
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
* to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
-static void
-add_stream_log_impl(const log_severity_list_t *severity,
- const char *name, int fd)
+MOCK_IMPL(STATIC void,
+add_stream_log_impl,(const log_severity_list_t *severity,
+ const char *name, int fd))
{
logfile_t *lf;
lf = tor_malloc_zero(sizeof(logfile_t));
@@ -995,18 +995,16 @@ logs_set_domain_logging(int enabled)
UNLOCK_LOGS();
}
-/** Add a log handler to receive messages during startup (before the real
- * logs are initialized).
+/** Add a log handler to accept messages when no other log is configured.
*/
void
-add_temp_log(int min_severity)
+add_default_log(int min_severity)
{
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
set_log_severity_config(min_severity, LOG_ERR, s);
LOCK_LOGS();
- add_stream_log_impl(s, "<temp>", fileno(stdout));
+ add_stream_log_impl(s, "<default>", fileno(stdout));
tor_free(s);
- logfiles->is_temporary = 1;
UNLOCK_LOGS();
}
@@ -1149,8 +1147,7 @@ flush_log_messages_from_startup(void)
UNLOCK_LOGS();
}
-/** Close any log handlers added by add_temp_log() or marked by
- * mark_logs_temp(). */
+/** Close any log handlers marked by mark_logs_temp(). */
void
close_temp_logs(void)
{
@@ -1202,10 +1199,10 @@ mark_logs_temp(void)
* opening the logfile failed, -1 is returned and errno is set appropriately
* (by open(2)). Takes ownership of fd.
*/
-int
-add_file_log(const log_severity_list_t *severity,
- const char *filename,
- int fd)
+MOCK_IMPL(int,
+add_file_log,(const log_severity_list_t *severity,
+ const char *filename,
+ int fd))
{
logfile_t *lf;
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index 8e36012616..5cf8a36cf7 100644
--- a/src/lib/log/log.h
+++ b/src/lib/log/log.h
@@ -23,9 +23,11 @@
#include <syslog.h>
#define LOG_WARN LOG_WARNING
#if LOG_DEBUG < LOG_ERR
+#ifndef COCCI
#error "Your syslog.h thinks high numbers are more important. " \
"We aren't prepared to deal with that."
#endif
+#endif /* LOG_DEBUG < LOG_ERR */
#else /* !defined(HAVE_SYSLOG_H) */
/* Note: Syslog's logging code refers to priorities, with 0 being the most
* important. Thus, all our comparisons needed to be reversed when we added
@@ -163,11 +165,11 @@ int parse_log_severity_config(const char **cfg,
log_severity_list_t *severity_out);
void set_log_severity_config(int minSeverity, int maxSeverity,
log_severity_list_t *severity_out);
-void add_stream_log(const log_severity_list_t *severity, const char *name,
- int fd);
-int add_file_log(const log_severity_list_t *severity,
- const char *filename,
- int fd);
+void add_stream_log(const log_severity_list_t *severity,
+ const char *name, int fd);
+MOCK_DECL(int, add_file_log,(const log_severity_list_t *severity,
+ const char *filename,
+ int fd));
#ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity,
@@ -185,7 +187,7 @@ 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 add_default_log(int min_severity);
void close_temp_logs(void);
void rollback_log_changes(void);
void mark_logs_temp(void);
@@ -194,7 +196,7 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
void flush_pending_log_callbacks(void);
void flush_log_messages_from_startup(void);
void log_set_application_name(const char *name);
-void set_log_time_granularity(int granularity_msec);
+MOCK_DECL(void, set_log_time_granularity,(int granularity_msec));
void truncate_logs(void);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
@@ -306,7 +308,9 @@ extern const log_domain_mask_t LD_GENERAL_;
MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format,
va_list ap) CHECK_PRINTF(5,0));
-#endif
+MOCK_DECL(STATIC void, add_stream_log_impl,(
+ const log_severity_list_t *severity, const char *name, int fd));
+#endif /* defined(LOG_PRIVATE) */
#if defined(LOG_PRIVATE) || defined(TOR_UNIT_TESTS)
/** Given a severity, yields an index into log_severity_list_t.masks to use
diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h
index 1db54ba726..64f52df666 100644
--- a/src/lib/log/ratelim.h
+++ b/src/lib/log/ratelim.h
@@ -45,7 +45,9 @@ typedef struct ratelim_t {
int n_calls_since_last_time;
} ratelim_t;
+#ifndef COCCI
#define RATELIM_INIT(r) { (r), 0, 0 }
+#endif
#define RATELIM_TOOMANY (16*1000*1000)
char *rate_limit_log(ratelim_t *lim, time_t now);
diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h
index c3141754de..b7dcefcd96 100644
--- a/src/lib/log/util_bug.h
+++ b/src/lib/log/util_bug.h
@@ -131,7 +131,9 @@
#undef BUG
// Coverity defines this in global headers; let's override it. This is a
// magic coverity-only preprocessor thing.
+#ifndef COCCI
#nodef BUG(x) (x)
+#endif
#endif /* defined(__COVERITY__) */
#if defined(__COVERITY__) || defined(__clang_analyzer__)
@@ -200,6 +202,7 @@
: 0)
#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
+#ifndef COCCI
#ifdef __GNUC__
#define IF_BUG_ONCE__(cond,var) \
if (( { \
@@ -208,7 +211,7 @@
if (bool_result && !var) { \
var = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1, NULL); \
+ ("!("#cond")"), 1, NULL); \
} \
bool_result; } ))
#else /* !defined(__GNUC__) */
@@ -218,10 +221,12 @@
(var ? 1 : \
(var=1, \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
- "!("#cond")", 1, NULL), \
+ ("!("#cond")"), 1, NULL), \
1)) \
: 0)
#endif /* defined(__GNUC__) */
+#endif /* !defined(COCCI) */
+
#define IF_BUG_ONCE_VARNAME_(a) \
warning_logged_on_ ## a ## __
#define IF_BUG_ONCE_VARNAME__(a) \
@@ -242,10 +247,12 @@
void tor_assertion_failed_(const char *fname, unsigned int line,
const char *func, const char *expr,
- const char *fmt, ...);
+ const char *fmt, ...)
+ CHECK_PRINTF(5,6);
void tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
- int once, const char *fmt, ...);
+ int once, const char *fmt, ...)
+ CHECK_PRINTF(6,7);
void tor_abort_(void) ATTR_NORETURN;
diff --git a/src/lib/malloc/lib_malloc.md b/src/lib/malloc/lib_malloc.md
new file mode 100644
index 0000000000..ff61722f02
--- /dev/null
+++ b/src/lib/malloc/lib_malloc.md
@@ -0,0 +1,76 @@
+@dir /lib/malloc
+@brief lib/malloc: Wrappers and utilities for memory management.
+
+
+Tor imposes a few light wrappers over C's native malloc and free
+functions, to improve convenience, and to allow wholescale replacement
+of malloc and free as needed.
+
+You should never use 'malloc', 'calloc', 'realloc, or 'free' on their
+own; always use the variants prefixed with 'tor_'.
+They are the same as the standard C functions, with the following
+exceptions:
+
+ * `tor_free(NULL)` is a no-op.
+ * `tor_free()` is a macro that takes an lvalue as an argument and sets it to
+ NULL after freeing it. To avoid this behavior, you can use `tor_free_()`
+ instead.
+ * tor_malloc() and friends fail with an assertion if they are asked to
+ allocate a value so large that it is probably an underflow.
+ * It is always safe to `tor_malloc(0)`, regardless of whether your libc
+ allows it.
+ * `tor_malloc()`, `tor_realloc()`, and friends are never allowed to fail.
+ Instead, Tor will die with an assertion. This means that you never
+ need to check their return values. See the next subsection for
+ information on why we think this is a good idea.
+
+We define additional general-purpose memory allocation functions as well:
+
+ * `tor_malloc_zero(x)` behaves as `calloc(1, x)`, except the it makes clear
+ the intent to allocate a single zeroed-out value.
+ * `tor_reallocarray(x,y)` behaves as the OpenBSD reallocarray function.
+ Use it for cases when you need to realloc() in a multiplication-safe
+ way.
+
+And specific-purpose functions as well:
+
+ * `tor_strdup()` and `tor_strndup()` behaves as the underlying libc
+ functions, but use `tor_malloc()` instead of the underlying function.
+ * `tor_memdup()` copies a chunk of memory of a given size.
+ * `tor_memdup_nulterm()` copies a chunk of memory of a given size, then
+ NUL-terminates it just to be safe.
+
+#### Why assert on allocation failure?
+
+Why don't we allow `tor_malloc()` and its allies to return NULL?
+
+First, it's error-prone. Many programmers forget to check for NULL return
+values, and testing for `malloc()` failures is a major pain.
+
+Second, it's not necessarily a great way to handle OOM conditions. It's
+probably better (we think) to have a memory target where we dynamically free
+things ahead of time in order to stay under the target. Trying to respond to
+an OOM at the point of `tor_malloc()` failure, on the other hand, would involve
+a rare operation invoked from deep in the call stack. (Again, that's
+error-prone and hard to debug.)
+
+Third, thanks to the rise of Linux and other operating systems that allow
+memory to be overcommitted, you can't actually ever rely on getting a NULL
+from `malloc()` when you're out of memory; instead you have to use an approach
+closer to tracking the total memory usage.
+
+#### Conventions for your own allocation functions.
+
+Whenever you create a new type, the convention is to give it a pair of
+`x_new()` and `x_free_()` functions, named after the type.
+
+Calling `x_free(NULL)` should always be a no-op.
+
+There should additionally be an `x_free()` macro, defined in terms of
+`x_free_()`. This macro should set its lvalue to NULL. You can define it
+using the FREE_AND_NULL macro, as follows:
+
+```
+#define x_free(ptr) FREE_AND_NULL(x_t, x_free_, (ptr))
+```
+
diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c
index 9559cbe2d4..0e78521bd8 100644
--- a/src/lib/malloc/map_anon.c
+++ b/src/lib/malloc/map_anon.c
@@ -78,8 +78,8 @@
#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."
+#warning "minherit() is defined, but we couldn't find the right flag for it."
+#warning "This is probably a bug in Tor's support for this platform."
#endif
/**
diff --git a/src/lib/math/lib_math.md b/src/lib/math/lib_math.md
new file mode 100644
index 0000000000..9cc256d24b
--- /dev/null
+++ b/src/lib/math/lib_math.md
@@ -0,0 +1,6 @@
+@dir /lib/math
+@brief lib/math: Floating-point math utilities.
+
+This module includes a bunch of floating-point compatibility code, and
+implementations for several probability distributions.
+
diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index f9d65073ff..02dbc5de54 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -52,14 +52,15 @@
#include <math.h>
#include <stddef.h>
+#ifndef COCCI
/** 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) { \
+ const struct name##_t * \
+ dist_to_const_##name(const struct dist_t *obj) { \
tor_assert(obj->ops == &name##_ops); \
- return SUBTYPE_P(obj, struct name, base); \
+ return SUBTYPE_P(obj, struct name ## _t, base); \
}
DECLARE_PROB_DISTR_DOWNCAST_FN(uniform)
DECLARE_PROB_DISTR_DOWNCAST_FN(geometric)
@@ -67,6 +68,7 @@ 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)
+#endif /* !defined(COCCI) */
/**
* Count number of one bits in 32-bit word.
@@ -1324,42 +1326,42 @@ sample_geometric(uint32_t s, double p0, double p)
/** Returns the name of the distribution in <b>dist</b>. */
const char *
-dist_name(const struct dist *dist)
+dist_name(const struct dist_t *dist)
{
return dist->ops->name;
}
/* Sample a value from <b>dist</b> and return it. */
double
-dist_sample(const struct dist *dist)
+dist_sample(const struct dist_t *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)
+dist_cdf(const struct dist_t *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)
+dist_sf(const struct dist_t *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)
+dist_icdf(const struct dist_t *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)
+dist_isf(const struct dist_t *dist, double p)
{
return dist->ops->isf(dist, p);
}
@@ -1367,18 +1369,18 @@ dist_isf(const struct dist *dist, double p)
/** Functions for uniform distribution */
static double
-uniform_sample(const struct dist *dist)
+uniform_sample(const struct dist_t *dist)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
double p0 = random_uniform_01();
return sample_uniform_interval(p0, U->a, U->b);
}
static double
-uniform_cdf(const struct dist *dist, double x)
+uniform_cdf(const struct dist_t *dist, double x)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
if (x < U->a)
return 0;
else if (x < U->b)
@@ -1388,9 +1390,9 @@ uniform_cdf(const struct dist *dist, double x)
}
static double
-uniform_sf(const struct dist *dist, double x)
+uniform_sf(const struct dist_t *dist, double x)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *U = dist_to_const_uniform(dist);
if (x > U->b)
return 0;
@@ -1401,24 +1403,24 @@ uniform_sf(const struct dist *dist, double x)
}
static double
-uniform_icdf(const struct dist *dist, double p)
+uniform_icdf(const struct dist_t *dist, double p)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *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)));
}
static double
-uniform_isf(const struct dist *dist, double p)
+uniform_isf(const struct dist_t *dist, double p)
{
- const struct uniform *U = dist_to_const_uniform(dist);
+ const struct uniform_t *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)));
}
-const struct dist_ops uniform_ops = {
+const struct dist_ops_t uniform_ops = {
.name = "uniform",
.sample = uniform_sample,
.cdf = uniform_cdf,
@@ -1434,9 +1436,9 @@ const struct dist_ops uniform_ops = {
/** Functions for logistic distribution: */
static double
-logistic_sample(const struct dist *dist)
+logistic_sample(const struct dist_t *dist)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *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();
@@ -1445,34 +1447,34 @@ logistic_sample(const struct dist *dist)
}
static double
-logistic_cdf(const struct dist *dist, double x)
+logistic_cdf(const struct dist_t *dist, double x)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return cdf_logistic(x, L->mu, L->sigma);
}
static double
-logistic_sf(const struct dist *dist, double x)
+logistic_sf(const struct dist_t *dist, double x)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return sf_logistic(x, L->mu, L->sigma);
}
static double
-logistic_icdf(const struct dist *dist, double p)
+logistic_icdf(const struct dist_t *dist, double p)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return icdf_logistic(p, L->mu, L->sigma);
}
static double
-logistic_isf(const struct dist *dist, double p)
+logistic_isf(const struct dist_t *dist, double p)
{
- const struct logistic *L = dist_to_const_logistic(dist);
+ const struct logistic_t *L = dist_to_const_logistic(dist);
return isf_logistic(p, L->mu, L->sigma);
}
-const struct dist_ops logistic_ops = {
+const struct dist_ops_t logistic_ops = {
.name = "logistic",
.sample = logistic_sample,
.cdf = logistic_cdf,
@@ -1484,9 +1486,9 @@ const struct dist_ops logistic_ops = {
/** Functions for log-logistic distribution: */
static double
-log_logistic_sample(const struct dist *dist)
+log_logistic_sample(const struct dist_t *dist)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1494,34 +1496,34 @@ log_logistic_sample(const struct dist *dist)
}
static double
-log_logistic_cdf(const struct dist *dist, double x)
+log_logistic_cdf(const struct dist_t *dist, double x)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *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)
+log_logistic_sf(const struct dist_t *dist, double x)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *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)
+log_logistic_icdf(const struct dist_t *dist, double p)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *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)
+log_logistic_isf(const struct dist_t *dist, double p)
{
- const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+ const struct log_logistic_t *LL = dist_to_const_log_logistic(dist);
return isf_log_logistic(p, LL->alpha, LL->beta);
}
-const struct dist_ops log_logistic_ops = {
+const struct dist_ops_t log_logistic_ops = {
.name = "log logistic",
.sample = log_logistic_sample,
.cdf = log_logistic_cdf,
@@ -1533,9 +1535,9 @@ const struct dist_ops log_logistic_ops = {
/** Functions for Weibull distribution */
static double
-weibull_sample(const struct dist *dist)
+weibull_sample(const struct dist_t *dist)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1543,34 +1545,34 @@ weibull_sample(const struct dist *dist)
}
static double
-weibull_cdf(const struct dist *dist, double x)
+weibull_cdf(const struct dist_t *dist, double x)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return cdf_weibull(x, W->lambda, W->k);
}
static double
-weibull_sf(const struct dist *dist, double x)
+weibull_sf(const struct dist_t *dist, double x)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return sf_weibull(x, W->lambda, W->k);
}
static double
-weibull_icdf(const struct dist *dist, double p)
+weibull_icdf(const struct dist_t *dist, double p)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return icdf_weibull(p, W->lambda, W->k);
}
static double
-weibull_isf(const struct dist *dist, double p)
+weibull_isf(const struct dist_t *dist, double p)
{
- const struct weibull *W = dist_to_const_weibull(dist);
+ const struct weibull_t *W = dist_to_const_weibull(dist);
return isf_weibull(p, W->lambda, W->k);
}
-const struct dist_ops weibull_ops = {
+const struct dist_ops_t weibull_ops = {
.name = "Weibull",
.sample = weibull_sample,
.cdf = weibull_cdf,
@@ -1582,9 +1584,9 @@ const struct dist_ops weibull_ops = {
/** Functions for generalized Pareto distributions */
static double
-genpareto_sample(const struct dist *dist)
+genpareto_sample(const struct dist_t *dist)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1592,34 +1594,34 @@ genpareto_sample(const struct dist *dist)
}
static double
-genpareto_cdf(const struct dist *dist, double x)
+genpareto_cdf(const struct dist_t *dist, double x)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *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)
+genpareto_sf(const struct dist_t *dist, double x)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *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)
+genpareto_icdf(const struct dist_t *dist, double p)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *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)
+genpareto_isf(const struct dist_t *dist, double p)
{
- const struct genpareto *GP = dist_to_const_genpareto(dist);
+ const struct genpareto_t *GP = dist_to_const_genpareto(dist);
return isf_genpareto(p, GP->mu, GP->sigma, GP->xi);
}
-const struct dist_ops genpareto_ops = {
+const struct dist_ops_t genpareto_ops = {
.name = "generalized Pareto",
.sample = genpareto_sample,
.cdf = genpareto_cdf,
@@ -1631,9 +1633,9 @@ const struct dist_ops genpareto_ops = {
/** Functions for geometric distribution on number of trials before success */
static double
-geometric_sample(const struct dist *dist)
+geometric_sample(const struct dist_t *dist)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
double p0 = random_uniform_01();
@@ -1641,9 +1643,9 @@ geometric_sample(const struct dist *dist)
}
static double
-geometric_cdf(const struct dist *dist, double x)
+geometric_cdf(const struct dist_t *dist, double x)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1652,9 +1654,9 @@ geometric_cdf(const struct dist *dist, double x)
}
static double
-geometric_sf(const struct dist *dist, double x)
+geometric_sf(const struct dist_t *dist, double x)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
if (x < 1)
return 0;
@@ -1663,22 +1665,22 @@ geometric_sf(const struct dist *dist, double x)
}
static double
-geometric_icdf(const struct dist *dist, double p)
+geometric_icdf(const struct dist_t *dist, double p)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
return log1p(-p)/log1p(-G->p);
}
static double
-geometric_isf(const struct dist *dist, double p)
+geometric_isf(const struct dist_t *dist, double p)
{
- const struct geometric *G = dist_to_const_geometric(dist);
+ const struct geometric_t *G = dist_to_const_geometric(dist);
return log(p)/log1p(-G->p);
}
-const struct dist_ops geometric_ops = {
+const struct dist_ops_t geometric_ops = {
.name = "geometric (1-based)",
.sample = geometric_sample,
.cdf = geometric_cdf,
diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h
index a93d888950..a036073b93 100644
--- a/src/lib/math/prob_distr.h
+++ b/src/lib/math/prob_distr.h
@@ -15,13 +15,13 @@
/**
* Container for distribution parameters for sampling, CDF, &c.
*/
-struct dist {
- const struct dist_ops *ops;
+struct dist_t {
+ const struct dist_ops_t *ops;
};
/**
- * Untyped initializer element for struct dist using the specified
- * struct dist_ops pointer. Don't actually use this directly -- use
+ * Untyped initializer element for struct dist_t using the specified
+ * struct dist_ops_t 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:
*
@@ -61,13 +61,13 @@ struct dist {
#endif /* defined(__COVERITY__) */
/**
-* Typed initializer element for struct dist using the specified struct
-* dist_ops pointer. Don't actually use this directly -- use a
+* Typed initializer element for struct dist_t using the specified struct
+* dist_ops_t 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),
+* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull_t),
* .lambda = ...,
* .k = ...,
* };
@@ -75,20 +75,20 @@ struct dist {
* 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;
+* struct foo_t {
+* struct dist_t base;
* int omega;
* double tau;
* double phi;
* };
*
-* struct dist_ops foo_ops = ...;
+* struct dist_ops_t foo_ops = ...;
*
-* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo)
+* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo_t)
*
* Then users can do:
*
-* struct foo mydist = {
+* struct foo_t mydist = {
* FOO(mydist),
* .omega = ...,
* .tau = ...,
@@ -97,7 +97,7 @@ struct dist {
*
* If you accidentally write
*
-* struct bar mydist = {
+* struct bar_t mydist = {
* FOO(mydist),
* ...
* };
@@ -110,107 +110,107 @@ struct dist {
/**
* Generic operations on distributions. These simply defer to the
- * corresponding dist_ops function. In the parlance of C++, these call
+ * corresponding dist_ops_t 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);
-double dist_sf(const struct dist *, double x);
-double dist_icdf(const struct dist *, double p);
-double dist_isf(const struct dist *, double p);
+const char *dist_name(const struct dist_t *);
+double dist_sample(const struct dist_t *);
+double dist_cdf(const struct dist_t *, double x);
+double dist_sf(const struct dist_t *, double x);
+double dist_icdf(const struct dist_t *, double p);
+double dist_isf(const struct dist_t *, 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 {
+struct dist_ops_t {
const char *name;
- double (*sample)(const struct dist *);
- double (*cdf)(const struct dist *, double x);
- double (*sf)(const struct dist *, double x);
- double (*icdf)(const struct dist *, double p);
- double (*isf)(const struct dist *, double p);
+ double (*sample)(const struct dist_t *);
+ double (*cdf)(const struct dist_t *, double x);
+ double (*sf)(const struct dist_t *, double x);
+ double (*icdf)(const struct dist_t *, double p);
+ double (*isf)(const struct dist_t *, double p);
};
/* Geometric distribution on positive number of trials before first success */
-struct geometric {
- struct dist base;
+struct geometric_t {
+ struct dist_t base;
double p; /* success probability */
};
-extern const struct dist_ops geometric_ops;
+extern const struct dist_ops_t geometric_ops;
#define GEOMETRIC(OBJ) \
- DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric)
+ DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric_t)
/* Pareto distribution */
-struct genpareto {
- struct dist base;
+struct genpareto_t {
+ struct dist_t base;
double mu;
double sigma;
double xi;
};
-extern const struct dist_ops genpareto_ops;
+extern const struct dist_ops_t genpareto_ops;
#define GENPARETO(OBJ) \
- DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto)
+ DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto_t)
/* Weibull distribution */
-struct weibull {
- struct dist base;
+struct weibull_t {
+ struct dist_t base;
double lambda;
double k;
};
-extern const struct dist_ops weibull_ops;
+extern const struct dist_ops_t weibull_ops;
#define WEIBULL(OBJ) \
- DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull)
+ DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull_t)
/* Log-logistic distribution */
-struct log_logistic {
- struct dist base;
+struct log_logistic_t {
+ struct dist_t base;
double alpha;
double beta;
};
-extern const struct dist_ops log_logistic_ops;
+extern const struct dist_ops_t log_logistic_ops;
#define LOG_LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic)
+ DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic_t)
/* Logistic distribution */
-struct logistic {
- struct dist base;
+struct logistic_t {
+ struct dist_t base;
double mu;
double sigma;
};
-extern const struct dist_ops logistic_ops;
+extern const struct dist_ops_t logistic_ops;
#define LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic)
+ DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic_t)
/* Uniform distribution */
-struct uniform {
- struct dist base;
+struct uniform_t {
+ struct dist_t base;
double a;
double b;
};
-extern const struct dist_ops uniform_ops;
+extern const struct dist_ops_t uniform_ops;
#define UNIFORM(OBJ) \
- DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform)
+ DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform_t)
/** Only by unittests */
diff --git a/src/lib/memarea/lib_memarea.md b/src/lib/memarea/lib_memarea.md
new file mode 100644
index 0000000000..fe5cb8293f
--- /dev/null
+++ b/src/lib/memarea/lib_memarea.md
@@ -0,0 +1,28 @@
+@dir /lib/memarea
+@brief lib/memarea: A fast arena-style allocator.
+
+This module has a fast "arena" style allocator, where memory is freed all at
+once. This kind of allocation is very fast and avoids fragmentation, at the
+expense of requiring all the data to be freed at the same time. We use this
+for parsing and diff calculations.
+
+It's often handy to allocate a large number of tiny objects, all of which
+need to disappear at the same time. You can do this in tor using the
+memarea.c abstraction, which uses a set of grow-only buffers for allocation,
+and only supports a single "free" operation at the end.
+
+Using memareas also helps you avoid memory fragmentation. You see, some libc
+malloc implementations perform badly on the case where a large number of
+small temporary objects are allocated at the same time as a few long-lived
+objects of similar size. But if you use tor_malloc() for the long-lived ones
+and a memarea for the temporary object, the malloc implementation is likelier
+to do better.
+
+To create a new memarea, use `memarea_new()`. To drop all the storage from a
+memarea, and invalidate its pointers, use `memarea_drop_all()`.
+
+The allocation functions `memarea_alloc()`, `memarea_alloc_zero()`,
+`memarea_memdup()`, `memarea_strdup()`, and `memarea_strndup()` are analogous
+to the similarly-named malloc() functions. There is intentionally no
+`memarea_free()` or `memarea_realloc()`.
+
diff --git a/src/lib/memarea/memarea.h b/src/lib/memarea/memarea.h
index 9c23cf62e9..dd0ed57fb0 100644
--- a/src/lib/memarea/memarea.h
+++ b/src/lib/memarea/memarea.h
@@ -16,6 +16,9 @@ typedef struct memarea_t memarea_t;
memarea_t *memarea_new(void);
void memarea_drop_all_(memarea_t *area);
+/** @copydoc memarea_drop_all_
+ *
+ * Additionally, set <b>area</b> to NULL. */
#define memarea_drop_all(area) \
do { \
memarea_drop_all_(area); \
diff --git a/src/lib/meminfo/lib_meminfo.md b/src/lib/meminfo/lib_meminfo.md
new file mode 100644
index 0000000000..87f509d648
--- /dev/null
+++ b/src/lib/meminfo/lib_meminfo.md
@@ -0,0 +1,5 @@
+@dir /lib/meminfo
+@brief lib/meminfo: Inspecting malloc() usage.
+
+Only available when malloc() provides mallinfo() or something similar.
+
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index dbff3bbb0d..106e560a48 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -1392,7 +1392,7 @@ get_interface_addresses_win32(int severity, sa_family_t family)
/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
-#define _SIZEOF_ADDR_IFREQ sizeof
+#define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
#endif
/* Free ifc->ifc_buf safely. */
diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c
index d9ae7cd562..a655ca6ad8 100644
--- a/src/lib/net/inaddr.c
+++ b/src/lib/net/inaddr.c
@@ -35,11 +35,11 @@
* (Like inet_aton(str,addr), but works on Windows and Solaris.)
*/
int
-tor_inet_aton(const char *str, struct in_addr* addr)
+tor_inet_aton(const char *str, struct in_addr *addr)
{
unsigned a,b,c,d;
char more;
- if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4)
+ if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4)
return 0;
if (a > 255) return 0;
if (b > 255) return 0;
diff --git a/src/lib/net/lib_net.md b/src/lib/net/lib_net.md
new file mode 100644
index 0000000000..b61878d827
--- /dev/null
+++ b/src/lib/net/lib_net.md
@@ -0,0 +1,6 @@
+@dir /lib/net
+@brief lib/net: Low-level network-related code.
+
+This module includes address manipulation, compatibility wrappers,
+convenience functions, and so on.
+
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
index e1b82251ed..b25be91f48 100644
--- a/src/lib/net/socket.c
+++ b/src/lib/net/socket.c
@@ -9,7 +9,6 @@
* sockets.
**/
-#define SOCKET_PRIVATE
#include "lib/net/socket.h"
#include "lib/net/socketpair.h"
#include "lib/net/address.h"
diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c
index f3a0c3770a..aa88c58266 100644
--- a/src/lib/net/socketpair.c
+++ b/src/lib/net/socketpair.c
@@ -2,6 +2,11 @@
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/**
+ * @file socketpair.c
+ * @brief Replacement socketpair() for systems that lack it
+ **/
+
#include "lib/cc/torint.h"
#include "lib/net/socketpair.h"
#include "lib/net/inaddr_st.h"
diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h
index 5820606973..c2e99d505e 100644
--- a/src/lib/net/socketpair.h
+++ b/src/lib/net/socketpair.h
@@ -6,6 +6,11 @@
#ifndef TOR_SOCKETPAIR_H
#define TOR_SOCKETPAIR_H
+/**
+ * @file socketpair.h
+ * @brief Header for socketpair.c
+ **/
+
#include "orconfig.h"
#include "lib/testsupport/testsupport.h"
#include "lib/net/nettypes.h"
diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h
index e55119e0b0..a2a479dd51 100644
--- a/src/lib/net/socks5_status.h
+++ b/src/lib/net/socks5_status.h
@@ -27,6 +27,16 @@ typedef enum {
SOCKS5_TTL_EXPIRED = 0x06,
SOCKS5_COMMAND_NOT_SUPPORTED = 0x07,
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
+
+ /* Extended error code (see prop304). Only used if the SocksPort flag
+ * "ExtendedErrors" is set. */
+ SOCKS5_HS_NOT_FOUND = 0xF0,
+ SOCKS5_HS_IS_INVALID = 0xF1,
+ SOCKS5_HS_INTRO_FAILED = 0xF2,
+ SOCKS5_HS_REND_FAILED = 0xF3,
+ SOCKS5_HS_MISSING_CLIENT_AUTH = 0xF4,
+ SOCKS5_HS_BAD_CLIENT_AUTH = 0xF5,
+ SOCKS5_HS_BAD_ADDRESS = 0xF6,
} socks5_reply_status_t;
#endif /* !defined(TOR_SOCKS5_STATUS_H) */
diff --git a/src/lib/osinfo/lib_osinfo.md b/src/lib/osinfo/lib_osinfo.md
new file mode 100644
index 0000000000..0678ecc21e
--- /dev/null
+++ b/src/lib/osinfo/lib_osinfo.md
@@ -0,0 +1,8 @@
+@dir /lib/osinfo
+@brief lib/osinfo: For inspecting the OS version and capabilities.
+
+In general, we use this module when we're telling the user what operating
+system they are running. We shouldn't make decisions based on the output of
+these checks: instead, we should have more specific checks, either at compile
+time or run time, based on the observed system behavior.
+
diff --git a/src/lib/process/env.c b/src/lib/process/env.c
index 3912ade197..88619d1e47 100644
--- a/src/lib/process/env.c
+++ b/src/lib/process/env.c
@@ -16,7 +16,6 @@
#include "lib/container/smartlist.h"
#include "lib/log/util_bug.h"
#include "lib/log/log.h"
-#include "lib/malloc/malloc.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
diff --git a/src/lib/process/lib_process.md b/src/lib/process/lib_process.md
new file mode 100644
index 0000000000..354129e70e
--- /dev/null
+++ b/src/lib/process/lib_process.md
@@ -0,0 +1,2 @@
+@dir /lib/process
+@brief lib/process: Launch and manage subprocesses.
diff --git a/src/lib/process/process.c b/src/lib/process/process.c
index 2194a603ff..b01c99992c 100644
--- a/src/lib/process/process.c
+++ b/src/lib/process/process.c
@@ -550,6 +550,7 @@ process_vprintf(process_t *process,
char *data;
size = tor_vasprintf(&data, format, args);
+ tor_assert(data != NULL);
process_write(process, (uint8_t *)data, size);
tor_free(data);
}
diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c
index 332b432c54..8191bdc1f0 100644
--- a/src/lib/process/process_unix.c
+++ b/src/lib/process/process_unix.c
@@ -253,22 +253,15 @@ process_unix_exec(process_t *process)
process_environment_t *env = process_get_environment(process);
/* Call the requested program. */
- retval = execve(argv[0], argv, env->unixoid_environment_block);
+ execve(argv[0], argv, env->unixoid_environment_block);
/* If we made it here it is because execve failed :-( */
- if (-1 == retval)
- fprintf(stderr, "Call to execve() failed: %s", strerror(errno));
-
tor_free(argv);
process_environment_free(env);
- tor_assert_unreached();
-
error:
- /* LCOV_EXCL_START */
fprintf(stderr, "Error from child process: %s", strerror(errno));
_exit(1);
- /* LCOV_EXCL_STOP */
}
/* We are in the parent process. */
diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c
index 624333d4a3..7e4082ad13 100644
--- a/src/lib/process/process_win32.c
+++ b/src/lib/process/process_win32.c
@@ -234,6 +234,24 @@ process_win32_exec(process_t *process)
CloseHandle(stdin_pipe_read);
CloseHandle(stdin_pipe_write);
+ /* In the Unix backend, we do not get an error in the Tor process when a
+ * child process fails to spawn its target executable since we need to
+ * first do the fork() call in the Tor process and then the child process
+ * is responsible for doing the call to execve().
+ *
+ * This means that the user of the process_exec() API must check for
+ * whether it returns PROCESS_STATUS_ERROR, which will rarely happen on
+ * Unix, but will happen for error cases on Windows where it does not
+ * happen on Unix. For example: when the target executable does not exist
+ * on the file system.
+ *
+ * To have somewhat feature compatibility between the Unix and the Windows
+ * backend, we here notify the process_t owner that the process have exited
+ * (even though it never managed to run) to ensure that the exit callback
+ * is executed.
+ */
+ process_notify_event_exit(process, 0);
+
return PROCESS_STATUS_ERROR;
}
diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c
index 3c94ce4bac..6cbdd99bb8 100644
--- a/src/lib/process/setuid.c
+++ b/src/lib/process/setuid.c
@@ -64,7 +64,7 @@ log_credential_status(void)
/* log UIDs */
#ifdef HAVE_GETRESUID
- if (getresuid(&ruid, &euid, &suid) != 0 ) {
+ if (getresuid(&ruid, &euid, &suid) != 0) {
log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno));
return -1;
} else {
@@ -85,7 +85,7 @@ log_credential_status(void)
/* log GIDs */
#ifdef HAVE_GETRESGID
- if (getresgid(&rgid, &egid, &sgid) != 0 ) {
+ if (getresgid(&rgid, &egid, &sgid) != 0) {
log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno));
return -1;
} else {
diff --git a/src/lib/pubsub/lib_pubsub.md b/src/lib/pubsub/lib_pubsub.md
new file mode 100644
index 0000000000..3f4c473436
--- /dev/null
+++ b/src/lib/pubsub/lib_pubsub.md
@@ -0,0 +1,14 @@
+@dir /lib/pubsub
+@brief lib/pubsub: Publish-subscribe message passing.
+
+This module wraps the \refdir{lib/dispatch} module, to provide a more
+ergonomic and type-safe approach to message passing.
+
+In general, we favor this mechanism for cases where higher-level modules
+need to be notified when something happens in lower-level modules. (The
+alternative would be calling up from the lower-level modules, which
+would be error-prone; or maintaining lists of function-pointers, which
+would be clumsy and tend to complicate the call graph.)
+
+See pubsub.c for more information.
+
diff --git a/src/lib/pubsub/publish_subscribe.md b/src/lib/pubsub/publish_subscribe.md
new file mode 100644
index 0000000000..bb05b100b1
--- /dev/null
+++ b/src/lib/pubsub/publish_subscribe.md
@@ -0,0 +1,144 @@
+
+@page publish_subscribe Publish-subscribe message passing in Tor
+
+@tableofcontents
+
+## Introduction
+
+Tor has introduced a generic publish-subscribe mechanism for delivering
+messages internally. It is meant to help us improve the modularity of
+our code, by avoiding direct coupling between modules that don't
+actually need to invoke one another.
+
+This publish-subscribe mechanism is *not* meant for handing
+multithreading or multiprocess issues, thought we hope that eventually
+it might be extended and adapted for that purpose. Instead, we use
+publish-subscribe today to decouple modules that shouldn't be calling
+each other directly.
+
+For example, there are numerous parts of our code that might need to
+take action when a circuit is completed: a controller might need to be
+informed, an onion service negotiation might need to be attached, a
+guard might need to be marked as working, or a client connection might
+need to be attached. But many of those actions occur at a higher layer
+than circuit completion: calling them directly is a layering violation,
+and makes our code harder to understand and analyze.
+
+But with message-passing, we can invert this layering violation: circuit
+completion can become a "message" that the circuit code publishes, and
+to which higher-level layers subscribe. This means that circuit
+handling can be decoupled from higher-level modules, and stay nice and
+simple. (@ref pubsub_notyet "1")
+
+> @anchor pubsub_notyet 1. Unfortunately, like most of our code, circuit
+> handling is _not_ yet refactored to use publish-subscribe throughout.
+> Instead, layer violations of the type described here are pretty common
+> in Tor today. To see a small part of what happens when a circuit is
+> completed today, have a look at circuit_build_no_more_hops() and its
+> associated code.
+
+## Channels and delivery policies
+
+To work with messages, especially when refactoring existing code, you'll
+need to understand "channels" and "delivery policies".
+
+Every message is delivered on a "message channel". Each channel
+(conceptually) a queue-like structure that can support an arbitrarily
+number of message types. Where channels vary is their delivery
+mechanisms, and their guarantees about when messages are processed.
+
+Currently, three delivery policies are possible:
+
+ - `DELIV_PROMPT` -- causes messages to be processed via a callback in
+ Tor's event loop. This is generally the best choice, since it
+ avoids unexpected growth of the stack.
+
+ - `DELIV_IMMEDIATE` -- causes messages to be processed immediately
+ on the call stack when they are published. This choice grows the
+ stack, and can lead to unexpected complexity in the call graph.
+ We should only use it when necessary.
+
+ - `DELIV_NEVER` -- causes messages not to be delivered by the message
+ dispatch system at all. Instead, some other part of the code must
+ call dispatch_flush() to get the messages delivered.
+
+See mainloop_pubsub.c and mainloop_pubsub.h for more information and
+implementation details.
+
+## Layers: Dispatch vs publish-subsubscribe vs mainloop.
+
+At the lowest level, messages are sent via the "dispatcher" module in
+@refdir{lib/dispatch}. For performance, this dispatcher works with a
+untyped messages. Publishers, subscribers, channels, and messages are
+distinguished by short integers. Associated data is handled as
+dynamically-typed data pointers, and its types are also stored as short
+integers.
+
+Naturally, this results in a type-unsafe C API, so most other modules
+shouldn't invoke @refdir{lib/dispatch} directly. At a higher level,
+@refdir{lib/pubsub} defines a set of functions and macros that make
+messages named and type-safe. This is the one that other modules should
+use when they want to send or receive a message.
+
+The two modules above do not handle message delivery. Instead, the
+dispatch module takes a callback that it can invoke when a channel
+becomes nonempty, and defines a dispatch_flush() function to deliver all
+the messages queued in a channel. The work of actually making sure that
+dispatch_flush() is called when appropriate falls to the main loop,
+which needs to integrate the message dispatcher with the rest of our
+events and callbacks. This work happens in mainloop_pubsub.c.
+
+
+## How to publish and subscribe
+
+This section gives an overview of how to make new messages and how to
+use them. For full details, see pubsub_macros.h.
+
+Before anybody can publish or subscribe to a message, the message must
+be declared, typically in a header. This uses DECLARE_MESSAGE() or
+DECLARE_MESSAGE_INT().
+
+Only subsystems can publish or subscribe messages. For more information
+about the subsystems architecture, see @ref initialization.
+
+To publish a message, you must:
+ - Include the header that declares the message.
+ - Declare a set of helper functions via DECLARE_PUBLISH(). These
+ must be visible wherever you call PUBLISH().
+ - Call PUBLISH() to actually send a message.
+ - Connect your subsystem to the dispatcher by calling
+ DISPATCH_ADD_PUB() from your subsystem's subsys_fns_t.add_pubsub
+ callback.
+
+To subscribe to a message, you must:
+ - Include the header that declares the message.
+ - Declare a callback function to be invoked when the message is delivered.
+ - Use DISPATCH_SUBSCRIBE at file scope to define a set of wrapper
+ functions to call your callback function with the appropriate type.
+ - Connect your subsystem to the dispatcher by calling
+ DISPATCH_ADD_SUB() from your subsystem's subsys_fns_t.add_pubsub
+ callback.
+
+Again, the file-level documentation for pubsub_macros.h describes how to
+declare a message, how to publish it, and how to subscribe to it.
+
+## Designing good messages
+
+**Frequency**:
+The publish-subscribe system uses a few function calls
+and allocations for each message sent. This makes it unsuitable for
+very-high-bandwidth events, like "receiving a single data cell" or "a
+socket has become writable." It's fine, however, for events that
+ordinarily happen a bit less frequently than that, like a circuit
+getting finished, a new connection getting opened, or so on.
+
+**Semantics**:
+A message should declare that something has happened or is happening,
+not that something in particular should be done.
+
+For example, suppose you want to set up a message so that onion services
+clean up their replay caches whenever we're low on memory. The event
+should be something like `memory_low`, not `clean_up_replay_caches`.
+The latter name would imply that the publisher knew who was subscribing
+to the message and what they intended to do about it, which would be a
+layering violation.
diff --git a/src/lib/pubsub/pubsub_build.h b/src/lib/pubsub/pubsub_build.h
index 5a0c5f5bd3..13ec09c983 100644
--- a/src/lib/pubsub/pubsub_build.h
+++ b/src/lib/pubsub/pubsub_build.h
@@ -85,6 +85,11 @@ struct dispatch_t *pubsub_builder_finalize(pubsub_builder_t *,
**/
void pubsub_items_clear_bindings(pubsub_items_t *items);
+/**
+ * @copydoc pubsub_items_free_
+ *
+ * Additionally, set the pointer <b>cfg</b> to NULL.
+ **/
#define pubsub_items_free(cfg) \
FREE_AND_NULL(pubsub_items_t, pubsub_items_free_, (cfg))
void pubsub_items_free_(pubsub_items_t *cfg);
diff --git a/src/lib/pubsub/pubsub_check.c b/src/lib/pubsub/pubsub_check.c
index bf1196df2c..38723e56ed 100644
--- a/src/lib/pubsub/pubsub_check.c
+++ b/src/lib/pubsub/pubsub_check.c
@@ -9,7 +9,9 @@
* @brief Enforce various requirements on a pubsub_builder.
**/
+/** @{ */
#define PUBSUB_PRIVATE
+/** @} */
#include "lib/dispatch/dispatch_naming.h"
#include "lib/dispatch/msgtypes.h"
diff --git a/src/lib/pubsub/pubsub_macros.h b/src/lib/pubsub/pubsub_macros.h
index 357e59fd54..5c02fc354d 100644
--- a/src/lib/pubsub/pubsub_macros.h
+++ b/src/lib/pubsub/pubsub_macros.h
@@ -163,7 +163,7 @@
* hookfn with the appropriate arguments.
*/
-/* Macro to declare common elements shared by DECLARE_MESSAGE and
+/** 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
@@ -288,7 +288,7 @@
( 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) \
@@ -322,7 +322,7 @@
#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) \
@@ -334,7 +334,7 @@
(flags), \
__FILE__, \
__LINE__)
-/*
+/**
* Use a given connector and channel name to declare that this subsystem will
* receive a given message type.
*
diff --git a/src/lib/pubsub/pubsub_publish.h b/src/lib/pubsub/pubsub_publish.h
index 0686a465de..6369725405 100644
--- a/src/lib/pubsub/pubsub_publish.h
+++ b/src/lib/pubsub/pubsub_publish.h
@@ -4,6 +4,11 @@
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file pubsub_publish.h
+ * @brief Header for pubsub_publish.c
+ **/
+
#ifndef TOR_PUBSUB_PUBLISH_H
#define TOR_PUBSUB_PUBLISH_H
diff --git a/src/lib/sandbox/lib_sandbox.md b/src/lib/sandbox/lib_sandbox.md
new file mode 100644
index 0000000000..dd168c9b13
--- /dev/null
+++ b/src/lib/sandbox/lib_sandbox.md
@@ -0,0 +1,15 @@
+@dir /lib/sandbox
+@brief lib/sandbox: Linux seccomp2-based sandbox.
+
+This module uses Linux's seccomp2 facility via the
+[`libseccomp` library](https://github.com/seccomp/libseccomp), to restrict
+the set of system calls that Tor is allowed to invoke while it is running.
+
+Because there are many libc versions that invoke different system calls, and
+because handling strings is quite complex, this module is more complex and
+less portable than it needs to be.
+
+A better architecture would put the responsibility for invoking tricky system
+calls (like open()) in another, less restricted process, and give that
+process responsibility for enforcing our sandbox rules.
+
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index 0b316e9c6a..badf730f15 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -82,7 +82,7 @@
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
#define USE_BACKTRACE
-#define EXPOSE_CLEAN_BACKTRACE
+#define BACKTRACE_PRIVATE
#include "lib/err/backtrace.h"
#endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */
@@ -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
@@ -491,24 +492,6 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
}
- rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open),
- SCMP_CMP_MASKED(1, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW,
- O_RDONLY));
- if (rc != 0) {
- log_err(LD_BUG,"(Sandbox) failed to add open syscall, received libseccomp "
- "error %d", rc);
- return rc;
- }
-
- rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(openat),
- SCMP_CMP_MASKED(2, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW,
- O_RDONLY));
- if (rc != 0) {
- log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
- "libseccomp error %d", rc);
- return rc;
- }
-
return 0;
}
@@ -562,23 +545,6 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
-static int
-sb__sysctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
-{
- int rc;
- (void) filter;
- (void) ctx;
-
- rc = seccomp_rule_add_0(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(_sysctl));
- if (rc != 0) {
- log_err(LD_BUG,"(Sandbox) failed to add _sysctl syscall, "
- "received libseccomp error %d", rc);
- return rc;
- }
-
- return 0;
-}
-
/**
* Function responsible for setting up the rename syscall for
* the seccomp filter sandbox.
@@ -1147,7 +1113,6 @@ static sandbox_filter_func_t filter_func[] = {
sb_chmod,
sb_open,
sb_openat,
- sb__sysctl,
sb_rename,
#ifdef __NR_fcntl64
sb_fcntl64,
@@ -1524,14 +1489,14 @@ install_syscall_filter(sandbox_cfg_t* cfg)
int rc = 0;
scmp_filter_ctx ctx;
- ctx = seccomp_init(SCMP_ACT_TRAP);
+ ctx = seccomp_init(SCMP_ACT_ERRNO(EPERM));
if (ctx == NULL) {
log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context");
rc = -1;
goto end;
}
- // protectign sandbox parameter strings
+ // protecting sandbox parameter strings
if ((rc = prot_strings(ctx, cfg))) {
goto end;
}
diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h
index b4ae6e5c07..5e0591ba83 100644
--- a/src/lib/sandbox/sandbox.h
+++ b/src/lib/sandbox/sandbox.h
@@ -29,10 +29,10 @@
#define USE_LIBSECCOMP
#endif
-struct sandbox_cfg_elem;
+struct sandbox_cfg_elem_t;
/** Typedef to structure used to manage a sandbox configuration. */
-typedef struct sandbox_cfg_elem sandbox_cfg_t;
+typedef struct sandbox_cfg_elem_t sandbox_cfg_t;
/**
* Linux definitions
@@ -58,7 +58,7 @@ typedef enum {
* Configuration parameter structure associated with the LIBSECCOMP2
* implementation.
*/
-typedef struct smp_param {
+typedef struct smp_param_t {
/** syscall associated with parameter. */
int syscall;
@@ -77,7 +77,7 @@ typedef struct smp_param {
* It is implemented as a linked list of parameters. Currently only controls
* parameters for open, openat, execve, stat64.
*/
-struct sandbox_cfg_elem {
+struct sandbox_cfg_elem_t {
/** Sandbox implementation which dictates the parameter type. */
SB_IMPL implem;
@@ -85,7 +85,7 @@ struct sandbox_cfg_elem {
smp_param_t *param;
/** Next element of the configuration*/
- struct sandbox_cfg_elem *next;
+ struct sandbox_cfg_elem_t *next;
};
/** Function pointer defining the prototype of a filter function.*/
diff --git a/src/lib/smartlist_core/lib_smartlist_core.md b/src/lib/smartlist_core/lib_smartlist_core.md
new file mode 100644
index 0000000000..c031dd6f24
--- /dev/null
+++ b/src/lib/smartlist_core/lib_smartlist_core.md
@@ -0,0 +1,10 @@
+@dir /lib/smartlist_core
+@brief lib/smartlist_core: Minimal dynamic array implementation
+
+A `smartlist_t` is a dynamic array type for holding `void *`. We use it
+throughout the rest of the codebase.
+
+There are higher-level pieces in \refdir{lib/container} but
+the ones in lib/smartlist_core are used by the logging code, and therefore
+cannot use the logging code.
+
diff --git a/src/lib/string/lib_string.md b/src/lib/string/lib_string.md
new file mode 100644
index 0000000000..98e3e652ed
--- /dev/null
+++ b/src/lib/string/lib_string.md
@@ -0,0 +1,13 @@
+@dir /lib/string
+@brief lib/string: Low-level string manipulation.
+
+We have a number of compatibility functions here: some are for handling
+functionality that is not implemented (or not implemented the same) on every
+platform; some are for providing locale-independent versions of libc
+functions that would otherwise be defined differently for different users.
+
+Other functions here are for common string-manipulation operations that we do
+in the rest of the codebase.
+
+Any string function high-level enough to need logging belongs in a
+higher-level module.
diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c
index fbdd554a47..fd4422ecd0 100644
--- a/src/lib/string/parse_int.c
+++ b/src/lib/string/parse_int.c
@@ -9,6 +9,7 @@
**/
#include "lib/string/parse_int.h"
+#include "lib/cc/compat_compiler.h"
#include <errno.h>
#include <stdlib.h>
@@ -17,6 +18,7 @@
/* Helper: common code to check whether the result of a strtol or strtoul or
* strtoll is correct. */
#define CHECK_STRTOX_RESULT() \
+ STMT_BEGIN \
/* Did an overflow occur? */ \
if (errno == ERANGE) \
goto err; \
@@ -38,7 +40,8 @@
err: \
if (ok) *ok = 0; \
if (next) *next = endptr; \
- return 0
+ return 0; \
+ STMT_END
/** Extract a long from the start of <b>s</b>, in the given numeric
* <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal,
diff --git a/src/lib/string/strings.md b/src/lib/string/strings.md
new file mode 100644
index 0000000000..b22574a05a
--- /dev/null
+++ b/src/lib/string/strings.md
@@ -0,0 +1,102 @@
+
+@page strings String processing in Tor
+
+Since you're reading about a C program, you probably expected this
+section: it's full of functions for manipulating the (notoriously
+dubious) C string abstraction. I'll describe some often-missed
+highlights here.
+
+### Comparing strings and memory chunks ###
+
+We provide strcmpstart() and strcmpend() to perform a strcmp with the start
+or end of a string.
+
+ tor_assert(!strcmpstart("Hello world","Hello"));
+ tor_assert(!strcmpend("Hello world","world"));
+
+ tor_assert(!strcasecmpstart("HELLO WORLD","Hello"));
+ tor_assert(!strcasecmpend("HELLO WORLD","world"));
+
+To compare two string pointers, either of which might be NULL, use
+strcmp_opt().
+
+To search for a string or a chunk of memory within a non-null
+terminated memory block, use tor_memstr or tor_memmem respectively.
+
+We avoid using memcmp() directly, since it tends to be used in cases
+when having a constant-time operation would be better. Instead, we
+recommend tor_memeq() and tor_memneq() for when you need a
+constant-time operation. In cases when you need a fast comparison,
+and timing leaks are not a danger, you can use fast_memeq() and
+fast_memneq().
+
+It's a common pattern to take a string representing one or more lines
+of text, and search within it for some other string, at the start of a
+line. You could search for "\\ntarget", but that would miss the first
+line. Instead, use find_str_at_start_of_line.
+
+### Parsing text ###
+
+Over the years, we have accumulated lots of ways to parse text --
+probably too many. Refactoring them to be safer and saner could be a
+good project! The one that seems most error-resistant is tokenizing
+text with smartlist_split_strings(). This function takes a smartlist,
+a string, and a separator, and splits the string along occurrences of
+the separator, adding new strings for the sub-elements to the given
+smartlist.
+
+To handle time, you can use one of the functions mentioned above in
+"Parsing and encoding time values".
+
+For numbers in general, use the tor_parse_{long,ulong,double,uint64}
+family of functions. Each of these can be called in a few ways. The
+most general is as follows:
+
+ const int BASE = 10;
+ const int MINVAL = 10, MAXVAL = 10000;
+ const char *next;
+ int ok;
+ long lng = tor_parse_long("100", BASE, MINVAL, MAXVAL, &ok, &next);
+
+The return value should be ignored if "ok" is set to false. The input
+string needs to contain an entire number, or it's considered
+invalid... unless the "next" pointer is available, in which case extra
+characters at the end are allowed, and "next" is set to point to the
+first such character.
+
+### Generating blocks of text ###
+
+For not-too-large blocks of text, we provide tor_asprintf(), which
+behaves like other members of the sprintf() family, except that it
+always allocates enough memory on the heap for its output.
+
+For larger blocks: Rather than using strlcat and strlcpy to build
+text, or keeping pointers to the interior of a memory block, we
+recommend that you use the smartlist_* functions to build a smartlist
+full of substrings in order. Then you can concatenate them into a
+single string with smartlist_join_strings(), which also takes optional
+separator and terminator arguments.
+
+Alternatively, you might find it more convenient (and more
+allocation-efficient) to use the buffer API in buffers.c: Construct a buf_t
+object, add your data to it with buf_add_string(), buf_add_printf(), and so
+on, then call buf_extract() to get the resulting output.
+
+As a convenience, we provide smartlist_add_asprintf(), which combines
+the two methods above together. Many of the cryptographic digest
+functions also accept a not-yet-concatenated smartlist of strings.
+
+### Logging helpers ###
+
+Often we'd like to log a value that comes from an untrusted source.
+To do this, use escaped() to escape the nonprintable characters and
+other confusing elements in a string, and surround it by quotes. (Use
+esc_for_log() if you need to allocate a new string.)
+
+It's also handy to put memory chunks into hexadecimal before logging;
+you can use hex_str(memory, length) for that.
+
+The escaped() and hex_str() functions both provide outputs that are
+only valid till they are next invoked; they are not threadsafe.
+
+*/
diff --git a/src/lib/subsys/initialization.md b/src/lib/subsys/initialization.md
new file mode 100644
index 0000000000..012ab7000d
--- /dev/null
+++ b/src/lib/subsys/initialization.md
@@ -0,0 +1,75 @@
+
+@page initialization Initialization and shutdown
+
+@tableofcontents
+
+@section overview Overview
+
+Tor has a single entry point: tor_run_main() in main.c. All the ways of
+starting a Tor process (ntmain.c, tor_main.c, and tor_api.c) work by invoking tor_run_main().
+
+The tor_run_main() function normally exits (@ref init_exceptwhen "1") by
+returning: not by calling abort() or exit(). Before it returns, it calls
+tor_cleanup() in shutdown.c.
+
+Conceptually, there are several stages in running Tor.
+
+1. First, we initialize those modules that do not depend on the
+ configuration. This happens in the first half of tor_run_main(), and the
+ first half of tor_init(). (@ref init_pending_refactor "2")
+
+2. Second, we parse the command line and our configuration, and configure
+ systems that depend on our configuration or state. This configuration
+ happens midway through tor_init(), which invokes
+ options_init_from_torrc(). We then initialize more systems from the
+ second half of tor_init().
+
+3. At this point we may exit early if we have been asked to do something
+ requiring no further initialization, like printing our version number or
+ creating a new signing key. Otherwise, we proceed to run_tor_main_loop(),
+ which initializes some network-specific parts of Tor, grabs some
+ daemon-only resources (like the data directory lock) and starts Tor itself
+ running.
+
+
+> @anchor init_exceptwhen 1. tor_run_main() _can_ terminate with a call to
+> abort() or exit(), but only when crashing due to a bug, or when forking to
+> run as a daemon.
+
+> @anchor init_pending_refactor 2. The pieces of code that I'm describing as
+> "the first part of tor_init()" and so on deserve to be functions with their
+> own name. I'd like to refactor them, but before I do so, there is some
+> slight reorganization that needs to happen. Notably, the
+> nt_service_parse_options() call ought logically to be later in our
+> initialization sequence. See @ticket{32447} for our refactoring progress.
+
+
+@section subsys Subsystems and initialization
+
+Our current convention is to use the subsystem mechanism to initialize and
+clean up pieces of Tor. The more recently updated pieces of Tor will use
+this mechanism. For examples, see e.g. time_sys.c or log_sys.c.
+
+In simplest terms, a **subsytem** is a logically separate part of Tor that
+can be initialized, shut down, managed, and configured somewhat independently
+of the rest of the program.
+
+The subsys_fns_t type describes a subsystem and a set of functions that
+initialize it, desconstruct it, and so on. To define a subsystem, we declare
+a `const` instance of subsys_fns_t. See the documentation for subsys_fns_t
+for a full list of these functions.
+
+After defining a subsytem, it must be inserted in subsystem_list.c. At that
+point, table-driven mechanisms in subsysmgr.c will invoke its functions when
+appropriate.
+
+@subsection vsconfig Initialization versus configuration
+
+We note that the initialization phase of Tor occurs before any configuration
+is read from disk -- and therefore before any other files are read from
+disk. Therefore, any behavior that depends on Tor's configuration or state
+must occur _after_ the initialization process, during configuration.
+
+
+
+
diff --git a/src/lib/subsys/lib_subsys.md b/src/lib/subsys/lib_subsys.md
new file mode 100644
index 0000000000..764d25d1b6
--- /dev/null
+++ b/src/lib/subsys/lib_subsys.md
@@ -0,0 +1,32 @@
+@dir /lib/subsys
+@brief lib/subsys: Types for declaring a "subsystem".
+
+## Subsystems in Tor
+
+A subsystem is a module with support for initialization, shutdown,
+configuration, and so on.
+
+Many parts of Tor can be initialized, cleaned up, and configured somewhat
+independently through a table-driven mechanism. Each such part is called a
+"subsystem".
+
+To declare a subsystem, make a global `const` instance of the `subsys_fns_t`
+type, filling in the function pointer fields that you require with ones
+corresponding to your subsystem. Any function pointers left as "NULL" will
+be a no-op. Each system must have a name and a "level", which corresponds to
+the order in which it is initialized. (See `app/main/subsystem_list.c` for a
+list of current subsystems and their levels.)
+
+Then, insert your subsystem in the list in `app/main/subsystem_list.c`. It
+will need to occupy a position corresponding to its level.
+
+At this point, your subsystem will be handled like the others: it will get
+initialized at startup, torn down at exit, and so on.
+
+Historical note: Not all of Tor's code is currently handled as
+subsystems. As you work with older code, you may see some parts of the code
+that are initialized from `tor_init()` or `run_tor_main_loop()` or
+`tor_run_main()`; and torn down from `tor_cleanup()`. We aim to migrate
+these to subsystems over time; please don't add any new code that follows
+this pattern.
+
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index 21f984f32d..324f4f2947 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -3,12 +3,18 @@
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file subsys.h
+ * @brief Types used to declare a subsystem.
+ **/
+
#ifndef TOR_SUBSYS_T
#define TOR_SUBSYS_T
#include <stdbool.h>
struct pubsub_connector_t;
+struct config_format_t;
/**
* A subsystem is a part of Tor that is initialized, shut down, configured,
@@ -17,8 +23,16 @@ struct pubsub_connector_t;
* All callbacks are optional -- if a callback is set to NULL, the subsystem
* manager will treat it as a no-op.
*
- * You should use c99 named-field initializers with this structure: we
- * will be adding more fields, often in the middle of the structure.
+ * You should use c99 named-field initializers with this structure, for
+ * readability and safety. (There are a lot of functions here, all of them
+ * optional, and many of them with similar signatures.)
+ *
+ * See @ref initialization for more information about initialization and
+ * shutdown in Tor.
+ *
+ * To make a new subsystem, you declare a const instance of this type, and
+ * include it on the list in subsystem_list.c. The code that manages these
+ * subsystems is in subsysmgr.c.
**/
typedef struct subsys_fns_t {
/**
@@ -49,7 +63,7 @@ typedef struct subsys_fns_t {
* it is only for global state or pre-configuration state.
*
* (If you need to do any setup that depends on configuration, you'll need
- * to declare a configuration callback. (Not yet designed))
+ * to declare a configuration callback instead. (Not yet designed))
*
* This function MUST NOT have any parts that can fail.
**/
@@ -57,22 +71,49 @@ typedef struct subsys_fns_t {
/**
* Connect a subsystem to the message dispatch system.
+ *
+ * This function should use the macros in @refdir{lib/pubsub} to register a
+ * set of messages that this subsystem may publish, and may subscribe to.
+ *
+ * See pubsub_macros.h for more information, and for examples.
**/
int (*add_pubsub)(struct pubsub_connector_t *);
/**
* Perform any necessary pre-fork cleanup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.postfork callback, it is run
+ * from the parent process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*prefork)(void);
/**
* Perform any necessary post-fork setup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.prefork callback, it is run
+ * from the child process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*postfork)(void);
/**
* Free any thread-local resources held by this subsystem. Called before
* the thread exits.
+ *
+ * This function is not allowed to fail.
+ *
+ * \bug Note that this callback is currently buggy: See \ticket{32103}.
*/
void (*thread_cleanup)(void);
@@ -80,16 +121,85 @@ typedef struct subsys_fns_t {
* Free all resources held by this subsystem.
*
* This function is not allowed to fail.
+ *
+ * Subsystems are shut down when Tor is about to exit or return control to
+ * an embedding program. This callback must return the process to a state
+ * such that subsys_fns_t.init will succeed if invoked again.
**/
void (*shutdown)(void);
+ /**
+ * A config_format_t describing all of the torrc fields owned by this
+ * subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's options,
+ * and used to parse option fields from the command line and torrc file.
+ **/
+ const struct config_format_t *options_format;
+
+ /**
+ * A config_format_t describing all of the DataDir/state fields owned by
+ * this subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's state,
+ * and used to parse state fields from the DataDir/state file.
+ **/
+ const struct config_format_t *state_format;
+
+ /**
+ * Receive an options object as defined by options_format. Return 0
+ * on success, -1 on failure.
+ *
+ * It is safe to store the pointer to the object until set_options()
+ * is called again.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.options_format has passed.
+ **/
+ int (*set_options)(void *);
+
+ /* XXXX Add an implementation for options_act_reversible() later in this
+ * branch. */
+
+ /**
+ * Receive a state object as defined by state_format. Return 0 on success,
+ * -1 on failure.
+ *
+ * It is safe to store the pointer to the object; set_state() is only
+ * called on startup.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.state_format has passed.
+ *
+ * This function will only be called once per invocation of Tor, since
+ * Tor does not reload its state while it is running.
+ **/
+ int (*set_state)(void *);
+
+ /**
+ * Update any information that needs to be stored in the provided state
+ * object (as defined by state_format). Return 0 on success, -1 on failure.
+ *
+ * The object provided here will be the same one as provided earlier to
+ * set_state(). This method is called when we are about to save the state
+ * to disk.
+ **/
+ int (*flush_state)(void *);
} subsys_fns_t;
+/**
+ * Lowest allowed subsystem level.
+ **/
#define MIN_SUBSYS_LEVEL -100
+/**
+ * Highest allowed subsystem level.
+ **/
#define MAX_SUBSYS_LEVEL 100
-/* All tor "libraries" (in src/libs) should have a subsystem level equal to or
- * less than this value. */
+/**
+ * All tor "libraries" (in src/libs) should have a subsystem level equal to or
+ * less than this value.
+ */
#define SUBSYS_LEVEL_LIBS -10
#endif /* !defined(TOR_SUBSYS_T) */
diff --git a/src/lib/term/lib_term.md b/src/lib/term/lib_term.md
new file mode 100644
index 0000000000..f96d25ffe8
--- /dev/null
+++ b/src/lib/term/lib_term.md
@@ -0,0 +1,2 @@
+@dir /lib/term
+@brief lib/term: Terminal operations (password input).
diff --git a/src/lib/testsupport/lib_testsupport.md b/src/lib/testsupport/lib_testsupport.md
new file mode 100644
index 0000000000..7358e6a80f
--- /dev/null
+++ b/src/lib/testsupport/lib_testsupport.md
@@ -0,0 +1,2 @@
+@dir /lib/testsupport
+@brief lib/testsupport: Helpers for test-only code and for function mocking.
diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h
index 90b7c43b19..833515c32f 100644
--- a/src/lib/testsupport/testsupport.h
+++ b/src/lib/testsupport/testsupport.h
@@ -15,17 +15,42 @@
#ifndef TOR_TESTSUPPORT_H
#define TOR_TESTSUPPORT_H
-#ifdef TOR_UNIT_TESTS
/** The "STATIC" macro marks a function or variable that is static when
* building Tor for production, but non-static when building the unit
- * tests. */
+ * tests.
+ *
+ * For example, a function declared as:
+ *
+ * STATIC int internal_function(void);
+ *
+ * should be only visible for the file on which it is declared, and in the
+ * unit tests.
+ */
+#ifdef TOR_UNIT_TESTS
#define STATIC
-#define EXTERN(type, name) extern type name;
#else /* !defined(TOR_UNIT_TESTS) */
#define STATIC static
-#define EXTERN(type, name)
#endif /* defined(TOR_UNIT_TESTS) */
+/** The "EXTERN" macro is used along with "STATIC" for variables declarations:
+ * it expands to an extern declaration when Tor building unit tests, and to
+ * nothing otherwise.
+ *
+ * For example, to declare a variable as visible only visible in one
+ * file and in the unit tests, you would put this in the header:
+ *
+ * EXTERN(int, local_variable)
+ *
+ * and this in the source:
+ *
+ * STATIC int local_variable;
+ */
+#ifdef TOR_UNIT_TESTS
+#define EXTERN(type, name) extern type name;
+#else
+#define EXTERN(type, name)
+#endif
+
/** Quick and dirty macros to implement test mocking.
*
* To use them, suppose that you have a function you'd like to mock
@@ -70,32 +95,42 @@
*
* @{ */
#ifdef TOR_UNIT_TESTS
+/** Declare a mocked function. For use in headers. */
#define MOCK_DECL(rv, funcname, arglist) \
rv funcname ##__real arglist; \
extern rv(*funcname) arglist
+/** Define the implementation of a mocked function. */
#define MOCK_IMPL(rv, funcname, arglist) \
rv(*funcname) arglist = funcname ##__real; \
rv funcname ##__real arglist
+/** As MOCK_DECL(), but allow attributes. */
#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
rv funcname ##__real arglist attr; \
extern rv(*funcname) arglist
-#define MOCK_IMPL(rv, funcname, arglist) \
- rv(*funcname) arglist = funcname ##__real; \
- rv funcname ##__real arglist
+/**
+ * Replace <b>func</b> (a mockable function) with a replacement function.
+ *
+ * Only usable when Tor has been built for unit tests. */
#define MOCK(func, replacement) \
do { \
(func) = (replacement); \
} while (0)
+/** Replace <b>func</b> (a mockable function) with its original value.
+ *
+ * Only usable when Tor has been built for unit tests. */
#define UNMOCK(func) \
do { \
func = func ##__real; \
} while (0)
#else /* !defined(TOR_UNIT_TESTS) */
+/** Declare a mocked function. For use in headers. */
#define MOCK_DECL(rv, funcname, arglist) \
rv funcname arglist
-#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
+/** As MOCK_DECL(), but allow */
+#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
rv funcname arglist attr
-#define MOCK_IMPL(rv, funcname, arglist) \
+/** Define the implementation of a mocked function. */
+#define MOCK_IMPL(rv, funcname, arglist) \
rv funcname arglist
#endif /* defined(TOR_UNIT_TESTS) */
/** @} */
diff --git a/src/lib/thread/lib_thread.md b/src/lib/thread/lib_thread.md
new file mode 100644
index 0000000000..5870ad790f
--- /dev/null
+++ b/src/lib/thread/lib_thread.md
@@ -0,0 +1,7 @@
+@dir /lib/thread
+@brief lib/thread: Mid-level threading.
+
+This module contains compatibility and convenience code for multithreading,
+except for low-level locks (which are in \refdir{lib/lock} and
+workqueue/threadpool code (which belongs in \refdir{lib/evloop}.)
+
diff --git a/src/lib/thread/threading.md b/src/lib/thread/threading.md
new file mode 100644
index 0000000000..a1058c97de
--- /dev/null
+++ b/src/lib/thread/threading.md
@@ -0,0 +1,26 @@
+
+@page threading Threading in Tor
+
+Tor is based around a single main thread and one or more worker
+threads. We aim (with middling success) to use worker threads for
+CPU-intensive activities and the main thread for our networking.
+Fortunately (?) we have enough cryptography that moving what we can
+of the cryptographic processes to the workers should achieve good
+parallelism under most loads. Unfortunately, we only have a small
+fraction of our cryptography done in our worker threads right now.
+
+Our threads-and-workers abstraction is defined in workqueue.c, which
+combines a work queue with a thread pool, and integrates the
+signalling with libevent. Tor's main instance of a work queue is
+instantiated in cpuworker.c. It will probably need some refactoring
+as more types of work are added.
+
+On a lower level, we provide locks with tor_mutex_t in \refdir{lib/lock}, and
+higher-level locking/threading tools in \refdir{lib/thread}, including
+conditions (tor_cond_t), thread-local storage (tor_threadlocal_t), and more.
+
+
+Try to minimize sharing between threads: it is usually best to simply
+make the worker "own" all the data it needs while the work is in
+progress, and to give up ownership when it's complete.
+
diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h
index 4b42b9abd9..2b956b4760 100644
--- a/src/lib/thread/threads.h
+++ b/src/lib/thread/threads.h
@@ -63,7 +63,7 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex,
void tor_cond_signal_one(tor_cond_t *cond);
void tor_cond_signal_all(tor_cond_t *cond);
-typedef struct tor_threadlocal_s {
+typedef struct tor_threadlocal_t {
#ifdef _WIN32
DWORD index;
#else
@@ -106,7 +106,9 @@ void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);
typedef struct atomic_counter_t {
atomic_size_t val;
} atomic_counter_t;
+#ifndef COCCI
#define ATOMIC_LINKAGE static
+#endif
#else /* !defined(HAVE_WORKING_STDATOMIC) */
typedef struct atomic_counter_t {
tor_mutex_t mutex;
diff --git a/src/lib/time/lib_time.md b/src/lib/time/lib_time.md
new file mode 100644
index 0000000000..8e58aafcd8
--- /dev/null
+++ b/src/lib/time/lib_time.md
@@ -0,0 +1,9 @@
+@dir /lib/time
+@brief lib/time: Higher-level time functions
+
+This includes both fine-grained timers and monotonic timers, along with
+wrappers for them to try to improve efficiency.
+
+For "what time is it" in UTC, see \refdir{lib/wallclock}. For parsing and
+encoding times and dates, see \refdir{lib/encoding}.
+
diff --git a/src/lib/tls/lib_tls.md b/src/lib/tls/lib_tls.md
new file mode 100644
index 0000000000..26fea723f9
--- /dev/null
+++ b/src/lib/tls/lib_tls.md
@@ -0,0 +1,11 @@
+@dir /lib/tls
+@brief lib/tls: TLS library wrappers
+
+This module has compatibility wrappers around the library (NSS or OpenSSL,
+depending on configuration) that Tor uses to implement the TLS link security
+protocol.
+
+It also implements the logic for some legacy TLS protocol usage we used to
+support in old versions of Tor, involving conditional delivery of certificate
+chains (v1 link protocol) and conditional renegotiation (v2 link protocol).
+
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 1aff40c437..f3c117efa3 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -3,6 +3,11 @@
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tortls.c
+ * @brief Shared functionality for our TLS backends.
+ **/
+
#define TORTLS_PRIVATE
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index 866483a94c..a7aee524f3 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -3,6 +3,11 @@
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file tortls_internal.h
+ * @brief Declare internal functions for lib/tls
+ **/
+
#ifndef TORTLS_INTERNAL_H
#define TORTLS_INTERNAL_H
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 5bafcf676d..9184cafd60 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -464,7 +464,9 @@ static const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
/** List of ciphers that clients should advertise, omitting items that
* our OpenSSL doesn't know about. */
static const char CLIENT_CIPHER_LIST[] =
+#ifndef COCCI
#include "lib/tls/ciphers.inc"
+#endif
/* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version
* of any cipher we say. */
"!SSLv2"
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 73f6e6ecca..37935894f3 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -6,6 +6,14 @@
#ifndef TOR_TORTLS_ST_H
#define TOR_TORTLS_ST_H
+/**
+ * @file tortls_st.h
+ * @brief Structure declarations for internal TLS types.
+ *
+ * These should generally be treated as opaque outside of the
+ * lib/tls module.
+ **/
+
#include "lib/net/socket.h"
#define TOR_TLS_MAGIC 0x71571571
diff --git a/src/lib/trace/lib_trace.md b/src/lib/trace/lib_trace.md
new file mode 100644
index 0000000000..a7a32529b0
--- /dev/null
+++ b/src/lib/trace/lib_trace.md
@@ -0,0 +1,6 @@
+@dir /lib/trace
+@brief lib/trace: Function-tracing functionality API.
+
+This module is used for adding "trace" support (low-granularity function
+logging) to Tor. Right now it doesn't have many users.
+
diff --git a/src/lib/version/git_revision.c b/src/lib/version/git_revision.c
index 900a1e12a0..9ee49f0c37 100644
--- a/src/lib/version/git_revision.c
+++ b/src/lib/version/git_revision.c
@@ -6,19 +6,34 @@
#include "orconfig.h"
#include "lib/version/git_revision.h"
+/**
+ * @file git_revision.c
+ * @brief Strings to describe the current Git commit.
+ **/
+
/** String describing which Tor Git repository version the source was
* built from. This string is generated by a bit of shell kludging in
* src/core/include.am, and is usually right.
*/
const char tor_git_revision[] =
+#ifndef COCCI
#ifndef _MSC_VER
#include "micro-revision.i"
#endif
+#endif
"";
+/**
+ * String appended to Tor bug messages describing the Tor version.
+ *
+ * It has the form "(on Tor 0.4.3.1-alpha)" or
+ * "(on Tor 0.4.3.1-alpha git-b994397f1af193f8)"
+ **/
const char tor_bug_suffix[] = " (on Tor " VERSION
+#ifndef COCCI
#ifndef _MSC_VER
" "
#include "micro-revision.i"
#endif
+#endif /* !defined(COCCI) */
")";
diff --git a/src/lib/version/git_revision.h b/src/lib/version/git_revision.h
index 79e3c6684b..5d08e84b84 100644
--- a/src/lib/version/git_revision.h
+++ b/src/lib/version/git_revision.h
@@ -6,6 +6,11 @@
#ifndef TOR_GIT_REVISION_H
#define TOR_GIT_REVISION_H
+/**
+ * @file git_revision.h
+ * @brief Header for git_revision.c
+ **/
+
extern const char tor_git_revision[];
extern const char tor_bug_suffix[];
diff --git a/src/lib/version/lib_version.md b/src/lib/version/lib_version.md
new file mode 100644
index 0000000000..ccc45920f9
--- /dev/null
+++ b/src/lib/version/lib_version.md
@@ -0,0 +1,2 @@
+@dir /lib/version
+@brief lib/version: holds the current version of Tor.
diff --git a/src/lib/version/torversion.h b/src/lib/version/torversion.h
index 7b0fb66ec0..50d646bd23 100644
--- a/src/lib/version/torversion.h
+++ b/src/lib/version/torversion.h
@@ -6,6 +6,11 @@
#ifndef TOR_VERSION_H
#define TOR_VERSION_H
+/**
+ * @file torversion.h
+ * @brief Header for version.c.
+ **/
+
const char *get_version(void);
const char *get_short_version(void);
diff --git a/src/lib/version/version.c b/src/lib/version/version.c
index 434e6fb424..b08d566e12 100644
--- a/src/lib/version/version.c
+++ b/src/lib/version/version.c
@@ -10,6 +10,11 @@
#include <stdio.h>
#include <string.h>
+/**
+ * @file version.c
+ * @brief Functions to get the version of Tor.
+ **/
+
/** A shorter version of this Tor process's version, for export in our router
* descriptor. (Does not include the git version, if any.) */
static const char the_short_tor_version[] =
@@ -19,6 +24,10 @@ static const char the_short_tor_version[] =
#endif
"";
+/**
+ * Longest possible version length. We make this a constant so that we
+ * can statically allocate the_tor_version.
+ **/
#define MAX_VERSION_LEN 128
/** The version of this Tor process, possibly including git version */
diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c
index 77eeddaf56..c3cac8b9f6 100644
--- a/src/lib/wallclock/approx_time.c
+++ b/src/lib/wallclock/approx_time.c
@@ -44,6 +44,9 @@ update_approx_time(time_t now)
}
#endif /* !defined(TIME_IS_FAST) */
+/**
+ * Initialize the "wallclock" subsystem by setting the current cached time.
+ **/
static int
subsys_wallclock_initialize(void)
{
@@ -51,6 +54,9 @@ subsys_wallclock_initialize(void)
return 0;
}
+/**
+ * Subsystem function table describing the "wallclock" subsystem.
+ **/
const subsys_fns_t sys_wallclock = {
.name = "wallclock",
.supported = true,
diff --git a/src/lib/wallclock/lib_wallclock.md b/src/lib/wallclock/lib_wallclock.md
new file mode 100644
index 0000000000..f21721f6f6
--- /dev/null
+++ b/src/lib/wallclock/lib_wallclock.md
@@ -0,0 +1,11 @@
+@dir /lib/wallclock
+@brief lib/wallclock: Inspect and manipulate the current time.
+
+This module handles our concept of "what time is it" or "what time does the
+world agree it is?" Generally, if you want something derived from UTC, this
+is the module for you.
+
+For versions of the time that are more local, more monotonic, or more
+accurate, see \refdir{lib/time}. For parsing and encoding times and dates,
+see \refdir{lib/encoding}.
+
diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h
index e632d04a04..4710a3dfd7 100644
--- a/src/lib/wallclock/timeval.h
+++ b/src/lib/wallclock/timeval.h
@@ -69,6 +69,7 @@
} while (0)
#endif /* !defined(timersub) */
+#ifndef COCCI
#ifndef timercmp
/** Replacement for timercmp on platforms that do not have it: returns true
* iff the relational operator "op" makes the expression tv1 op tv2 true.
@@ -82,5 +83,6 @@
((tv1)->tv_usec op (tv2)->tv_usec) : \
((tv1)->tv_sec op (tv2)->tv_sec))
#endif /* !defined(timercmp) */
+#endif /* !defined(COCCI) */
#endif /* !defined(TOR_TIMEVAL_H) */