1 /* Copyright (c) 2017-2020, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define CIRCUITBUILD_PRIVATE
5 #define CIRCUITSTATS_PRIVATE
6 #define CIRCUITLIST_PRIVATE
7 #define CHANNEL_FILE_PRIVATE
9 #include "core/or/or.h"
10 #include "test/test.h"
11 #include "test/test_helpers.h"
12 #include "test/log_test_helpers.h"
13 #include "app/config/config.h"
14 #include "core/or/circuitlist.h"
15 #include "core/or/circuitbuild.h"
16 #include "core/or/circuitstats.h"
17 #include "core/or/circuituse.h"
18 #include "core/or/channel.h"
20 #include "core/or/crypt_path_st.h"
21 #include "core/or/extend_info_st.h"
22 #include "core/or/origin_circuit_st.h"
24 static origin_circuit_t
*add_opened_threehop(void);
25 static origin_circuit_t
*build_unopened_fourhop(struct timeval
);
26 static origin_circuit_t
*subtest_fourhop_circuit(struct timeval
, int);
28 static int marked_for_close
;
29 /* Mock function because we are not trying to test the close circuit that does
30 * an awful lot of checks on the circuit object. */
32 mock_circuit_mark_for_close(circuit_t
*circ
, int reason
, int line
,
43 static origin_circuit_t
*
44 add_opened_threehop(void)
46 struct timeval circ_start_time
;
47 memset(&circ_start_time
, 0, sizeof(circ_start_time
));
48 extend_info_t fakehop
;
49 memset(&fakehop
, 0, sizeof(fakehop
));
50 extend_info_t
*fakehop_list
[DEFAULT_ROUTE_LEN
] = {&fakehop
,
54 return new_test_origin_circuit(true,
60 static origin_circuit_t
*
61 build_unopened_fourhop(struct timeval circ_start_time
)
63 extend_info_t fakehop
;
64 memset(&fakehop
, 0, sizeof(fakehop
));
65 extend_info_t
*fakehop_list
[4] = {&fakehop
,
70 return new_test_origin_circuit(false,
76 static origin_circuit_t
*
77 subtest_fourhop_circuit(struct timeval circ_start_time
, int should_timeout
)
79 origin_circuit_t
*origin_circ
= build_unopened_fourhop(circ_start_time
);
81 // Now make them open one at a time and call
82 // circuit_build_times_handle_completed_hop();
83 origin_circ
->cpath
->state
= CPATH_STATE_OPEN
;
84 circuit_build_times_handle_completed_hop(origin_circ
);
85 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 0);
87 origin_circ
->cpath
->next
->state
= CPATH_STATE_OPEN
;
88 circuit_build_times_handle_completed_hop(origin_circ
);
89 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 0);
91 // Third hop: We should count it now.
92 origin_circ
->cpath
->next
->next
->state
= CPATH_STATE_OPEN
;
93 circuit_build_times_handle_completed_hop(origin_circ
);
94 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
,
95 !should_timeout
); // 1 if counted, 0 otherwise
97 // Fourth hop: Don't double count
98 origin_circ
->cpath
->next
->next
->next
->state
= CPATH_STATE_OPEN
;
99 circuit_build_times_handle_completed_hop(origin_circ
);
100 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
,
108 test_circuitstats_hoplen(void *arg
)
111 * 0. Test no other opened circs (relaxed timeout)
112 * 1. Check >3 hop circ building w/o timeout
113 * 2. Check >3 hop circs w/ timeouts..
115 struct timeval circ_start_time
;
116 origin_circuit_t
*threehop
= NULL
;
117 origin_circuit_t
*fourhop
= NULL
;
119 MOCK(circuit_mark_for_close_
, mock_circuit_mark_for_close
);
121 circuit_build_times_init(get_circuit_build_times_mutable());
123 // Let's set a close_ms to 2X the initial timeout, so we can
124 // test relaxed functionality (which uses the close_ms timeout)
125 get_circuit_build_times_mutable()->close_ms
*= 2;
127 tor_gettimeofday(&circ_start_time
);
128 circ_start_time
.tv_sec
-= 119; // make us hit "relaxed" cutoff
130 // Test 1: Build a fourhop circuit that should get marked
131 // as relaxed and eventually counted by circuit_expire_building
133 fourhop
= subtest_fourhop_circuit(circ_start_time
, 0);
134 tt_int_op(fourhop
->relaxed_timeout
, OP_EQ
, 0);
135 tt_int_op(marked_for_close
, OP_EQ
, 0);
136 circuit_expire_building();
137 tt_int_op(marked_for_close
, OP_EQ
, 0);
138 tt_int_op(fourhop
->relaxed_timeout
, OP_EQ
, 1);
139 TO_CIRCUIT(fourhop
)->timestamp_began
.tv_sec
-= 119;
140 circuit_expire_building();
141 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 1);
142 tt_int_op(marked_for_close
, OP_EQ
, 1);
144 circuit_free_(TO_CIRCUIT(fourhop
));
145 circuit_build_times_reset(get_circuit_build_times_mutable());
147 // Test 2: Add a threehop circuit for non-relaxed timeouts
148 threehop
= add_opened_threehop();
150 /* This circuit should not timeout */
151 tor_gettimeofday(&circ_start_time
);
152 circ_start_time
.tv_sec
-= 59;
153 fourhop
= subtest_fourhop_circuit(circ_start_time
, 0);
154 circuit_expire_building();
155 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 1);
156 tt_int_op(TO_CIRCUIT(fourhop
)->purpose
, OP_NE
,
157 CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT
);
159 circuit_free_((circuit_t
*)fourhop
);
160 circuit_build_times_reset(get_circuit_build_times_mutable());
162 /* Test 3: This circuit should now time out and get marked as a
163 * measurement circuit, but still get counted (and counted only once)
165 circ_start_time
.tv_sec
-= 2;
166 fourhop
= subtest_fourhop_circuit(circ_start_time
, 0);
167 tt_int_op(TO_CIRCUIT(fourhop
)->purpose
, OP_EQ
,
168 CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT
);
169 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 1);
170 circuit_expire_building();
171 tt_int_op(get_circuit_build_times()->total_build_times
, OP_EQ
, 1);
174 UNMOCK(circuit_mark_for_close_
);
175 circuit_free_(TO_CIRCUIT(threehop
));
176 circuit_free_(TO_CIRCUIT(fourhop
));
177 circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
180 #define TEST_CIRCUITSTATS(name, flags) \
181 { #name, test_##name, (flags), &helper_pubsub_setup, NULL }
183 struct testcase_t circuitstats_tests
[] = {
184 TEST_CIRCUITSTATS(circuitstats_hoplen
, TT_FORK
),