mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
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:
@@ -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 }
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1681,6 +1681,8 @@ static const struct signal_t signal_table[] = {
|
||||
{ SIGNEWNYM, "NEWNYM" },
|
||||
{ SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
|
||||
{ SIGHEARTBEAT, "HEARTBEAT"},
|
||||
{ SIGACTIVE, "ACTIVE" },
|
||||
{ SIGDORMANT, "DORMANT" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
|
||||
@@ -187,4 +187,3 @@ struct testcase_t compat_libevent_tests[] = {
|
||||
TT_FORK, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user