summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c1
-rw-r--r--src/app/main/main.c1
-rw-r--r--src/core/include.am6
-rw-r--r--src/core/mainloop/mainloop.c1
-rw-r--r--src/core/or/circuitbuild.c2
-rw-r--r--src/core/or/circuitlist.c1
-rw-r--r--src/core/or/circuituse.c2
-rw-r--r--src/core/or/connection_edge.c1
-rw-r--r--src/feature/control/control.c2
-rw-r--r--src/feature/dircache/dirserv.c2
-rw-r--r--src/feature/dirclient/dirclient.c2
-rw-r--r--src/feature/rend/rendservice.c2
-rw-r--r--src/feature/stats/predict_ports.c311
-rw-r--r--src/feature/stats/predict_ports.h30
-rw-r--r--src/feature/stats/rephist.c309
-rw-r--r--src/feature/stats/rephist.h14
-rw-r--r--src/test/testing_common.c1
17 files changed, 366 insertions, 322 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 91e2758650..2818cdaad8 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -103,6 +103,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_init.h"
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 90bc8c510f..c756e55b9f 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -61,6 +61,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/container/buffers.h"
diff --git a/src/core/include.am b/src/core/include.am
index 64a593ca51..68bbf94743 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -117,7 +117,8 @@ LIBTOR_APP_A_SOURCES = \
src/feature/rend/rendmid.c \
src/feature/rend/rendservice.c \
src/feature/stats/geoip.c \
- src/feature/stats/rephist.c
+ src/feature/stats/rephist.c \
+ src/feature/stats/predict_ports.c
# These should eventually move into module_dirauth_sources, but for now
# the separation is only in the code location.
@@ -347,7 +348,8 @@ noinst_HEADERS += \
src/feature/rend/rendmid.h \
src/feature/rend/rendservice.h \
src/feature/stats/geoip.h \
- src/feature/stats/rephist.h
+ src/feature/stats/rephist.h \
+ src/feature/stats/predict_ports.h
noinst_HEADERS += \
src/app/config/auth_dirs.inc \
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 4a9da43c9c..ebfdf1c943 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -93,6 +93,7 @@
#include "feature/rend/rendcache.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/container/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 26f0fc4d4f..822129d80e 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -67,7 +67,7 @@
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "feature/rend/rendcommon.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/cell_st.h"
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index c07c8e97a0..5ff142c15c 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -85,6 +85,7 @@
#include "core/crypto/relay_crypto.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index d035d66ea2..088358a4d6 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -57,7 +57,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "lib/math/fp.h"
#include "lib/time/tvdiff.h"
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index d8b45fe350..627a2f1a1c 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -95,6 +95,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/container/buffers.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/feature/control/control.c b/src/feature/control/control.c
index d8d08f2c86..b8ddb3c13e 100644
--- a/src/feature/control/control.c
+++ b/src/feature/control/control.c
@@ -84,7 +84,7 @@
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "lib/container/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c
index 4fa3cd7f93..57178cd506 100644
--- a/src/feature/dircache/dirserv.c
+++ b/src/feature/dircache/dirserv.c
@@ -16,7 +16,7 @@
#include "feature/nodelist/routerlist.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "feature/dircache/cached_dir_st.h"
#include "feature/dircommon/dir_connection_st.h"
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index 334012602c..f6a712e429 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -43,7 +43,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_format.h"
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
index 8257919ac4..057ca2d0c7 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -36,7 +36,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
new file mode 100644
index 0000000000..8abf34f50f
--- /dev/null
+++ b/src/feature/stats/predict_ports.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file predict_ports.c
+ * \brief Remember what ports we've needed so we can have circuits ready.
+ *
+ * Predicted ports are used by clients to remember how long it's been
+ * since they opened an exit connection to each given target
+ * port. Clients use this information in order to try to keep circuits
+ * open to exit nodes that can connect to the ports that they care
+ * about. (The predicted ports mechanism also handles predicted circuit
+ * usage that _isn't_ port-specific, such as resolves, internal circuits,
+ * and so on.)
+ **/
+
+#include "core/or/or.h"
+
+#include "app/config/config.h"
+#include "core/or/channelpadding.h"
+#include "core/or/circuituse.h"
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+#include "feature/stats/predict_ports.h"
+#include "lib/container/bitarray.h"
+#include "lib/time/tvdiff.h"
+
+static size_t predicted_ports_total_alloc = 0;
+
+static void predicted_ports_alloc(void);
+
+/** A single predicted port: used to remember which ports we've made
+ * connections to, so that we can try to keep making circuits that can handle
+ * those ports. */
+typedef struct predicted_port_t {
+ /** The port we connected to */
+ uint16_t port;
+ /** The time at which we last used it */
+ time_t time;
+} predicted_port_t;
+
+/** A list of port numbers that have been used recently. */
+static smartlist_t *predicted_ports_list=NULL;
+/** How long do we keep predicting circuits? */
+static time_t prediction_timeout=0;
+/** When was the last time we added a prediction entry (HS or port) */
+static time_t last_prediction_add_time=0;
+
+/**
+ * How much time left until we stop predicting circuits?
+ */
+int
+predicted_ports_prediction_time_remaining(time_t now)
+{
+ time_t seconds_waited;
+ time_t seconds_left;
+
+ /* Protect against overflow of return value. This can happen if the clock
+ * jumps backwards in time. Update the last prediction time (aka last
+ * active time) to prevent it. This update is preferable to using monotonic
+ * time because it prevents clock jumps into the past from simply causing
+ * very long idle timeouts while the monotonic time stands still. */
+ seconds_waited = time_diff(last_prediction_add_time, now);
+ if (seconds_waited == TIME_MAX) {
+ last_prediction_add_time = now;
+ seconds_waited = 0;
+ }
+
+ /* Protect against underflow of the return value. This can happen for very
+ * large periods of inactivity/system sleep. */
+ if (seconds_waited > prediction_timeout)
+ return 0;
+
+ seconds_left = time_diff(seconds_waited, prediction_timeout);
+ if (BUG(seconds_left == TIME_MAX))
+ return INT_MAX;
+
+ return (int)(seconds_left);
+}
+
+/** We just got an application request for a connection with
+ * port <b>port</b>. Remember it for the future, so we can keep
+ * some circuits open that will exit to this port.
+ */
+static void
+add_predicted_port(time_t now, uint16_t port)
+{
+ predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
+
+ // If the list is empty, re-randomize predicted ports lifetime
+ if (!any_predicted_circuits(now)) {
+ prediction_timeout =
+ (time_t)channelpadding_get_circuits_available_timeout();
+ }
+
+ last_prediction_add_time = now;
+
+ log_info(LD_CIRC,
+ "New port prediction added. Will continue predictive circ building "
+ "for %d more seconds.",
+ predicted_ports_prediction_time_remaining(now));
+
+ pp->port = port;
+ pp->time = now;
+ predicted_ports_total_alloc += sizeof(*pp);
+ smartlist_add(predicted_ports_list, pp);
+}
+
+/** Remember that <b>port</b> has been asked for as of time <b>now</b>.
+ * This is used for predicting what sorts of streams we'll make in the
+ * future and making exit circuits to anticipate that.
+ */
+void
+rep_hist_note_used_port(time_t now, uint16_t port)
+{
+ tor_assert(predicted_ports_list);
+
+ if (!port) /* record nothing */
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
+ if (pp->port == port) {
+ pp->time = now;
+
+ last_prediction_add_time = now;
+ log_info(LD_CIRC,
+ "New port prediction added. Will continue predictive circ "
+ "building for %d more seconds.",
+ predicted_ports_prediction_time_remaining(now));
+ return;
+ }
+ } SMARTLIST_FOREACH_END(pp);
+ /* it's not there yet; we need to add it */
+ add_predicted_port(now, port);
+}
+
+/** Return a newly allocated pointer to a list of uint16_t * for ports that
+ * are likely to be asked for in the near future.
+ */
+smartlist_t *
+rep_hist_get_predicted_ports(time_t now)
+{
+ int predicted_circs_relevance_time;
+ smartlist_t *out = smartlist_new();
+ tor_assert(predicted_ports_list);
+
+ predicted_circs_relevance_time = (int)prediction_timeout;
+
+ /* clean out obsolete entries */
+ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
+ if (pp->time + predicted_circs_relevance_time < now) {
+ log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);
+
+ predicted_ports_total_alloc -= sizeof(predicted_port_t);
+ tor_free(pp);
+ SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
+ } else {
+ smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
+ }
+ } SMARTLIST_FOREACH_END(pp);
+ return out;
+}
+
+/**
+ * Take a list of uint16_t *, and remove every port in the list from the
+ * current list of predicted ports.
+ */
+void
+rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports)
+{
+ /* Let's do this on O(N), not O(N^2). */
+ bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX);
+ SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p,
+ bitarray_set(remove_ports, *p));
+ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
+ if (bitarray_is_set(remove_ports, pp->port)) {
+ tor_free(pp);
+ predicted_ports_total_alloc -= sizeof(*pp);
+ SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
+ }
+ } SMARTLIST_FOREACH_END(pp);
+ bitarray_free(remove_ports);
+}
+
+/** The user asked us to do a resolve. Rather than keeping track of
+ * timings and such of resolves, we fake it for now by treating
+ * it the same way as a connection to port 80. This way we will continue
+ * to have circuits lying around if the user only uses Tor for resolves.
+ */
+void
+rep_hist_note_used_resolve(time_t now)
+{
+ rep_hist_note_used_port(now, 80);
+}
+
+/** The last time at which we needed an internal circ. */
+static time_t predicted_internal_time = 0;
+/** The last time we needed an internal circ with good uptime. */
+static time_t predicted_internal_uptime_time = 0;
+/** The last time we needed an internal circ with good capacity. */
+static time_t predicted_internal_capacity_time = 0;
+
+/** Remember that we used an internal circ at time <b>now</b>. */
+void
+rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
+{
+ // If the list is empty, re-randomize predicted ports lifetime
+ if (!any_predicted_circuits(now)) {
+ prediction_timeout = channelpadding_get_circuits_available_timeout();
+ }
+
+ last_prediction_add_time = now;
+
+ log_info(LD_CIRC,
+ "New port prediction added. Will continue predictive circ building "
+ "for %d more seconds.",
+ predicted_ports_prediction_time_remaining(now));
+
+ predicted_internal_time = now;
+ if (need_uptime)
+ predicted_internal_uptime_time = now;
+ if (need_capacity)
+ predicted_internal_capacity_time = now;
+}
+
+/** Return 1 if we've used an internal circ recently; else return 0. */
+int
+rep_hist_get_predicted_internal(time_t now, int *need_uptime,
+ int *need_capacity)
+{
+ int predicted_circs_relevance_time;
+
+ predicted_circs_relevance_time = (int)prediction_timeout;
+
+ if (!predicted_internal_time) { /* initialize it */
+ predicted_internal_time = now;
+ predicted_internal_uptime_time = now;
+ predicted_internal_capacity_time = now;
+ }
+ if (predicted_internal_time + predicted_circs_relevance_time < now)
+ return 0; /* too long ago */
+ if (predicted_internal_uptime_time + predicted_circs_relevance_time >= now)
+ *need_uptime = 1;
+ // Always predict that we need capacity.
+ *need_capacity = 1;
+ return 1;
+}
+
+/** Any ports used lately? These are pre-seeded if we just started
+ * up or if we're running a hidden service. */
+int
+any_predicted_circuits(time_t now)
+{
+ int predicted_circs_relevance_time;
+ predicted_circs_relevance_time = (int)prediction_timeout;
+
+ return smartlist_len(predicted_ports_list) ||
+ predicted_internal_time + predicted_circs_relevance_time >= now;
+}
+
+/** Return 1 if we have no need for circuits currently, else return 0. */
+int
+rep_hist_circbuilding_dormant(time_t now)
+{
+ const or_options_t *options = get_options();
+
+ if (any_predicted_circuits(now))
+ return 0;
+
+ /* see if we'll still need to build testing circuits */
+ if (server_mode(options) &&
+ (!check_whether_orport_reachable(options) ||
+ !circuit_enough_testing_circs()))
+ return 0;
+ if (!check_whether_dirport_reachable(options))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Allocate whatever memory and structs are needed for predicting
+ * which ports will be used. Also seed it with port 80, so we'll build
+ * circuits on start-up.
+ */
+static void
+predicted_ports_alloc(void)
+{
+ predicted_ports_list = smartlist_new();
+}
+
+void
+predicted_ports_init(void)
+{
+ predicted_ports_alloc();
+ add_predicted_port(time(NULL), 443); // Add a port to get us started
+}
+
+/** Free whatever memory is needed for predicting which ports will
+ * be used.
+ */
+void
+predicted_ports_free_all(void)
+{
+ predicted_ports_total_alloc -=
+ smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
+ SMARTLIST_FOREACH(predicted_ports_list, predicted_port_t *,
+ pp, tor_free(pp));
+ smartlist_free(predicted_ports_list);
+}
diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h
new file mode 100644
index 0000000000..ecb2e9caf2
--- /dev/null
+++ b/src/feature/stats/predict_ports.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file predict_portst.h
+ * \brief Header file for predict_ports.c.
+ **/
+
+#ifndef TOR_PREDICT_PORTS_H
+#define TOR_PREDICT_PORTS_H
+
+void predicted_ports_init(void);
+void rep_hist_note_used_port(time_t now, uint16_t port);
+smartlist_t *rep_hist_get_predicted_ports(time_t now);
+void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports);
+void rep_hist_note_used_resolve(time_t now);
+void rep_hist_note_used_internal(time_t now, int need_uptime,
+ int need_capacity);
+int rep_hist_get_predicted_internal(time_t now, int *need_uptime,
+ int *need_capacity);
+
+int any_predicted_circuits(time_t now);
+int rep_hist_circbuilding_dormant(time_t now);
+int predicted_ports_prediction_time_remaining(time_t now);
+void predicted_ports_free_all(void);
+
+#endif
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index fa4bd0ba4e..37c4759f37 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -76,38 +76,29 @@
#define REPHIST_PRIVATE
#include "core/or/or.h"
-#include "core/or/circuitlist.h"
-#include "core/or/circuituse.h"
#include "app/config/config.h"
-#include "lib/crypt_ops/crypto_rand.h"
+#include "app/config/statefile.h"
+#include "core/or/circuitlist.h"
+#include "core/or/connection_or.h"
+#include "feature/dirauth/authmode.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/stats/rephist.h"
#include "feature/relay/routermode.h"
-#include "feature/relay/selftest.h"
-#include "feature/nodelist/routerlist.h"
-#include "ht.h"
-#include "core/or/channelpadding.h"
-#include "core/or/connection_or.h"
-#include "app/config/statefile.h"
-#include "feature/dirauth/authmode.h"
+#include "feature/stats/predict_ports.h"
+#include "feature/stats/rephist.h"
+#include "lib/container/order.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/math/laplace.h"
#include "feature/nodelist/networkstatus_st.h"
#include "core/or/or_circuit_st.h"
#include "app/config/or_state_st.h"
-#include "lib/container/bloomfilt.h"
-#include "lib/container/order.h"
-#include "lib/math/fp.h"
-#include "lib/math/laplace.h"
-#include "lib/time/tvdiff.h"
-
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
static void bw_arrays_init(void);
-static void predicted_ports_alloc(void);
/** Total number of bytes currently allocated in fields used by rephist.c. */
uint64_t rephist_total_alloc=0;
@@ -242,7 +233,6 @@ rep_hist_init(void)
{
history_map = digestmap_new();
bw_arrays_init();
- predicted_ports_alloc();
}
/** We have just decided that this router with identity digest <b>id</b> is
@@ -1537,287 +1527,6 @@ rep_hist_load_state(or_state_t *state, char **err)
return 0;
}
-/*********************************************************************/
-
-/** A single predicted port: used to remember which ports we've made
- * connections to, so that we can try to keep making circuits that can handle
- * those ports. */
-typedef struct predicted_port_t {
- /** The port we connected to */
- uint16_t port;
- /** The time at which we last used it */
- time_t time;
-} predicted_port_t;
-
-/** A list of port numbers that have been used recently. */
-static smartlist_t *predicted_ports_list=NULL;
-/** How long do we keep predicting circuits? */
-static time_t prediction_timeout=0;
-/** When was the last time we added a prediction entry (HS or port) */
-static time_t last_prediction_add_time=0;
-
-/**
- * How much time left until we stop predicting circuits?
- */
-int
-predicted_ports_prediction_time_remaining(time_t now)
-{
- time_t seconds_waited;
- time_t seconds_left;
-
- /* Protect against overflow of return value. This can happen if the clock
- * jumps backwards in time. Update the last prediction time (aka last
- * active time) to prevent it. This update is preferable to using monotonic
- * time because it prevents clock jumps into the past from simply causing
- * very long idle timeouts while the monotonic time stands still. */
- seconds_waited = time_diff(last_prediction_add_time, now);
- if (seconds_waited == TIME_MAX) {
- last_prediction_add_time = now;
- seconds_waited = 0;
- }
-
- /* Protect against underflow of the return value. This can happen for very
- * large periods of inactivity/system sleep. */
- if (seconds_waited > prediction_timeout)
- return 0;
-
- seconds_left = time_diff(seconds_waited, prediction_timeout);
- if (BUG(seconds_left == TIME_MAX))
- return INT_MAX;
-
- return (int)(seconds_left);
-}
-
-/** We just got an application request for a connection with
- * port <b>port</b>. Remember it for the future, so we can keep
- * some circuits open that will exit to this port.
- */
-static void
-add_predicted_port(time_t now, uint16_t port)
-{
- predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
-
- // If the list is empty, re-randomize predicted ports lifetime
- if (!any_predicted_circuits(now)) {
- prediction_timeout =
- (time_t)channelpadding_get_circuits_available_timeout();
- }
-
- last_prediction_add_time = now;
-
- log_info(LD_CIRC,
- "New port prediction added. Will continue predictive circ building "
- "for %d more seconds.",
- predicted_ports_prediction_time_remaining(now));
-
- pp->port = port;
- pp->time = now;
- rephist_total_alloc += sizeof(*pp);
- smartlist_add(predicted_ports_list, pp);
-}
-
-/**
- * Allocate whatever memory and structs are needed for predicting
- * which ports will be used. Also seed it with port 80, so we'll build
- * circuits on start-up.
- */
-static void
-predicted_ports_alloc(void)
-{
- predicted_ports_list = smartlist_new();
-}
-
-void
-predicted_ports_init(void)
-{
- add_predicted_port(time(NULL), 443); // Add a port to get us started
-}
-
-/** Free whatever memory is needed for predicting which ports will
- * be used.
- */
-static void
-predicted_ports_free_all(void)
-{
- rephist_total_alloc -=
- smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
- SMARTLIST_FOREACH(predicted_ports_list, predicted_port_t *,
- pp, tor_free(pp));
- smartlist_free(predicted_ports_list);
-}
-
-/** Remember that <b>port</b> has been asked for as of time <b>now</b>.
- * This is used for predicting what sorts of streams we'll make in the
- * future and making exit circuits to anticipate that.
- */
-void
-rep_hist_note_used_port(time_t now, uint16_t port)
-{
- tor_assert(predicted_ports_list);
-
- if (!port) /* record nothing */
- return;
-
- SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
- if (pp->port == port) {
- pp->time = now;
-
- last_prediction_add_time = now;
- log_info(LD_CIRC,
- "New port prediction added. Will continue predictive circ "
- "building for %d more seconds.",
- predicted_ports_prediction_time_remaining(now));
- return;
- }
- } SMARTLIST_FOREACH_END(pp);
- /* it's not there yet; we need to add it */
- add_predicted_port(now, port);
-}
-
-/** Return a newly allocated pointer to a list of uint16_t * for ports that
- * are likely to be asked for in the near future.
- */
-smartlist_t *
-rep_hist_get_predicted_ports(time_t now)
-{
- int predicted_circs_relevance_time;
- smartlist_t *out = smartlist_new();
- tor_assert(predicted_ports_list);
-
- predicted_circs_relevance_time = (int)prediction_timeout;
-
- /* clean out obsolete entries */
- SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
- if (pp->time + predicted_circs_relevance_time < now) {
- log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);
-
- rephist_total_alloc -= sizeof(predicted_port_t);
- tor_free(pp);
- SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
- } else {
- smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
- }
- } SMARTLIST_FOREACH_END(pp);
- return out;
-}
-
-/**
- * Take a list of uint16_t *, and remove every port in the list from the
- * current list of predicted ports.
- */
-void
-rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports)
-{
- /* Let's do this on O(N), not O(N^2). */
- bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX);
- SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p,
- bitarray_set(remove_ports, *p));
- SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
- if (bitarray_is_set(remove_ports, pp->port)) {
- tor_free(pp);
- rephist_total_alloc -= sizeof(*pp);
- SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
- }
- } SMARTLIST_FOREACH_END(pp);
- bitarray_free(remove_ports);
-}
-
-/** The user asked us to do a resolve. Rather than keeping track of
- * timings and such of resolves, we fake it for now by treating
- * it the same way as a connection to port 80. This way we will continue
- * to have circuits lying around if the user only uses Tor for resolves.
- */
-void
-rep_hist_note_used_resolve(time_t now)
-{
- rep_hist_note_used_port(now, 80);
-}
-
-/** The last time at which we needed an internal circ. */
-static time_t predicted_internal_time = 0;
-/** The last time we needed an internal circ with good uptime. */
-static time_t predicted_internal_uptime_time = 0;
-/** The last time we needed an internal circ with good capacity. */
-static time_t predicted_internal_capacity_time = 0;
-
-/** Remember that we used an internal circ at time <b>now</b>. */
-void
-rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
-{
- // If the list is empty, re-randomize predicted ports lifetime
- if (!any_predicted_circuits(now)) {
- prediction_timeout = channelpadding_get_circuits_available_timeout();
- }
-
- last_prediction_add_time = now;
-
- log_info(LD_CIRC,
- "New port prediction added. Will continue predictive circ building "
- "for %d more seconds.",
- predicted_ports_prediction_time_remaining(now));
-
- predicted_internal_time = now;
- if (need_uptime)
- predicted_internal_uptime_time = now;
- if (need_capacity)
- predicted_internal_capacity_time = now;
-}
-
-/** Return 1 if we've used an internal circ recently; else return 0. */
-int
-rep_hist_get_predicted_internal(time_t now, int *need_uptime,
- int *need_capacity)
-{
- int predicted_circs_relevance_time;
-
- predicted_circs_relevance_time = (int)prediction_timeout;
-
- if (!predicted_internal_time) { /* initialize it */
- predicted_internal_time = now;
- predicted_internal_uptime_time = now;
- predicted_internal_capacity_time = now;
- }
- if (predicted_internal_time + predicted_circs_relevance_time < now)
- return 0; /* too long ago */
- if (predicted_internal_uptime_time + predicted_circs_relevance_time >= now)
- *need_uptime = 1;
- // Always predict that we need capacity.
- *need_capacity = 1;
- return 1;
-}
-
-/** Any ports used lately? These are pre-seeded if we just started
- * up or if we're running a hidden service. */
-int
-any_predicted_circuits(time_t now)
-{
- int predicted_circs_relevance_time;
- predicted_circs_relevance_time = (int)prediction_timeout;
-
- return smartlist_len(predicted_ports_list) ||
- predicted_internal_time + predicted_circs_relevance_time >= now;
-}
-
-/** Return 1 if we have no need for circuits currently, else return 0. */
-int
-rep_hist_circbuilding_dormant(time_t now)
-{
- const or_options_t *options = get_options();
-
- if (any_predicted_circuits(now))
- return 0;
-
- /* see if we'll still need to build testing circuits */
- if (server_mode(options) &&
- (!check_whether_orport_reachable(options) ||
- !circuit_enough_testing_circs()))
- return 0;
- if (!check_whether_dirport_reachable(options))
- return 0;
-
- return 1;
-}
-
/*** Exit port statistics ***/
/* Some constants */
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 842184f815..0584b4684a 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -41,20 +41,6 @@ double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when);
long rep_hist_get_weighted_time_known(const char *id, time_t when);
int rep_hist_have_measured_enough_stability(void);
-void predicted_ports_init(void);
-void rep_hist_note_used_port(time_t now, uint16_t port);
-smartlist_t *rep_hist_get_predicted_ports(time_t now);
-void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports);
-void rep_hist_note_used_resolve(time_t now);
-void rep_hist_note_used_internal(time_t now, int need_uptime,
- int need_capacity);
-int rep_hist_get_predicted_internal(time_t now, int *need_uptime,
- int *need_capacity);
-
-int any_predicted_circuits(time_t now);
-int rep_hist_circbuilding_dormant(time_t now);
-int predicted_ports_prediction_time_remaining(time_t now);
-
void rep_hist_exit_stats_init(time_t now);
void rep_hist_reset_exit_stats(time_t now);
void rep_hist_exit_stats_term(void);
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 2d00ecb651..c52683afca 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -16,6 +16,7 @@
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/err/backtrace.h"
#include "test/test.h"