summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-12-13 08:26:10 -0500
committerNick Mathewson <nickm@torproject.org>2018-12-13 08:26:10 -0500
commit69264f96f3561c72d14c1e518ca84ad18557d905 (patch)
tree510c4795aa9116cd179ae7ad1652fd5e6cec0aa4 /src
parente17dd46cfdb33299db71a052840f069a364c85fe (diff)
parente3b7fd2a8129f0d2a7879976e57496b6fd4a7d00 (diff)
downloadtor-69264f96f3561c72d14c1e518ca84ad18557d905.tar.gz
tor-69264f96f3561c72d14c1e518ca84ad18557d905.zip
Merge branch 'dormant_persist_squashed'
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c1
-rw-r--r--src/app/config/or_options_st.h4
-rw-r--r--src/app/config/or_state_st.h7
-rw-r--r--src/app/config/statefile.c8
-rw-r--r--src/core/mainloop/mainloop.c26
-rw-r--r--src/core/mainloop/netstatus.c59
-rw-r--r--src/core/mainloop/netstatus.h4
-rw-r--r--src/lib/intmath/cmp.h3
-rw-r--r--src/test/test_mainloop.c76
9 files changed, 173 insertions, 15 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index d40e362b32..dcefa3d6a4 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -392,6 +392,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("DNSListenAddress"),
V(DormantClientTimeout, INTERVAL, "24 hours"),
V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"),
+ V(DormantOnFirstStartup, BOOL, "0"),
/* DoS circuit creation options. */
V(DoSCircuitCreationEnabled, AUTOBOOL, "auto"),
V(DoSCircuitCreationMinConnections, UINT, "0"),
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 9065248a9c..c2bc1079a5 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -1085,6 +1085,10 @@ struct or_options_t {
* from becoming dormant.
**/
int DormantTimeoutDisabledByIdleStreams;
+
+ /** Boolean: true if Tor should be dormant the first time it starts with
+ * a datadirectory; false otherwise. */
+ int DormantOnFirstStartup;
};
#endif
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index d95df6236b..00968d3731 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -87,6 +87,13 @@ struct or_state_t {
/** When did we last rotate our onion key? "0" for 'no idea'. */
time_t LastRotatedOnionKey;
+
+ /** Number of minutes since the last user-initiated request (as defined by
+ * the dormant net-status system.) Set to zero if we are dormant. */
+ int MinutesSinceUserActivity;
+ /** True if we were dormant when we last wrote the file; false if we
+ * weren't. "auto" on initial startup. */
+ int Dormant;
};
#endif
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index 4ba7be1519..97b96f1149 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -34,6 +34,7 @@
#include "app/config/config.h"
#include "app/config/confparse.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/netstatus.h"
#include "core/mainloop/connection.h"
#include "feature/control/control.h"
#include "feature/client/entrynodes.h"
@@ -132,6 +133,9 @@ static config_var_t state_vars_[] = {
VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
+ V(MinutesSinceUserActivity, UINT, NULL),
+ V(Dormant, AUTOBOOL, "auto"),
+
END_OF_CONFIG_VARS
};
@@ -309,6 +313,8 @@ or_state_set(or_state_t *new_state)
get_circuit_build_times_mutable(),global_state) < 0) {
ret = -1;
}
+ netstatus_load_from_state(global_state, time(NULL));
+
return ret;
}
@@ -500,6 +506,8 @@ or_state_save(time_t now)
entry_guards_update_state(global_state);
rep_hist_update_state(global_state);
circuit_build_times_update_state(get_circuit_build_times(), global_state);
+ netstatus_flush_to_state(global_state, now);
+
if (accounting_is_enabled(get_options()))
accounting_run_housekeeping(now);
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 17ceeb22de..985f5e5dac 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -2686,6 +2686,17 @@ update_current_time(time_t now)
memcpy(&last_updated, &current_second_last_changed, sizeof(last_updated));
monotime_coarse_get(&current_second_last_changed);
+ /** How much clock jumping means that we should adjust our idea of when
+ * to go dormant? */
+#define NUM_JUMPED_SECONDS_BEFORE_NETSTATUS_UPDATE 20
+
+ /* Don't go dormant early or late just because we jumped in time. */
+ if (ABS(seconds_elapsed) >= NUM_JUMPED_SECONDS_BEFORE_NETSTATUS_UPDATE) {
+ if (is_participating_on_network()) {
+ netstatus_note_clock_jumped(seconds_elapsed);
+ }
+ }
+
/** How much clock jumping do we tolerate? */
#define NUM_JUMPED_SECONDS_BEFORE_WARN 100
@@ -2696,10 +2707,6 @@ update_current_time(time_t now)
// moving back in time is always a bad sign.
circuit_note_clock_jumped(seconds_elapsed, false);
- /* Don't go dormant just because we jumped in time. */
- if (is_participating_on_network()) {
- reset_user_activity(now);
- }
} else if (seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) {
/* Compare the monotonic clock to the result of time(). */
const int32_t monotime_msec_passed =
@@ -2721,11 +2728,6 @@ update_current_time(time_t now)
if (clock_jumped || seconds_elapsed >= NUM_IDLE_SECONDS_BEFORE_WARN) {
circuit_note_clock_jumped(seconds_elapsed, ! clock_jumped);
}
-
- /* Don't go dormant just because we jumped in time. */
- if (is_participating_on_network()) {
- reset_user_activity(now);
- }
} else if (seconds_elapsed > 0) {
stats_n_seconds_working += seconds_elapsed;
}
@@ -2818,12 +2820,6 @@ initialize_mainloop_events(void)
int
do_main_loop(void)
{
- /* For now, starting Tor always counts as user activity. Later, we might
- * have an option to control this.
- */
- reset_user_activity(approx_time());
- set_network_participation(true);
-
/* initialize the periodic events first, so that code that depends on the
* events being present does not assert.
*/
diff --git a/src/core/mainloop/netstatus.c b/src/core/mainloop/netstatus.c
index ed7c952dcd..d1989cb839 100644
--- a/src/core/mainloop/netstatus.c
+++ b/src/core/mainloop/netstatus.c
@@ -10,6 +10,8 @@
#include "app/config/config.h"
#include "feature/hibernate/hibernate.h"
+#include "app/config/or_state_st.h"
+
/** Return true iff our network is in some sense disabled or shutting down:
* either we're hibernating, entering hibernation, or the network is turned
* off with DisableNetwork. */
@@ -31,6 +33,10 @@ net_is_completely_disabled(void)
/**
* The time at which we've last seen "user activity" -- that is, any activity
* that should keep us as a participant on the network.
+ *
+ * This is not actually the true time. We will adjust this forward if
+ * our clock jumps, or if Tor is shut down for a while, so that the time
+ * since our last activity remains as it was before the jump or shutdown.
*/
static time_t last_user_activity_seen = 0;
@@ -99,3 +105,56 @@ is_participating_on_network(void)
{
return participating_on_network;
}
+
+/**
+ * Update 'state' with the last time at which we were active on the network.
+ **/
+void
+netstatus_flush_to_state(or_state_t *state, time_t now)
+{
+ state->Dormant = ! participating_on_network;
+ if (participating_on_network) {
+ time_t sec_since_activity = MAX(0, now - last_user_activity_seen);
+ state->MinutesSinceUserActivity = (int)(sec_since_activity / 60);
+ } else {
+ state->MinutesSinceUserActivity = 0;
+ }
+}
+
+/**
+ * Update our current view of network participation from an or_state_t object.
+ **/
+void
+netstatus_load_from_state(const or_state_t *state, time_t now)
+{
+ time_t last_activity;
+ if (state->Dormant == -1) { // Initial setup.
+ if (get_options()->DormantOnFirstStartup) {
+ last_activity = 0;
+ participating_on_network = false;
+ } else {
+ // Start up as active, treat activity as happening now.
+ last_activity = now;
+ participating_on_network = true;
+ }
+ } else if (state->Dormant) {
+ last_activity = 0;
+ participating_on_network = false;
+ } else {
+ last_activity = now - 60 * state->MinutesSinceUserActivity;
+ participating_on_network = true;
+ }
+ reset_user_activity(last_activity);
+}
+
+/**
+ * Adjust the time at which the user was last active by <b>seconds_diff</b>
+ * in response to a clock jump.
+ */
+void
+netstatus_note_clock_jumped(time_t seconds_diff)
+{
+ time_t last_active = get_last_user_activity_time();
+ if (last_active)
+ reset_user_activity(last_active + seconds_diff);
+}
diff --git a/src/core/mainloop/netstatus.h b/src/core/mainloop/netstatus.h
index 58c994fd14..9a0fa410fd 100644
--- a/src/core/mainloop/netstatus.h
+++ b/src/core/mainloop/netstatus.h
@@ -17,4 +17,8 @@ time_t get_last_user_activity_time(void);
void set_network_participation(bool participation);
bool is_participating_on_network(void);
+void netstatus_flush_to_state(or_state_t *state, time_t now);
+void netstatus_load_from_state(const or_state_t *state, time_t now);
+void netstatus_note_clock_jumped(time_t seconds_diff);
+
#endif
diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h
index 16952bee3e..11b6fdf98e 100644
--- a/src/lib/intmath/cmp.h
+++ b/src/lib/intmath/cmp.h
@@ -36,4 +36,7 @@
((v) > (max)) ? (max) : \
(v) )
+/** Give the absolute value of <b>x</b>, independent of its type. */
+#define ABS(x) ( ((x)<0) ? -(x) : (x) )
+
#endif /* !defined(TOR_INTMATH_CMP_H) */
diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c
index 8dfd5f619a..d797417912 100644
--- a/src/test/test_mainloop.c
+++ b/src/test/test_mainloop.c
@@ -8,6 +8,7 @@
#define CONFIG_PRIVATE
#define MAINLOOP_PRIVATE
+#define STATEFILE_PRIVATE
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -20,6 +21,8 @@
#include "feature/hs/hs_service.h"
#include "app/config/config.h"
+#include "app/config/statefile.h"
+#include "app/config/or_state_st.h"
static const uint64_t BILLION = 1000000000;
@@ -190,6 +193,13 @@ test_mainloop_user_activity(void *arg)
tt_int_op(true, OP_EQ, is_participating_on_network());
tt_int_op(schedule_rescan_called, OP_EQ, 1);
+ // We _will_ adjust if the clock jumps though.
+ netstatus_note_clock_jumped(500);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+525);
+
+ netstatus_note_clock_jumped(-400);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+125);
+
done:
UNMOCK(schedule_rescan_periodic_events);
}
@@ -273,6 +283,70 @@ test_mainloop_check_participation(void *arg)
UNMOCK(connection_get_by_type_nonlinked);
}
+static void
+test_mainloop_dormant_load_state(void *arg)
+{
+ (void)arg;
+ or_state_t *state = or_state_new();
+ const time_t start = 1543956575;
+
+ reset_user_activity(0);
+ set_network_participation(false);
+
+ // When we construct a new state, it starts out in "auto" mode.
+ tt_int_op(state->Dormant, OP_EQ, -1);
+
+ // Initializing from "auto" makes us start out (by default) non-Dormant,
+ // with activity right now.
+ netstatus_load_from_state(state, start);
+ tt_assert(is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
+
+ // Initializing from dormant clears the last user activity time, and
+ // makes us dormant.
+ state->Dormant = 1;
+ netstatus_load_from_state(state, start);
+ tt_assert(! is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, 0);
+
+ // Initializing from non-dormant sets the last user activity time, and
+ // makes us non-dormant.
+ state->Dormant = 0;
+ state->MinutesSinceUserActivity = 123;
+ netstatus_load_from_state(state, start);
+ tt_assert(is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60);
+
+ done:
+ or_state_free(state);
+}
+
+static void
+test_mainloop_dormant_save_state(void *arg)
+{
+ (void)arg;
+ or_state_t *state = or_state_new();
+ const time_t start = 1543956575;
+
+ // Can we save a non-dormant state correctly?
+ reset_user_activity(start - 1000);
+ set_network_participation(true);
+ netstatus_flush_to_state(state, start);
+
+ tt_int_op(state->Dormant, OP_EQ, 0);
+ tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 1000 / 60);
+
+ // Can we save a dormant state correctly?
+ set_network_participation(false);
+ netstatus_flush_to_state(state, start);
+
+ tt_int_op(state->Dormant, OP_EQ, 1);
+ tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
+
+ done:
+ or_state_free(state);
+}
+
#define MAINLOOP_TEST(name) \
{ #name, test_mainloop_## name , TT_FORK, NULL, NULL }
@@ -281,5 +355,7 @@ struct testcase_t mainloop_tests[] = {
MAINLOOP_TEST(update_time_jumps),
MAINLOOP_TEST(user_activity),
MAINLOOP_TEST(check_participation),
+ MAINLOOP_TEST(dormant_load_state),
+ MAINLOOP_TEST(dormant_save_state),
END_OF_TESTCASES
};