/work/auto_tests/forwarding_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <assert.h> |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | |
5 | | #include "../toxcore/tox.h" |
6 | | #include "../toxcore/announce.h" |
7 | | #include "../testing/misc_tools.h" |
8 | | #include "../toxcore/mono_time.h" |
9 | | #include "../toxcore/forwarding.h" |
10 | | #include "../toxcore/net_crypto.h" |
11 | | #include "../toxcore/util.h" |
12 | | #include "auto_test_support.h" |
13 | | #include "check_compat.h" |
14 | | |
15 | | #ifndef USE_IPV6 |
16 | | #define USE_IPV6 1 |
17 | | #endif |
18 | | |
19 | | static inline IP get_loopback(void) |
20 | 96 | { |
21 | 96 | IP ip; |
22 | | #if USE_IPV6 |
23 | | ip.family = net_family_ipv6(); |
24 | | ip.ip.v6 = get_ip6_loopback(); |
25 | | #else |
26 | 96 | ip.family = net_family_ipv4(); |
27 | 96 | ip.ip.v4 = get_ip4_loopback(); |
28 | 96 | #endif |
29 | 96 | return ip; |
30 | 96 | } |
31 | | |
32 | 6.38k | #define NUM_FORWARDER 20 |
33 | 483 | #define NUM_FORWARDER_TCP 5 |
34 | 183 | #define NUM_FORWARDER_DHT (NUM_FORWARDER - NUM_FORWARDER_TCP) |
35 | 2 | #define NUM_FORWARDING_ITERATIONS 1 |
36 | 389 | #define FORWARD_SEND_INTERVAL 2 |
37 | 49 | #define FORWARDING_BASE_PORT 36571 |
38 | | |
39 | | typedef struct Test_Data { |
40 | | Networking_Core *net; |
41 | | uint32_t send_back; |
42 | | uint64_t sent; |
43 | | bool returned; |
44 | | } Test_Data; |
45 | | |
46 | | static void test_forwarded_request_cb(void *object, const IP_Port *forwarder, |
47 | | const uint8_t *sendback, uint16_t sendback_length, |
48 | | const uint8_t *data, uint16_t length, void *userdata) |
49 | 20 | { |
50 | 20 | const Test_Data *test_data = (const Test_Data *)object; |
51 | 20 | const uint8_t *index = (const uint8_t *)userdata; |
52 | | |
53 | 20 | if (length != 12 || memcmp("hello: ", data, 8) != 0) { |
54 | 0 | printf("[%u] got unexpected data of length %d\n", *index, length); |
55 | 0 | return; |
56 | 0 | } |
57 | | |
58 | 20 | uint8_t reply[12]; |
59 | 20 | memcpy(reply, "reply: ", 8); |
60 | 20 | memcpy(reply + 8, data + 8, 4); |
61 | 20 | ck_assert_msg(forward_reply(test_data->net, forwarder, sendback, sendback_length, reply, 12), |
62 | 20 | "[%u] forward_reply failed", *index); |
63 | 20 | } |
64 | | |
65 | | static void test_forwarded_response_cb(void *object, |
66 | | const uint8_t *data, uint16_t length, void *userdata) |
67 | 20 | { |
68 | 20 | Test_Data *test_data = (Test_Data *)object; |
69 | 20 | const uint8_t *index = (const uint8_t *)userdata; |
70 | | |
71 | 20 | if (length != 12 || memcmp("reply: ", data, 8) != 0) { |
72 | 0 | printf("[%u] got unexpected data of length %d\n", *index, length); |
73 | 0 | return; |
74 | 0 | } |
75 | | |
76 | 20 | uint32_t send_back; |
77 | 20 | net_unpack_u32(data + 8, &send_back); |
78 | | |
79 | 20 | if (test_data->send_back == send_back) { |
80 | 20 | test_data->returned = true; |
81 | 20 | } |
82 | 20 | } |
83 | | |
84 | | static bool all_returned(Test_Data *test_data) |
85 | 256 | { |
86 | 732 | for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { |
87 | 731 | if (!test_data[i].returned) { |
88 | 255 | return false; |
89 | 255 | } |
90 | 731 | } |
91 | | |
92 | 1 | return true; |
93 | 256 | } |
94 | | |
95 | | typedef struct Forwarding_Subtox { |
96 | | Logger *log; |
97 | | Mono_Time *mono_time; |
98 | | Networking_Core *net; |
99 | | DHT *dht; |
100 | | Net_Crypto *c; |
101 | | Forwarding *forwarding; |
102 | | Announcements *announce; |
103 | | } Forwarding_Subtox; |
104 | | |
105 | | static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp, uint32_t *index, uint16_t port) |
106 | 20 | { |
107 | 20 | const Random *rng = os_random(); |
108 | 20 | ck_assert(rng != nullptr); |
109 | 20 | const Network *ns = os_network(); |
110 | 20 | ck_assert(ns != nullptr); |
111 | | |
112 | 20 | Forwarding_Subtox *subtox = (Forwarding_Subtox *)calloc(1, sizeof(Forwarding_Subtox)); |
113 | 20 | ck_assert(subtox != nullptr); |
114 | | |
115 | 20 | subtox->log = logger_new(); |
116 | 20 | ck_assert(subtox->log != nullptr); |
117 | 20 | logger_callback_log(subtox->log, print_debug_logger, nullptr, index); |
118 | 20 | subtox->mono_time = mono_time_new(mem, nullptr, nullptr); |
119 | | |
120 | 20 | if (no_udp) { |
121 | 5 | subtox->net = new_networking_no_udp(subtox->log, mem, ns); |
122 | 15 | } else { |
123 | 15 | const IP ip = get_loopback(); |
124 | 15 | subtox->net = new_networking_ex(subtox->log, mem, ns, &ip, port, port, nullptr); |
125 | 15 | } |
126 | | |
127 | 20 | subtox->dht = new_dht(subtox->log, mem, rng, ns, subtox->mono_time, subtox->net, true, true); |
128 | | |
129 | 20 | const TCP_Proxy_Info inf = {{{{0}}}}; |
130 | 20 | subtox->c = new_net_crypto(subtox->log, mem, rng, ns, subtox->mono_time, subtox->dht, &inf); |
131 | | |
132 | 20 | subtox->forwarding = new_forwarding(subtox->log, rng, subtox->mono_time, subtox->dht); |
133 | 20 | ck_assert(subtox->forwarding != nullptr); |
134 | | |
135 | 20 | subtox->announce = new_announcements(subtox->log, mem, rng, subtox->mono_time, subtox->forwarding); |
136 | 20 | ck_assert(subtox->announce != nullptr); |
137 | | |
138 | 20 | return subtox; |
139 | 20 | } |
140 | | |
141 | | static void kill_forwarding_subtox(const Memory *mem, Forwarding_Subtox *subtox) |
142 | 20 | { |
143 | 20 | kill_announcements(subtox->announce); |
144 | 20 | kill_forwarding(subtox->forwarding); |
145 | 20 | kill_net_crypto(subtox->c); |
146 | 20 | kill_dht(subtox->dht); |
147 | 20 | kill_networking(subtox->net); |
148 | 20 | mono_time_free(mem, subtox->mono_time); |
149 | 20 | logger_kill(subtox->log); |
150 | 20 | free(subtox); |
151 | 20 | } |
152 | | |
153 | | static void test_forwarding(void) |
154 | 1 | { |
155 | 1 | const Memory *mem = os_memory(); |
156 | 1 | ck_assert(mem != nullptr); |
157 | 1 | const Random *rng = os_random(); |
158 | 1 | ck_assert(rng != nullptr); |
159 | 1 | const Network *ns = os_network(); |
160 | 1 | ck_assert(ns != nullptr); |
161 | | |
162 | 1 | uint32_t index[NUM_FORWARDER]; |
163 | 1 | Forwarding_Subtox *subtoxes[NUM_FORWARDER]; |
164 | 1 | Test_Data test_data[NUM_FORWARDER]; |
165 | | |
166 | 1 | const IP ip = get_loopback(); |
167 | | |
168 | 21 | for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { |
169 | 20 | index[i] = i + 1; |
170 | 20 | subtoxes[i] = new_forwarding_subtox(mem, i < NUM_FORWARDER_TCP, &index[i], FORWARDING_BASE_PORT + i); |
171 | | |
172 | 20 | test_data[i].net = subtoxes[i]->net; |
173 | 20 | test_data[i].send_back = 0; |
174 | 20 | test_data[i].sent = 0; |
175 | 20 | test_data[i].returned = false; |
176 | 20 | set_callback_forwarded_request(subtoxes[i]->forwarding, test_forwarded_request_cb, &test_data[i]); |
177 | 20 | set_callback_forwarded_response(subtoxes[i]->forwarding, test_forwarded_response_cb, &test_data[i]); |
178 | 20 | set_forwarding_packet_tcp_connection_callback(nc_get_tcp_c(subtoxes[i]->c), test_forwarded_response_cb, &test_data[i]); |
179 | 20 | } |
180 | | |
181 | 1 | printf("testing forwarding via tcp relays and dht\n"); |
182 | | |
183 | 1 | struct Tox_Options *opts = tox_options_new(nullptr); |
184 | 1 | uint16_t forwarder_tcp_relay_port = 36570; |
185 | 1 | Tox *relay = nullptr; |
186 | | // Try a few different ports. |
187 | 1 | for (uint8_t i = 0; i < 100; ++i) { |
188 | 1 | tox_options_set_tcp_port(opts, forwarder_tcp_relay_port); |
189 | 1 | relay = tox_new_log(opts, nullptr, nullptr); |
190 | 1 | if (relay != nullptr) { |
191 | 1 | break; |
192 | 1 | } |
193 | 0 | ++forwarder_tcp_relay_port; |
194 | 0 | } |
195 | 1 | tox_options_free(opts); |
196 | 1 | ck_assert_msg(relay != nullptr, "Failed to create TCP relay"); |
197 | | |
198 | 1 | IP_Port relay_ipport_tcp = {ip, net_htons(forwarder_tcp_relay_port)}; |
199 | | |
200 | 1 | uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; |
201 | 1 | tox_self_get_dht_id(relay, dpk); |
202 | | |
203 | 1 | printf("1-%d connected only to TCP server; %d-%d connected only to DHT\n", |
204 | 1 | NUM_FORWARDER_TCP, NUM_FORWARDER_TCP + 1, NUM_FORWARDER); |
205 | | |
206 | 6 | for (uint32_t i = 0; i < NUM_FORWARDER_TCP; ++i) { |
207 | 5 | set_tcp_onion_status(nc_get_tcp_c(subtoxes[i]->c), 1); |
208 | 5 | ck_assert_msg(add_tcp_relay(subtoxes[i]->c, &relay_ipport_tcp, dpk) == 0, |
209 | 5 | "Failed to add TCP relay"); |
210 | 5 | } |
211 | | |
212 | 1 | IP_Port relay_ipport_udp = {ip, net_htons(tox_self_get_udp_port(relay, nullptr))}; |
213 | | |
214 | 16 | for (uint32_t i = NUM_FORWARDER_TCP; i < NUM_FORWARDER; ++i) { |
215 | 15 | dht_bootstrap(subtoxes[i]->dht, &relay_ipport_udp, dpk); |
216 | 15 | } |
217 | | |
218 | 1 | printf("allowing DHT to populate\n"); |
219 | 1 | uint16_t dht_establish_iterations = NUM_FORWARDER * 5; |
220 | | |
221 | 2 | for (uint32_t n = 0; n < NUM_FORWARDING_ITERATIONS; ++n) { |
222 | 21 | for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { |
223 | 20 | test_data[i].sent = 0; |
224 | 20 | test_data[i].returned = false; |
225 | 20 | } |
226 | | |
227 | 256 | do { |
228 | 5.37k | for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { |
229 | 5.12k | Forwarding_Subtox *const subtox = subtoxes[i]; |
230 | 5.12k | mono_time_update(subtox->mono_time); |
231 | 5.12k | networking_poll(subtox->net, &index[i]); |
232 | 5.12k | do_net_crypto(subtox->c, &index[i]); |
233 | 5.12k | do_dht(subtox->dht); |
234 | | |
235 | 5.12k | if (dht_establish_iterations || |
236 | 5.12k | test_data[i].returned || |
237 | 5.12k | !mono_time_is_timeout(subtox->mono_time, test_data[i].sent, FORWARD_SEND_INTERVAL)) { |
238 | 5.09k | continue; |
239 | 5.09k | } |
240 | | |
241 | 29 | printf("%u", i + 1); |
242 | | |
243 | 29 | if (i < NUM_FORWARDER_TCP) { |
244 | 9 | printf(" --> TCPRelay"); |
245 | 9 | } |
246 | | |
247 | 29 | const uint16_t chain_length = i < NUM_FORWARDER_TCP ? i % 5 : i % 4 + 1; |
248 | 29 | uint8_t chain_keys[4 * CRYPTO_PUBLIC_KEY_SIZE]; |
249 | | |
250 | 29 | uint32_t chain_i = NUM_FORWARDER_TCP + (random_u32(rng) % NUM_FORWARDER_DHT); |
251 | 29 | const IP_Port first_ipp = {ip, net_htons(FORWARDING_BASE_PORT + chain_i)}; |
252 | | |
253 | 29 | printf(" --> %u", chain_i + 1); |
254 | | |
255 | 106 | for (uint16_t j = 0; j < chain_length; ++j) { |
256 | | // pick random different dht node: |
257 | 77 | chain_i += 1 + random_u32(rng) % (NUM_FORWARDER_DHT - 1); |
258 | 77 | chain_i = NUM_FORWARDER_TCP + (chain_i - NUM_FORWARDER_TCP) % NUM_FORWARDER_DHT; |
259 | | |
260 | 77 | const uint8_t *dest_pubkey = dht_get_self_public_key(subtoxes[chain_i]->dht); |
261 | | |
262 | 77 | memcpy(chain_keys + j * CRYPTO_PUBLIC_KEY_SIZE, dest_pubkey, CRYPTO_PUBLIC_KEY_SIZE); |
263 | 77 | printf(" --> %u", chain_i + 1); |
264 | 77 | } |
265 | | |
266 | 29 | printf("\n"); |
267 | | |
268 | 29 | const uint16_t length = 12; |
269 | 29 | uint8_t data[12]; |
270 | | |
271 | 29 | memcpy(data, "hello: ", 8); |
272 | 29 | test_data[i].send_back = random_u32(rng); |
273 | 29 | net_pack_u32(data + 8, test_data[i].send_back); |
274 | | |
275 | 29 | if (i < NUM_FORWARDER_TCP) { |
276 | 9 | IP_Port tcp_forwarder; |
277 | | |
278 | 9 | if (!get_random_tcp_conn_ip_port(subtox->c, &tcp_forwarder)) { |
279 | 0 | continue; |
280 | 0 | } |
281 | | |
282 | 9 | if (send_tcp_forward_request(subtox->log, subtox->c, &tcp_forwarder, &first_ipp, |
283 | 9 | chain_keys, chain_length, data, length) == 0) { |
284 | 9 | test_data[i].sent = mono_time_get(subtox->mono_time); |
285 | 9 | } |
286 | 20 | } else { |
287 | 20 | if (send_forward_request(subtox->net, &first_ipp, |
288 | 20 | chain_keys, chain_length, data, length)) { |
289 | 20 | test_data[i].sent = mono_time_get(subtox->mono_time); |
290 | 20 | } |
291 | 20 | } |
292 | 29 | } |
293 | | |
294 | 256 | tox_iterate(relay, nullptr); |
295 | | |
296 | 256 | if (dht_establish_iterations) { |
297 | 100 | --dht_establish_iterations; |
298 | | |
299 | 100 | if (!dht_establish_iterations) { |
300 | 1 | printf("making forward requests and expecting replies\n"); |
301 | 1 | } |
302 | 100 | } |
303 | | |
304 | 256 | c_sleep(50); |
305 | 256 | } while (!all_returned(test_data)); |
306 | | |
307 | | // This doesn't really belong in this test. |
308 | | // It can be removed once the full announce client test is in place. |
309 | 1 | printf("checking that nodes are marked as announce nodes\n"); |
310 | 1 | Node_format nodes[MAX_SENT_NODES]; |
311 | 1 | ck_assert(NUM_FORWARDER - NUM_FORWARDER_TCP > 1); |
312 | | |
313 | 16 | for (uint32_t i = NUM_FORWARDER_TCP; i < NUM_FORWARDER; ++i) { |
314 | 15 | ck_assert_msg(get_close_nodes(subtoxes[i]->dht, dht_get_self_public_key(subtoxes[i]->dht), nodes, net_family_unspec(), true, |
315 | 15 | true) > 0, |
316 | 15 | "node %u has no nodes marked as announce nodes", i); |
317 | 15 | } |
318 | 1 | } |
319 | | |
320 | | |
321 | 21 | for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { |
322 | 20 | kill_forwarding_subtox(mem, subtoxes[i]); |
323 | 20 | } |
324 | | |
325 | 1 | tox_kill(relay); |
326 | 1 | } |
327 | | |
328 | | |
329 | | int main(void) |
330 | 721 | { |
331 | 721 | setvbuf(stdout, nullptr, _IONBF, 0); |
332 | | |
333 | 721 | test_forwarding(); |
334 | | |
335 | 721 | return 0; |
336 | 721 | } |