1 /* Copyright (c) 2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 * \file test_periodic_event.c
6 * \brief Test the periodic events that Tor uses for different roles. They are
7 * part of the libevent mainloop
10 #define CONFIG_PRIVATE
11 #define HS_SERVICE_PRIVATE
12 #define MAINLOOP_PRIVATE
14 #include "test/test.h"
15 #include "test/test_helpers.h"
17 #include "core/or/or.h"
18 #include "app/config/config.h"
19 #include "feature/hibernate/hibernate.h"
20 #include "feature/hs/hs_service.h"
21 #include "core/mainloop/mainloop.h"
22 #include "core/mainloop/netstatus.h"
23 #include "core/mainloop/periodic.h"
25 /** Helper function: This is replaced in some tests for the event callbacks so
26 * we don't actually go into the code path of those callbacks. */
28 dumb_event_fn(time_t now
, const or_options_t
*options
)
33 /* Will get rescheduled in 300 seconds. It just can't be 0. */
38 register_dummy_hidden_service(hs_service_t
*service
)
40 memset(service
, 0, sizeof(hs_service_t
));
41 memset(&service
->keys
.identity_pk
, 'A', sizeof(service
->keys
.identity_pk
));
42 (void) register_service(get_hs_service_map(), service
);
46 test_pe_initialize(void *arg
)
50 /* Initialize the events but the callback won't get called since we would
51 * need to run the main loop and then wait for a second delaying the unit
52 * tests. Instead, we'll test the callback work indepedently elsewhere. */
53 initialize_periodic_events();
54 set_network_participation(false);
55 rescan_periodic_events(get_options());
57 /* Validate that all events have been set up. */
58 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
59 periodic_event_item_t
*item
= &periodic_events
[i
];
62 tt_u64_op(item
->last_action_time
, OP_EQ
, 0);
63 /* Every event must have role(s) assign to it. This is done statically. */
64 tt_u64_op(item
->roles
, OP_NE
, 0);
65 int should_be_enabled
= (item
->roles
& PERIODIC_EVENT_ROLE_ALL
) &&
66 !(item
->flags
& PERIODIC_EVENT_FLAG_NEED_NET
);
67 tt_uint_op(periodic_event_is_enabled(item
), OP_EQ
, should_be_enabled
);
71 teardown_periodic_events();
75 test_pe_launch(void *arg
)
77 hs_service_t service
, *to_remove
= NULL
;
78 or_options_t
*options
;
83 /* We need to put tor in hibernation live state so the events requiring
84 * network gets enabled. */
85 consider_hibernation(time(NULL
));
87 set_network_participation(true);
89 /* Hack: We'll set a dumb fn() of each events so they don't get called when
90 * dispatching them. We just want to test the state of the callbacks, not
91 * the whole code path. */
92 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
93 periodic_event_item_t
*item
= &periodic_events
[i
];
94 item
->fn
= dumb_event_fn
;
97 options
= get_options_mutable();
98 options
->SocksPort_set
= 1;
99 periodic_events_on_new_options(options
);
102 /* Lets make sure that before intialization, we can't scan the periodic
103 * events list and launch them. Lets try by being a Client. */
104 /* XXXX We make sure these events are initialized now way earlier than we
106 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
107 periodic_event_item_t
*item
= &periodic_events
[i
];
108 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 0);
112 initialize_periodic_events();
114 /* Now that we've initialized, rescan the list to launch. */
115 periodic_events_on_new_options(options
);
117 int mask
= PERIODIC_EVENT_ROLE_CLIENT
|PERIODIC_EVENT_ROLE_ALL
|
118 PERIODIC_EVENT_ROLE_NET_PARTICIPANT
;
119 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
120 periodic_event_item_t
*item
= &periodic_events
[i
];
121 int should_be_enabled
= !!(item
->roles
& mask
);
122 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, should_be_enabled
);
123 // enabled or not, the event has not yet been run.
124 tt_u64_op(item
->last_action_time
, OP_EQ
, 0);
127 /* Remove Client but become a Relay. */
128 options
->SocksPort_set
= 0;
129 options
->ORPort_set
= 1;
130 periodic_events_on_new_options(options
);
132 unsigned roles
= get_my_roles(options
);
133 tt_uint_op(roles
, OP_EQ
,
134 PERIODIC_EVENT_ROLE_RELAY
|PERIODIC_EVENT_ROLE_DIRSERVER
|
135 PERIODIC_EVENT_ROLE_ALL
|PERIODIC_EVENT_ROLE_NET_PARTICIPANT
);
137 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
138 periodic_event_item_t
*item
= &periodic_events
[i
];
139 /* Only Client role should be disabled. */
140 if (item
->roles
== PERIODIC_EVENT_ROLE_CLIENT
) {
141 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 0);
143 if (item
->roles
& PERIODIC_EVENT_ROLE_RELAY
) {
144 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 1);
146 /* Non Relay role should be disabled, except for Dirserver. */
147 if (!(item
->roles
& roles
)) {
148 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 0);
152 /* Disable everything and we'll enable them ALL. */
153 options
->SocksPort_set
= 0;
154 options
->ORPort_set
= 0;
155 options
->DisableNetwork
= 1;
156 set_network_participation(false);
157 periodic_events_on_new_options(options
);
159 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
160 periodic_event_item_t
*item
= &periodic_events
[i
];
161 int should_be_enabled
= (item
->roles
& PERIODIC_EVENT_ROLE_ALL
) &&
162 !(item
->flags
& PERIODIC_EVENT_FLAG_NEED_NET
);
163 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, should_be_enabled
);
166 /* Enable everything. */
167 options
->SocksPort_set
= 1; options
->ORPort_set
= 1;
168 options
->BridgeRelay
= 1; options
->AuthoritativeDir
= 1;
169 options
->V3AuthoritativeDir
= 1; options
->BridgeAuthoritativeDir
= 1;
170 options
->DisableNetwork
= 0;
171 set_network_participation(true);
172 register_dummy_hidden_service(&service
);
173 periodic_events_on_new_options(options
);
174 /* Note down the reference because we need to remove this service from the
175 * global list before the hs_free_all() call so it doesn't try to free
176 * memory on the stack. Furthermore, we can't remove it now else it will
177 * trigger a rescan of the event disabling the HS service event. */
178 to_remove
= &service
;
180 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
181 periodic_event_item_t
*item
= &periodic_events
[i
];
182 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
,
183 (item
->roles
!= PERIODIC_EVENT_ROLE_CONTROLEV
));
188 remove_service(get_hs_service_map(), to_remove
);
194 test_pe_get_roles(void *arg
)
200 /* Just so the HS global map exists. */
203 or_options_t
*options
= get_options_mutable();
205 set_network_participation(true);
207 const int ALL
= PERIODIC_EVENT_ROLE_ALL
|
208 PERIODIC_EVENT_ROLE_NET_PARTICIPANT
;
210 /* Nothing configured, should be no roles. */
211 tt_assert(net_is_disabled());
212 roles
= get_my_roles(options
);
213 tt_int_op(roles
, OP_EQ
, ALL
);
215 /* Indicate we have a SocksPort, roles should be come Client. */
216 options
->SocksPort_set
= 1;
217 roles
= get_my_roles(options
);
218 tt_int_op(roles
, OP_EQ
, PERIODIC_EVENT_ROLE_CLIENT
|ALL
);
220 /* Now, we'll add a ORPort so should now be a Relay + Client. */
221 options
->ORPort_set
= 1;
222 roles
= get_my_roles(options
);
223 tt_int_op(roles
, OP_EQ
,
224 (PERIODIC_EVENT_ROLE_CLIENT
| PERIODIC_EVENT_ROLE_RELAY
|
225 PERIODIC_EVENT_ROLE_DIRSERVER
| ALL
));
227 /* Now add a Bridge. */
228 options
->BridgeRelay
= 1;
229 roles
= get_my_roles(options
);
230 tt_int_op(roles
, OP_EQ
,
231 (PERIODIC_EVENT_ROLE_CLIENT
| PERIODIC_EVENT_ROLE_RELAY
|
232 PERIODIC_EVENT_ROLE_BRIDGE
| PERIODIC_EVENT_ROLE_DIRSERVER
|
234 tt_assert(roles
& PERIODIC_EVENT_ROLE_ROUTER
);
235 /* Unset client so we can solely test Router role. */
236 options
->SocksPort_set
= 0;
237 roles
= get_my_roles(options
);
238 tt_int_op(roles
, OP_EQ
,
239 PERIODIC_EVENT_ROLE_ROUTER
| PERIODIC_EVENT_ROLE_DIRSERVER
|
242 /* Reset options so we can test authorities. */
243 options
->SocksPort_set
= 0;
244 options
->ORPort_set
= 0;
245 options
->BridgeRelay
= 0;
246 roles
= get_my_roles(options
);
247 tt_int_op(roles
, OP_EQ
, ALL
);
249 /* Now upgrade to Dirauth. */
250 options
->DirPort_set
= 1;
251 options
->AuthoritativeDir
= 1;
252 options
->V3AuthoritativeDir
= 1;
253 roles
= get_my_roles(options
);
254 tt_int_op(roles
, OP_EQ
,
255 PERIODIC_EVENT_ROLE_DIRAUTH
|PERIODIC_EVENT_ROLE_DIRSERVER
|ALL
);
256 tt_assert(roles
& PERIODIC_EVENT_ROLE_AUTHORITIES
);
258 /* Now Bridge Authority. */
259 options
->V3AuthoritativeDir
= 0;
260 options
->BridgeAuthoritativeDir
= 1;
261 roles
= get_my_roles(options
);
262 tt_int_op(roles
, OP_EQ
,
263 PERIODIC_EVENT_ROLE_BRIDGEAUTH
|PERIODIC_EVENT_ROLE_DIRSERVER
|ALL
);
264 tt_assert(roles
& PERIODIC_EVENT_ROLE_AUTHORITIES
);
266 /* Move that bridge auth to become a relay. */
267 options
->ORPort_set
= 1;
268 roles
= get_my_roles(options
);
269 tt_int_op(roles
, OP_EQ
,
270 (PERIODIC_EVENT_ROLE_BRIDGEAUTH
| PERIODIC_EVENT_ROLE_RELAY
271 | PERIODIC_EVENT_ROLE_DIRSERVER
|ALL
));
272 tt_assert(roles
& PERIODIC_EVENT_ROLE_AUTHORITIES
);
274 /* And now an Hidden service. */
275 hs_service_t service
;
276 register_dummy_hidden_service(&service
);
277 roles
= get_my_roles(options
);
278 /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
279 remove_service(get_hs_service_map(), &service
);
280 tt_int_op(roles
, OP_EQ
,
281 (PERIODIC_EVENT_ROLE_BRIDGEAUTH
| PERIODIC_EVENT_ROLE_RELAY
|
282 PERIODIC_EVENT_ROLE_HS_SERVICE
| PERIODIC_EVENT_ROLE_DIRSERVER
|
284 tt_assert(roles
& PERIODIC_EVENT_ROLE_AUTHORITIES
);
291 test_pe_hs_service(void *arg
)
293 hs_service_t service
, *to_remove
= NULL
;
298 /* We need to put tor in hibernation live state so the events requiring
299 * network gets enabled. */
300 consider_hibernation(time(NULL
));
301 /* Initialize the events so we can enable them */
302 initialize_periodic_events();
304 /* Hack: We'll set a dumb fn() of each events so they don't get called when
305 * dispatching them. We just want to test the state of the callbacks, not
306 * the whole code path. */
307 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
308 periodic_event_item_t
*item
= &periodic_events
[i
];
309 item
->fn
= dumb_event_fn
;
312 /* This should trigger a rescan of the list and enable the HS service
314 register_dummy_hidden_service(&service
);
315 /* Note down the reference because we need to remove this service from the
316 * global list before the hs_free_all() call so it doesn't try to free
317 * memory on the stack. Furthermore, we can't remove it now else it will
318 * trigger a rescan of the event disabling the HS service event. */
319 to_remove
= &service
;
321 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
322 periodic_event_item_t
*item
= &periodic_events
[i
];
323 if (item
->roles
& PERIODIC_EVENT_ROLE_HS_SERVICE
) {
324 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 1);
329 /* Remove the service from the global map, it should trigger a rescan and
330 * disable the HS service events. */
331 remove_service(get_hs_service_map(), &service
);
332 for (int i
= 0; periodic_events
[i
].name
; ++i
) {
333 periodic_event_item_t
*item
= &periodic_events
[i
];
334 if (item
->roles
& PERIODIC_EVENT_ROLE_HS_SERVICE
) {
335 tt_int_op(periodic_event_is_enabled(item
), OP_EQ
, 0);
341 remove_service(get_hs_service_map(), to_remove
);
346 #define PE_TEST(name) \
347 { #name, test_pe_## name , TT_FORK, NULL, NULL }
349 struct testcase_t periodic_event_tests
[] = {