Make the NET_PARTICIPANT role dependent on user activity

This patch implements all of 28337, except for the part where we
turn off the role if we've been idle for a long time.
This commit is contained in:
Nick Mathewson
2018-11-13 15:33:46 -05:00
parent ccbb36048f
commit 2c15b65381
11 changed files with 149 additions and 4 deletions
+15
View File
@@ -303,6 +303,19 @@ process_signal(int sig)
log_heartbeat(time(NULL));
control_event_signal(sig);
break;
case SIGACTIVE:
/* "SIGACTIVE" counts as ersatz user activity. */
note_user_activity(approx_time());
control_event_signal(sig);
break;
case SIGDORMANT:
/* "SIGDORMANT" means to ignore past user activity */
log_notice(LD_GENERAL, "Going dormant because of controller request.");
reset_user_activity(0);
set_network_participation(false);
schedule_rescan_periodic_events();
control_event_signal(sig);
break;
}
}
@@ -472,6 +485,8 @@ static struct {
{ SIGNEWNYM, 0, NULL },
{ SIGCLEARDNSCACHE, 0, NULL },
{ SIGHEARTBEAT, 0, NULL },
{ SIGACTIVE, 0, NULL },
{ SIGDORMANT, 0, NULL },
{ -1, -1, NULL }
};
+3
View File
@@ -1874,6 +1874,9 @@ connection_init_accepted_conn(connection_t *conn,
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type;
/* Any incoming connection on an entry port counts as user activity. */
note_user_activity(approx_time());
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
+32 -2
View File
@@ -1513,8 +1513,7 @@ get_my_roles(const or_options_t *options)
options->ControlPort_set ||
options->OwningControllerFD != UINT64_MAX;
/* We actually want a better definition here for our work on dormancy. */
int is_net_participant = ! net_is_disabled();
int is_net_participant = is_participating_on_network();
if (is_bridge) roles |= PERIODIC_EVENT_ROLE_BRIDGE;
if (is_client) roles |= PERIODIC_EVENT_ROLE_CLIENT;
@@ -1592,6 +1591,30 @@ teardown_periodic_events(void)
periodic_events_initialized = 0;
}
static mainloop_event_t *rescan_periodic_events_ev = NULL;
/** Callback: rescan the periodic event list. */
static void
rescan_periodic_events_cb(mainloop_event_t *event, void *arg)
{
(void)event;
(void)arg;
rescan_periodic_events(get_options());
}
/**
* Schedule an event that will rescan which periodic events should run.
**/
void
schedule_rescan_periodic_events(void)
{
if (!rescan_periodic_events_ev) {
rescan_periodic_events_ev =
mainloop_event_new(rescan_periodic_events_cb, NULL);
}
mainloop_event_activate(rescan_periodic_events_ev);
}
/** Do a pass at all our periodic events, disable those we don't need anymore
* and enable those we need now using the given options. */
void
@@ -2714,6 +2737,12 @@ 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.
*/
@@ -2912,6 +2941,7 @@ tor_mainloop_free_all(void)
mainloop_event_free(postloop_cleanup_ev);
mainloop_event_free(handle_deferred_signewnym_ev);
mainloop_event_free(scheduled_shutdown_ev);
mainloop_event_free(rescan_periodic_events_ev);
#ifdef HAVE_SYSTEMD_209
periodic_timer_free(systemd_watchdog_timer);
+1
View File
@@ -65,6 +65,7 @@ void reschedule_or_state_save(void);
void reschedule_dirvote(const or_options_t *options);
void mainloop_schedule_postloop_cleanup(void);
void rescan_periodic_events(const or_options_t *options);
void schedule_rescan_periodic_events(void);
void update_current_time(time_t now);
+73
View File
@@ -6,6 +6,7 @@
#include "core/or/or.h"
#include "core/mainloop/netstatus.h"
#include "core/mainloop/mainloop.h"
#include "app/config/config.h"
#include "feature/hibernate/hibernate.h"
@@ -26,3 +27,75 @@ net_is_completely_disabled(void)
{
return get_options()->DisableNetwork || we_are_fully_hibernating();
}
/**
* The time at which we've last seen "user activity" -- that is, any activity
* that should keep us as a participant on the network.
*/
static time_t last_user_activity_seen = 0;
/**
* True iff we are currently a "network participant" -- that is, we
* are building circuits, fetching directory information, and so on.
**/
static bool participating_on_network = false;
/**
* Record the fact that we have seen "user activity" at the time now. Move
* "last activity seen" time forwards, but never backwards.
*
* If we were previously not participating on the network, set our
* participation status to true, and launch periodic events as appropriate.
**/
void
note_user_activity(time_t now)
{
last_user_activity_seen = MAX(now, last_user_activity_seen);
if (! participating_on_network) {
log_notice(LD_GENERAL, "Tor is no longer dormant.");
set_network_participation(true);
schedule_rescan_periodic_events();
}
}
/**
* Change the time at which "user activitiy" was last seen to <b>now</b>.
*
* Unlike note_user_actity, this function sets the time without checking
* whether it is in the past, and without causing any rescan of periodic events
* or change in participation status.
*/
void
reset_user_activity(time_t now)
{
last_user_activity_seen = now;
}
/**
* Return the most recent time at which we recorded "user activity".
**/
time_t
get_last_user_activity_time(void)
{
return last_user_activity_seen;
}
/**
* Set the field that remembers whether we are currently participating on the
* network. Does not schedule or un-schedule periodic events.
**/
void
set_network_participation(bool participation)
{
participating_on_network = participation;
}
/**
* Return true iff we are currently participating on the network.
**/
bool
is_participating_on_network(void)
{
return participating_on_network;
}
+7
View File
@@ -10,4 +10,11 @@
int net_is_disabled(void);
int net_is_completely_disabled(void);
void note_user_activity(time_t now);
void reset_user_activity(time_t now);
time_t get_last_user_activity_time(void);
void set_network_participation(bool participation);
bool is_participating_on_network(void);
#endif
+2
View File
@@ -97,6 +97,8 @@ struct curve25519_public_key_t;
#define SIGNEWNYM 129
#define SIGCLEARDNSCACHE 130
#define SIGHEARTBEAT 131
#define SIGACTIVE 132
#define SIGDORMANT 133
#if (SIZEOF_CELL_T != 0)
/* On Irix, stdlib.h defines a cell_t type, so we need to make sure
+4
View File
@@ -28,6 +28,7 @@
#include "core/or/connection_edge.h"
#include "feature/control/control.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/or/policies.h"
#include "feature/control/control_connection_st.h"
@@ -213,6 +214,9 @@ dnsserv_launch_request(const char *name, int reverse,
edge_connection_t *conn;
char *q_name;
/* Launching a request for a user counts as user activity. */
note_user_activity(approx_time());
/* Make a new dummy AP connection, and attach the request to it. */
entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
entry_conn->entry_cfg.dns_request = 1;
+2
View File
@@ -1681,6 +1681,8 @@ static const struct signal_t signal_table[] = {
{ SIGNEWNYM, "NEWNYM" },
{ SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
{ SIGHEARTBEAT, "HEARTBEAT"},
{ SIGACTIVE, "ACTIVE" },
{ SIGDORMANT, "DORMANT" },
{ 0, NULL },
};
-1
View File
@@ -187,4 +187,3 @@ struct testcase_t compat_libevent_tests[] = {
TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
+10 -1
View File
@@ -51,6 +51,8 @@ test_pe_initialize(void *arg)
* need to run the main loop and then wait for a second delaying the unit
* tests. Instead, we'll test the callback work indepedently elsewhere. */
initialize_periodic_events();
set_network_participation(false);
rescan_periodic_events(get_options());
/* Validate that all events have been set up. */
for (int i = 0; periodic_events[i].name; ++i) {
@@ -82,6 +84,8 @@ test_pe_launch(void *arg)
* network gets enabled. */
consider_hibernation(time(NULL));
set_network_participation(true);
/* Hack: We'll set a dumb fn() of each events so they don't get called when
* dispatching them. We just want to test the state of the callbacks, not
* the whole code path. */
@@ -93,6 +97,7 @@ test_pe_launch(void *arg)
options = get_options_mutable();
options->SocksPort_set = 1;
periodic_events_on_new_options(options);
#if 0
/* Lets make sure that before intialization, we can't scan the periodic
* events list and launch them. Lets try by being a Client. */
@@ -148,6 +153,7 @@ test_pe_launch(void *arg)
options->SocksPort_set = 0;
options->ORPort_set = 0;
options->DisableNetwork = 1;
set_network_participation(false);
periodic_events_on_new_options(options);
for (int i = 0; periodic_events[i].name; ++i) {
@@ -162,6 +168,7 @@ test_pe_launch(void *arg)
options->BridgeRelay = 1; options->AuthoritativeDir = 1;
options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
options->DisableNetwork = 0;
set_network_participation(true);
register_dummy_hidden_service(&service);
periodic_events_on_new_options(options);
/* Note down the reference because we need to remove this service from the
@@ -195,8 +202,10 @@ test_pe_get_roles(void *arg)
or_options_t *options = get_options_mutable();
tt_assert(options);
set_network_participation(true);
const int ALL = PERIODIC_EVENT_ROLE_ALL;
const int ALL = PERIODIC_EVENT_ROLE_ALL |
PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
/* Nothing configured, should be no roles. */
tt_assert(net_is_disabled());