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