1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file test_mainloop.c
6  * \brief Tests for functions closely related to the Tor main loop
7  */
8 
9 #define CONFIG_PRIVATE
10 #define MAINLOOP_PRIVATE
11 #define STATEFILE_PRIVATE
12 
13 #include "test/test.h"
14 #include "test/log_test_helpers.h"
15 
16 #include "lib/confmgt/confmgt.h"
17 
18 #include "core/or/or.h"
19 #include "core/mainloop/connection.h"
20 #include "core/mainloop/mainloop.h"
21 #include "core/mainloop/mainloop_state_st.h"
22 #include "core/mainloop/mainloop_sys.h"
23 #include "core/mainloop/netstatus.h"
24 
25 #include "feature/hs/hs_service.h"
26 
27 #include "app/config/config.h"
28 #include "app/config/statefile.h"
29 #include "app/config/or_state_st.h"
30 
31 #include "app/main/subsysmgr.h"
32 
33 static const uint64_t BILLION = 1000000000;
34 
35 static void
test_mainloop_update_time_normal(void * arg)36 test_mainloop_update_time_normal(void *arg)
37 {
38   (void)arg;
39 
40   monotime_enable_test_mocking();
41   /* This is arbitrary */
42   uint64_t mt_now = UINT64_C(7493289274986);
43   /* This time is in the past as of when this test was written. */
44   time_t now = 1525272090;
45   monotime_coarse_set_mock_time_nsec(mt_now);
46   reset_uptime();
47   update_current_time(now);
48   tt_int_op(approx_time(), OP_EQ, now);
49   tt_int_op(get_uptime(), OP_EQ, 0);
50 
51   update_current_time(now); // Same time as before is a no-op.
52   tt_int_op(get_uptime(), OP_EQ, 0);
53 
54   now += 1;
55   mt_now += BILLION;
56   monotime_coarse_set_mock_time_nsec(mt_now);
57   update_current_time(now);
58   tt_int_op(approx_time(), OP_EQ, now);
59   tt_int_op(get_uptime(), OP_EQ, 1);
60 
61   now += 2; // two-second jump is unremarkable.
62   mt_now += 2*BILLION;
63   update_current_time(now);
64   monotime_coarse_set_mock_time_nsec(mt_now);
65   tt_int_op(approx_time(), OP_EQ, now);
66   tt_int_op(get_uptime(), OP_EQ, 3);
67 
68   now -= 1; // a one-second hop backwards is also unremarkable.
69   update_current_time(now);
70   tt_int_op(approx_time(), OP_EQ, now); // it changes the approx time...
71   tt_int_op(get_uptime(), OP_EQ, 3); // but it doesn't roll back our uptime
72 
73  done:
74   monotime_disable_test_mocking();
75 }
76 
77 static void
test_mainloop_update_time_jumps(void * arg)78 test_mainloop_update_time_jumps(void *arg)
79 {
80   (void)arg;
81 
82   monotime_enable_test_mocking();
83   /* This is arbitrary */
84   uint64_t mt_now = UINT64_C(7493289274986);
85   /* This time is in the past as of when this test was written. */
86   time_t now = 220897152;
87   monotime_coarse_set_mock_time_nsec(mt_now);
88   reset_uptime();
89   update_current_time(now);
90   tt_int_op(approx_time(), OP_EQ, now);
91   tt_int_op(get_uptime(), OP_EQ, 0);
92 
93   /* Put some uptime on the clock.. */
94   now += 3;
95   mt_now += 3*BILLION;
96   monotime_coarse_set_mock_time_nsec(mt_now);
97   update_current_time(now);
98   tt_int_op(approx_time(), OP_EQ, now);
99   tt_int_op(get_uptime(), OP_EQ, 3);
100 
101   /* Now try jumping forward and backward, without updating the monotonic
102    * clock.  */
103   setup_capture_of_logs(LOG_NOTICE);
104   now += 1800;
105   update_current_time(now);
106   expect_single_log_msg_containing(
107                "Your system clock just jumped 1800 seconds forward");
108   tt_int_op(approx_time(), OP_EQ, now);
109   tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
110   mock_clean_saved_logs();
111 
112   now -= 600;
113   update_current_time(now);
114   expect_single_log_msg_containing(
115                "Your system clock just jumped 600 seconds backward");
116   tt_int_op(approx_time(), OP_EQ, now);
117   tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
118   mock_clean_saved_logs();
119 
120   /* uptime tracking should go normally now if the clock moves sensibly. */
121   now += 2;
122   mt_now += 2*BILLION;
123   update_current_time(now);
124   tt_int_op(approx_time(), OP_EQ, now);
125   tt_int_op(get_uptime(), OP_EQ, 5);
126 
127   /* If we skip forward by a few minutes but the monotonic clock agrees,
128    * we've just been idle: that counts as not worth warning about. */
129   now += 1800;
130   mt_now += 1800*BILLION;
131   monotime_coarse_set_mock_time_nsec(mt_now);
132   update_current_time(now);
133   expect_no_log_entry();
134   tt_int_op(approx_time(), OP_EQ, now);
135   tt_int_op(get_uptime(), OP_EQ, 5); // this doesn't count to uptime, though.
136 
137   /* If we skip forward by a long time, even if the clock agrees, it's
138    * idnless that counts. */
139   now += 4000;
140   mt_now += 4000*BILLION;
141   monotime_coarse_set_mock_time_nsec(mt_now);
142   update_current_time(now);
143   expect_single_log_msg_containing("Tor has been idle for 4000 seconds");
144   tt_int_op(approx_time(), OP_EQ, now);
145   tt_int_op(get_uptime(), OP_EQ, 5);
146 
147  done:
148   teardown_capture_of_logs();
149   monotime_disable_test_mocking();
150 }
151 
152 static int schedule_rescan_called = 0;
153 static void
mock_schedule_rescan_periodic_events(void)154 mock_schedule_rescan_periodic_events(void)
155 {
156   ++schedule_rescan_called;
157 }
158 
159 static void
test_mainloop_user_activity(void * arg)160 test_mainloop_user_activity(void *arg)
161 {
162   (void)arg;
163   const time_t start = 1542658829;
164   update_approx_time(start);
165 
166   MOCK(schedule_rescan_periodic_events, mock_schedule_rescan_periodic_events);
167 
168   reset_user_activity(start);
169   tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
170 
171   set_network_participation(false);
172 
173   // reset can move backwards and forwards, but does not change network
174   // participation.
175   reset_user_activity(start-10);
176   tt_i64_op(get_last_user_activity_time(), OP_EQ, start-10);
177   reset_user_activity(start+10);
178   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
179 
180   tt_int_op(schedule_rescan_called, OP_EQ, 0);
181   tt_int_op(false, OP_EQ, is_participating_on_network());
182 
183   // "note" can only move forward.  Calling it from a non-participating
184   // state makes us rescan the periodic callbacks and set participation.
185   note_user_activity(start+20);
186   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+20);
187   tt_int_op(true, OP_EQ, is_participating_on_network());
188   tt_int_op(schedule_rescan_called, OP_EQ, 1);
189 
190   // Calling it again will move us forward, but not call rescan again.
191   note_user_activity(start+25);
192   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
193   tt_int_op(true, OP_EQ, is_participating_on_network());
194   tt_int_op(schedule_rescan_called, OP_EQ, 1);
195 
196   // We won't move backwards.
197   note_user_activity(start+20);
198   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
199   tt_int_op(true, OP_EQ, is_participating_on_network());
200   tt_int_op(schedule_rescan_called, OP_EQ, 1);
201 
202   // We _will_ adjust if the clock jumps though.
203   netstatus_note_clock_jumped(500);
204   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+525);
205 
206   netstatus_note_clock_jumped(-400);
207   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+125);
208 
209  done:
210   UNMOCK(schedule_rescan_periodic_events);
211 }
212 
213 static unsigned int
mock_get_num_services(void)214 mock_get_num_services(void)
215 {
216   return 1;
217 }
218 
219 static connection_t *
mock_connection_gbtu(int type)220 mock_connection_gbtu(int type)
221 {
222   (void) type;
223   return (void *)"hello fellow connections";
224 }
225 
226 static void
test_mainloop_check_participation(void * arg)227 test_mainloop_check_participation(void *arg)
228 {
229   (void)arg;
230   or_options_t *options = options_new();
231   const time_t start = 1542658829;
232   const time_t ONE_DAY = 24*60*60;
233 
234   options->DormantTimeoutEnabled = 1;
235 
236   // Suppose we've been idle for a day or two
237   reset_user_activity(start - 2*ONE_DAY);
238   set_network_participation(true);
239   check_network_participation_callback(start, options);
240   tt_int_op(is_participating_on_network(), OP_EQ, false);
241   tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
242 
243   // suppose we've been idle for 2 days... but we are a server.
244   reset_user_activity(start - 2*ONE_DAY);
245   options->ORPort_set = 1;
246   set_network_participation(true);
247   check_network_participation_callback(start+2, options);
248   tt_int_op(is_participating_on_network(), OP_EQ, true);
249   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+2);
250   options->ORPort_set = 0;
251 
252   // idle for 2 days, but we have a hidden service.
253   reset_user_activity(start - 2*ONE_DAY);
254   set_network_participation(true);
255   MOCK(hs_service_get_num_services, mock_get_num_services);
256   check_network_participation_callback(start+3, options);
257   tt_int_op(is_participating_on_network(), OP_EQ, true);
258   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+3);
259   UNMOCK(hs_service_get_num_services);
260 
261   // idle for 2 days but we have at least one user connection
262   MOCK(connection_get_by_type_nonlinked, mock_connection_gbtu);
263   reset_user_activity(start - 2*ONE_DAY);
264   set_network_participation(true);
265   options->DormantTimeoutDisabledByIdleStreams = 1;
266   check_network_participation_callback(start+10, options);
267   tt_int_op(is_participating_on_network(), OP_EQ, true);
268   tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
269 
270   // as above, but DormantTimeoutDisabledByIdleStreams is not set
271   reset_user_activity(start - 2*ONE_DAY);
272   set_network_participation(true);
273   options->DormantTimeoutDisabledByIdleStreams = 0;
274   check_network_participation_callback(start+13, options);
275   tt_int_op(is_participating_on_network(), OP_EQ, false);
276   tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
277   UNMOCK(connection_get_by_type_nonlinked);
278   options->DormantTimeoutDisabledByIdleStreams = 1;
279 
280   // idle for 2 days but DormantClientTimeout is 3 days
281   reset_user_activity(start - 2*ONE_DAY);
282   set_network_participation(true);
283   options->DormantClientTimeout = ONE_DAY * 3;
284   check_network_participation_callback(start+30, options);
285   tt_int_op(is_participating_on_network(), OP_EQ, true);
286   tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
287 
288  done:
289   or_options_free(options);
290   UNMOCK(hs_service_get_num_services);
291   UNMOCK(connection_get_by_type_nonlinked);
292 }
293 
294 static void
test_mainloop_dormant_load_state(void * arg)295 test_mainloop_dormant_load_state(void *arg)
296 {
297   (void)arg;
298   or_state_t *or_state = or_state_new();
299   mainloop_state_t *state;
300   {
301     int idx = subsystems_get_state_idx(&sys_mainloop);
302     tor_assert(idx >= 0);
303     state = config_mgr_get_obj_mutable(get_state_mgr(), or_state, idx);
304   }
305   const time_t start = 1543956575;
306 
307   reset_user_activity(0);
308   set_network_participation(false);
309 
310   // When we construct a new state, it starts out in "auto" mode.
311   tt_int_op(state->Dormant, OP_EQ, -1);
312 
313   // Initializing from "auto" makes us start out (by default) non-Dormant,
314   // with activity right now.
315   netstatus_load_from_state(state, start);
316   tt_assert(is_participating_on_network());
317   tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
318 
319   // Initializing from dormant clears the last user activity time, and
320   // makes us dormant.
321   state->Dormant = 1;
322   netstatus_load_from_state(state, start);
323   tt_assert(! is_participating_on_network());
324   tt_i64_op(get_last_user_activity_time(), OP_EQ, 0);
325 
326   // Initializing from non-dormant sets the last user activity time, and
327   // makes us non-dormant.
328   state->Dormant = 0;
329   state->MinutesSinceUserActivity = 123;
330   netstatus_load_from_state(state, start);
331   tt_assert(is_participating_on_network());
332   tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60);
333 
334   // If we would start dormant, but DormantCanceledByStartup is set, then
335   // we start up non-dormant.
336   state->Dormant = 1;
337   get_options_mutable()->DormantCanceledByStartup = 1;
338   netstatus_load_from_state(state, start);
339   tt_assert(is_participating_on_network());
340   tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
341 
342  done:
343   or_state_free(or_state);
344 }
345 
346 static void
test_mainloop_dormant_save_state(void * arg)347 test_mainloop_dormant_save_state(void *arg)
348 {
349   (void)arg;
350   mainloop_state_t *state = tor_malloc_zero(sizeof(mainloop_state_t));
351   const time_t start = 1543956575;
352 
353   // Can we save a non-dormant state correctly?
354   reset_user_activity(start - 1000);
355   set_network_participation(true);
356   netstatus_flush_to_state(state, start);
357 
358   tt_int_op(state->Dormant, OP_EQ, 0);
359   tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 1000 / 60);
360 
361   // Can we save a dormant state correctly?
362   set_network_participation(false);
363   netstatus_flush_to_state(state, start);
364 
365   tt_int_op(state->Dormant, OP_EQ, 1);
366   tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
367 
368  done:
369   tor_free(state);
370 }
371 
372 #define MAINLOOP_TEST(name) \
373   { #name, test_mainloop_## name , TT_FORK, NULL, NULL }
374 
375 struct testcase_t mainloop_tests[] = {
376   MAINLOOP_TEST(update_time_normal),
377   MAINLOOP_TEST(update_time_jumps),
378   MAINLOOP_TEST(user_activity),
379   MAINLOOP_TEST(check_participation),
380   MAINLOOP_TEST(dormant_load_state),
381   MAINLOOP_TEST(dormant_save_state),
382   END_OF_TESTCASES
383 };
384