diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app/config/config.c | 1 | ||||
-rw-r--r-- | src/app/main/main.c | 1 | ||||
-rw-r--r-- | src/core/include.am | 6 | ||||
-rw-r--r-- | src/core/mainloop/mainloop.c | 1 | ||||
-rw-r--r-- | src/core/or/circuitbuild.c | 2 | ||||
-rw-r--r-- | src/core/or/circuitlist.c | 1 | ||||
-rw-r--r-- | src/core/or/circuituse.c | 2 | ||||
-rw-r--r-- | src/core/or/connection_edge.c | 1 | ||||
-rw-r--r-- | src/feature/control/control.c | 2 | ||||
-rw-r--r-- | src/feature/dircache/dirserv.c | 2 | ||||
-rw-r--r-- | src/feature/dirclient/dirclient.c | 2 | ||||
-rw-r--r-- | src/feature/rend/rendservice.c | 2 | ||||
-rw-r--r-- | src/feature/stats/predict_ports.c | 311 | ||||
-rw-r--r-- | src/feature/stats/predict_ports.h | 30 | ||||
-rw-r--r-- | src/feature/stats/rephist.c | 309 | ||||
-rw-r--r-- | src/feature/stats/rephist.h | 14 | ||||
-rw-r--r-- | src/test/testing_common.c | 1 |
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" |