Line data Source code
1 : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : #define CIRCUITBUILD_PRIVATE
5 : #define CIRCUITSTATS_PRIVATE
6 : #define CIRCUITLIST_PRIVATE
7 : #define CHANNEL_FILE_PRIVATE
8 :
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"
19 :
20 : #include "core/or/crypt_path_st.h"
21 : #include "core/or/extend_info_st.h"
22 : #include "core/or/origin_circuit_st.h"
23 :
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);
27 :
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. */
31 : static void
32 1 : mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
33 : const char *file)
34 : {
35 1 : (void) circ;
36 1 : (void) reason;
37 1 : (void) line;
38 1 : (void) file;
39 1 : marked_for_close = 1;
40 1 : return;
41 : }
42 :
43 : static origin_circuit_t *
44 1 : add_opened_threehop(void)
45 : {
46 1 : struct timeval circ_start_time;
47 1 : memset(&circ_start_time, 0, sizeof(circ_start_time));
48 1 : extend_info_t fakehop;
49 1 : memset(&fakehop, 0, sizeof(fakehop));
50 1 : extend_info_t *fakehop_list[DEFAULT_ROUTE_LEN] = {&fakehop,
51 : &fakehop,
52 : &fakehop};
53 :
54 1 : return new_test_origin_circuit(true,
55 : circ_start_time,
56 : DEFAULT_ROUTE_LEN,
57 : fakehop_list);
58 : }
59 :
60 : static origin_circuit_t *
61 3 : build_unopened_fourhop(struct timeval circ_start_time)
62 : {
63 3 : extend_info_t fakehop;
64 3 : memset(&fakehop, 0, sizeof(fakehop));
65 3 : extend_info_t *fakehop_list[4] = {&fakehop,
66 : &fakehop,
67 : &fakehop,
68 : &fakehop};
69 :
70 3 : return new_test_origin_circuit(false,
71 : circ_start_time,
72 : 4,
73 : fakehop_list);
74 : }
75 :
76 : static origin_circuit_t *
77 3 : subtest_fourhop_circuit(struct timeval circ_start_time, int should_timeout)
78 : {
79 3 : origin_circuit_t *origin_circ = build_unopened_fourhop(circ_start_time);
80 :
81 : // Now make them open one at a time and call
82 : // circuit_build_times_handle_completed_hop();
83 3 : origin_circ->cpath->state = CPATH_STATE_OPEN;
84 3 : circuit_build_times_handle_completed_hop(origin_circ);
85 3 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
86 :
87 3 : origin_circ->cpath->next->state = CPATH_STATE_OPEN;
88 3 : circuit_build_times_handle_completed_hop(origin_circ);
89 3 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
90 :
91 : // Third hop: We should count it now.
92 3 : origin_circ->cpath->next->next->state = CPATH_STATE_OPEN;
93 3 : circuit_build_times_handle_completed_hop(origin_circ);
94 3 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
95 : !should_timeout); // 1 if counted, 0 otherwise
96 :
97 : // Fourth hop: Don't double count
98 3 : origin_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
99 3 : circuit_build_times_handle_completed_hop(origin_circ);
100 3 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
101 : !should_timeout);
102 :
103 3 : done:
104 3 : return origin_circ;
105 : }
106 :
107 : static void
108 1 : test_circuitstats_hoplen(void *arg)
109 : {
110 : /* Plan:
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..
114 : */
115 1 : struct timeval circ_start_time;
116 1 : origin_circuit_t *threehop = NULL;
117 1 : origin_circuit_t *fourhop = NULL;
118 1 : (void)arg;
119 1 : MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
120 :
121 1 : circuit_build_times_init(get_circuit_build_times_mutable());
122 :
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 1 : get_circuit_build_times_mutable()->close_ms *= 2;
126 :
127 1 : tor_gettimeofday(&circ_start_time);
128 1 : circ_start_time.tv_sec -= 119; // make us hit "relaxed" cutoff
129 :
130 : // Test 1: Build a fourhop circuit that should get marked
131 : // as relaxed and eventually counted by circuit_expire_building
132 : // (but not before)
133 1 : fourhop = subtest_fourhop_circuit(circ_start_time, 0);
134 1 : tt_int_op(fourhop->relaxed_timeout, OP_EQ, 0);
135 1 : tt_int_op(marked_for_close, OP_EQ, 0);
136 1 : circuit_expire_building();
137 1 : tt_int_op(marked_for_close, OP_EQ, 0);
138 1 : tt_int_op(fourhop->relaxed_timeout, OP_EQ, 1);
139 1 : TO_CIRCUIT(fourhop)->timestamp_began.tv_sec -= 119;
140 1 : circuit_expire_building();
141 1 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
142 1 : tt_int_op(marked_for_close, OP_EQ, 1);
143 :
144 1 : circuit_free_(TO_CIRCUIT(fourhop));
145 1 : circuit_build_times_reset(get_circuit_build_times_mutable());
146 :
147 : // Test 2: Add a threehop circuit for non-relaxed timeouts
148 1 : threehop = add_opened_threehop();
149 :
150 : /* This circuit should not timeout */
151 1 : tor_gettimeofday(&circ_start_time);
152 1 : circ_start_time.tv_sec -= 59;
153 1 : fourhop = subtest_fourhop_circuit(circ_start_time, 0);
154 1 : circuit_expire_building();
155 1 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
156 1 : tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_NE,
157 : CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
158 :
159 1 : circuit_free_((circuit_t *)fourhop);
160 1 : circuit_build_times_reset(get_circuit_build_times_mutable());
161 :
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)
164 : */
165 1 : circ_start_time.tv_sec -= 2;
166 1 : fourhop = subtest_fourhop_circuit(circ_start_time, 0);
167 1 : tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_EQ,
168 : CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
169 1 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
170 1 : circuit_expire_building();
171 1 : tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1);
172 :
173 1 : done:
174 1 : UNMOCK(circuit_mark_for_close_);
175 1 : circuit_free_(TO_CIRCUIT(threehop));
176 1 : circuit_free_(TO_CIRCUIT(fourhop));
177 1 : circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
178 1 : }
179 :
180 : #define TEST_CIRCUITSTATS(name, flags) \
181 : { #name, test_##name, (flags), &helper_pubsub_setup, NULL }
182 :
183 : struct testcase_t circuitstats_tests[] = {
184 : TEST_CIRCUITSTATS(circuitstats_hoplen, TT_FORK),
185 : END_OF_TESTCASES
186 : };
187 :
|