tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 16 participants
- 2190 discussions

[tor/master] Move tor_parse_long and friends into parse_int.h in libtor-string
by nickm@torproject.org 27 Jun '18
by nickm@torproject.org 27 Jun '18
27 Jun '18
commit 80730c45e032544155074022c0df5b6909b68faa
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Jun 26 21:02:29 2018 -0400
Move tor_parse_long and friends into parse_int.h in libtor-string
---
src/common/util.c | 116 -----------------------------------------
src/common/util.h | 10 +---
src/lib/string/include.am | 2 +
src/lib/string/parse_int.c | 126 +++++++++++++++++++++++++++++++++++++++++++++
src/lib/string/parse_int.h | 20 +++++++
src/test/test_util.c | 21 +-------
6 files changed, 150 insertions(+), 145 deletions(-)
diff --git a/src/common/util.c b/src/common/util.c
index dbde0aa5b..2ea990d79 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -443,122 +443,6 @@ tor_digest256_is_zero(const char *digest)
return tor_mem_is_zero(digest, DIGEST256_LEN);
}
-/* Helper: common code to check whether the result of a strtol or strtoul or
- * strtoll is correct. */
-#define CHECK_STRTOX_RESULT() \
- /* Did an overflow occur? */ \
- if (errno == ERANGE) \
- goto err; \
- /* Was at least one character converted? */ \
- if (endptr == s) \
- goto err; \
- /* Were there unexpected unconverted characters? */ \
- if (!next && *endptr) \
- goto err; \
- /* Illogical (max, min) inputs? */ \
- if (BUG(max < min)) \
- goto err; \
- /* Is r within limits? */ \
- if (r < min || r > max) \
- goto err; \
- if (ok) *ok = 1; \
- if (next) *next = endptr; \
- return r; \
- err: \
- if (ok) *ok = 0; \
- if (next) *next = endptr; \
- return 0
-
-/** 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,
- * octal, or hex number in the syntax of a C integer literal. If
- * there is unconverted data and <b>next</b> is provided, set
- * *<b>next</b> to the first unconverted character. An error has
- * occurred if no characters are converted; or if there are
- * unconverted characters and <b>next</b> is NULL; or if the parsed
- * value is not between <b>min</b> and <b>max</b>. When no error
- * occurs, return the parsed value and set *<b>ok</b> (if provided) to
- * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided)
- * to 0.
- */
-long
-tor_parse_long(const char *s, int base, long min, long max,
- int *ok, char **next)
-{
- char *endptr;
- long r;
-
- if (BUG(base < 0)) {
- if (ok)
- *ok = 0;
- return 0;
- }
-
- errno = 0;
- r = strtol(s, &endptr, base);
- CHECK_STRTOX_RESULT();
-}
-
-/** As tor_parse_long(), but return an unsigned long. */
-unsigned long
-tor_parse_ulong(const char *s, int base, unsigned long min,
- unsigned long max, int *ok, char **next)
-{
- char *endptr;
- unsigned long r;
-
- if (BUG(base < 0)) {
- if (ok)
- *ok = 0;
- return 0;
- }
-
- errno = 0;
- r = strtoul(s, &endptr, base);
- CHECK_STRTOX_RESULT();
-}
-
-/** As tor_parse_long(), but return a double. */
-double
-tor_parse_double(const char *s, double min, double max, int *ok, char **next)
-{
- char *endptr;
- double r;
-
- errno = 0;
- r = strtod(s, &endptr);
- CHECK_STRTOX_RESULT();
-}
-
-/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to
- * work for now. */
-uint64_t
-tor_parse_uint64(const char *s, int base, uint64_t min,
- uint64_t max, int *ok, char **next)
-{
- char *endptr;
- uint64_t r;
-
- if (BUG(base < 0)) {
- if (ok)
- *ok = 0;
- return 0;
- }
-
- errno = 0;
-#ifdef HAVE_STRTOULL
- r = (uint64_t)strtoull(s, &endptr, base);
-#elif defined(_WIN32)
- r = (uint64_t)_strtoui64(s, &endptr, base);
-#elif SIZEOF_LONG == 8
- r = (uint64_t)strtoul(s, &endptr, base);
-#else
-#error "I don't know how to parse 64-bit numbers."
-#endif /* defined(HAVE_STRTOULL) || ... */
-
- CHECK_STRTOX_RESULT();
-}
-
/** Return a newly allocated string equal to <b>string</b>, except that every
* character in <b>chars_to_escape</b> is preceded by a backslash. */
char *
diff --git a/src/common/util.h b/src/common/util.h
index d2c27064e..26ee2d75a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -26,6 +26,7 @@
#include "lib/malloc/util_malloc.h"
#include "lib/wallclock/approx_time.h"
#include "lib/string/util_string.h"
+#include "lib/string/parse_int.h"
#include "lib/string/scanf.h"
#include "lib/intmath/bits.h"
#include "lib/intmath/addsub.h"
@@ -79,15 +80,6 @@ int64_t clamp_double_to_int64(double number);
/* String manipulation */
-long tor_parse_long(const char *s, int base, long min,
- long max, int *ok, char **next);
-unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
- unsigned long max, int *ok, char **next);
-double tor_parse_double(const char *s, double min, double max, int *ok,
- char **next);
-uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
- uint64_t max, int *ok, char **next);
-
const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1));
int string_is_key_value(int severity, const char *string);
diff --git a/src/lib/string/include.am b/src/lib/string/include.am
index e532d5030..edd74b8a3 100644
--- a/src/lib/string/include.am
+++ b/src/lib/string/include.am
@@ -9,6 +9,7 @@ src_lib_libtor_string_a_SOURCES = \
src/lib/string/compat_ctype.c \
src/lib/string/compat_string.c \
src/lib/string/util_string.c \
+ src/lib/string/parse_int.c \
src/lib/string/printf.c \
src/lib/string/scanf.c
@@ -21,5 +22,6 @@ noinst_HEADERS += \
src/lib/string/compat_ctype.h \
src/lib/string/compat_string.h \
src/lib/string/util_string.h \
+ src/lib/string/parse_int.h \
src/lib/string/printf.h \
src/lib/string/scanf.h
diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c
new file mode 100644
index 000000000..e552730cc
--- /dev/null
+++ b/src/lib/string/parse_int.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/string/parse_int.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Helper: common code to check whether the result of a strtol or strtoul or
+ * strtoll is correct. */
+#define CHECK_STRTOX_RESULT() \
+ /* Did an overflow occur? */ \
+ if (errno == ERANGE) \
+ goto err; \
+ /* Was at least one character converted? */ \
+ if (endptr == s) \
+ goto err; \
+ /* Were there unexpected unconverted characters? */ \
+ if (!next && *endptr) \
+ goto err; \
+ /* Illogical (max, min) inputs? */ \
+ if (max < min) \
+ goto err; \
+ /* Is r within limits? */ \
+ if (r < min || r > max) \
+ goto err; \
+ if (ok) *ok = 1; \
+ if (next) *next = endptr; \
+ return r; \
+ err: \
+ if (ok) *ok = 0; \
+ if (next) *next = endptr; \
+ return 0
+
+/** 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,
+ * octal, or hex number in the syntax of a C integer literal. If
+ * there is unconverted data and <b>next</b> is provided, set
+ * *<b>next</b> to the first unconverted character. An error has
+ * occurred if no characters are converted; or if there are
+ * unconverted characters and <b>next</b> is NULL; or if the parsed
+ * value is not between <b>min</b> and <b>max</b>. When no error
+ * occurs, return the parsed value and set *<b>ok</b> (if provided) to
+ * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided)
+ * to 0.
+ */
+long
+tor_parse_long(const char *s, int base, long min, long max,
+ int *ok, char **next)
+{
+ char *endptr;
+ long r;
+
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
+ errno = 0;
+ r = strtol(s, &endptr, base);
+ CHECK_STRTOX_RESULT();
+}
+
+/** As tor_parse_long(), but return an unsigned long. */
+unsigned long
+tor_parse_ulong(const char *s, int base, unsigned long min,
+ unsigned long max, int *ok, char **next)
+{
+ char *endptr;
+ unsigned long r;
+
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
+ errno = 0;
+ r = strtoul(s, &endptr, base);
+ CHECK_STRTOX_RESULT();
+}
+
+/** As tor_parse_long(), but return a double. */
+double
+tor_parse_double(const char *s, double min, double max, int *ok, char **next)
+{
+ char *endptr;
+ double r;
+
+ errno = 0;
+ r = strtod(s, &endptr);
+ CHECK_STRTOX_RESULT();
+}
+
+/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to
+ * work for now. */
+uint64_t
+tor_parse_uint64(const char *s, int base, uint64_t min,
+ uint64_t max, int *ok, char **next)
+{
+ char *endptr;
+ uint64_t r;
+
+ if (base < 0) {
+ if (ok)
+ *ok = 0;
+ return 0;
+ }
+
+ errno = 0;
+#ifdef HAVE_STRTOULL
+ r = (uint64_t)strtoull(s, &endptr, base);
+#elif defined(_WIN32)
+ r = (uint64_t)_strtoui64(s, &endptr, base);
+#elif SIZEOF_LONG == 8
+ r = (uint64_t)strtoul(s, &endptr, base);
+#else
+#error "I don't know how to parse 64-bit numbers."
+#endif /* defined(HAVE_STRTOULL) || ... */
+
+ CHECK_STRTOX_RESULT();
+}
diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h
new file mode 100644
index 000000000..6f56fc32a
--- /dev/null
+++ b/src/lib/string/parse_int.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_PARSE_INT_H
+#define TOR_PARSE_INT_H
+
+#include "lib/cc/torint.h"
+
+long tor_parse_long(const char *s, int base, long min,
+ long max, int *ok, char **next);
+unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
+ unsigned long max, int *ok, char **next);
+double tor_parse_double(const char *s, double min, double max, int *ok,
+ char **next);
+uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
+ uint64_t max, int *ok, char **next);
+
+#endif
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 73f353a3f..41570e14d 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -2117,20 +2117,10 @@ test_util_parse_integer(void *arg)
tt_int_op(1,OP_EQ, i);
tt_str_op(cp,OP_EQ, " plus garbage");
/* Illogical min max */
- tor_capture_bugs_(1);
tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL));
tt_int_op(0,OP_EQ, i);
- tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
- tt_str_op("!(max < min)", OP_EQ,
- smartlist_get(tor_get_captured_bug_log_(), 0));
- tor_end_capture_bugs_();
- tor_capture_bugs_(1);
tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL));
tt_int_op(0,OP_EQ, i);
- tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
- tt_str_op("!(max < min)", OP_EQ,
- smartlist_get(tor_get_captured_bug_log_(), 0));
- tor_end_capture_bugs_();
/* Out of bounds */
tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL));
tt_int_op(0,OP_EQ, i);
@@ -2141,11 +2131,8 @@ test_util_parse_integer(void *arg)
tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
- tor_capture_bugs_(2);
tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
- tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
- tor_end_capture_bugs_();
tt_int_op(i,OP_EQ, 0);
/* Test parse_ulong */
@@ -2158,10 +2145,7 @@ test_util_parse_integer(void *arg)
tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL));
tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL));
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL));
- tor_capture_bugs_(1);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL));
- tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
- tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL));
tt_int_op(0,OP_EQ, i);
@@ -2177,11 +2161,8 @@ test_util_parse_integer(void *arg)
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
tt_int_op(0,OP_EQ, i);
- tor_capture_bugs_(1);
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
- tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
- tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
{
@@ -2226,7 +2207,7 @@ test_util_parse_integer(void *arg)
tt_int_op(i,OP_EQ, 0);
}
done:
- tor_end_capture_bugs_();
+ ;
}
static void
1
0

27 Jun '18
commit 7159edf9090e0a0e4c7d02e80b81bc00083884cc
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Jun 26 20:51:17 2018 -0400
Move the escape-for-log code into src/lib/log
It doesn't need anything higher-level, and everything that needs the
logs potentially needs this.
---
src/common/util.c | 122 ---------------------------------------------
src/common/util.h | 5 +-
src/lib/log/escape.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++
src/lib/log/escape.h | 18 +++++++
src/lib/log/include.am | 2 +
5 files changed, 153 insertions(+), 126 deletions(-)
diff --git a/src/common/util.c b/src/common/util.c
index fa95f933c..dbde0aa5b 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -559,128 +559,6 @@ tor_parse_uint64(const char *s, int base, uint64_t min,
CHECK_STRTOX_RESULT();
}
-/** Allocate and return a new string representing the contents of <b>s</b>,
- * surrounded by quotes and using standard C escapes.
- *
- * Generally, we use this for logging values that come in over the network to
- * keep them from tricking users, and for sending certain values to the
- * controller.
- *
- * We trust values from the resolver, OS, configuration file, and command line
- * to not be maliciously ill-formed. We validate incoming routerdescs and
- * SOCKS requests and addresses from BEGIN cells as they're parsed;
- * afterwards, we trust them as non-malicious.
- */
-char *
-esc_for_log(const char *s)
-{
- const char *cp;
- char *result, *outp;
- size_t len = 3;
- if (!s) {
- return tor_strdup("(null)");
- }
-
- for (cp = s; *cp; ++cp) {
- switch (*cp) {
- case '\\':
- case '\"':
- case '\'':
- case '\r':
- case '\n':
- case '\t':
- len += 2;
- break;
- default:
- if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
- ++len;
- else
- len += 4;
- break;
- }
- }
-
- tor_assert(len <= SSIZE_MAX);
-
- result = outp = tor_malloc(len);
- *outp++ = '\"';
- for (cp = s; *cp; ++cp) {
- /* This assertion should always succeed, since we will write at least
- * one char here, and two chars for closing quote and nul later */
- tor_assert((outp-result) < (ssize_t)len-2);
- switch (*cp) {
- case '\\':
- case '\"':
- case '\'':
- *outp++ = '\\';
- *outp++ = *cp;
- break;
- case '\n':
- *outp++ = '\\';
- *outp++ = 'n';
- break;
- case '\t':
- *outp++ = '\\';
- *outp++ = 't';
- break;
- case '\r':
- *outp++ = '\\';
- *outp++ = 'r';
- break;
- default:
- if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
- *outp++ = *cp;
- } else {
- tor_assert((outp-result) < (ssize_t)len-4);
- tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
- outp += 4;
- }
- break;
- }
- }
-
- tor_assert((outp-result) <= (ssize_t)len-2);
- *outp++ = '\"';
- *outp++ = 0;
-
- return result;
-}
-
-/** Similar to esc_for_log. Allocate and return a new string representing
- * the first n characters in <b>chars</b>, surround by quotes and using
- * standard C escapes. If a NUL character is encountered in <b>chars</b>,
- * the resulting string will be terminated there.
- */
-char *
-esc_for_log_len(const char *chars, size_t n)
-{
- char *string = tor_strndup(chars, n);
- char *string_escaped = esc_for_log(string);
- tor_free(string);
- return string_escaped;
-}
-
-/** Allocate and return a new string representing the contents of <b>s</b>,
- * surrounded by quotes and using standard C escapes.
- *
- * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
- * thread. Also, each call invalidates the last-returned value, so don't
- * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
- */
-const char *
-escaped(const char *s)
-{
- static char *escaped_val_ = NULL;
- tor_free(escaped_val_);
-
- if (s)
- escaped_val_ = esc_for_log(s);
- else
- escaped_val_ = NULL;
-
- return escaped_val_;
-}
-
/** Return a newly allocated string equal to <b>string</b>, except that every
* character in <b>chars_to_escape</b> is preceded by a backslash. */
char *
diff --git a/src/common/util.h b/src/common/util.h
index d1b4e8fe9..d2c27064e 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -33,6 +33,7 @@
#include "lib/intmath/cmp.h"
#include "lib/log/ratelim.h"
#include "lib/log/util_bug.h"
+#include "lib/log/escape.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -99,10 +100,6 @@ int tor_mem_is_zero(const char *mem, size_t len);
int tor_digest_is_zero(const char *digest);
int tor_digest256_is_zero(const char *digest);
-char *esc_for_log(const char *string) ATTR_MALLOC;
-char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
-const char *escaped(const char *string);
-
char *tor_escape_str_for_pt_args(const char *string,
const char *chars_to_escape);
diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c
new file mode 100644
index 000000000..756171030
--- /dev/null
+++ b/src/lib/log/escape.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/log/escape.h"
+#include "lib/log/util_bug.h"
+#include "lib/string/compat_ctype.h"
+#include "lib/string/printf.h"
+#include "lib/malloc/util_malloc.h"
+
+/** Allocate and return a new string representing the contents of <b>s</b>,
+ * surrounded by quotes and using standard C escapes.
+ *
+ * Generally, we use this for logging values that come in over the network to
+ * keep them from tricking users, and for sending certain values to the
+ * controller.
+ *
+ * We trust values from the resolver, OS, configuration file, and command line
+ * to not be maliciously ill-formed. We validate incoming routerdescs and
+ * SOCKS requests and addresses from BEGIN cells as they're parsed;
+ * afterwards, we trust them as non-malicious.
+ */
+char *
+esc_for_log(const char *s)
+{
+ const char *cp;
+ char *result, *outp;
+ size_t len = 3;
+ if (!s) {
+ return tor_strdup("(null)");
+ }
+
+ for (cp = s; *cp; ++cp) {
+ switch (*cp) {
+ case '\\':
+ case '\"':
+ case '\'':
+ case '\r':
+ case '\n':
+ case '\t':
+ len += 2;
+ break;
+ default:
+ if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
+ ++len;
+ else
+ len += 4;
+ break;
+ }
+ }
+
+ tor_assert(len <= SSIZE_MAX);
+
+ result = outp = tor_malloc(len);
+ *outp++ = '\"';
+ for (cp = s; *cp; ++cp) {
+ /* This assertion should always succeed, since we will write at least
+ * one char here, and two chars for closing quote and nul later */
+ tor_assert((outp-result) < (ssize_t)len-2);
+ switch (*cp) {
+ case '\\':
+ case '\"':
+ case '\'':
+ *outp++ = '\\';
+ *outp++ = *cp;
+ break;
+ case '\n':
+ *outp++ = '\\';
+ *outp++ = 'n';
+ break;
+ case '\t':
+ *outp++ = '\\';
+ *outp++ = 't';
+ break;
+ case '\r':
+ *outp++ = '\\';
+ *outp++ = 'r';
+ break;
+ default:
+ if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
+ *outp++ = *cp;
+ } else {
+ tor_assert((outp-result) < (ssize_t)len-4);
+ tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
+ outp += 4;
+ }
+ break;
+ }
+ }
+
+ tor_assert((outp-result) <= (ssize_t)len-2);
+ *outp++ = '\"';
+ *outp++ = 0;
+
+ return result;
+}
+
+/** Similar to esc_for_log. Allocate and return a new string representing
+ * the first n characters in <b>chars</b>, surround by quotes and using
+ * standard C escapes. If a NUL character is encountered in <b>chars</b>,
+ * the resulting string will be terminated there.
+ */
+char *
+esc_for_log_len(const char *chars, size_t n)
+{
+ char *string = tor_strndup(chars, n);
+ char *string_escaped = esc_for_log(string);
+ tor_free(string);
+ return string_escaped;
+}
+
+/** Allocate and return a new string representing the contents of <b>s</b>,
+ * surrounded by quotes and using standard C escapes.
+ *
+ * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
+ * thread. Also, each call invalidates the last-returned value, so don't
+ * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
+ */
+const char *
+escaped(const char *s)
+{
+ static char *escaped_val_ = NULL;
+ tor_free(escaped_val_);
+
+ if (s)
+ escaped_val_ = esc_for_log(s);
+ else
+ escaped_val_ = NULL;
+
+ return escaped_val_;
+}
diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h
new file mode 100644
index 000000000..5d2e79d6c
--- /dev/null
+++ b/src/lib/log/escape.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_ESCAPE_H
+#define TOR_ESCAPE_H
+
+#include "orconfig.h"
+#include "lib/cc/compat_compiler.h"
+#include <stddef.h>
+
+char *esc_for_log(const char *string) ATTR_MALLOC;
+char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
+const char *escaped(const char *string);
+
+#endif /* !defined(TOR_TORLOG_H) */
diff --git a/src/lib/log/include.am b/src/lib/log/include.am
index bbe345de7..235c95fdf 100644
--- a/src/lib/log/include.am
+++ b/src/lib/log/include.am
@@ -6,6 +6,7 @@ noinst_LIBRARIES += src/lib/libtor-log-testing.a
endif
src_lib_libtor_log_a_SOURCES = \
+ src/lib/log/escape.c \
src/lib/log/ratelim.c \
src/lib/log/torlog.c \
src/lib/log/util_bug.c
@@ -19,6 +20,7 @@ src/lib/log/torlog.$(OBJEXT) \
src/lib/log/src_lib_libtor_log_testing_a-torlog.$(OBJEXT): micro-revision.i
noinst_HEADERS += \
+ src/lib/log/escape.h \
src/lib/log/ratelim.h \
src/lib/log/torlog.h \
src/lib/log/util_bug.h
1
0
commit 42b3caa6ad70106e7bca90bceca378b91045f545
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Jun 26 20:42:47 2018 -0400
Move network code to libtor-net.
There are some additional changes to come: those points are marked
by XXXX.
---
.gitignore | 2 +
Makefile.am | 2 +
src/common/compat.c | 869 +-------------------------------------
src/common/compat.h | 186 +-------
src/common/include.am | 2 -
src/common/sandbox.c | 179 +-------
src/common/sandbox.h | 24 --
src/include.am | 1 +
src/lib/net/.may_include | 13 +
src/{common => lib/net}/address.c | 44 +-
src/{common => lib/net}/address.h | 21 +-
src/lib/net/include.am | 26 ++
src/lib/net/ipv4.c | 52 +++
src/lib/net/ipv4.h | 17 +
src/lib/net/ipv6.c | 221 ++++++++++
src/lib/net/ipv6.h | 86 ++++
src/lib/net/nettypes.h | 39 ++
src/lib/net/resolve.c | 236 +++++++++++
src/lib/net/resolve.h | 50 +++
src/lib/net/socket.c | 649 ++++++++++++++++++++++++++++
src/lib/net/socket.h | 113 +++++
src/rust/build.rs | 1 +
src/test/test_util.c | 1 +
23 files changed, 1554 insertions(+), 1280 deletions(-)
diff --git a/.gitignore b/.gitignore
index 025d7202d..d6f56f525 100644
--- a/.gitignore
+++ b/.gitignore
@@ -183,6 +183,8 @@ uptime-*.json
/src/lib/libtor-log-testing.a
/src/lib/libtor-malloc.a
/src/lib/libtor-malloc-testing.a
+/src/lib/libtor-net.a
+/src/lib/libtor-net-testing.a
/src/lib/libtor-string.a
/src/lib/libtor-string-testing.a
/src/lib/libtor-tls.a
diff --git a/Makefile.am b/Makefile.am
index 61451ed26..d80f81de1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,6 +40,7 @@ endif
# "Common" libraries used to link tor's utility code.
TOR_UTIL_LIBS = \
src/common/libor.a \
+ src/lib/libtor-net.a \
src/lib/libtor-log.a \
src/lib/libtor-lock.a \
src/lib/libtor-fdio.a \
@@ -55,6 +56,7 @@ TOR_UTIL_LIBS = \
# and tests)
TOR_UTIL_TESTING_LIBS = \
src/common/libor-testing.a \
+ src/lib/libtor-net-testing.a \
src/lib/libtor-log-testing.a \
src/lib/libtor-lock-testing.a \
src/lib/libtor-fdio-testing.a \
diff --git a/src/common/compat.c b/src/common/compat.c
index 8e418f4c1..265e82a48 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -131,11 +131,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#include "common/address.h"
#include "common/sandbox.h"
-/* When set_max_file_descriptors() is called, update this with the max file
- * descriptor value so we can use it to check the limit when opening a new
- * socket. Default value is what Debian sets as the default hard limit. */
-static int max_sockets = 1024;
-
/** As open(path, flags, mode), but return an fd with the close-on-exec mode
* set. */
int
@@ -707,618 +702,6 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
tor_free(lockfile);
}
-#undef DEBUG_SOCKET_COUNTING
-#ifdef DEBUG_SOCKET_COUNTING
-/** A bitarray of all fds that should be passed to tor_socket_close(). Only
- * used if DEBUG_SOCKET_COUNTING is defined. */
-static bitarray_t *open_sockets = NULL;
-/** The size of <b>open_sockets</b>, in bits. */
-static int max_socket = -1;
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
-
-/** Count of number of sockets currently open. (Undercounts sockets opened by
- * eventdns and libevent.) */
-static int n_sockets_open = 0;
-
-/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */
-static tor_mutex_t *socket_accounting_mutex = NULL;
-
-/** Helper: acquire the socket accounting lock. */
-static inline void
-socket_accounting_lock(void)
-{
- if (PREDICT_UNLIKELY(!socket_accounting_mutex))
- socket_accounting_mutex = tor_mutex_new();
- tor_mutex_acquire(socket_accounting_mutex);
-}
-
-/** Helper: release the socket accounting lock. */
-static inline void
-socket_accounting_unlock(void)
-{
- tor_mutex_release(socket_accounting_mutex);
-}
-
-/** As close(), but guaranteed to work for sockets across platforms (including
- * Windows, where close()ing a socket doesn't work. Returns 0 on success and
- * the socket error code on failure. */
-int
-tor_close_socket_simple(tor_socket_t s)
-{
- int r = 0;
-
- /* On Windows, you have to call close() on fds returned by open(),
- * and closesocket() on fds returned by socket(). On Unix, everything
- * gets close()'d. We abstract this difference by always using
- * tor_close_socket to close sockets, and always using close() on
- * files.
- */
- #if defined(_WIN32)
- r = closesocket(s);
- #else
- r = close(s);
- #endif
-
- if (r != 0) {
- int err = tor_socket_errno(-1);
- log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
- return err;
- }
-
- return r;
-}
-
-/** As tor_close_socket_simple(), but keeps track of the number
- * of open sockets. Returns 0 on success, -1 on failure. */
-MOCK_IMPL(int,
-tor_close_socket,(tor_socket_t s))
-{
- int r = tor_close_socket_simple(s);
-
- socket_accounting_lock();
-#ifdef DEBUG_SOCKET_COUNTING
- if (s > max_socket || ! bitarray_is_set(open_sockets, s)) {
- log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_"
- "socket(), or that was already closed or something.", s);
- } else {
- tor_assert(open_sockets && s <= max_socket);
- bitarray_clear(open_sockets, s);
- }
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
- if (r == 0) {
- --n_sockets_open;
- } else {
-#ifdef _WIN32
- if (r != WSAENOTSOCK)
- --n_sockets_open;
-#else
- if (r != EBADF)
- --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force.
-#endif /* defined(_WIN32) */
- r = -1;
- }
-
- tor_assert_nonfatal(n_sockets_open >= 0);
- socket_accounting_unlock();
- return r;
-}
-
-/** @{ */
-#ifdef DEBUG_SOCKET_COUNTING
-/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is
- * now an open socket. */
-static inline void
-mark_socket_open(tor_socket_t s)
-{
- /* XXXX This bitarray business will NOT work on windows: sockets aren't
- small ints there. */
- if (s > max_socket) {
- if (max_socket == -1) {
- open_sockets = bitarray_init_zero(s+128);
- max_socket = s+128;
- } else {
- open_sockets = bitarray_expand(open_sockets, max_socket, s+128);
- max_socket = s+128;
- }
- }
- if (bitarray_is_set(open_sockets, s)) {
- log_warn(LD_BUG, "I thought that %d was already open, but socket() just "
- "gave it to me!", s);
- }
- bitarray_set(open_sockets, s);
-}
-#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
-#define mark_socket_open(s) ((void) (s))
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
-/** @} */
-
-/** As socket(), but counts the number of open sockets. */
-MOCK_IMPL(tor_socket_t,
-tor_open_socket,(int domain, int type, int protocol))
-{
- return tor_open_socket_with_extensions(domain, type, protocol, 1, 0);
-}
-
-/** Mockable wrapper for connect(). */
-MOCK_IMPL(tor_socket_t,
-tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address,
- socklen_t address_len))
-{
- return connect(sock,address,address_len);
-}
-
-/** As socket(), but creates a nonblocking socket and
- * counts the number of open sockets. */
-tor_socket_t
-tor_open_socket_nonblocking(int domain, int type, int protocol)
-{
- return tor_open_socket_with_extensions(domain, type, protocol, 1, 1);
-}
-
-/** As socket(), but counts the number of open sockets and handles
- * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
- * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
- * if the corresponding extension should be used.*/
-tor_socket_t
-tor_open_socket_with_extensions(int domain, int type, int protocol,
- int cloexec, int nonblock)
-{
- tor_socket_t s;
-
- /* We are about to create a new file descriptor so make sure we have
- * enough of them. */
- if (get_n_open_sockets() >= max_sockets - 1) {
-#ifdef _WIN32
- WSASetLastError(WSAEMFILE);
-#else
- errno = EMFILE;
-#endif
- return TOR_INVALID_SOCKET;
- }
-
-#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
- int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
- (nonblock ? SOCK_NONBLOCK : 0);
- s = socket(domain, type|ext_flags, protocol);
- if (SOCKET_OK(s))
- goto socket_ok;
- /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
- * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK
- * support, we are running on one without. */
- if (errno != EINVAL)
- return s;
-#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */
-
- s = socket(domain, type, protocol);
- if (! SOCKET_OK(s))
- return s;
-
-#if defined(FD_CLOEXEC)
- if (cloexec) {
- if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
- log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
- tor_close_socket_simple(s);
- return TOR_INVALID_SOCKET;
- }
- }
-#else /* !(defined(FD_CLOEXEC)) */
- (void)cloexec;
-#endif /* defined(FD_CLOEXEC) */
-
- if (nonblock) {
- if (set_socket_nonblocking(s) == -1) {
- tor_close_socket_simple(s);
- return TOR_INVALID_SOCKET;
- }
- }
-
- goto socket_ok; /* So that socket_ok will not be unused. */
-
- socket_ok:
- tor_take_socket_ownership(s);
- return s;
-}
-
-/**
- * For socket accounting: remember that we are the owner of the socket
- * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
- * from asserting later when we close the socket <b>s</b>.
- */
-void
-tor_take_socket_ownership(tor_socket_t s)
-{
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
-}
-
-/** As accept(), but counts the number of open sockets. */
-tor_socket_t
-tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
-{
- return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0);
-}
-
-/** As accept(), but returns a nonblocking socket and
- * counts the number of open sockets. */
-tor_socket_t
-tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr,
- socklen_t *len)
-{
- return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1);
-}
-
-/** As accept(), but counts the number of open sockets and handles
- * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
- * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
- * if the corresponding extension should be used.*/
-tor_socket_t
-tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
- socklen_t *len, int cloexec, int nonblock)
-{
- tor_socket_t s;
-
- /* We are about to create a new file descriptor so make sure we have
- * enough of them. */
- if (get_n_open_sockets() >= max_sockets - 1) {
-#ifdef _WIN32
- WSASetLastError(WSAEMFILE);
-#else
- errno = EMFILE;
-#endif
- return TOR_INVALID_SOCKET;
- }
-
-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \
- && defined(SOCK_NONBLOCK)
- int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
- (nonblock ? SOCK_NONBLOCK : 0);
- s = accept4(sockfd, addr, len, ext_flags);
- if (SOCKET_OK(s))
- goto socket_ok;
- /* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
- * even though we were built on a system with accept4 support, we
- * are running on one without. Also, check for EINVAL, which indicates that
- * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */
- if (errno != EINVAL && errno != ENOSYS)
- return s;
-#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */
-
- s = accept(sockfd, addr, len);
- if (!SOCKET_OK(s))
- return s;
-
-#if defined(FD_CLOEXEC)
- if (cloexec) {
- if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
- log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
- tor_close_socket_simple(s);
- return TOR_INVALID_SOCKET;
- }
- }
-#else /* !(defined(FD_CLOEXEC)) */
- (void)cloexec;
-#endif /* defined(FD_CLOEXEC) */
-
- if (nonblock) {
- if (set_socket_nonblocking(s) == -1) {
- tor_close_socket_simple(s);
- return TOR_INVALID_SOCKET;
- }
- }
-
- goto socket_ok; /* So that socket_ok will not be unused. */
-
- socket_ok:
- tor_take_socket_ownership(s);
- return s;
-}
-
-/** Return the number of sockets we currently have opened. */
-int
-get_n_open_sockets(void)
-{
- int n;
- socket_accounting_lock();
- n = n_sockets_open;
- socket_accounting_unlock();
- return n;
-}
-
-/** Mockable wrapper for getsockname(). */
-MOCK_IMPL(int,
-tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
- socklen_t *address_len))
-{
- return getsockname(sock, address, address_len);
-}
-
-/**
- * Find the local address associated with the socket <b>sock</b>, and
- * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure.
- *
- * (As tor_getsockname, but instead places the result in a tor_addr_t.) */
-int
-tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock)
-{
- struct sockaddr_storage ss;
- socklen_t ss_len = sizeof(ss);
- memset(&ss, 0, sizeof(ss));
-
- if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0)
- return -1;
-
- return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL);
-}
-
-/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
- * on failure.
- */
-int
-set_socket_nonblocking(tor_socket_t sock)
-{
-#if defined(_WIN32)
- unsigned long nonblocking = 1;
- ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);
-#else
- int flags;
-
- flags = fcntl(sock, F_GETFL, 0);
- if (flags == -1) {
- log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
- return -1;
- }
- flags |= O_NONBLOCK;
- if (fcntl(sock, F_SETFL, flags) == -1) {
- log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
- return -1;
- }
-#endif /* defined(_WIN32) */
-
- return 0;
-}
-
-/**
- * Allocate a pair of connected sockets. (Like socketpair(family,
- * type,protocol,fd), but works on systems that don't have
- * socketpair.)
- *
- * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported.
- *
- * Note that on systems without socketpair, this call will fail if
- * localhost is inaccessible (for example, if the networking
- * stack is down). And even if it succeeds, the socket pair will not
- * be able to read while localhost is down later (the socket pair may
- * even close, depending on OS-specific timeouts).
- *
- * Returns 0 on success and -errno on failure; do not rely on the value
- * of errno or WSAGetLastError().
- **/
-/* It would be nicer just to set errno, but that won't work for windows. */
-int
-tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
-{
-//don't use win32 socketpairs (they are always bad)
-#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
- int r;
-
-#ifdef SOCK_CLOEXEC
- r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
- if (r == 0)
- goto sockets_ok;
- /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
- * even though we were built on a system with SOCK_CLOEXEC support, we
- * are running on one without. */
- if (errno != EINVAL)
- return -errno;
-#endif /* defined(SOCK_CLOEXEC) */
-
- r = socketpair(family, type, protocol, fd);
- if (r < 0)
- return -errno;
-
-#if defined(FD_CLOEXEC)
- if (SOCKET_OK(fd[0])) {
- r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
- if (r == -1) {
- close(fd[0]);
- close(fd[1]);
- return -errno;
- }
- }
- if (SOCKET_OK(fd[1])) {
- r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
- if (r == -1) {
- close(fd[0]);
- close(fd[1]);
- return -errno;
- }
- }
-#endif /* defined(FD_CLOEXEC) */
- goto sockets_ok; /* So that sockets_ok will not be unused. */
-
- sockets_ok:
- socket_accounting_lock();
- if (SOCKET_OK(fd[0])) {
- ++n_sockets_open;
- mark_socket_open(fd[0]);
- }
- if (SOCKET_OK(fd[1])) {
- ++n_sockets_open;
- mark_socket_open(fd[1]);
- }
- socket_accounting_unlock();
-
- return 0;
-#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */
- return tor_ersatz_socketpair(family, type, protocol, fd);
-#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
-}
-
-#ifdef NEED_ERSATZ_SOCKETPAIR
-
-static inline socklen_t
-SIZEOF_SOCKADDR(int domain)
-{
- switch (domain) {
- case AF_INET:
- return sizeof(struct sockaddr_in);
- case AF_INET6:
- return sizeof(struct sockaddr_in6);
- default:
- return 0;
- }
-}
-
-/**
- * Helper used to implement socketpair on systems that lack it, by
- * making a direct connection to localhost.
- */
-STATIC int
-tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
-{
- /* This socketpair does not work when localhost is down. So
- * it's really not the same thing at all. But it's close enough
- * for now, and really, when localhost is down sometimes, we
- * have other problems too.
- */
- tor_socket_t listener = TOR_INVALID_SOCKET;
- tor_socket_t connector = TOR_INVALID_SOCKET;
- tor_socket_t acceptor = TOR_INVALID_SOCKET;
- tor_addr_t listen_tor_addr;
- struct sockaddr_storage connect_addr_ss, listen_addr_ss;
- struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
- uint16_t listen_port = 0;
- tor_addr_t connect_tor_addr;
- uint16_t connect_port = 0;
- struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
- socklen_t size;
- int saved_errno = -1;
- int ersatz_domain = AF_INET;
-
- memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
- memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
- memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
- memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
-
- if (protocol
-#ifdef AF_UNIX
- || family != AF_UNIX
-#endif
- ) {
-#ifdef _WIN32
- return -WSAEAFNOSUPPORT;
-#else
- return -EAFNOSUPPORT;
-#endif
- }
- if (!fd) {
- return -EINVAL;
- }
-
- listener = tor_open_socket(ersatz_domain, type, 0);
- if (!SOCKET_OK(listener)) {
- int first_errno = tor_socket_errno(-1);
- if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
- && ersatz_domain == AF_INET) {
- /* Assume we're on an IPv6-only system */
- ersatz_domain = AF_INET6;
- listener = tor_open_socket(ersatz_domain, type, 0);
- if (!SOCKET_OK(listener)) {
- /* Keep the previous behaviour, which was to return the IPv4 error.
- * (This may be less informative on IPv6-only systems.)
- * XX/teor - is there a better way to decide which errno to return?
- * (I doubt we care much either way, once there is an error.)
- */
- return -first_errno;
- }
- }
- }
- /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
- * risk exposing a socketpair on a routable IP address. (Some BSD jails
- * use a routable address for localhost. Fortunately, they have the real
- * AF_UNIX socketpair.) */
- if (ersatz_domain == AF_INET) {
- tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
- } else {
- tor_addr_parse(&listen_tor_addr, "[::1]");
- }
- tor_assert(tor_addr_is_loopback(&listen_tor_addr));
- size = tor_addr_to_sockaddr(&listen_tor_addr,
- 0 /* kernel chooses port. */,
- listen_addr,
- sizeof(listen_addr_ss));
- if (bind(listener, listen_addr, size) == -1)
- goto tidy_up_and_fail;
- if (listen(listener, 1) == -1)
- goto tidy_up_and_fail;
-
- connector = tor_open_socket(ersatz_domain, type, 0);
- if (!SOCKET_OK(connector))
- goto tidy_up_and_fail;
- /* We want to find out the port number to connect to. */
- size = sizeof(connect_addr_ss);
- if (getsockname(listener, connect_addr, &size) == -1)
- goto tidy_up_and_fail;
- if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
- goto abort_tidy_up_and_fail;
- if (connect(connector, connect_addr, size) == -1)
- goto tidy_up_and_fail;
-
- size = sizeof(listen_addr_ss);
- acceptor = tor_accept_socket(listener, listen_addr, &size);
- if (!SOCKET_OK(acceptor))
- goto tidy_up_and_fail;
- if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
- goto abort_tidy_up_and_fail;
- /* Now check we are talking to ourself by matching port and host on the
- two sockets. */
- if (getsockname(connector, connect_addr, &size) == -1)
- goto tidy_up_and_fail;
- /* Set *_tor_addr and *_port to the address and port that was used */
- tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
- tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
- if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
- || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
- || listen_port != connect_port) {
- goto abort_tidy_up_and_fail;
- }
- tor_close_socket(listener);
- fd[0] = connector;
- fd[1] = acceptor;
-
- return 0;
-
- abort_tidy_up_and_fail:
-#ifdef _WIN32
- saved_errno = WSAECONNABORTED;
-#else
- saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
-#endif
- tidy_up_and_fail:
- if (saved_errno < 0)
- saved_errno = errno;
- if (SOCKET_OK(listener))
- tor_close_socket(listener);
- if (SOCKET_OK(connector))
- tor_close_socket(connector);
- if (SOCKET_OK(acceptor))
- tor_close_socket(acceptor);
- return -saved_errno;
-}
-
-#undef SIZEOF_SOCKADDR
-
-#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
-
-/* Return the maximum number of allowed sockets. */
-int
-get_max_sockets(void)
-{
- return max_sockets;
-}
-
/** Number of extra file descriptors to keep in reserve beyond those that we
* tell Tor it's allowed to use. */
#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
@@ -1396,7 +779,8 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
}
/* Set the current limit value so if the attempt to set the limit to the
* max fails at least we'll have a valid value of maximum sockets. */
- *max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER;
+ *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
+ set_max_sockets(*max_out);
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
@@ -1438,7 +822,9 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
if (limit > INT_MAX)
limit = INT_MAX;
tor_assert(max_out);
- *max_out = max_sockets = (int)limit - ULIMIT_BUFFER;
+ *max_out = (int)limit - ULIMIT_BUFFER;
+ set_max_sockets(*max_out);
+
return 0;
}
@@ -2124,251 +1510,6 @@ tor_gethostname,(char *name, size_t namelen))
return gethostname(name,namelen);
}
-/** Set *addr to the IP address (in dotted-quad notation) stored in *str.
- * Return 1 on success, 0 if *str is badly formatted.
- * (Like inet_aton(str,addr), but works on Windows and Solaris.)
- */
-int
-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)
- return 0;
- if (a > 255) return 0;
- if (b > 255) return 0;
- if (c > 255) return 0;
- if (d > 255) return 0;
- addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
- return 1;
-}
-
-/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or
- * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the
- * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns
- * <b>dst</b> on success, NULL on failure.
- *
- * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
- * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
- * support.) */
-const char *
-tor_inet_ntop(int af, const void *src, char *dst, size_t len)
-{
- if (af == AF_INET) {
- if (tor_inet_ntoa(src, dst, len) < 0)
- return NULL;
- else
- return dst;
- } else if (af == AF_INET6) {
- const struct in6_addr *addr = src;
- char buf[64], *cp;
- int longestGapLen = 0, longestGapPos = -1, i,
- curGapPos = -1, curGapLen = 0;
- uint16_t words[8];
- for (i = 0; i < 8; ++i) {
- words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
- }
- if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
- words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
- (words[5] == 0xffff))) {
- /* This is an IPv4 address. */
- if (words[5] == 0) {
- tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
- addr->s6_addr[12], addr->s6_addr[13],
- addr->s6_addr[14], addr->s6_addr[15]);
- } else {
- tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
- addr->s6_addr[12], addr->s6_addr[13],
- addr->s6_addr[14], addr->s6_addr[15]);
- }
- if ((strlen(buf) + 1) > len) /* +1 for \0 */
- return NULL;
- strlcpy(dst, buf, len);
- return dst;
- }
- i = 0;
- while (i < 8) {
- if (words[i] == 0) {
- curGapPos = i++;
- curGapLen = 1;
- while (i<8 && words[i] == 0) {
- ++i; ++curGapLen;
- }
- if (curGapLen > longestGapLen) {
- longestGapPos = curGapPos;
- longestGapLen = curGapLen;
- }
- } else {
- ++i;
- }
- }
- if (longestGapLen<=1)
- longestGapPos = -1;
-
- cp = buf;
- for (i = 0; i < 8; ++i) {
- if (words[i] == 0 && longestGapPos == i) {
- if (i == 0)
- *cp++ = ':';
- *cp++ = ':';
- while (i < 8 && words[i] == 0)
- ++i;
- --i; /* to compensate for loop increment. */
- } else {
- tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
- cp += strlen(cp);
- if (i != 7)
- *cp++ = ':';
- }
- }
- *cp = '\0';
- if ((strlen(buf) + 1) > len) /* +1 for \0 */
- return NULL;
- strlcpy(dst, buf, len);
- return dst;
- } else {
- return NULL;
- }
-}
-
-/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
- * encoding an IPv4 address or IPv6 address correspondingly, try to parse the
- * address and store the result in <b>dst</b> (which must have space for a
- * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success,
- * 0 on a bad parse, and -1 on a bad <b>af</b>.
- *
- * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
- * sometimes needs to format ipv6 addresses even on platforms without ipv6
- * support.) */
-int
-tor_inet_pton(int af, const char *src, void *dst)
-{
- if (af == AF_INET) {
- return tor_inet_aton(src, dst);
- } else if (af == AF_INET6) {
- struct in6_addr *out = dst;
- uint16_t words[8];
- int gapPos = -1, i, setWords=0;
- const char *dot = strchr(src, '.');
- const char *eow; /* end of words. */
- memset(words, 0xf8, sizeof(words));
- if (dot == src)
- return 0;
- else if (!dot)
- eow = src+strlen(src);
- else {
- unsigned byte1,byte2,byte3,byte4;
- char more;
- for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
- ;
- if (*eow != ':')
- return 0;
- ++eow;
-
- /* We use "scanf" because some platform inet_aton()s are too lax
- * about IPv4 addresses of the form "1.2.3" */
- if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
- &byte1,&byte2,&byte3,&byte4,&more) != 4)
- return 0;
-
- if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
- return 0;
-
- words[6] = (byte1<<8) | byte2;
- words[7] = (byte3<<8) | byte4;
- setWords += 2;
- }
-
- i = 0;
- while (src < eow) {
- if (i > 7)
- return 0;
- if (TOR_ISXDIGIT(*src)) {
- char *next;
- ssize_t len;
- long r = strtol(src, &next, 16);
- if (next == NULL || next == src) {
- /* The 'next == src' error case can happen on versions of openbsd
- * which treat "0xfoo" as an error, rather than as "0" followed by
- * "xfoo". */
- return 0;
- }
-
- len = *next == '\0' ? eow - src : next - src;
- if (len > 4)
- return 0;
- if (len > 1 && !TOR_ISXDIGIT(src[1]))
- return 0; /* 0x is not valid */
-
- tor_assert(r >= 0);
- tor_assert(r < 65536);
- words[i++] = (uint16_t)r;
- setWords++;
- src = next;
- if (*src != ':' && src != eow)
- return 0;
- ++src;
- } else if (*src == ':' && i > 0 && gapPos == -1) {
- gapPos = i;
- ++src;
- } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
- gapPos == -1) {
- gapPos = i;
- src += 2;
- } else {
- return 0;
- }
- }
-
- if (setWords > 8 ||
- (setWords == 8 && gapPos != -1) ||
- (setWords < 8 && gapPos == -1))
- return 0;
-
- if (gapPos >= 0) {
- int nToMove = setWords - (dot ? 2 : 0) - gapPos;
- int gapLen = 8 - setWords;
- tor_assert(nToMove >= 0);
- memmove(&words[gapPos+gapLen], &words[gapPos],
- sizeof(uint16_t)*nToMove);
- memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
- }
- for (i = 0; i < 8; ++i) {
- out->s6_addr[2*i ] = words[i] >> 8;
- out->s6_addr[2*i+1] = words[i] & 0xff;
- }
-
- return 1;
- } else {
- return -1;
- }
-}
-
-/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
- * *<b>addr</b> to the proper IP address, in host byte order. Returns 0
- * on success, -1 on failure; 1 on transient failure.
- *
- * (This function exists because standard windows gethostbyname
- * doesn't treat raw IP addresses properly.)
- */
-
-MOCK_IMPL(int,
-tor_lookup_hostname,(const char *name, uint32_t *addr))
-{
- tor_addr_t myaddr;
- int ret;
-
- if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
- return ret;
-
- if (tor_addr_family(&myaddr) == AF_INET) {
- *addr = tor_addr_to_ipv4h(&myaddr);
- return ret;
- }
-
- return -1;
-}
-
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
diff --git a/src/common/compat.h b/src/common/compat.h
index 691824a2e..efd436324 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -50,6 +50,10 @@
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
#include "lib/string/printf.h"
+#include "lib/net/socket.h"
+#include "lib/net/ipv4.h"
+#include "lib/net/ipv6.h"
+#include "lib/net/resolve.h"
#include <stdio.h>
#include <errno.h>
@@ -162,180 +166,7 @@ int64_t tor_get_avail_disk_space(const char *path);
/* ===== Net compatibility */
-#if (SIZEOF_SOCKLEN_T == 0)
-typedef int socklen_t;
-#endif
-
-#ifdef _WIN32
-/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that
- * any inadvertent checks for the socket being <= 0 or > 0 will probably
- * still work. */
-#define tor_socket_t intptr_t
-#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
-#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
-#define TOR_INVALID_SOCKET INVALID_SOCKET
-#else /* !(defined(_WIN32)) */
-/** Type used for a network socket. */
-#define tor_socket_t int
-#define TOR_SOCKET_T_FORMAT "%d"
-/** Macro: true iff 's' is a possible value for a valid initialized socket. */
-#define SOCKET_OK(s) ((s) >= 0)
-/** Error/uninitialized value for a tor_socket_t. */
-#define TOR_INVALID_SOCKET (-1)
-#endif /* defined(_WIN32) */
-
-int tor_close_socket_simple(tor_socket_t s);
-MOCK_DECL(int, tor_close_socket, (tor_socket_t s));
-void tor_take_socket_ownership(tor_socket_t s);
-tor_socket_t tor_open_socket_with_extensions(
- int domain, int type, int protocol,
- int cloexec, int nonblock);
-MOCK_DECL(tor_socket_t,
-tor_open_socket,(int domain, int type, int protocol));
-tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol);
-tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr,
- socklen_t *len);
-tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd,
- struct sockaddr *addr,
- socklen_t *len);
-tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd,
- struct sockaddr *addr,
- socklen_t *len,
- int cloexec, int nonblock);
-MOCK_DECL(tor_socket_t,
-tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address,
- socklen_t address_len));
-int get_n_open_sockets(void);
-
-MOCK_DECL(int,
-tor_getsockname,(tor_socket_t socket, struct sockaddr *address,
- socklen_t *address_len));
-struct tor_addr_t;
-int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock);
-
-#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
-#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags)
-
-/** Implementation of struct in6_addr for platforms that do not have it.
- * Generally, these platforms are ones without IPv6 support, but we want to
- * have a working in6_addr there anyway, so we can use it to parse IPv6
- * addresses. */
-#if !defined(HAVE_STRUCT_IN6_ADDR)
-struct in6_addr
-{
- union {
- uint8_t u6_addr8[16];
- uint16_t u6_addr16[8];
- uint32_t u6_addr32[4];
- } in6_u;
-#define s6_addr in6_u.u6_addr8
-#define s6_addr16 in6_u.u6_addr16
-#define s6_addr32 in6_u.u6_addr32
-};
-#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */
-
-/** @{ */
-/** Many BSD variants seem not to define these. */
-#if defined(__APPLE__) || defined(__darwin__) || \
- defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-#ifndef s6_addr16
-#define s6_addr16 __u6_addr.__u6_addr16
-#endif
-#ifndef s6_addr32
-#define s6_addr32 __u6_addr.__u6_addr32
-#endif
-#endif /* defined(__APPLE__) || defined(__darwin__) || ... */
-/** @} */
-
-#ifndef HAVE_SA_FAMILY_T
-typedef uint16_t sa_family_t;
-#endif
-
-/** @{ */
-/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these
- * macros get you a pointer to s6_addr32 or local equivalent. */
-#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32
-#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32)
-#else
-#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr))
-#endif
-#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16
-#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16)
-#else
-#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr))
-#endif
-/** @} */
-
-/** Implementation of struct sockaddr_in6 on platforms that do not have
- * it. See notes on struct in6_addr. */
-#if !defined(HAVE_STRUCT_SOCKADDR_IN6)
-struct sockaddr_in6 {
- sa_family_t sin6_family;
- uint16_t sin6_port;
- // uint32_t sin6_flowinfo;
- struct in6_addr sin6_addr;
- // uint32_t sin6_scope_id;
-};
-#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */
-
MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen));
-int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
-const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
-int tor_inet_pton(int af, const char *src, void *dst);
-MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr));
-int set_socket_nonblocking(tor_socket_t socket);
-int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
-int network_init(void);
-
-/* For stupid historical reasons, windows sockets have an independent
- * set of errnos, and an independent way to get them. Also, you can't
- * always believe WSAEWOULDBLOCK. Use the macros below to compare
- * errnos against expected values, and use tor_socket_errno to find
- * the actual errno after a socket operation fails.
- */
-#if defined(_WIN32)
-/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */
-#define SOCK_ERRNO(e) WSA##e
-/** Return true if e is EAGAIN or the local equivalent. */
-#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
-/** Return true if e is EINPROGRESS or the local equivalent. */
-#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS)
-/** Return true if e is EINPROGRESS or the local equivalent as returned by
- * a call to connect(). */
-#define ERRNO_IS_CONN_EINPROGRESS(e) \
- ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK)
-/** Return true if e is EAGAIN or another error indicating that a call to
- * accept() has no pending connections to return. */
-#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e)
-/** Return true if e is EMFILE or another error indicating that a call to
- * accept() has failed because we're out of fds or something. */
-#define ERRNO_IS_RESOURCE_LIMIT(e) \
- ((e) == WSAEMFILE || (e) == WSAENOBUFS)
-/** Return true if e is EADDRINUSE or the local equivalent. */
-#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE)
-/** Return true if e is EINTR or the local equivalent */
-#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0)
-int tor_socket_errno(tor_socket_t sock);
-const char *tor_socket_strerror(int e);
-#else /* !(defined(_WIN32)) */
-#define SOCK_ERRNO(e) e
-#if EAGAIN == EWOULDBLOCK
-/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
-#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0)
-#else
-#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
-#endif /* EAGAIN == EWOULDBLOCK */
-#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0)
-#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
-#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
-#define ERRNO_IS_ACCEPT_EAGAIN(e) \
- (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
-#define ERRNO_IS_RESOURCE_LIMIT(e) \
- ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
-#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0)
-#define tor_socket_errno(sock) (errno)
-#define tor_socket_strerror(e) strerror(e)
-#endif /* defined(_WIN32) */
/** Specified SOCKS5 status codes. */
typedef enum {
@@ -372,7 +203,6 @@ set_uint8(void *cp, uint8_t v)
#if !defined(HAVE_RLIM_T)
typedef unsigned long rlim_t;
#endif
-int get_max_sockets(void);
int set_max_file_descriptors(rlim_t limit, int *max);
int tor_disable_debugger_attach(void);
@@ -440,14 +270,6 @@ char *format_win32_error(DWORD err);
#endif /* defined(_WIN32) */
-#ifdef COMPAT_PRIVATE
-#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
-#define NEED_ERSATZ_SOCKETPAIR
-STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
- tor_socket_t fd[2]);
-#endif
-#endif /* defined(COMPAT_PRIVATE) */
-
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
/* This needs some of the declarations above so we include it here. */
diff --git a/src/common/include.am b/src/common/include.am
index 4927f5742..56666b87f 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -31,7 +31,6 @@ readpassphrase_source=
endif
LIBOR_A_SRC = \
- src/common/address.c \
src/common/address_set.c \
src/common/buffers.c \
src/common/compat.c \
@@ -76,7 +75,6 @@ src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
COMMONHEADERS = \
- src/common/address.h \
src/common/address_set.h \
src/common/buffers.h \
src/common/compat.h \
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index b41b8f4ba..9842fd983 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -37,6 +37,7 @@
#include "lib/err/torerr.h"
#include "lib/log/torlog.h"
#include "lib/cc/torint.h"
+#include "lib/net/resolve.h"
#include "common/util.h"
#include "tor_queue.h"
@@ -1458,183 +1459,6 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
return 0;
}
-/** Cache entry for getaddrinfo results; used when sandboxing is implemented
- * so that we can consult the cache when the sandbox prevents us from doing
- * getaddrinfo.
- *
- * We support only a limited range of getaddrinfo calls, where servname is null
- * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC.
- */
-typedef struct cached_getaddrinfo_item_t {
- HT_ENTRY(cached_getaddrinfo_item_t) node;
- char *name;
- int family;
- /** set if no error; otherwise NULL */
- struct addrinfo *res;
- /** 0 for no error; otherwise an EAI_* value */
- int err;
-} cached_getaddrinfo_item_t;
-
-static unsigned
-cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
-{
- return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
-}
-
-static unsigned
-cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
- const cached_getaddrinfo_item_t *b)
-{
- return (a->family == b->family) && 0 == strcmp(a->name, b->name);
-}
-
-#define cached_getaddrinfo_item_free(item) \
- FREE_AND_NULL(cached_getaddrinfo_item_t, \
- cached_getaddrinfo_item_free_, (item))
-
-static void
-cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
-{
- if (item == NULL)
- return;
-
- tor_free(item->name);
- if (item->res)
- freeaddrinfo(item->res);
- tor_free(item);
-}
-
-static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
- getaddrinfo_cache = HT_INITIALIZER();
-
-HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
- cached_getaddrinfo_item_hash,
- cached_getaddrinfo_items_eq)
-HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
- cached_getaddrinfo_item_hash,
- cached_getaddrinfo_items_eq,
- 0.6, tor_reallocarray_, tor_free_)
-
-/** If true, don't try to cache getaddrinfo results. */
-static int sandbox_getaddrinfo_cache_disabled = 0;
-
-/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in
- * tor-resolve, when we have no intention of initializing crypto or of
- * installing the sandbox.*/
-void
-sandbox_disable_getaddrinfo_cache(void)
-{
- sandbox_getaddrinfo_cache_disabled = 1;
-}
-
-void
-sandbox_freeaddrinfo(struct addrinfo *ai)
-{
- if (sandbox_getaddrinfo_cache_disabled)
- freeaddrinfo(ai);
-}
-
-int
-sandbox_getaddrinfo(const char *name, const char *servname,
- const struct addrinfo *hints,
- struct addrinfo **res)
-{
- int err;
- struct cached_getaddrinfo_item_t search, *item;
-
- if (sandbox_getaddrinfo_cache_disabled) {
- return getaddrinfo(name, NULL, hints, res);
- }
-
- if (servname != NULL) {
- log_warn(LD_BUG, "called with non-NULL servname");
- return EAI_NONAME;
- }
- if (name == NULL) {
- log_warn(LD_BUG, "called with NULL name");
- return EAI_NONAME;
- }
-
- *res = NULL;
-
- memset(&search, 0, sizeof(search));
- search.name = (char *) name;
- search.family = hints ? hints->ai_family : AF_UNSPEC;
- item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
-
- if (! sandbox_is_active()) {
- /* If the sandbox is not turned on yet, then getaddrinfo and store the
- result. */
-
- err = getaddrinfo(name, NULL, hints, res);
- log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
-
- if (! item) {
- item = tor_malloc_zero(sizeof(*item));
- item->name = tor_strdup(name);
- item->family = hints ? hints->ai_family : AF_UNSPEC;
- HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
- }
-
- if (item->res) {
- freeaddrinfo(item->res);
- item->res = NULL;
- }
- item->res = *res;
- item->err = err;
- return err;
- }
-
- /* Otherwise, the sandbox is on. If we have an item, yield its cached
- result. */
- if (item) {
- *res = item->res;
- return item->err;
- }
-
- /* getting here means something went wrong */
- log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
- return EAI_NONAME;
-}
-
-int
-sandbox_add_addrinfo(const char *name)
-{
- struct addrinfo *res;
- struct addrinfo hints;
- int i;
- static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_socktype = SOCK_STREAM;
- for (i = 0; i < 3; ++i) {
- hints.ai_family = families[i];
-
- res = NULL;
- (void) sandbox_getaddrinfo(name, NULL, &hints, &res);
- if (res)
- sandbox_freeaddrinfo(res);
- }
-
- return 0;
-}
-
-void
-sandbox_free_getaddrinfo_cache(void)
-{
- cached_getaddrinfo_item_t **next, **item, *this;
-
- for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
- item;
- item = next) {
- this = *item;
- next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
- cached_getaddrinfo_item_free(this);
- }
-
- HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
-}
-
/**
* Function responsible for going through the parameter syscall filters and
* call each function pointer in the list.
@@ -1727,6 +1551,7 @@ install_syscall_filter(sandbox_cfg_t* cfg)
// marking the sandbox as active
sandbox_active = 1;
+ sandbox_make_getaddrinfo_cache_active();
end:
seccomp_release(ctx);
diff --git a/src/common/sandbox.h b/src/common/sandbox.h
index f7c990e01..60d8e8816 100644
--- a/src/common/sandbox.h
+++ b/src/common/sandbox.h
@@ -104,27 +104,6 @@ typedef struct {
#endif /* defined(USE_LIBSECCOMP) */
#ifdef USE_LIBSECCOMP
-/** Pre-calls getaddrinfo in order to pre-record result. */
-int sandbox_add_addrinfo(const char *addr);
-
-struct addrinfo;
-/** Replacement for getaddrinfo(), using pre-recorded results. */
-int sandbox_getaddrinfo(const char *name, const char *servname,
- const struct addrinfo *hints,
- struct addrinfo **res);
-void sandbox_freeaddrinfo(struct addrinfo *addrinfo);
-void sandbox_free_getaddrinfo_cache(void);
-#else /* !(defined(USE_LIBSECCOMP)) */
-#define sandbox_getaddrinfo(name, servname, hints, res) \
- getaddrinfo((name),(servname), (hints),(res))
-#define sandbox_add_addrinfo(name) \
- ((void)(name))
-#define sandbox_freeaddrinfo(addrinfo) \
- freeaddrinfo((addrinfo))
-#define sandbox_free_getaddrinfo_cache()
-#endif /* defined(USE_LIBSECCOMP) */
-
-#ifdef USE_LIBSECCOMP
/** Returns a registered protected string used with the sandbox, given that
* it matches the parameter.
*/
@@ -168,7 +147,4 @@ int sandbox_init(sandbox_cfg_t* cfg);
/** Return true iff the sandbox is turned on. */
int sandbox_is_active(void);
-void sandbox_disable_getaddrinfo_cache(void);
-
#endif /* !defined(SANDBOX_H_) */
-
diff --git a/src/include.am b/src/include.am
index 1d2a037e9..5b8aacdd5 100644
--- a/src/include.am
+++ b/src/include.am
@@ -12,6 +12,7 @@ include src/lib/intmath/include.am
include src/lib/lock/include.am
include src/lib/log/include.am
include src/lib/malloc/include.am
+include src/lib/net/include.am
include src/lib/string/include.am
include src/lib/testsupport/include.am
include src/lib/tls/include.am
diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include
new file mode 100644
index 000000000..479f85293
--- /dev/null
+++ b/src/lib/net/.may_include
@@ -0,0 +1,13 @@
+orconfig.h
+siphash.h
+ht.h
+
+lib/cc/*.h
+lib/container/*.h
+lib/ctime/*.h
+lib/lock/*.h
+lib/log/*.h
+lib/net/*.h
+lib/string/*.h
+lib/testsupport/*.h
+lib/malloc/*.h
\ No newline at end of file
diff --git a/src/common/address.c b/src/lib/net/address.c
similarity index 98%
rename from src/common/address.c
rename to src/lib/net/address.c
index 42052f85e..70b09b419 100644
--- a/src/common/address.c
+++ b/src/lib/net/address.c
@@ -35,13 +35,21 @@
#include <iphlpapi.h>
#endif /* defined(_WIN32) */
-#include "common/compat.h"
-#include "common/util.h"
-#include "common/util_format.h"
-#include "common/address.h"
-#include "lib/log/torlog.h"
+#include "lib/net/address.h"
+#include "lib/net/socket.h"
+#include "lib/net/resolve.h"
#include "lib/container/smartlist.h"
-#include "common/sandbox.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/log/torlog.h"
+#include "lib/log/escape.h"
+#include "lib/malloc/util_malloc.h"
+#include "lib/net/ipv4.h"
+#include "lib/string/compat_ctype.h"
+#include "lib/string/compat_string.h"
+#include "lib/string/parse_int.h"
+#include "lib/string/printf.h"
+#include "lib/string/util_string.h"
+
#include "siphash.h"
#ifdef HAVE_SYS_TIME_H
@@ -53,9 +61,6 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
@@ -1474,7 +1479,10 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
STATIC smartlist_t *
get_interface_addresses_win32(int severity, sa_family_t family)
{
-
+ /*
+ XXXX We can assume that this function exists now; we can't
+ XXXX provide backward compatibility to pre-windows-XP.
+ */
/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
"GetAdaptersInfo", but that's deprecated; let's just try
GetAdaptersAddresses and fall back to connect+getsockname.
@@ -2087,22 +2095,6 @@ parse_port_range(const char *port, uint16_t *port_min_out,
return 0;
}
-/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
- * write it as a string into the <b>buf_len</b>-byte buffer in
- * <b>buf</b>. Returns a non-negative integer on success.
- * Returns -1 on failure.
- */
-int
-tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
-{
- uint32_t a = ntohl(in->s_addr);
- return tor_snprintf(buf, buf_len, "%d.%d.%d.%d",
- (int)(uint8_t)((a>>24)&0xff),
- (int)(uint8_t)((a>>16)&0xff),
- (int)(uint8_t)((a>>8 )&0xff),
- (int)(uint8_t)((a )&0xff));
-}
-
/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it
* and return a strdup of the resulting address.
*/
diff --git a/src/common/address.h b/src/lib/net/address.h
similarity index 97%
rename from src/common/address.h
rename to src/lib/net/address.h
index b95ee364a..78b798755 100644
--- a/src/common/address.h
+++ b/src/lib/net/address.h
@@ -11,11 +11,22 @@
#ifndef TOR_ADDRESS_H
#define TOR_ADDRESS_H
-//#include <sys/sockio.h>
#include "orconfig.h"
#include "lib/cc/torint.h"
-#include "common/compat.h"
#include "lib/log/util_bug.h"
+#include "lib/net/ipv6.h"
+#include "lib/net/nettypes.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
#ifdef ADDRESS_PRIVATE
@@ -73,6 +84,9 @@ typedef struct tor_addr_port_t
#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
+/* XXXX To do: extract all of the functions here that can possibly invoke
+ * XXXX resolver, and make sure they have distinctive names. */
+
static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static inline const struct in6_addr *tor_addr_to_in6_assert(
const tor_addr_t *a);
@@ -321,9 +335,6 @@ int addr_port_lookup(int severity, const char *addrport, char **address,
int parse_port_range(const char *port, uint16_t *port_min_out,
uint16_t *port_max_out);
int addr_mask_get_bits(uint32_t mask);
-/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
-#define INET_NTOA_BUF_LEN 16
-int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
#define interface_address_list_free(lst)\
diff --git a/src/lib/net/include.am b/src/lib/net/include.am
new file mode 100644
index 000000000..6bd829165
--- /dev/null
+++ b/src/lib/net/include.am
@@ -0,0 +1,26 @@
+
+noinst_LIBRARIES += src/lib/libtor-net.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-net-testing.a
+endif
+
+src_lib_libtor_net_a_SOURCES = \
+ src/lib/net/address.c \
+ src/lib/net/ipv4.c \
+ src/lib/net/ipv6.c \
+ src/lib/net/resolve.c \
+ src/lib/net/socket.c
+
+src_lib_libtor_net_testing_a_SOURCES = \
+ $(src_lib_libtor_net_a_SOURCES)
+src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+noinst_HEADERS += \
+ src/lib/net/address.h \
+ src/lib/net/ipv4.h \
+ src/lib/net/ipv6.h \
+ src/lib/net/nettypes.h \
+ src/lib/net/resolve.h \
+ src/lib/net/socket.h
diff --git a/src/lib/net/ipv4.c b/src/lib/net/ipv4.c
new file mode 100644
index 000000000..18e69761e
--- /dev/null
+++ b/src/lib/net/ipv4.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "lib/cc/torint.h"
+#include "lib/net/ipv4.h"
+#include "lib/string/printf.h"
+#include "lib/string/scanf.h"
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+/** Set *addr to the IP address (in dotted-quad notation) stored in *str.
+ * Return 1 on success, 0 if *str is badly formatted.
+ * (Like inet_aton(str,addr), but works on Windows and Solaris.)
+ */
+int
+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)
+ return 0;
+ if (a > 255) return 0;
+ if (b > 255) return 0;
+ if (c > 255) return 0;
+ if (d > 255) return 0;
+ addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
+ return 1;
+}
+
+/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
+ * write it as a string into the <b>buf_len</b>-byte buffer in
+ * <b>buf</b>. Returns a non-negative integer on success.
+ * Returns -1 on failure.
+ */
+int
+tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
+{
+ uint32_t a = ntohl(in->s_addr);
+ return tor_snprintf(buf, buf_len, "%d.%d.%d.%d",
+ (int)(uint8_t)((a>>24)&0xff),
+ (int)(uint8_t)((a>>16)&0xff),
+ (int)(uint8_t)((a>>8 )&0xff),
+ (int)(uint8_t)((a )&0xff));
+}
diff --git a/src/lib/net/ipv4.h b/src/lib/net/ipv4.h
new file mode 100644
index 000000000..1ccc72997
--- /dev/null
+++ b/src/lib/net/ipv4.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_IPV4_H
+#define TOR_IPV4_H
+
+#include <stddef.h>
+
+struct in_addr;
+int tor_inet_aton(const char *str, struct in_addr *addr);
+/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
+#define INET_NTOA_BUF_LEN 16
+int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
+
+#endif
diff --git a/src/lib/net/ipv6.c b/src/lib/net/ipv6.c
new file mode 100644
index 000000000..35d7ddb90
--- /dev/null
+++ b/src/lib/net/ipv6.c
@@ -0,0 +1,221 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/net/ipv6.h"
+#include "lib/net/ipv4.h"
+#include "lib/string/util_string.h"
+#include "lib/string/compat_string.h"
+#include "lib/string/compat_ctype.h"
+#include "lib/string/printf.h"
+#include "lib/string/scanf.h"
+#include "lib/log/util_bug.h"
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or
+ * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the
+ * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns
+ * <b>dst</b> on success, NULL on failure.
+ *
+ * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
+ * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
+ * support.) */
+const char *
+tor_inet_ntop(int af, const void *src, char *dst, size_t len)
+{
+ if (af == AF_INET) {
+ if (tor_inet_ntoa(src, dst, len) < 0)
+ return NULL;
+ else
+ return dst;
+ } else if (af == AF_INET6) {
+ const struct in6_addr *addr = src;
+ char buf[64], *cp;
+ int longestGapLen = 0, longestGapPos = -1, i,
+ curGapPos = -1, curGapLen = 0;
+ uint16_t words[8];
+ for (i = 0; i < 8; ++i) {
+ words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
+ }
+ if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
+ words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
+ (words[5] == 0xffff))) {
+ /* This is an IPv4 address. */
+ if (words[5] == 0) {
+ tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ } else {
+ tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ }
+ if ((strlen(buf) + 1) > len) /* +1 for \0 */
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+ }
+ i = 0;
+ while (i < 8) {
+ if (words[i] == 0) {
+ curGapPos = i++;
+ curGapLen = 1;
+ while (i<8 && words[i] == 0) {
+ ++i; ++curGapLen;
+ }
+ if (curGapLen > longestGapLen) {
+ longestGapPos = curGapPos;
+ longestGapLen = curGapLen;
+ }
+ } else {
+ ++i;
+ }
+ }
+ if (longestGapLen<=1)
+ longestGapPos = -1;
+
+ cp = buf;
+ for (i = 0; i < 8; ++i) {
+ if (words[i] == 0 && longestGapPos == i) {
+ if (i == 0)
+ *cp++ = ':';
+ *cp++ = ':';
+ while (i < 8 && words[i] == 0)
+ ++i;
+ --i; /* to compensate for loop increment. */
+ } else {
+ tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
+ cp += strlen(cp);
+ if (i != 7)
+ *cp++ = ':';
+ }
+ }
+ *cp = '\0';
+ if ((strlen(buf) + 1) > len) /* +1 for \0 */
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+ } else {
+ return NULL;
+ }
+}
+
+/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
+ * encoding an IPv4 address or IPv6 address correspondingly, try to parse the
+ * address and store the result in <b>dst</b> (which must have space for a
+ * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success,
+ * 0 on a bad parse, and -1 on a bad <b>af</b>.
+ *
+ * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
+ * sometimes needs to format ipv6 addresses even on platforms without ipv6
+ * support.) */
+int
+tor_inet_pton(int af, const char *src, void *dst)
+{
+ if (af == AF_INET) {
+ return tor_inet_aton(src, dst);
+ } else if (af == AF_INET6) {
+ struct in6_addr *out = dst;
+ uint16_t words[8];
+ int gapPos = -1, i, setWords=0;
+ const char *dot = strchr(src, '.');
+ const char *eow; /* end of words. */
+ memset(words, 0xf8, sizeof(words));
+ if (dot == src)
+ return 0;
+ else if (!dot)
+ eow = src+strlen(src);
+ else {
+ unsigned byte1,byte2,byte3,byte4;
+ char more;
+ for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
+ ;
+ if (*eow != ':')
+ return 0;
+ ++eow;
+
+ /* We use "scanf" because some platform inet_aton()s are too lax
+ * about IPv4 addresses of the form "1.2.3" */
+ if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
+ &byte1,&byte2,&byte3,&byte4,&more) != 4)
+ return 0;
+
+ if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
+ return 0;
+
+ words[6] = (byte1<<8) | byte2;
+ words[7] = (byte3<<8) | byte4;
+ setWords += 2;
+ }
+
+ i = 0;
+ while (src < eow) {
+ if (i > 7)
+ return 0;
+ if (TOR_ISXDIGIT(*src)) {
+ char *next;
+ ssize_t len;
+ long r = strtol(src, &next, 16);
+ if (next == NULL || next == src) {
+ /* The 'next == src' error case can happen on versions of openbsd
+ * which treat "0xfoo" as an error, rather than as "0" followed by
+ * "xfoo". */
+ return 0;
+ }
+
+ len = *next == '\0' ? eow - src : next - src;
+ if (len > 4)
+ return 0;
+ if (len > 1 && !TOR_ISXDIGIT(src[1]))
+ return 0; /* 0x is not valid */
+
+ tor_assert(r >= 0);
+ tor_assert(r < 65536);
+ words[i++] = (uint16_t)r;
+ setWords++;
+ src = next;
+ if (*src != ':' && src != eow)
+ return 0;
+ ++src;
+ } else if (*src == ':' && i > 0 && gapPos == -1) {
+ gapPos = i;
+ ++src;
+ } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
+ gapPos == -1) {
+ gapPos = i;
+ src += 2;
+ } else {
+ return 0;
+ }
+ }
+
+ if (setWords > 8 ||
+ (setWords == 8 && gapPos != -1) ||
+ (setWords < 8 && gapPos == -1))
+ return 0;
+
+ if (gapPos >= 0) {
+ int nToMove = setWords - (dot ? 2 : 0) - gapPos;
+ int gapLen = 8 - setWords;
+ tor_assert(nToMove >= 0);
+ memmove(&words[gapPos+gapLen], &words[gapPos],
+ sizeof(uint16_t)*nToMove);
+ memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
+ }
+ for (i = 0; i < 8; ++i) {
+ out->s6_addr[2*i ] = words[i] >> 8;
+ out->s6_addr[2*i+1] = words[i] & 0xff;
+ }
+
+ return 1;
+ } else {
+ return -1;
+ }
+}
diff --git a/src/lib/net/ipv6.h b/src/lib/net/ipv6.h
new file mode 100644
index 000000000..0a12e046a
--- /dev/null
+++ b/src/lib/net/ipv6.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_IPV6_H
+#define TOR_IPV6_H
+
+#include "orconfig.h"
+#include <stddef.h>
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#endif
+#include "lib/cc/torint.h"
+
+/** Implementation of struct in6_addr for platforms that do not have it.
+ * Generally, these platforms are ones without IPv6 support, but we want to
+ * have a working in6_addr there anyway, so we can use it to parse IPv6
+ * addresses. */
+#if !defined(HAVE_STRUCT_IN6_ADDR)
+struct in6_addr
+{
+ union {
+ uint8_t u6_addr8[16];
+ uint16_t u6_addr16[8];
+ uint32_t u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+};
+#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */
+
+/** @{ */
+/** Many BSD variants seem not to define these. */
+#if defined(__APPLE__) || defined(__darwin__) || \
+ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#ifndef s6_addr16
+#define s6_addr16 __u6_addr.__u6_addr16
+#endif
+#ifndef s6_addr32
+#define s6_addr32 __u6_addr.__u6_addr32
+#endif
+#endif /* defined(__APPLE__) || defined(__darwin__) || ... */
+/** @} */
+
+#ifndef HAVE_SA_FAMILY_T
+typedef uint16_t sa_family_t;
+#endif
+
+/** @{ */
+/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these
+ * macros get you a pointer to s6_addr32 or local equivalent. */
+#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32
+#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32)
+#else
+#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr))
+#endif
+#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16
+#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16)
+#else
+#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr))
+#endif
+/** @} */
+
+/** Implementation of struct sockaddr_in6 on platforms that do not have
+ * it. See notes on struct in6_addr. */
+#if !defined(HAVE_STRUCT_SOCKADDR_IN6)
+struct sockaddr_in6 {
+ sa_family_t sin6_family;
+ uint16_t sin6_port;
+ // uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ // uint32_t sin6_scope_id;
+};
+#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */
+
+const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
+int tor_inet_pton(int af, const char *src, void *dst);
+
+#endif
diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h
new file mode 100644
index 000000000..9bae70d5f
--- /dev/null
+++ b/src/lib/net/nettypes.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_NET_TYPES_H
+#define TOR_NET_TYPES_H
+
+#include "orconfig.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#if (SIZEOF_SOCKLEN_T == 0)
+typedef int socklen_t;
+#endif
+
+#ifdef _WIN32
+/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that
+ * any inadvertent checks for the socket being <= 0 or > 0 will probably
+ * still work. */
+#define tor_socket_t intptr_t
+#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
+#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
+#define TOR_INVALID_SOCKET INVALID_SOCKET
+#else /* !(defined(_WIN32)) */
+/** Type used for a network socket. */
+#define tor_socket_t int
+#define TOR_SOCKET_T_FORMAT "%d"
+/** Macro: true iff 's' is a possible value for a valid initialized socket. */
+#define SOCKET_OK(s) ((s) >= 0)
+/** Error/uninitialized value for a tor_socket_t. */
+#define TOR_INVALID_SOCKET (-1)
+#endif /* defined(_WIN32) */
+
+#endif
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
new file mode 100644
index 000000000..fefd5cceb
--- /dev/null
+++ b/src/lib/net/resolve.c
@@ -0,0 +1,236 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/net/resolve.h"
+#include "lib/net/address.h"
+#include "lib/malloc/util_malloc.h"
+
+#include "siphash.h"
+#include "ht.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <string.h>
+
+/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
+ * *<b>addr</b> to the proper IP address, in host byte order. Returns 0
+ * on success, -1 on failure; 1 on transient failure.
+ *
+ * (This function exists because standard windows gethostbyname
+ * doesn't treat raw IP addresses properly.)
+ */
+
+MOCK_IMPL(int,
+tor_lookup_hostname,(const char *name, uint32_t *addr))
+{
+ tor_addr_t myaddr;
+ int ret;
+
+ if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
+ return ret;
+
+ if (tor_addr_family(&myaddr) == AF_INET) {
+ *addr = tor_addr_to_ipv4h(&myaddr);
+ return ret;
+ }
+
+ return -1;
+}
+
+#ifdef USE_SANDBOX_GETADDRINFO
+/** True if we should only return cached values */
+static int sandbox_getaddrinfo_is_active = 0;
+
+/** Cache entry for getaddrinfo results; used when sandboxing is implemented
+ * so that we can consult the cache when the sandbox prevents us from doing
+ * getaddrinfo.
+ *
+ * We support only a limited range of getaddrinfo calls, where servname is null
+ * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC.
+ */
+typedef struct cached_getaddrinfo_item_t {
+ HT_ENTRY(cached_getaddrinfo_item_t) node;
+ char *name;
+ int family;
+ /** set if no error; otherwise NULL */
+ struct addrinfo *res;
+ /** 0 for no error; otherwise an EAI_* value */
+ int err;
+} cached_getaddrinfo_item_t;
+
+static unsigned
+cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
+{
+ return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
+}
+
+static unsigned
+cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
+ const cached_getaddrinfo_item_t *b)
+{
+ return (a->family == b->family) && 0 == strcmp(a->name, b->name);
+}
+
+#define cached_getaddrinfo_item_free(item) \
+ FREE_AND_NULL(cached_getaddrinfo_item_t, \
+ cached_getaddrinfo_item_free_, (item))
+
+static void
+cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
+{
+ if (item == NULL)
+ return;
+
+ tor_free(item->name);
+ if (item->res)
+ freeaddrinfo(item->res);
+ tor_free(item);
+}
+
+static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
+ getaddrinfo_cache = HT_INITIALIZER();
+
+HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
+ cached_getaddrinfo_item_hash,
+ cached_getaddrinfo_items_eq)
+HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
+ cached_getaddrinfo_item_hash,
+ cached_getaddrinfo_items_eq,
+ 0.6, tor_reallocarray_, tor_free_)
+
+/** If true, don't try to cache getaddrinfo results. */
+static int sandbox_getaddrinfo_cache_disabled = 0;
+
+/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in
+ * tor-resolve, when we have no intention of initializing crypto or of
+ * installing the sandbox.*/
+void
+sandbox_disable_getaddrinfo_cache(void)
+{
+ sandbox_getaddrinfo_cache_disabled = 1;
+}
+
+void
+sandbox_freeaddrinfo(struct addrinfo *ai)
+{
+ if (sandbox_getaddrinfo_cache_disabled)
+ freeaddrinfo(ai);
+}
+
+int
+sandbox_getaddrinfo(const char *name, const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ int err;
+ struct cached_getaddrinfo_item_t search, *item;
+
+ if (sandbox_getaddrinfo_cache_disabled) {
+ return getaddrinfo(name, NULL, hints, res);
+ }
+
+ if (servname != NULL) {
+ log_warn(LD_BUG, "called with non-NULL servname");
+ return EAI_NONAME;
+ }
+ if (name == NULL) {
+ log_warn(LD_BUG, "called with NULL name");
+ return EAI_NONAME;
+ }
+
+ *res = NULL;
+
+ memset(&search, 0, sizeof(search));
+ search.name = (char *) name;
+ search.family = hints ? hints->ai_family : AF_UNSPEC;
+ item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
+
+ if (! sandbox_getaddrinfo_is_active) {
+ /* If the sandbox is not turned on yet, then getaddrinfo and store the
+ result. */
+
+ err = getaddrinfo(name, NULL, hints, res);
+ log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
+
+ if (! item) {
+ item = tor_malloc_zero(sizeof(*item));
+ item->name = tor_strdup(name);
+ item->family = hints ? hints->ai_family : AF_UNSPEC;
+ HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
+ }
+
+ if (item->res) {
+ freeaddrinfo(item->res);
+ item->res = NULL;
+ }
+ item->res = *res;
+ item->err = err;
+ return err;
+ }
+
+ /* Otherwise, the sandbox is on. If we have an item, yield its cached
+ result. */
+ if (item) {
+ *res = item->res;
+ return item->err;
+ }
+
+ /* getting here means something went wrong */
+ log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
+ return EAI_NONAME;
+}
+
+int
+sandbox_add_addrinfo(const char *name)
+{
+ struct addrinfo *res;
+ struct addrinfo hints;
+ int i;
+ static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ for (i = 0; i < 3; ++i) {
+ hints.ai_family = families[i];
+
+ res = NULL;
+ (void) sandbox_getaddrinfo(name, NULL, &hints, &res);
+ if (res)
+ sandbox_freeaddrinfo(res);
+ }
+
+ return 0;
+}
+
+void
+sandbox_free_getaddrinfo_cache(void)
+{
+ cached_getaddrinfo_item_t **next, **item, *this;
+
+ for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
+ item;
+ item = next) {
+ this = *item;
+ next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
+ cached_getaddrinfo_item_free(this);
+ }
+
+ HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
+}
+
+void
+sandbox_make_getaddrinfo_cache_active(void)
+{
+ sandbox_getaddrinfo_is_active = 1;
+}
+#endif
diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h
new file mode 100644
index 000000000..a225be87f
--- /dev/null
+++ b/src/lib/net/resolve.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_RESOLVE_H
+#define TOR_RESOLVE_H
+
+#include "orconfig.h"
+#include "lib/cc/torint.h"
+#include "lib/testsupport/testsupport.h"
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#if defined(HAVE_SECCOMP_H) && defined(__linux__)
+#define USE_SANDBOX_GETADDRINFO
+#endif
+
+MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr));
+
+struct addrinfo;
+#ifdef USE_SANDBOX_GETADDRINFO
+/** Pre-calls getaddrinfo in order to pre-record result. */
+int sandbox_add_addrinfo(const char *addr);
+
+// XXXX rename these. They are named as though they were sandbox-only,
+// XXXX but in fact they're the only allowed entry point to getaddrinfo.
+// XXXX They don't invoke the sandbox code; they only have an internal cache.
+struct addrinfo;
+/** Replacement for getaddrinfo(), using pre-recorded results. */
+int sandbox_getaddrinfo(const char *name, const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+void sandbox_freeaddrinfo(struct addrinfo *addrinfo);
+void sandbox_free_getaddrinfo_cache(void);
+void sandbox_make_getaddrinfo_cache_active(void);
+#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */
+#define sandbox_getaddrinfo(name, servname, hints, res) \
+ getaddrinfo((name),(servname), (hints),(res))
+#define sandbox_add_addrinfo(name) \
+ ((void)(name))
+#define sandbox_freeaddrinfo(addrinfo) \
+ freeaddrinfo((addrinfo))
+#define sandbox_free_getaddrinfo_cache()
+#endif /* defined(USE_SANDBOX_GETADDRINFO) */
+
+void sandbox_disable_getaddrinfo_cache(void);
+
+#endif
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
new file mode 100644
index 000000000..4c14a4289
--- /dev/null
+++ b/src/lib/net/socket.c
@@ -0,0 +1,649 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define SOCKET_PRIVATE
+#include "lib/net/socket.h"
+#include "lib/net/address.h"
+#include "lib/cc/compat_compiler.h"
+#include "lib/lock/compat_mutex.h"
+#include "lib/log/torlog.h"
+#include "lib/log/util_bug.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <stddef.h>
+#include <string.h>
+
+/* When set_max_file_sockets() is called, update this with the max file
+ * descriptor value so we can use it to check the limit when opening a new
+ * socket. Default value is what Debian sets as the default hard limit. */
+static int max_sockets = 1024;
+
+/** Return the maximum number of allowed sockets. */
+int
+get_max_sockets(void)
+{
+ return max_sockets;
+}
+
+/** Set the maximum number of allowed sockets to <b>n</b> */
+void
+set_max_sockets(int n)
+{
+ max_sockets = n;
+}
+
+#undef DEBUG_SOCKET_COUNTING
+#ifdef DEBUG_SOCKET_COUNTING
+#include "lib/container/bitarray.h"
+
+/** A bitarray of all fds that should be passed to tor_socket_close(). Only
+ * used if DEBUG_SOCKET_COUNTING is defined. */
+static bitarray_t *open_sockets = NULL;
+/** The size of <b>open_sockets</b>, in bits. */
+static int max_socket = -1;
+#endif /* defined(DEBUG_SOCKET_COUNTING) */
+
+/** Count of number of sockets currently open. (Undercounts sockets opened by
+ * eventdns and libevent.) */
+static int n_sockets_open = 0;
+
+/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */
+static tor_mutex_t *socket_accounting_mutex = NULL;
+
+/** Helper: acquire the socket accounting lock. */
+static inline void
+socket_accounting_lock(void)
+{
+ if (PREDICT_UNLIKELY(!socket_accounting_mutex))
+ socket_accounting_mutex = tor_mutex_new();
+ tor_mutex_acquire(socket_accounting_mutex);
+}
+
+/** Helper: release the socket accounting lock. */
+static inline void
+socket_accounting_unlock(void)
+{
+ tor_mutex_release(socket_accounting_mutex);
+}
+
+/** As close(), but guaranteed to work for sockets across platforms (including
+ * Windows, where close()ing a socket doesn't work. Returns 0 on success and
+ * the socket error code on failure. */
+int
+tor_close_socket_simple(tor_socket_t s)
+{
+ int r = 0;
+
+ /* On Windows, you have to call close() on fds returned by open(),
+ * and closesocket() on fds returned by socket(). On Unix, everything
+ * gets close()'d. We abstract this difference by always using
+ * tor_close_socket to close sockets, and always using close() on
+ * files.
+ */
+ #if defined(_WIN32)
+ r = closesocket(s);
+ #else
+ r = close(s);
+ #endif
+
+ if (r != 0) {
+ int err = tor_socket_errno(-1);
+ log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
+ return err;
+ }
+
+ return r;
+}
+
+/** As tor_close_socket_simple(), but keeps track of the number
+ * of open sockets. Returns 0 on success, -1 on failure. */
+MOCK_IMPL(int,
+tor_close_socket,(tor_socket_t s))
+{
+ int r = tor_close_socket_simple(s);
+
+ socket_accounting_lock();
+#ifdef DEBUG_SOCKET_COUNTING
+ if (s > max_socket || ! bitarray_is_set(open_sockets, s)) {
+ log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_"
+ "socket(), or that was already closed or something.", s);
+ } else {
+ tor_assert(open_sockets && s <= max_socket);
+ bitarray_clear(open_sockets, s);
+ }
+#endif /* defined(DEBUG_SOCKET_COUNTING) */
+ if (r == 0) {
+ --n_sockets_open;
+ } else {
+#ifdef _WIN32
+ if (r != WSAENOTSOCK)
+ --n_sockets_open;
+#else
+ if (r != EBADF)
+ --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force.
+#endif /* defined(_WIN32) */
+ r = -1;
+ }
+
+ tor_assert_nonfatal(n_sockets_open >= 0);
+ socket_accounting_unlock();
+ return r;
+}
+
+/** @{ */
+#ifdef DEBUG_SOCKET_COUNTING
+/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is
+ * now an open socket. */
+static inline void
+mark_socket_open(tor_socket_t s)
+{
+ /* XXXX This bitarray business will NOT work on windows: sockets aren't
+ small ints there. */
+ if (s > max_socket) {
+ if (max_socket == -1) {
+ open_sockets = bitarray_init_zero(s+128);
+ max_socket = s+128;
+ } else {
+ open_sockets = bitarray_expand(open_sockets, max_socket, s+128);
+ max_socket = s+128;
+ }
+ }
+ if (bitarray_is_set(open_sockets, s)) {
+ log_warn(LD_BUG, "I thought that %d was already open, but socket() just "
+ "gave it to me!", s);
+ }
+ bitarray_set(open_sockets, s);
+}
+#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
+#define mark_socket_open(s) ((void) (s))
+#endif /* defined(DEBUG_SOCKET_COUNTING) */
+/** @} */
+
+/** As socket(), but counts the number of open sockets. */
+MOCK_IMPL(tor_socket_t,
+tor_open_socket,(int domain, int type, int protocol))
+{
+ return tor_open_socket_with_extensions(domain, type, protocol, 1, 0);
+}
+
+/** Mockable wrapper for connect(). */
+MOCK_IMPL(tor_socket_t,
+tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address,
+ socklen_t address_len))
+{
+ return connect(sock,address,address_len);
+}
+
+/** As socket(), but creates a nonblocking socket and
+ * counts the number of open sockets. */
+tor_socket_t
+tor_open_socket_nonblocking(int domain, int type, int protocol)
+{
+ return tor_open_socket_with_extensions(domain, type, protocol, 1, 1);
+}
+
+/** As socket(), but counts the number of open sockets and handles
+ * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
+ * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
+ * if the corresponding extension should be used.*/
+tor_socket_t
+tor_open_socket_with_extensions(int domain, int type, int protocol,
+ int cloexec, int nonblock)
+{
+ tor_socket_t s;
+
+ /* We are about to create a new file descriptor so make sure we have
+ * enough of them. */
+ if (get_n_open_sockets() >= max_sockets - 1) {
+#ifdef _WIN32
+ WSASetLastError(WSAEMFILE);
+#else
+ errno = EMFILE;
+#endif
+ return TOR_INVALID_SOCKET;
+ }
+
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
+ (nonblock ? SOCK_NONBLOCK : 0);
+ s = socket(domain, type|ext_flags, protocol);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK
+ * support, we are running on one without. */
+ if (errno != EINVAL)
+ return s;
+#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */
+
+ s = socket(domain, type, protocol);
+ if (! SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ if (cloexec) {
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ tor_close_socket_simple(s);
+ return TOR_INVALID_SOCKET;
+ }
+ }
+#else /* !(defined(FD_CLOEXEC)) */
+ (void)cloexec;
+#endif /* defined(FD_CLOEXEC) */
+
+ if (nonblock) {
+ if (set_socket_nonblocking(s) == -1) {
+ tor_close_socket_simple(s);
+ return TOR_INVALID_SOCKET;
+ }
+ }
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ tor_take_socket_ownership(s);
+ return s;
+}
+
+/**
+ * For socket accounting: remember that we are the owner of the socket
+ * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
+ * from asserting later when we close the socket <b>s</b>.
+ */
+void
+tor_take_socket_ownership(tor_socket_t s)
+{
+ socket_accounting_lock();
+ ++n_sockets_open;
+ mark_socket_open(s);
+ socket_accounting_unlock();
+}
+
+/** As accept(), but counts the number of open sockets. */
+tor_socket_t
+tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
+{
+ return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0);
+}
+
+/** As accept(), but returns a nonblocking socket and
+ * counts the number of open sockets. */
+tor_socket_t
+tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr,
+ socklen_t *len)
+{
+ return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1);
+}
+
+/** As accept(), but counts the number of open sockets and handles
+ * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
+ * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
+ * if the corresponding extension should be used.*/
+tor_socket_t
+tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
+ socklen_t *len, int cloexec, int nonblock)
+{
+ tor_socket_t s;
+
+ /* We are about to create a new file descriptor so make sure we have
+ * enough of them. */
+ if (get_n_open_sockets() >= max_sockets - 1) {
+#ifdef _WIN32
+ WSASetLastError(WSAEMFILE);
+#else
+ errno = EMFILE;
+#endif
+ return TOR_INVALID_SOCKET;
+ }
+
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \
+ && defined(SOCK_NONBLOCK)
+ int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
+ (nonblock ? SOCK_NONBLOCK : 0);
+ s = accept4(sockfd, addr, len, ext_flags);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
+ * even though we were built on a system with accept4 support, we
+ * are running on one without. Also, check for EINVAL, which indicates that
+ * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */
+ if (errno != EINVAL && errno != ENOSYS)
+ return s;
+#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */
+
+ s = accept(sockfd, addr, len);
+ if (!SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ if (cloexec) {
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ tor_close_socket_simple(s);
+ return TOR_INVALID_SOCKET;
+ }
+ }
+#else /* !(defined(FD_CLOEXEC)) */
+ (void)cloexec;
+#endif /* defined(FD_CLOEXEC) */
+
+ if (nonblock) {
+ if (set_socket_nonblocking(s) == -1) {
+ tor_close_socket_simple(s);
+ return TOR_INVALID_SOCKET;
+ }
+ }
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ tor_take_socket_ownership(s);
+ return s;
+}
+
+/** Return the number of sockets we currently have opened. */
+int
+get_n_open_sockets(void)
+{
+ int n;
+ socket_accounting_lock();
+ n = n_sockets_open;
+ socket_accounting_unlock();
+ return n;
+}
+
+/**
+ * Allocate a pair of connected sockets. (Like socketpair(family,
+ * type,protocol,fd), but works on systems that don't have
+ * socketpair.)
+ *
+ * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported.
+ *
+ * Note that on systems without socketpair, this call will fail if
+ * localhost is inaccessible (for example, if the networking
+ * stack is down). And even if it succeeds, the socket pair will not
+ * be able to read while localhost is down later (the socket pair may
+ * even close, depending on OS-specific timeouts).
+ *
+ * Returns 0 on success and -errno on failure; do not rely on the value
+ * of errno or WSAGetLastError().
+ **/
+/* It would be nicer just to set errno, but that won't work for windows. */
+int
+tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
+{
+//don't use win32 socketpairs (they are always bad)
+#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
+ int r;
+
+#ifdef SOCK_CLOEXEC
+ r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
+ if (r == 0)
+ goto sockets_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return -errno;
+#endif /* defined(SOCK_CLOEXEC) */
+
+ r = socketpair(family, type, protocol, fd);
+ if (r < 0)
+ return -errno;
+
+#if defined(FD_CLOEXEC)
+ if (SOCKET_OK(fd[0])) {
+ r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
+ if (SOCKET_OK(fd[1])) {
+ r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
+#endif /* defined(FD_CLOEXEC) */
+ goto sockets_ok; /* So that sockets_ok will not be unused. */
+
+ sockets_ok:
+ socket_accounting_lock();
+ if (SOCKET_OK(fd[0])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[0]);
+ }
+ if (SOCKET_OK(fd[1])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[1]);
+ }
+ socket_accounting_unlock();
+
+ return 0;
+#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */
+ return tor_ersatz_socketpair(family, type, protocol, fd);
+#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
+}
+
+#ifdef NEED_ERSATZ_SOCKETPAIR
+
+static inline socklen_t
+SIZEOF_SOCKADDR(int domain)
+{
+ switch (domain) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Helper used to implement socketpair on systems that lack it, by
+ * making a direct connection to localhost.
+ */
+STATIC int
+tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
+{
+ /* This socketpair does not work when localhost is down. So
+ * it's really not the same thing at all. But it's close enough
+ * for now, and really, when localhost is down sometimes, we
+ * have other problems too.
+ */
+ tor_socket_t listener = TOR_INVALID_SOCKET;
+ tor_socket_t connector = TOR_INVALID_SOCKET;
+ tor_socket_t acceptor = TOR_INVALID_SOCKET;
+ tor_addr_t listen_tor_addr;
+ struct sockaddr_storage connect_addr_ss, listen_addr_ss;
+ struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
+ uint16_t listen_port = 0;
+ tor_addr_t connect_tor_addr;
+ uint16_t connect_port = 0;
+ struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
+ socklen_t size;
+ int saved_errno = -1;
+ int ersatz_domain = AF_INET;
+
+ memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
+ memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
+ memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
+ memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
+
+ if (protocol
+#ifdef AF_UNIX
+ || family != AF_UNIX
+#endif
+ ) {
+#ifdef _WIN32
+ return -WSAEAFNOSUPPORT;
+#else
+ return -EAFNOSUPPORT;
+#endif
+ }
+ if (!fd) {
+ return -EINVAL;
+ }
+
+ listener = tor_open_socket(ersatz_domain, type, 0);
+ if (!SOCKET_OK(listener)) {
+ int first_errno = tor_socket_errno(-1);
+ if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
+ && ersatz_domain == AF_INET) {
+ /* Assume we're on an IPv6-only system */
+ ersatz_domain = AF_INET6;
+ listener = tor_open_socket(ersatz_domain, type, 0);
+ if (!SOCKET_OK(listener)) {
+ /* Keep the previous behaviour, which was to return the IPv4 error.
+ * (This may be less informative on IPv6-only systems.)
+ * XX/teor - is there a better way to decide which errno to return?
+ * (I doubt we care much either way, once there is an error.)
+ */
+ return -first_errno;
+ }
+ }
+ }
+ /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
+ * risk exposing a socketpair on a routable IP address. (Some BSD jails
+ * use a routable address for localhost. Fortunately, they have the real
+ * AF_UNIX socketpair.) */
+ if (ersatz_domain == AF_INET) {
+ tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
+ } else {
+ tor_addr_parse(&listen_tor_addr, "[::1]");
+ }
+ tor_assert(tor_addr_is_loopback(&listen_tor_addr));
+ size = tor_addr_to_sockaddr(&listen_tor_addr,
+ 0 /* kernel chooses port. */,
+ listen_addr,
+ sizeof(listen_addr_ss));
+ if (bind(listener, listen_addr, size) == -1)
+ goto tidy_up_and_fail;
+ if (listen(listener, 1) == -1)
+ goto tidy_up_and_fail;
+
+ connector = tor_open_socket(ersatz_domain, type, 0);
+ if (!SOCKET_OK(connector))
+ goto tidy_up_and_fail;
+ /* We want to find out the port number to connect to. */
+ size = sizeof(connect_addr_ss);
+ if (getsockname(listener, connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
+ goto abort_tidy_up_and_fail;
+ if (connect(connector, connect_addr, size) == -1)
+ goto tidy_up_and_fail;
+
+ size = sizeof(listen_addr_ss);
+ acceptor = tor_accept_socket(listener, listen_addr, &size);
+ if (!SOCKET_OK(acceptor))
+ goto tidy_up_and_fail;
+ if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
+ goto abort_tidy_up_and_fail;
+ /* Now check we are talking to ourself by matching port and host on the
+ two sockets. */
+ if (getsockname(connector, connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ /* Set *_tor_addr and *_port to the address and port that was used */
+ tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
+ tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
+ if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
+ || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
+ || listen_port != connect_port) {
+ goto abort_tidy_up_and_fail;
+ }
+ tor_close_socket(listener);
+ fd[0] = connector;
+ fd[1] = acceptor;
+
+ return 0;
+
+ abort_tidy_up_and_fail:
+#ifdef _WIN32
+ saved_errno = WSAECONNABORTED;
+#else
+ saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
+#endif
+ tidy_up_and_fail:
+ if (saved_errno < 0)
+ saved_errno = errno;
+ if (SOCKET_OK(listener))
+ tor_close_socket(listener);
+ if (SOCKET_OK(connector))
+ tor_close_socket(connector);
+ if (SOCKET_OK(acceptor))
+ tor_close_socket(acceptor);
+ return -saved_errno;
+}
+
+#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
+
+/** Mockable wrapper for getsockname(). */
+MOCK_IMPL(int,
+tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
+ socklen_t *address_len))
+{
+ return getsockname(sock, address, address_len);
+}
+
+/**
+ * Find the local address associated with the socket <b>sock</b>, and
+ * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure.
+ *
+ * (As tor_getsockname, but instead places the result in a tor_addr_t.) */
+int
+tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock)
+{
+ struct sockaddr_storage ss;
+ socklen_t ss_len = sizeof(ss);
+ memset(&ss, 0, sizeof(ss));
+
+ if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0)
+ return -1;
+
+ return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL);
+}
+
+/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
+ * on failure.
+ */
+int
+set_socket_nonblocking(tor_socket_t sock)
+{
+#if defined(_WIN32)
+ unsigned long nonblocking = 1;
+ ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);
+#else
+ int flags;
+
+ flags = fcntl(sock, F_GETFL, 0);
+ if (flags == -1) {
+ log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
+ return -1;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(sock, F_SETFL, flags) == -1) {
+ log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
+ return -1;
+ }
+#endif /* defined(_WIN32) */
+
+ return 0;
+}
diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h
new file mode 100644
index 000000000..93af92983
--- /dev/null
+++ b/src/lib/net/socket.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SOCKET_H
+#define TOR_SOCKET_H
+
+#include "orconfig.h"
+#include "lib/cc/torint.h"
+#include "lib/net/nettypes.h"
+#include "lib/testsupport/testsupport.h"
+
+#include <errno.h>
+
+struct sockaddr;
+
+int tor_close_socket_simple(tor_socket_t s);
+MOCK_DECL(int, tor_close_socket, (tor_socket_t s));
+void tor_take_socket_ownership(tor_socket_t s);
+tor_socket_t tor_open_socket_with_extensions(
+ int domain, int type, int protocol,
+ int cloexec, int nonblock);
+MOCK_DECL(tor_socket_t,tor_open_socket,(int domain, int type, int protocol));
+tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol);
+tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr,
+ socklen_t *len);
+tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd,
+ struct sockaddr *addr,
+ socklen_t *len);
+tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd,
+ struct sockaddr *addr,
+ socklen_t *len,
+ int cloexec, int nonblock);
+MOCK_DECL(tor_socket_t, tor_connect_socket,(tor_socket_t socket,
+ const struct sockaddr *address,
+ socklen_t address_len));
+int get_n_open_sockets(void);
+
+MOCK_DECL(int,tor_getsockname,(tor_socket_t socket, struct sockaddr *address,
+ socklen_t *address_len));
+struct tor_addr_t;
+int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock);
+
+#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
+#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags)
+
+int set_socket_nonblocking(tor_socket_t socket);
+int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
+int network_init(void);
+
+int get_max_sockets(void);
+void set_max_sockets(int);
+
+/* For stupid historical reasons, windows sockets have an independent
+ * set of errnos, and an independent way to get them. Also, you can't
+ * always believe WSAEWOULDBLOCK. Use the macros below to compare
+ * errnos against expected values, and use tor_socket_errno to find
+ * the actual errno after a socket operation fails.
+ */
+#if defined(_WIN32)
+/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */
+#define SOCK_ERRNO(e) WSA##e
+/** Return true if e is EAGAIN or the local equivalent. */
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
+/** Return true if e is EINPROGRESS or the local equivalent. */
+#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS)
+/** Return true if e is EINPROGRESS or the local equivalent as returned by
+ * a call to connect(). */
+#define ERRNO_IS_CONN_EINPROGRESS(e) \
+ ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK)
+/** Return true if e is EAGAIN or another error indicating that a call to
+ * accept() has no pending connections to return. */
+#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e)
+/** Return true if e is EMFILE or another error indicating that a call to
+ * accept() has failed because we're out of fds or something. */
+#define ERRNO_IS_RESOURCE_LIMIT(e) \
+ ((e) == WSAEMFILE || (e) == WSAENOBUFS)
+/** Return true if e is EADDRINUSE or the local equivalent. */
+#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE)
+/** Return true if e is EINTR or the local equivalent */
+#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0)
+int tor_socket_errno(tor_socket_t sock);
+const char *tor_socket_strerror(int e);
+#else /* !(defined(_WIN32)) */
+#define SOCK_ERRNO(e) e
+#if EAGAIN == EWOULDBLOCK
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0)
+#else
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif /* EAGAIN == EWOULDBLOCK */
+#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0)
+#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
+#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
+#define ERRNO_IS_ACCEPT_EAGAIN(e) \
+ (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
+#define ERRNO_IS_RESOURCE_LIMIT(e) \
+ ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
+#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0)
+#define tor_socket_errno(sock) (errno)
+#define tor_socket_strerror(e) strerror(e)
+#endif /* defined(_WIN32) */
+
+#ifdef SOCKET_PRIVATE
+#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
+#define NEED_ERSATZ_SOCKETPAIR
+STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
+ tor_socket_t fd[2]);
+#endif
+#endif /* defined(COMPAT_PRIVATE) */
+
+#endif
diff --git a/src/rust/build.rs b/src/rust/build.rs
index b43fbdceb..b51a87ab1 100644
--- a/src/rust/build.rs
+++ b/src/rust/build.rs
@@ -151,6 +151,7 @@ pub fn main() {
// moving forward!
cfg.component("tor-crypt-ops-testing");
cfg.component("or-testing");
+ cfg.component("tor-net");
cfg.component("tor-log");
cfg.component("tor-lock");
cfg.component("tor-fdio");
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 41570e14d..0c2febd46 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -9,6 +9,7 @@
#define CONTROL_PRIVATE
#define UTIL_PRIVATE
#define UTIL_MALLOC_PRIVATE
+#define SOCKET_PRIVATE
#include "or/or.h"
#include "common/buffers.h"
#include "or/config.h"
1
0

27 Jun '18
commit d893be190fc244330543c9e98613a3f0daebc6ed
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Jun 27 09:13:04 2018 -0400
rectify include paths (automatic) for address.h
---
src/common/address_set.c | 2 +-
src/common/compat.c | 2 +-
src/common/util.c | 2 +-
src/or/hs_descriptor.h | 2 +-
src/or/nodelist.c | 2 +-
src/or/or.h | 2 +-
src/test/test_address.c | 2 +-
src/test/test_bridges.c | 2 +-
src/test/test_channeltls.c | 2 +-
src/test/test_config.c | 2 +-
src/tools/tor-gencert.c | 2 +-
src/tools/tor-resolve.c | 2 +-
12 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/common/address_set.c b/src/common/address_set.c
index 369d33e9a..4e14021eb 100644
--- a/src/common/address_set.c
+++ b/src/common/address_set.c
@@ -12,7 +12,7 @@
#include "orconfig.h"
#include "common/address_set.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/compat.h"
#include "lib/container/bloomfilt.h"
#include "lib/crypt_ops/crypto_rand.h"
diff --git a/src/common/compat.c b/src/common/compat.c
index 265e82a48..9575ab080 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -128,7 +128,7 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#include "common/util.h"
#include "lib/container/smartlist.h"
#include "lib/wallclock/tm_cvt.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/sandbox.h"
/** As open(path, flags, mode), but return an fd with the close-on-exec mode
diff --git a/src/common/util.c b/src/common/util.c
index 2ea990d79..25eba4b57 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -20,7 +20,7 @@
#include "lib/cc/torint.h"
#include "lib/container/smartlist.h"
#include "lib/fdio/fdio.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/sandbox.h"
#include "lib/err/backtrace.h"
#include "common/util_process.h"
diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h
index 219b93444..d16234969 100644
--- a/src/or/hs_descriptor.h
+++ b/src/or/hs_descriptor.h
@@ -12,7 +12,7 @@
#include <stdint.h>
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "trunnel/ed25519_cert.h" /* needed for trunnel */
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 561ac9fda..bc04ab952 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -41,7 +41,7 @@
#define NODELIST_PRIVATE
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/address_set.h"
#include "or/bridges.h"
#include "or/config.h"
diff --git a/src/or/or.h b/src/or/or.h
index 528159b4c..a71cb6b00 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -72,7 +72,7 @@
#include "lib/container/smartlist.h"
#include "lib/container/map.h"
#include "lib/compress/compress.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/compat_libevent.h"
#include "ht.h"
#include "common/confline.h"
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 38a5310ed..52ca5137e 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -24,7 +24,7 @@
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c
index 747984140..98e85cd6d 100644
--- a/src/test/test_bridges.c
+++ b/src/test/test_bridges.c
@@ -12,7 +12,7 @@
#include <stdbool.h>
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "or/bridges.h"
#include "or/config.h"
#include "or/transports.h"
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 58bfaff68..bd1182677 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -7,7 +7,7 @@
#define TOR_CHANNEL_INTERNAL_
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/buffers.h"
#include "or/channel.h"
#include "or/channeltls.h"
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 177368c65..5abc97fc3 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -9,7 +9,7 @@
#define PT_PRIVATE
#define ROUTERSET_PRIVATE
#include "or/or.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "or/addressmap.h"
#include "or/bridges.h"
#include "or/circuitmux_ewma.h"
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index fc490ffeb..f65a0e250 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -41,7 +41,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "common/util_format.h"
#define IDENTITY_KEY_BITS 3072
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index d80a7400f..a13de0b57 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -6,7 +6,7 @@
#include "orconfig.h"
#include "common/compat.h"
#include "common/util.h"
-#include "common/address.h"
+#include "lib/net/address.h"
#include "lib/log/torlog.h"
#include "common/sandbox.h"
1
0

[tor/master] Link GetAdaptersAddresses, rather than loading it on-demand.
by nickm@torproject.org 27 Jun '18
by nickm@torproject.org 27 Jun '18
27 Jun '18
commit 3930416dec02f801ee9c0e1d99fd782c414ffef0
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Jun 27 09:09:10 2018 -0400
Link GetAdaptersAddresses, rather than loading it on-demand.
This function has been present since Windows XP.
---
changes/iphplapi | 4 ++++
src/lib/net/address.c | 29 +++--------------------------
src/or/include.am | 5 +++--
src/test/fuzz/include.am | 2 +-
src/test/include.am | 16 ++++++++--------
src/tools/include.am | 6 +++---
6 files changed, 22 insertions(+), 40 deletions(-)
diff --git a/changes/iphplapi b/changes/iphplapi
new file mode 100644
index 000000000..806f71c3f
--- /dev/null
+++ b/changes/iphplapi
@@ -0,0 +1,4 @@
+ o Removed features:
+ - Tor no longer attempts to run on Windows environments without the
+ GetAdaptersAddresses() function. This function has existed since
+ Windows XP, which is itself already older than we support.
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 70b09b419..69abb98a1 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -1479,17 +1479,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
STATIC smartlist_t *
get_interface_addresses_win32(int severity, sa_family_t family)
{
- /*
- XXXX We can assume that this function exists now; we can't
- XXXX provide backward compatibility to pre-windows-XP.
- */
- /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
- "GetAdaptersInfo", but that's deprecated; let's just try
- GetAdaptersAddresses and fall back to connect+getsockname.
- */
- HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll"));
smartlist_t *result = NULL;
- GetAdaptersAddresses_fn_t fn;
ULONG size, res;
IP_ADAPTER_ADDRESSES *addresses = NULL;
@@ -1499,27 +1489,16 @@ get_interface_addresses_win32(int severity, sa_family_t family)
GAA_FLAG_SKIP_MULTICAST | \
GAA_FLAG_SKIP_DNS_SERVER)
- if (!lib) {
- log_fn(severity, LD_NET, "Unable to load iphlpapi.dll");
- goto done;
- }
-
- if (!(fn = (GetAdaptersAddresses_fn_t)
- GetProcAddress(lib, "GetAdaptersAddresses"))) {
- log_fn(severity, LD_NET, "Unable to obtain pointer to "
- "GetAdaptersAddresses");
- goto done;
- }
-
/* Guess how much space we need. */
size = 15*1024;
addresses = tor_malloc(size);
- res = fn(family, FLAGS, NULL, addresses, &size);
+ /* Exists in windows XP and later. */
+ res = GetAdaptersAddresses(family, FLAGS, NULL, addresses, &size);
if (res == ERROR_BUFFER_OVERFLOW) {
/* we didn't guess that we needed enough space; try again */
tor_free(addresses);
addresses = tor_malloc(size);
- res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ res = GetAdaptersAddresses(AF_UNSPEC, FLAGS, NULL, addresses, &size);
}
if (res != NO_ERROR) {
log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res);
@@ -1529,8 +1508,6 @@ get_interface_addresses_win32(int severity, sa_family_t family)
result = ip_adapter_addresses_to_smartlist(addresses);
done:
- if (lib)
- FreeLibrary(lib);
tor_free(addresses);
return result;
}
diff --git a/src/or/include.am b/src/or/include.am
index 9e80de1f5..ed5d0c95c 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -162,7 +162,7 @@ src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libev
src_or_tor_LDADD = $(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -173,7 +173,8 @@ src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
src_or_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
+ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
endif
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 46f74ee82..b09e32d43 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -11,7 +11,7 @@ FUZZING_LIBS = \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
@TOR_ZSTD_LIBS@
diff --git a/src/test/include.am b/src/test/include.am
index 1080184ac..3dc555150 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -221,7 +221,7 @@ src_test_test_switch_id_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_USERENV@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@@ -230,7 +230,7 @@ src_test_test_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -253,7 +253,7 @@ src_test_bench_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -263,7 +263,7 @@ src_test_test_workqueue_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -275,7 +275,7 @@ src_test_test_timers_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_LZMA_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
@@ -305,7 +305,7 @@ src_test_test_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_LZMA_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -315,7 +315,7 @@ src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_test_test_hs_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -326,7 +326,7 @@ src_test_test_bt_cl_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
diff --git a/src/tools/include.am b/src/tools/include.am
index bbccb6d18..e6465233b 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -9,7 +9,7 @@ src_tools_tor_resolve_LDFLAGS =
src_tools_tor_resolve_LDADD = \
$(TOR_UTIL_LIBS) \
$(rust_ldadd) \
- @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_USERENV@
+ @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@
if COVERAGE_ENABLED
src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c
@@ -27,7 +27,7 @@ src_tools_tor_gencert_LDADD = \
$(TOR_UTIL_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
if COVERAGE_ENABLED
src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c
@@ -38,7 +38,7 @@ src_tools_tor_cov_gencert_LDADD = \
$(TOR_CRYPTO_TESTING_LIBS) \
$(TOR_UTIL_TESTING_LIBS) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
endif
if BUILD_LIBTORRUNNER
1
0
commit b9b05e437d09c4d06b554d0484c7ae1a3aa1d647
Merge: 300e3bebd d893be190
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Jun 27 12:52:31 2018 -0400
Merge branch 'net_refactor'
.gitignore | 2 +
Makefile.am | 2 +
changes/iphplapi | 4 +
src/common/address_set.c | 2 +-
src/common/compat.c | 871 +-------------------------------------
src/common/compat.h | 186 +-------
src/common/include.am | 2 -
src/common/sandbox.c | 179 +-------
src/common/sandbox.h | 24 --
src/common/util.c | 240 +----------
src/common/util.h | 15 +-
src/include.am | 1 +
src/lib/log/escape.c | 132 ++++++
src/lib/log/escape.h | 18 +
src/lib/log/include.am | 2 +
src/lib/net/.may_include | 13 +
src/{common => lib/net}/address.c | 65 +--
src/{common => lib/net}/address.h | 21 +-
src/lib/net/include.am | 26 ++
src/lib/net/ipv4.c | 52 +++
src/lib/net/ipv4.h | 17 +
src/lib/net/ipv6.c | 221 ++++++++++
src/lib/net/ipv6.h | 86 ++++
src/lib/net/nettypes.h | 39 ++
src/lib/net/resolve.c | 236 +++++++++++
src/lib/net/resolve.h | 50 +++
src/lib/net/socket.c | 649 ++++++++++++++++++++++++++++
src/lib/net/socket.h | 113 +++++
src/lib/string/include.am | 2 +
src/lib/string/parse_int.c | 126 ++++++
src/lib/string/parse_int.h | 20 +
src/or/hs_descriptor.h | 2 +-
src/or/include.am | 5 +-
src/or/nodelist.c | 2 +-
src/or/or.h | 2 +-
src/rust/build.rs | 1 +
src/test/fuzz/include.am | 2 +-
src/test/include.am | 16 +-
src/test/test_address.c | 2 +-
src/test/test_bridges.c | 2 +-
src/test/test_channeltls.c | 2 +-
src/test/test_config.c | 2 +-
src/test/test_util.c | 22 +-
src/tools/include.am | 6 +-
src/tools/tor-gencert.c | 2 +-
src/tools/tor-resolve.c | 2 +-
46 files changed, 1887 insertions(+), 1599 deletions(-)
diff --cc .gitignore
index 34f845442,d6f56f525..390859f5e
--- a/.gitignore
+++ b/.gitignore
@@@ -183,10 -183,10 +183,12 @@@ uptime-*.jso
/src/lib/libtor-log-testing.a
/src/lib/libtor-malloc.a
/src/lib/libtor-malloc-testing.a
+ /src/lib/libtor-net.a
+ /src/lib/libtor-net-testing.a
/src/lib/libtor-string.a
/src/lib/libtor-string-testing.a
+/src/lib/libtor-smartlist-core.a
+/src/lib/libtor-smartlist-core-testing.a
/src/lib/libtor-tls.a
/src/lib/libtor-tls-testing.a
/src/lib/libtor-trace.a
diff --cc Makefile.am
index 482189eeb,d80f81de1..c151d441c
--- a/Makefile.am
+++ b/Makefile.am
@@@ -40,7 -40,7 +40,8 @@@ endi
# "Common" libraries used to link tor's utility code.
TOR_UTIL_LIBS = \
src/common/libor.a \
+ src/lib/libtor-container.a \
+ src/lib/libtor-net.a \
src/lib/libtor-log.a \
src/lib/libtor-lock.a \
src/lib/libtor-fdio.a \
@@@ -56,7 -56,7 +57,8 @@@
# and tests)
TOR_UTIL_TESTING_LIBS = \
src/common/libor-testing.a \
+ src/lib/libtor-container-testing.a \
+ src/lib/libtor-net-testing.a \
src/lib/libtor-log-testing.a \
src/lib/libtor-lock-testing.a \
src/lib/libtor-fdio-testing.a \
diff --cc src/include.am
index 9e89fc8e0,5b8aacdd5..b6ef3cf16
--- a/src/include.am
+++ b/src/include.am
@@@ -12,8 -12,8 +12,9 @@@ include src/lib/intmath/include.a
include src/lib/lock/include.am
include src/lib/log/include.am
include src/lib/malloc/include.am
+ include src/lib/net/include.am
include src/lib/string/include.am
+include src/lib/smartlist_core/include.am
include src/lib/testsupport/include.am
include src/lib/tls/include.am
include src/lib/trace/include.am
1
0

[translation/tails-perl5lib_completed] Update translations for tails-perl5lib_completed
by translation@torproject.org 27 Jun '18
by translation@torproject.org 27 Jun '18
27 Jun '18
commit 093122ceb9dddfbffb490672aae65f62f73bf357
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jun 27 16:47:44 2018 +0000
Update translations for tails-perl5lib_completed
---
bn_BD.po | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/bn_BD.po b/bn_BD.po
index 6506e4094..92bc851c3 100644
--- a/bn_BD.po
+++ b/bn_BD.po
@@ -3,14 +3,15 @@
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
-# Al Shahrior <shahrior3814(a)gmail.com>, 2017
+# Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>, 2018
+# Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: Tails developers <tails(a)boum.org>\n"
-"POT-Creation-Date: 2017-05-20 10:59+0200\n"
-"PO-Revision-Date: 2017-11-14 19:16+0000\n"
-"Last-Translator: Al Shahrior <shahrior3814(a)gmail.com>\n"
+"POT-Creation-Date: 2018-03-15 12:15+0000\n"
+"PO-Revision-Date: 2018-06-27 16:21+0000\n"
+"Last-Translator: Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>\n"
"Language-Team: Bengali (Bangladesh) (http://www.transifex.com/otf/torproject/language/bn_BD/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -24,12 +25,12 @@ msgstr "ভুল"
#: ../lib/Tails/RunningSystem.pm:161
msgid ""
-"The device Tails is running from cannot be found. Maybe you used the `toram'"
+"The device Tails is running from cannot be found. Maybe you used the 'toram'"
" option?"
-msgstr "ডিভাইস টাইল থেকে চলমান হয় পাওয়া যাবে না। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
+msgstr "টাইল যে ডিভাইস থেকে চলছে তা পাওয়া যাবে নি। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
#: ../lib/Tails/RunningSystem.pm:192
msgid ""
-"The drive Tails is running from cannot be found. Maybe you used the `toram' "
+"The drive Tails is running from cannot be found. Maybe you used the 'toram' "
"option?"
-msgstr "ড্রাইভ টাইল থেকে চলমান হয় পাওয়া যাবে না। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
+msgstr "টাইল যে ডিভাইস থেকে চলছে তা পাওয়া যাবে নি। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
1
0

[translation/tails-perl5lib] Update translations for tails-perl5lib
by translation@torproject.org 27 Jun '18
by translation@torproject.org 27 Jun '18
27 Jun '18
commit 9c828155fa232651eb39e2a28e4b9ecb10b52cbc
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jun 27 16:47:40 2018 +0000
Update translations for tails-perl5lib
---
bn_BD.po | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/bn_BD.po b/bn_BD.po
index 0b056f900..92bc851c3 100644
--- a/bn_BD.po
+++ b/bn_BD.po
@@ -3,14 +3,15 @@
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
+# Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>, 2018
# Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: Tails developers <tails(a)boum.org>\n"
"POT-Creation-Date: 2018-03-15 12:15+0000\n"
-"PO-Revision-Date: 2018-03-31 13:21+0000\n"
-"Last-Translator: carolyn <carolyn(a)anhalt.org>\n"
+"PO-Revision-Date: 2018-06-27 16:21+0000\n"
+"Last-Translator: Al Shahrior Hasan Sagor <shahrior3814(a)gmail.com>\n"
"Language-Team: Bengali (Bangladesh) (http://www.transifex.com/otf/torproject/language/bn_BD/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -26,10 +27,10 @@ msgstr "ভুল"
msgid ""
"The device Tails is running from cannot be found. Maybe you used the 'toram'"
" option?"
-msgstr ""
+msgstr "টাইল যে ডিভাইস থেকে চলছে তা পাওয়া যাবে নি। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
#: ../lib/Tails/RunningSystem.pm:192
msgid ""
"The drive Tails is running from cannot be found. Maybe you used the 'toram' "
"option?"
-msgstr ""
+msgstr "টাইল যে ডিভাইস থেকে চলছে তা পাওয়া যাবে নি। হয়তো আপনি 'toram' বিকল্প ব্যবহার করেছেন?"
1
0

[tor/master] fixup! Extract core part of smartlist code into its own library.
by nickm@torproject.org 27 Jun '18
by nickm@torproject.org 27 Jun '18
27 Jun '18
commit 82a7343b061b110cb97e4d804f989bc34ee120c9
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Jun 26 12:21:35 2018 -0400
fixup! Extract core part of smartlist code into its own library.
---
src/lib/smartlist_core/smartlist_core.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c
index aefdd7709..b9c5f728c 100644
--- a/src/lib/smartlist_core/smartlist_core.c
+++ b/src/lib/smartlist_core/smartlist_core.c
@@ -169,7 +169,6 @@ smartlist_pop_last(smartlist_t *sl)
return NULL;
}
-
/** Return true iff some element E of sl has E==element.
*/
int
1
0

[tor/master] Extract core part of smartlist code into its own library.
by nickm@torproject.org 27 Jun '18
by nickm@torproject.org 27 Jun '18
27 Jun '18
commit b1de1e7a77275ad3e8a65d984ff1e9779920e933
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Jun 26 12:13:23 2018 -0400
Extract core part of smartlist code into its own library.
The smartlist_core library now contains only the parts of smartlists
that are needed for the logging library. This resolves the
circularity between "container" and "log".
The "containers" library still uses the logging code, and has the
higher-level smartlist functions.
---
.gitignore | 2 +
Makefile.am | 6 +-
src/include.am | 1 +
src/lib/container/.may_include | 1 +
src/lib/container/smartlist.c | 290 -----------------------------
src/lib/container/smartlist.h | 207 +-------------------
src/lib/log/.may_include | 2 +-
src/lib/log/torlog.c | 6 +-
src/lib/log/util_bug.c | 3 +-
src/lib/smartlist_core/.may_include | 7 +
src/lib/smartlist_core/include.am | 21 +++
src/lib/smartlist_core/smartlist_core.c | 237 +++++++++++++++++++++++
src/lib/smartlist_core/smartlist_core.h | 95 ++++++++++
src/lib/smartlist_core/smartlist_foreach.h | 128 +++++++++++++
src/lib/smartlist_core/smartlist_split.c | 89 +++++++++
src/lib/smartlist_core/smartlist_split.h | 15 ++
16 files changed, 610 insertions(+), 500 deletions(-)
diff --git a/.gitignore b/.gitignore
index 025d7202d..34f845442 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,6 +185,8 @@ uptime-*.json
/src/lib/libtor-malloc-testing.a
/src/lib/libtor-string.a
/src/lib/libtor-string-testing.a
+/src/lib/libtor-smartlist-core.a
+/src/lib/libtor-smartlist-core-testing.a
/src/lib/libtor-tls.a
/src/lib/libtor-tls-testing.a
/src/lib/libtor-trace.a
diff --git a/Makefile.am b/Makefile.am
index 61451ed26..482189eeb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,11 +40,12 @@ endif
# "Common" libraries used to link tor's utility code.
TOR_UTIL_LIBS = \
src/common/libor.a \
+ src/lib/libtor-container.a \
src/lib/libtor-log.a \
src/lib/libtor-lock.a \
src/lib/libtor-fdio.a \
- src/lib/libtor-container.a \
src/lib/libtor-string.a \
+ src/lib/libtor-smartlist-core.a \
src/lib/libtor-malloc.a \
src/lib/libtor-wallclock.a \
src/lib/libtor-err.a \
@@ -55,11 +56,12 @@ TOR_UTIL_LIBS = \
# and tests)
TOR_UTIL_TESTING_LIBS = \
src/common/libor-testing.a \
+ src/lib/libtor-container-testing.a \
src/lib/libtor-log-testing.a \
src/lib/libtor-lock-testing.a \
src/lib/libtor-fdio-testing.a \
- src/lib/libtor-container-testing.a \
src/lib/libtor-string-testing.a \
+ src/lib/libtor-smartlist-core-testing.a \
src/lib/libtor-malloc-testing.a \
src/lib/libtor-wallclock-testing.a \
src/lib/libtor-err-testing.a \
diff --git a/src/include.am b/src/include.am
index 1d2a037e9..9e89fc8e0 100644
--- a/src/include.am
+++ b/src/include.am
@@ -13,6 +13,7 @@ include src/lib/lock/include.am
include src/lib/log/include.am
include src/lib/malloc/include.am
include src/lib/string/include.am
+include src/lib/smartlist_core/include.am
include src/lib/testsupport/include.am
include src/lib/tls/include.am
include src/lib/trace/include.am
diff --git a/src/lib/container/.may_include b/src/lib/container/.may_include
index 1114ad845..2eecb503c 100644
--- a/src/lib/container/.may_include
+++ b/src/lib/container/.may_include
@@ -5,6 +5,7 @@ lib/ctime/*.h
lib/defs/*.h
lib/malloc/*.h
lib/err/*.h
+lib/smartlist_core/*.h
lib/string/*.h
lib/testsupport/testsupport.h
lib/intmath/*.h
diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c
index 3c0844384..9025cab9f 100644
--- a/src/lib/container/smartlist.c
+++ b/src/lib/container/smartlist.c
@@ -9,7 +9,6 @@
* with helper functions to use smartlists.
**/
-#include "lib/malloc/util_malloc.h"
#include "lib/container/smartlist.h"
#include "lib/err/torerr.h"
#include "lib/malloc/util_malloc.h"
@@ -24,108 +23,6 @@
#include <stdlib.h>
#include <string.h>
-/** All newly allocated smartlists have this capacity. */
-#define SMARTLIST_DEFAULT_CAPACITY 16
-
-/** Allocate and return an empty smartlist.
- */
-MOCK_IMPL(smartlist_t *,
-smartlist_new,(void))
-{
- smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
- sl->num_used = 0;
- sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
- sl->list = tor_calloc(sizeof(void *), sl->capacity);
- return sl;
-}
-
-/** Deallocate a smartlist. Does not release storage associated with the
- * list's elements.
- */
-MOCK_IMPL(void,
-smartlist_free_,(smartlist_t *sl))
-{
- if (!sl)
- return;
- tor_free(sl->list);
- tor_free(sl);
-}
-
-/** Remove all elements from the list.
- */
-void
-smartlist_clear(smartlist_t *sl)
-{
- memset(sl->list, 0, sizeof(void *) * sl->num_used);
- sl->num_used = 0;
-}
-
-#if SIZE_MAX < INT_MAX
-#error "We don't support systems where size_t is smaller than int."
-#endif
-
-/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */
-static inline void
-smartlist_ensure_capacity(smartlist_t *sl, size_t size)
-{
- /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */
-#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX
-#define MAX_CAPACITY (INT_MAX)
-#else
-#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*))))
-#endif
-
- raw_assert(size <= MAX_CAPACITY);
-
- if (size > (size_t) sl->capacity) {
- size_t higher = (size_t) sl->capacity;
- if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) {
- higher = MAX_CAPACITY;
- } else {
- while (size > higher)
- higher *= 2;
- }
- sl->list = tor_reallocarray(sl->list, sizeof(void *),
- ((size_t)higher));
- memset(sl->list + sl->capacity, 0,
- sizeof(void *) * (higher - sl->capacity));
- sl->capacity = (int) higher;
- }
-#undef ASSERT_CAPACITY
-#undef MAX_CAPACITY
-}
-
-/** Append element to the end of the list. */
-void
-smartlist_add(smartlist_t *sl, void *element)
-{
- smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
- sl->list[sl->num_used++] = element;
-}
-
-/** Append each element from S2 to the end of S1. */
-void
-smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
-{
- size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used;
- tor_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */
- smartlist_ensure_capacity(s1, new_size);
- memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*));
- tor_assert(new_size <= INT_MAX); /* redundant. */
- s1->num_used = (int) new_size;
-}
-
-/** Append a copy of string to sl */
-void
-smartlist_add_strdup(struct smartlist_t *sl, const char *string)
-{
- char *copy;
-
- copy = tor_strdup(string);
-
- smartlist_add(sl, copy);
-}
-
/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>)
* to <b>sl</b>. */
void
@@ -150,56 +47,6 @@ smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern,
smartlist_add(sl, str);
}
-/** Remove all elements E from sl such that E==element. Preserve
- * the order of any elements before E, but elements after E can be
- * rearranged.
- */
-void
-smartlist_remove(smartlist_t *sl, const void *element)
-{
- int i;
- if (element == NULL)
- return;
- for (i=0; i < sl->num_used; i++)
- if (sl->list[i] == element) {
- sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
- i--; /* so we process the new i'th element */
- sl->list[sl->num_used] = NULL;
- }
-}
-
-/** As <b>smartlist_remove</b>, but do not change the order of
- * any elements not removed */
-void
-smartlist_remove_keeporder(smartlist_t *sl, const void *element)
-{
- int i, j, num_used_orig = sl->num_used;
- if (element == NULL)
- return;
-
- for (i=j=0; j < num_used_orig; ++j) {
- if (sl->list[j] == element) {
- --sl->num_used;
- } else {
- sl->list[i++] = sl->list[j];
- }
- }
-}
-
-/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise,
- * return NULL. */
-void *
-smartlist_pop_last(smartlist_t *sl)
-{
- tor_assert(sl);
- if (sl->num_used) {
- void *tmp = sl->list[--sl->num_used];
- sl->list[sl->num_used] = NULL;
- return tmp;
- } else
- return NULL;
-}
-
/** Reverse the order of the items in <b>sl</b>. */
void
smartlist_reverse(smartlist_t *sl)
@@ -232,18 +79,6 @@ smartlist_string_remove(smartlist_t *sl, const char *element)
}
}
-/** Return true iff some element E of sl has E==element.
- */
-int
-smartlist_contains(const smartlist_t *sl, const void *element)
-{
- int i;
- for (i=0; i < sl->num_used; i++)
- if (sl->list[i] == element)
- return 1;
- return 0;
-}
-
/** Return true iff <b>sl</b> has some element E such that
* !strcmp(E,<b>element</b>)
*/
@@ -399,131 +234,6 @@ smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2)
smartlist_remove(sl1, sl2->list[i]);
}
-/** Remove the <b>idx</b>th element of sl; if idx is not the last
- * element, swap the last element of sl into the <b>idx</b>th space.
- */
-void
-smartlist_del(smartlist_t *sl, int idx)
-{
- tor_assert(sl);
- tor_assert(idx>=0);
- tor_assert(idx < sl->num_used);
- sl->list[idx] = sl->list[--sl->num_used];
- sl->list[sl->num_used] = NULL;
-}
-
-/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
- * moving all subsequent elements back one space. Return the old value
- * of the <b>idx</b>th element.
- */
-void
-smartlist_del_keeporder(smartlist_t *sl, int idx)
-{
- tor_assert(sl);
- tor_assert(idx>=0);
- tor_assert(idx < sl->num_used);
- --sl->num_used;
- if (idx < sl->num_used)
- memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
- sl->list[sl->num_used] = NULL;
-}
-
-/** Insert the value <b>val</b> as the new <b>idx</b>th element of
- * <b>sl</b>, moving all items previously at <b>idx</b> or later
- * forward one space.
- */
-void
-smartlist_insert(smartlist_t *sl, int idx, void *val)
-{
- tor_assert(sl);
- tor_assert(idx>=0);
- tor_assert(idx <= sl->num_used);
- if (idx == sl->num_used) {
- smartlist_add(sl, val);
- } else {
- smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
- /* Move other elements away */
- if (idx < sl->num_used)
- memmove(sl->list + idx + 1, sl->list + idx,
- sizeof(void*)*(sl->num_used-idx));
- sl->num_used++;
- sl->list[idx] = val;
- }
-}
-
-/**
- * Split a string <b>str</b> along all occurrences of <b>sep</b>,
- * appending the (newly allocated) split strings, in order, to
- * <b>sl</b>. Return the number of strings added to <b>sl</b>.
- *
- * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and
- * trailing space from each entry.
- * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries
- * of length 0.
- * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each
- * split string.
- *
- * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If
- * <b>sep</b> is NULL, split on any sequence of horizontal space.
- */
-int
-smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
- int flags, int max)
-{
- const char *cp, *end, *next;
- int n = 0;
-
- tor_assert(sl);
- tor_assert(str);
-
- cp = str;
- while (1) {
- if (flags&SPLIT_SKIP_SPACE) {
- while (TOR_ISSPACE(*cp)) ++cp;
- }
-
- if (max>0 && n == max-1) {
- end = strchr(cp,'\0');
- } else if (sep) {
- end = strstr(cp,sep);
- if (!end)
- end = strchr(cp,'\0');
- } else {
- for (end = cp; *end && *end != '\t' && *end != ' '; ++end)
- ;
- }
-
- tor_assert(end);
-
- if (!*end) {
- next = NULL;
- } else if (sep) {
- next = end+strlen(sep);
- } else {
- next = end+1;
- while (*next == '\t' || *next == ' ')
- ++next;
- }
-
- if (flags&SPLIT_SKIP_SPACE) {
- while (end > cp && TOR_ISSPACE(*(end-1)))
- --end;
- }
- if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
- char *string = tor_strndup(cp, end-cp);
- if (flags&SPLIT_STRIP_SPACE)
- tor_strstrip(string, " ");
- smartlist_add(sl, string);
- ++n;
- }
- if (!next)
- break;
- cp = next;
- }
-
- return n;
-}
-
/** Allocate and return a new string containing the concatenation of
* the elements of <b>sl</b>, in order, separated by <b>join</b>. If
* <b>terminate</b> is true, also terminate the string with <b>join</b>.
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index c202e134f..76ecbda0a 100644
--- a/src/lib/container/smartlist.h
+++ b/src/lib/container/smartlist.h
@@ -6,50 +6,19 @@
#ifndef TOR_SMARTLIST_H
#define TOR_SMARTLIST_H
-#include <stddef.h>
#include <stdarg.h>
-#include "lib/cc/compat_compiler.h"
-#include "lib/cc/torint.h"
-#include "lib/testsupport/testsupport.h"
+#include "lib/smartlist_core/smartlist_core.h"
+#include "lib/smartlist_core/smartlist_foreach.h"
+#include "lib/smartlist_core/smartlist_split.h"
-/** A resizeable list of pointers, with associated helpful functionality.
- *
- * The members of this struct are exposed only so that macros and inlines can
- * use them; all access to smartlist internals should go through the functions
- * and macros defined here.
- **/
-typedef struct smartlist_t {
- /** @{ */
- /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
- * before it needs to be resized. Only the first <b>num_used</b> (\<=
- * capacity) elements point to valid data.
- */
- void **list;
- int num_used;
- int capacity;
- /** @} */
-} smartlist_t;
-
-MOCK_DECL(smartlist_t *, smartlist_new, (void));
-MOCK_DECL(void, smartlist_free_, (smartlist_t *sl));
-#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl))
-
-void smartlist_clear(smartlist_t *sl);
-void smartlist_add(smartlist_t *sl, void *element);
-void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
-void smartlist_add_strdup(struct smartlist_t *sl, const char *string);
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...)
CHECK_PRINTF(2, 3);
void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern,
va_list args)
CHECK_PRINTF(2, 0);
-void smartlist_remove(smartlist_t *sl, const void *element);
-void smartlist_remove_keeporder(smartlist_t *sl, const void *element);
-void *smartlist_pop_last(smartlist_t *sl);
void smartlist_reverse(smartlist_t *sl);
void smartlist_string_remove(smartlist_t *sl, const char *element);
-int smartlist_contains(const smartlist_t *sl, const void *element);
int smartlist_contains_string(const smartlist_t *sl, const char *element);
int smartlist_pos(const smartlist_t *sl, const void *element);
int smartlist_string_pos(const smartlist_t *, const char *elt);
@@ -62,52 +31,6 @@ int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
-/* smartlist_choose() is defined in crypto.[ch] */
-#ifdef DEBUG_SMARTLIST
-#include "lib/err/torerr.h"
-#include <stdlib.h>
-/** Return the number of items in sl.
- */
-static inline int smartlist_len(const smartlist_t *sl);
-static inline int smartlist_len(const smartlist_t *sl) {
- raw_assert(sl);
- return (sl)->num_used;
-}
-/** Return the <b>idx</b>th element of sl.
- */
-static inline void *smartlist_get(const smartlist_t *sl, int idx);
-static inline void *smartlist_get(const smartlist_t *sl, int idx) {
- raw_assert(sl);
- raw_assert(idx>=0);
- raw_assert(sl->num_used > idx);
- return sl->list[idx];
-}
-static inline void smartlist_set(smartlist_t *sl, int idx, void *val) {
- raw_assert(sl);
- raw_assert(idx>=0);
- raw_assert(sl->num_used > idx);
- sl->list[idx] = val;
-}
-#else /* !(defined(DEBUG_SMARTLIST)) */
-#define smartlist_len(sl) ((sl)->num_used)
-#define smartlist_get(sl, idx) ((sl)->list[idx])
-#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val))
-#endif /* defined(DEBUG_SMARTLIST) */
-
-/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the
- * smartlist <b>sl</b>. */
-static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2)
-{
- if (idx1 != idx2) {
- void *elt = smartlist_get(sl, idx1);
- smartlist_set(sl, idx1, smartlist_get(sl, idx2));
- smartlist_set(sl, idx2, elt);
- }
-}
-
-void smartlist_del(smartlist_t *sl, int idx);
-void smartlist_del_keeporder(smartlist_t *sl, int idx);
-void smartlist_insert(smartlist_t *sl, int idx, void *val);
void smartlist_sort(smartlist_t *sl,
int (*compare)(const void **a, const void **b));
void *smartlist_get_most_frequent_(const smartlist_t *sl,
@@ -153,136 +76,12 @@ void smartlist_pqueue_assert_ok(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
int idx_field_offset);
-#define SPLIT_SKIP_SPACE 0x01
-#define SPLIT_IGNORE_BLANK 0x02
-#define SPLIT_STRIP_SPACE 0x04
-int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
- int flags, int max);
char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate,
size_t *len_out) ATTR_MALLOC;
char *smartlist_join_strings2(smartlist_t *sl, const char *join,
size_t join_len, int terminate, size_t *len_out)
ATTR_MALLOC;
-/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item,
- * assign it to a new local variable of type <b>type</b> named <b>var</b>, and
- * execute the statements inside the loop body. Inside the loop, the loop
- * index can be accessed as <b>var</b>_sl_idx and the length of the list can
- * be accessed as <b>var</b>_sl_len.
- *
- * NOTE: Do not change the length of the list while the loop is in progress,
- * unless you adjust the _sl_len variable correspondingly. See second example
- * below.
- *
- * Example use:
- * <pre>
- * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
- * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
- * printf("%d: %s\n", cp_sl_idx, cp);
- * tor_free(cp);
- * } SMARTLIST_FOREACH_END(cp);
- * smartlist_free(list);
- * </pre>
- *
- * Example use (advanced):
- * <pre>
- * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
- * if (!strcmp(cp, "junk")) {
- * tor_free(cp);
- * SMARTLIST_DEL_CURRENT(list, cp);
- * }
- * } SMARTLIST_FOREACH_END(cp);
- * </pre>
- */
-/* Note: these macros use token pasting, and reach into smartlist internals.
- * This can make them a little daunting. Here's the approximate unpacking of
- * the above examples, for entertainment value:
- *
- * <pre>
- * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
- * {
- * int cp_sl_idx, cp_sl_len = smartlist_len(list);
- * char *cp;
- * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
- * cp = smartlist_get(list, cp_sl_idx);
- * printf("%d: %s\n", cp_sl_idx, cp);
- * tor_free(cp);
- * }
- * }
- * smartlist_free(list);
- * </pre>
- *
- * <pre>
- * {
- * int cp_sl_idx, cp_sl_len = smartlist_len(list);
- * char *cp;
- * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
- * cp = smartlist_get(list, cp_sl_idx);
- * if (!strcmp(cp, "junk")) {
- * tor_free(cp);
- * smartlist_del(list, cp_sl_idx);
- * --cp_sl_idx;
- * --cp_sl_len;
- * }
- * }
- * }
- * </pre>
- */
-#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \
- STMT_BEGIN \
- int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \
- type var; \
- for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \
- ++var ## _sl_idx) { \
- var = (sl)->list[var ## _sl_idx];
-
-#define SMARTLIST_FOREACH_END(var) \
- var = NULL; \
- (void) var ## _sl_idx; \
- } STMT_END
-
-/**
- * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using
- * <b>cmd</b> as the loop body. This wrapper is here for convenience with
- * very short loops.
- *
- * By convention, we do not use this for loops which nest, or for loops over
- * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those.
- */
-#define SMARTLIST_FOREACH(sl, type, var, cmd) \
- SMARTLIST_FOREACH_BEGIN(sl,type,var) { \
- cmd; \
- } SMARTLIST_FOREACH_END(var)
-
-/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
- * with the variable <b>var</b>, remove the current element in a way that
- * won't confuse the loop. */
-#define SMARTLIST_DEL_CURRENT(sl, var) \
- STMT_BEGIN \
- smartlist_del(sl, var ## _sl_idx); \
- --var ## _sl_idx; \
- --var ## _sl_len; \
- STMT_END
-
-/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
- * with the variable <b>var</b>, remove the current element in a way that
- * won't confuse the loop. */
-#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \
- STMT_BEGIN \
- smartlist_del_keeporder(sl, var ## _sl_idx); \
- --var ## _sl_idx; \
- --var ## _sl_len; \
- STMT_END
-
-/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
- * with the variable <b>var</b>, replace the current element with <b>val</b>.
- * Does not deallocate the current value of <b>var</b>.
- */
-#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \
- STMT_BEGIN \
- smartlist_set(sl, var ## _sl_idx, val); \
- STMT_END
-
/* 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
diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include
index 36a164cce..852173aab 100644
--- a/src/lib/log/.may_include
+++ b/src/lib/log/.may_include
@@ -1,7 +1,7 @@
orconfig.h
lib/cc/*.h
-lib/container/smartlist.h
+lib/smartlist_core/*.h
lib/err/*.h
lib/fdio/*.h
lib/intmath/*.h
diff --git a/src/lib/log/torlog.c b/src/lib/log/torlog.c
index 5709dd819..bffffbf1b 100644
--- a/src/lib/log/torlog.c
+++ b/src/lib/log/torlog.c
@@ -5,7 +5,7 @@
/* See LICENSE for licensing information */
/**
- * \file log.c
+ * \file torlog.c
* \brief Functions to send messages to log files or the console.
**/
@@ -34,7 +34,9 @@
#include "lib/log/torlog.h"
#include "lib/log/ratelim.h"
#include "lib/lock/compat_mutex.h"
-#include "lib/container/smartlist.h"
+#include "lib/smartlist_core/smartlist_core.h"
+#include "lib/smartlist_core/smartlist_foreach.h"
+#include "lib/smartlist_core/smartlist_split.h"
#include "lib/err/torerr.h"
#include "lib/intmath/bits.h"
#include "lib/string/compat_string.h"
diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c
index 161b65e0b..78af08f02 100644
--- a/src/lib/log/util_bug.c
+++ b/src/lib/log/util_bug.c
@@ -12,7 +12,8 @@
#include "lib/log/torlog.h"
#include "lib/err/backtrace.h"
#ifdef TOR_UNIT_TESTS
-#include "lib/container/smartlist.h"
+#include "lib/smartlist_core/smartlist_core.h"
+#include "lib/smartlist_core/smartlist_foreach.h"
#endif
#include "lib/malloc/util_malloc.h"
#include "lib/string/printf.h"
diff --git a/src/lib/smartlist_core/.may_include b/src/lib/smartlist_core/.may_include
new file mode 100644
index 000000000..a8507761a
--- /dev/null
+++ b/src/lib/smartlist_core/.may_include
@@ -0,0 +1,7 @@
+orconfig.h
+lib/cc/*.h
+lib/malloc/*.h
+lib/err/*.h
+lib/string/*.h
+lib/smartlist_core/*.h
+lib/testsupport/testsupport.h
diff --git a/src/lib/smartlist_core/include.am b/src/lib/smartlist_core/include.am
new file mode 100644
index 000000000..9ee93fdee
--- /dev/null
+++ b/src/lib/smartlist_core/include.am
@@ -0,0 +1,21 @@
+
+noinst_LIBRARIES += src/lib/libtor-smartlist-core.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-smartlist-core-testing.a
+endif
+
+src_lib_libtor_smartlist_core_a_SOURCES = \
+ src/lib/smartlist_core/smartlist_core.c \
+ src/lib/smartlist_core/smartlist_split.c
+
+src_lib_libtor_smartlist_core_testing_a_SOURCES = \
+ $(src_lib_libtor_smartlist_core_a_SOURCES)
+src_lib_libtor_smartlist_core_testing_a_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_smartlist_core_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+noinst_HEADERS += \
+ src/lib/smartlist_core/smartlist_core.h \
+ src/lib/smartlist_core/smartlist_foreach.h \
+ src/lib/smartlist_core/smartlist_split.h
diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c
new file mode 100644
index 000000000..ca5c5f0bf
--- /dev/null
+++ b/src/lib/smartlist_core/smartlist_core.c
@@ -0,0 +1,237 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file smartlist_core.c
+ * \brief Implements the core functionality of a smartlist (a resizeable
+ * dynamic array). For more functionality and helper functions, see the
+ * container library.
+ **/
+
+#include "lib/err/torerr.h"
+#include "lib/malloc/util_malloc.h"
+#include "lib/smartlist_core/smartlist_core.h"
+
+#define tor_assert raw_assert
+
+#include <stdlib.h>
+#include <string.h>
+
+/** All newly allocated smartlists have this capacity. */
+#define SMARTLIST_DEFAULT_CAPACITY 16
+
+/** Allocate and return an empty smartlist.
+ */
+MOCK_IMPL(smartlist_t *,
+smartlist_new,(void))
+{
+ smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
+ sl->num_used = 0;
+ sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
+ sl->list = tor_calloc(sizeof(void *), sl->capacity);
+ return sl;
+}
+
+/** Deallocate a smartlist. Does not release storage associated with the
+ * list's elements.
+ */
+MOCK_IMPL(void,
+smartlist_free_,(smartlist_t *sl))
+{
+ if (!sl)
+ return;
+ tor_free(sl->list);
+ tor_free(sl);
+}
+
+/** Remove all elements from the list.
+ */
+void
+smartlist_clear(smartlist_t *sl)
+{
+ memset(sl->list, 0, sizeof(void *) * sl->num_used);
+ sl->num_used = 0;
+}
+
+#if SIZE_MAX < INT_MAX
+#error "We don't support systems where size_t is smaller than int."
+#endif
+
+/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */
+static inline void
+smartlist_ensure_capacity(smartlist_t *sl, size_t size)
+{
+ /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */
+#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX
+#define MAX_CAPACITY (INT_MAX)
+#else
+#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*))))
+#endif
+
+ raw_assert(size <= MAX_CAPACITY);
+
+ if (size > (size_t) sl->capacity) {
+ size_t higher = (size_t) sl->capacity;
+ if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) {
+ higher = MAX_CAPACITY;
+ } else {
+ while (size > higher)
+ higher *= 2;
+ }
+ sl->list = tor_reallocarray(sl->list, sizeof(void *),
+ ((size_t)higher));
+ memset(sl->list + sl->capacity, 0,
+ sizeof(void *) * (higher - sl->capacity));
+ sl->capacity = (int) higher;
+ }
+#undef ASSERT_CAPACITY
+#undef MAX_CAPACITY
+}
+
+/** Append element to the end of the list. */
+void
+smartlist_add(smartlist_t *sl, void *element)
+{
+ smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
+ sl->list[sl->num_used++] = element;
+}
+
+/** Append each element from S2 to the end of S1. */
+void
+smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
+{
+ size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used;
+ tor_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */
+ smartlist_ensure_capacity(s1, new_size);
+ memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*));
+ tor_assert(new_size <= INT_MAX); /* redundant. */
+ s1->num_used = (int) new_size;
+}
+
+/** Append a copy of string to sl */
+void
+smartlist_add_strdup(struct smartlist_t *sl, const char *string)
+{
+ char *copy;
+
+ copy = tor_strdup(string);
+
+ smartlist_add(sl, copy);
+}
+
+/** Remove all elements E from sl such that E==element. Preserve
+ * the order of any elements before E, but elements after E can be
+ * rearranged.
+ */
+void
+smartlist_remove(smartlist_t *sl, const void *element)
+{
+ int i;
+ if (element == NULL)
+ return;
+ for (i=0; i < sl->num_used; i++)
+ if (sl->list[i] == element) {
+ sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
+ i--; /* so we process the new i'th element */
+ sl->list[sl->num_used] = NULL;
+ }
+}
+
+/** As <b>smartlist_remove</b>, but do not change the order of
+ * any elements not removed */
+void
+smartlist_remove_keeporder(smartlist_t *sl, const void *element)
+{
+ int i, j, num_used_orig = sl->num_used;
+ if (element == NULL)
+ return;
+
+ for (i=j=0; j < num_used_orig; ++j) {
+ if (sl->list[j] == element) {
+ --sl->num_used;
+ } else {
+ sl->list[i++] = sl->list[j];
+ }
+ }
+}
+
+/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise,
+ * return NULL. */
+void *
+smartlist_pop_last(smartlist_t *sl)
+{
+ tor_assert(sl);
+ if (sl->num_used) {
+ void *tmp = sl->list[--sl->num_used];
+ sl->list[sl->num_used] = NULL;
+ return tmp;
+ } else
+ return NULL;
+}
+
+
+/** Return true iff some element E of sl has E==element.
+ */
+int
+smartlist_contains(const smartlist_t *sl, const void *element)
+{
+ int i;
+ for (i=0; i < sl->num_used; i++)
+ if (sl->list[i] == element)
+ return 1;
+ return 0;
+}
+
+/** Remove the <b>idx</b>th element of sl; if idx is not the last
+ * element, swap the last element of sl into the <b>idx</b>th space.
+ */
+void
+smartlist_del(smartlist_t *sl, int idx)
+{
+ tor_assert(sl);
+ tor_assert(idx>=0);
+ tor_assert(idx < sl->num_used);
+ sl->list[idx] = sl->list[--sl->num_used];
+ sl->list[sl->num_used] = NULL;
+}
+
+/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
+ * moving all subsequent elements back one space. Return the old value
+ * of the <b>idx</b>th element.
+ */
+void
+smartlist_del_keeporder(smartlist_t *sl, int idx)
+{
+ tor_assert(sl);
+ tor_assert(idx>=0);
+ tor_assert(idx < sl->num_used);
+ --sl->num_used;
+ if (idx < sl->num_used)
+ memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
+ sl->list[sl->num_used] = NULL;
+}
+
+/** Insert the value <b>val</b> as the new <b>idx</b>th element of
+ * <b>sl</b>, moving all items previously at <b>idx</b> or later
+ * forward one space.
+ */
+void
+smartlist_insert(smartlist_t *sl, int idx, void *val)
+{
+ tor_assert(sl);
+ tor_assert(idx>=0);
+ tor_assert(idx <= sl->num_used);
+ if (idx == sl->num_used) {
+ smartlist_add(sl, val);
+ } else {
+ smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
+ /* Move other elements away */
+ if (idx < sl->num_used)
+ memmove(sl->list + idx + 1, sl->list + idx,
+ sizeof(void*)*(sl->num_used-idx));
+ sl->num_used++;
+ sl->list[idx] = val;
+ }
+}
diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h
new file mode 100644
index 000000000..b1adf2ebd
--- /dev/null
+++ b/src/lib/smartlist_core/smartlist_core.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SMARTLIST_CORE_H
+#define TOR_SMARTLIST_CORE_H
+
+#include <stddef.h>
+
+#include "lib/cc/compat_compiler.h"
+#include "lib/cc/torint.h"
+#include "lib/testsupport/testsupport.h"
+
+/** A resizeable list of pointers, with associated helpful functionality.
+ *
+ * The members of this struct are exposed only so that macros and inlines can
+ * use them; all access to smartlist internals should go through the functions
+ * and macros defined here.
+ **/
+typedef struct smartlist_t {
+ /** @{ */
+ /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
+ * before it needs to be resized. Only the first <b>num_used</b> (\<=
+ * capacity) elements point to valid data.
+ */
+ void **list;
+ int num_used;
+ int capacity;
+ /** @} */
+} smartlist_t;
+
+MOCK_DECL(smartlist_t *, smartlist_new, (void));
+MOCK_DECL(void, smartlist_free_, (smartlist_t *sl));
+#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl))
+
+void smartlist_clear(smartlist_t *sl);
+void smartlist_add(smartlist_t *sl, void *element);
+void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
+void smartlist_add_strdup(struct smartlist_t *sl, const char *string);
+
+void smartlist_remove(smartlist_t *sl, const void *element);
+void smartlist_remove_keeporder(smartlist_t *sl, const void *element);
+void *smartlist_pop_last(smartlist_t *sl);
+
+int smartlist_contains(const smartlist_t *sl, const void *element);
+
+/* smartlist_choose() is defined in crypto.[ch] */
+#ifdef DEBUG_SMARTLIST
+#include "lib/err/torerr.h"
+#include <stdlib.h>
+/** Return the number of items in sl.
+ */
+static inline int smartlist_len(const smartlist_t *sl);
+static inline int smartlist_len(const smartlist_t *sl) {
+ raw_assert(sl);
+ return (sl)->num_used;
+}
+/** Return the <b>idx</b>th element of sl.
+ */
+static inline void *smartlist_get(const smartlist_t *sl, int idx);
+static inline void *smartlist_get(const smartlist_t *sl, int idx) {
+ raw_assert(sl);
+ raw_assert(idx>=0);
+ raw_assert(sl->num_used > idx);
+ return sl->list[idx];
+}
+static inline void smartlist_set(smartlist_t *sl, int idx, void *val) {
+ raw_assert(sl);
+ raw_assert(idx>=0);
+ raw_assert(sl->num_used > idx);
+ sl->list[idx] = val;
+}
+#else /* !(defined(DEBUG_SMARTLIST)) */
+#define smartlist_len(sl) ((sl)->num_used)
+#define smartlist_get(sl, idx) ((sl)->list[idx])
+#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val))
+#endif /* defined(DEBUG_SMARTLIST) */
+
+/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the
+ * smartlist <b>sl</b>. */
+static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2)
+{
+ if (idx1 != idx2) {
+ void *elt = smartlist_get(sl, idx1);
+ smartlist_set(sl, idx1, smartlist_get(sl, idx2));
+ smartlist_set(sl, idx2, elt);
+ }
+}
+
+void smartlist_del(smartlist_t *sl, int idx);
+void smartlist_del_keeporder(smartlist_t *sl, int idx);
+void smartlist_insert(smartlist_t *sl, int idx, void *val);
+
+#endif /* !defined(TOR_CONTAINER_H) */
diff --git a/src/lib/smartlist_core/smartlist_foreach.h b/src/lib/smartlist_core/smartlist_foreach.h
new file mode 100644
index 000000000..4bef36d99
--- /dev/null
+++ b/src/lib/smartlist_core/smartlist_foreach.h
@@ -0,0 +1,128 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SMARTLIST_FOREACH_H
+#define TOR_SMARTLIST_FOREACH_H
+
+/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item,
+ * assign it to a new local variable of type <b>type</b> named <b>var</b>, and
+ * execute the statements inside the loop body. Inside the loop, the loop
+ * index can be accessed as <b>var</b>_sl_idx and the length of the list can
+ * be accessed as <b>var</b>_sl_len.
+ *
+ * NOTE: Do not change the length of the list while the loop is in progress,
+ * unless you adjust the _sl_len variable correspondingly. See second example
+ * below.
+ *
+ * Example use:
+ * <pre>
+ * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
+ * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
+ * printf("%d: %s\n", cp_sl_idx, cp);
+ * tor_free(cp);
+ * } SMARTLIST_FOREACH_END(cp);
+ * smartlist_free(list);
+ * </pre>
+ *
+ * Example use (advanced):
+ * <pre>
+ * SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
+ * if (!strcmp(cp, "junk")) {
+ * tor_free(cp);
+ * SMARTLIST_DEL_CURRENT(list, cp);
+ * }
+ * } SMARTLIST_FOREACH_END(cp);
+ * </pre>
+ */
+/* Note: these macros use token pasting, and reach into smartlist internals.
+ * This can make them a little daunting. Here's the approximate unpacking of
+ * the above examples, for entertainment value:
+ *
+ * <pre>
+ * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
+ * {
+ * int cp_sl_idx, cp_sl_len = smartlist_len(list);
+ * char *cp;
+ * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
+ * cp = smartlist_get(list, cp_sl_idx);
+ * printf("%d: %s\n", cp_sl_idx, cp);
+ * tor_free(cp);
+ * }
+ * }
+ * smartlist_free(list);
+ * </pre>
+ *
+ * <pre>
+ * {
+ * int cp_sl_idx, cp_sl_len = smartlist_len(list);
+ * char *cp;
+ * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
+ * cp = smartlist_get(list, cp_sl_idx);
+ * if (!strcmp(cp, "junk")) {
+ * tor_free(cp);
+ * smartlist_del(list, cp_sl_idx);
+ * --cp_sl_idx;
+ * --cp_sl_len;
+ * }
+ * }
+ * }
+ * </pre>
+ */
+#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \
+ STMT_BEGIN \
+ int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \
+ type var; \
+ for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \
+ ++var ## _sl_idx) { \
+ var = (sl)->list[var ## _sl_idx];
+
+#define SMARTLIST_FOREACH_END(var) \
+ var = NULL; \
+ (void) var ## _sl_idx; \
+ } STMT_END
+
+/**
+ * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using
+ * <b>cmd</b> as the loop body. This wrapper is here for convenience with
+ * very short loops.
+ *
+ * By convention, we do not use this for loops which nest, or for loops over
+ * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those.
+ */
+#define SMARTLIST_FOREACH(sl, type, var, cmd) \
+ SMARTLIST_FOREACH_BEGIN(sl,type,var) { \
+ cmd; \
+ } SMARTLIST_FOREACH_END(var)
+
+/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
+ * with the variable <b>var</b>, remove the current element in a way that
+ * won't confuse the loop. */
+#define SMARTLIST_DEL_CURRENT(sl, var) \
+ STMT_BEGIN \
+ smartlist_del(sl, var ## _sl_idx); \
+ --var ## _sl_idx; \
+ --var ## _sl_len; \
+ STMT_END
+
+/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
+ * with the variable <b>var</b>, remove the current element in a way that
+ * won't confuse the loop. */
+#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \
+ STMT_BEGIN \
+ smartlist_del_keeporder(sl, var ## _sl_idx); \
+ --var ## _sl_idx; \
+ --var ## _sl_len; \
+ STMT_END
+
+/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
+ * with the variable <b>var</b>, replace the current element with <b>val</b>.
+ * Does not deallocate the current value of <b>var</b>.
+ */
+#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \
+ STMT_BEGIN \
+ smartlist_set(sl, var ## _sl_idx, val); \
+ STMT_END
+
+#endif /* !defined(TOR_SMARTLIST_FOREACH_H) */
diff --git a/src/lib/smartlist_core/smartlist_split.c b/src/lib/smartlist_core/smartlist_split.c
new file mode 100644
index 000000000..e24a742c2
--- /dev/null
+++ b/src/lib/smartlist_core/smartlist_split.c
@@ -0,0 +1,89 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "lib/smartlist_core/smartlist_core.h"
+#include "lib/smartlist_core/smartlist_split.h"
+
+#include "lib/err/torerr.h"
+#include "lib/string/util_string.h"
+#include "lib/string/compat_ctype.h"
+#include "lib/malloc/util_malloc.h"
+
+#include <string.h>
+
+#define tor_assert raw_assert
+
+/**
+ * Split a string <b>str</b> along all occurrences of <b>sep</b>,
+ * appending the (newly allocated) split strings, in order, to
+ * <b>sl</b>. Return the number of strings added to <b>sl</b>.
+ *
+ * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and
+ * trailing space from each entry.
+ * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries
+ * of length 0.
+ * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each
+ * split string.
+ *
+ * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If
+ * <b>sep</b> is NULL, split on any sequence of horizontal space.
+ */
+int
+smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
+ int flags, int max)
+{
+ const char *cp, *end, *next;
+ int n = 0;
+
+ tor_assert(sl);
+ tor_assert(str);
+
+ cp = str;
+ while (1) {
+ if (flags&SPLIT_SKIP_SPACE) {
+ while (TOR_ISSPACE(*cp)) ++cp;
+ }
+
+ if (max>0 && n == max-1) {
+ end = strchr(cp,'\0');
+ } else if (sep) {
+ end = strstr(cp,sep);
+ if (!end)
+ end = strchr(cp,'\0');
+ } else {
+ for (end = cp; *end && *end != '\t' && *end != ' '; ++end)
+ ;
+ }
+
+ tor_assert(end);
+
+ if (!*end) {
+ next = NULL;
+ } else if (sep) {
+ next = end+strlen(sep);
+ } else {
+ next = end+1;
+ while (*next == '\t' || *next == ' ')
+ ++next;
+ }
+
+ if (flags&SPLIT_SKIP_SPACE) {
+ while (end > cp && TOR_ISSPACE(*(end-1)))
+ --end;
+ }
+ if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
+ char *string = tor_strndup(cp, end-cp);
+ if (flags&SPLIT_STRIP_SPACE)
+ tor_strstrip(string, " ");
+ smartlist_add(sl, string);
+ ++n;
+ }
+ if (!next)
+ break;
+ cp = next;
+ }
+
+ return n;
+}
diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h
new file mode 100644
index 000000000..8ed2abafb
--- /dev/null
+++ b/src/lib/smartlist_core/smartlist_split.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SMARTLIST_SPLIT_H
+#define TOR_SMARTLIST_SPLIT_H
+
+#define SPLIT_SKIP_SPACE 0x01
+#define SPLIT_IGNORE_BLANK 0x02
+#define SPLIT_STRIP_SPACE 0x04
+int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
+ int flags, int max);
+
+#endif
1
0