/work/toxcore/friend_connection.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2026 The TokTok team. |
3 | | * Copyright © 2014 Tox project. |
4 | | */ |
5 | | |
6 | | /** |
7 | | * Connection to friends. |
8 | | */ |
9 | | #include "friend_connection.h" |
10 | | |
11 | | #include <string.h> |
12 | | |
13 | | #include "DHT.h" |
14 | | #include "LAN_discovery.h" |
15 | | #include "TCP_connection.h" |
16 | | #include "attributes.h" |
17 | | #include "ccompat.h" |
18 | | #include "crypto_core.h" |
19 | | #include "logger.h" |
20 | | #include "mem.h" |
21 | | #include "mono_time.h" |
22 | | #include "net_crypto.h" |
23 | | #include "network.h" |
24 | | #include "onion.h" |
25 | | #include "onion_announce.h" |
26 | | #include "onion_client.h" |
27 | | #include "util.h" |
28 | | |
29 | 18 | #define PORTS_PER_DISCOVERY 10 |
30 | | |
31 | | typedef struct Friend_Conn_Callbacks { |
32 | | fc_status_cb *_Nullable status_callback; |
33 | | fc_data_cb *_Nullable data_callback; |
34 | | fc_lossy_data_cb *_Nullable lossy_data_callback; |
35 | | |
36 | | void *_Nullable callback_object; |
37 | | int callback_id; |
38 | | } Friend_Conn_Callbacks; |
39 | | |
40 | | struct Friend_Conn { |
41 | | uint8_t status; |
42 | | |
43 | | uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
44 | | uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; |
45 | | uint32_t dht_lock_token; |
46 | | IP_Port dht_ip_port; |
47 | | uint64_t dht_pk_lastrecv; |
48 | | uint64_t dht_ip_port_lastrecv; |
49 | | |
50 | | int onion_friendnum; |
51 | | int crypt_connection_id; |
52 | | |
53 | | uint64_t ping_lastrecv; |
54 | | uint64_t ping_lastsent; |
55 | | uint64_t share_relays_lastsent; |
56 | | |
57 | | Friend_Conn_Callbacks callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; |
58 | | |
59 | | uint16_t lock_count; |
60 | | |
61 | | Node_format tcp_relays[FRIEND_MAX_STORED_TCP_RELAYS]; |
62 | | uint16_t tcp_relay_counter; |
63 | | uint32_t tcp_relay_share_index; |
64 | | |
65 | | bool hosting_tcp_relay; |
66 | | }; |
67 | | |
68 | | static const Friend_Conn empty_friend_conn = {0}; |
69 | | |
70 | | struct Friend_Connections { |
71 | | const Mono_Time *_Nonnull mono_time; |
72 | | const Memory *_Nonnull mem; |
73 | | const Logger *_Nonnull logger; |
74 | | Networking_Core *_Nonnull net; |
75 | | Net_Crypto *_Nonnull net_crypto; |
76 | | DHT *_Nonnull dht; |
77 | | Broadcast_Info *_Nullable broadcast; |
78 | | Onion_Client *_Nonnull onion_c; |
79 | | |
80 | | Friend_Conn *_Nullable conns; |
81 | | uint32_t num_cons; |
82 | | |
83 | | fr_request_cb *_Nullable fr_request_callback; |
84 | | void *_Nullable fr_request_object; |
85 | | |
86 | | global_status_cb *_Nullable global_status_callback; |
87 | | void *_Nullable global_status_callback_object; |
88 | | |
89 | | uint64_t last_lan_discovery; |
90 | | uint16_t next_lan_port; |
91 | | |
92 | | bool local_discovery_enabled; |
93 | | }; |
94 | | |
95 | | int friend_conn_get_onion_friendnum(const Friend_Conn *fc) |
96 | 119 | { |
97 | 119 | return fc->onion_friendnum; |
98 | 119 | } |
99 | | |
100 | | Net_Crypto *friendconn_net_crypto(const Friend_Connections *fr_c) |
101 | 2.56k | { |
102 | 2.56k | return fr_c->net_crypto; |
103 | 2.56k | } |
104 | | |
105 | | const IP_Port *friend_conn_get_dht_ip_port(const Friend_Conn *fc) |
106 | 106 | { |
107 | 106 | return &fc->dht_ip_port; |
108 | 106 | } |
109 | | |
110 | | /** |
111 | | * @retval true if the friendcon_id is valid. |
112 | | * @retval false if the friendcon_id is not valid. |
113 | | */ |
114 | | static bool friendconn_id_valid(const Friend_Connections *_Nonnull fr_c, int friendcon_id) |
115 | 873k | { |
116 | 873k | return (unsigned int)friendcon_id < fr_c->num_cons && |
117 | 873k | fr_c->conns != nullptr && |
118 | 873k | fr_c->conns[friendcon_id].status != FRIENDCONN_STATUS_NONE; |
119 | 873k | } |
120 | | |
121 | | /** @brief Set the size of the friend connections list to num. |
122 | | * |
123 | | * @retval false if realloc fails. |
124 | | * @retval true if it succeeds. |
125 | | */ |
126 | | static bool realloc_friendconns(Friend_Connections *_Nonnull fr_c, uint32_t num) |
127 | 1.48k | { |
128 | 1.48k | if (num == 0) { |
129 | 450 | mem_delete(fr_c->mem, fr_c->conns); |
130 | 450 | fr_c->conns = nullptr; |
131 | 450 | return true; |
132 | 450 | } |
133 | | |
134 | 1.03k | Friend_Conn *newgroup_cons = (Friend_Conn *)mem_vrealloc(fr_c->mem, fr_c->conns, num, sizeof(Friend_Conn)); |
135 | | |
136 | 1.03k | if (newgroup_cons == nullptr) { |
137 | 0 | return false; |
138 | 0 | } |
139 | | |
140 | 1.03k | fr_c->conns = newgroup_cons; |
141 | 1.03k | return true; |
142 | 1.03k | } |
143 | | |
144 | | /** @brief Create a new empty friend connection. |
145 | | * |
146 | | * @retval -1 on failure. |
147 | | * @return friendcon_id on success. |
148 | | */ |
149 | | static int create_friend_conn(Friend_Connections *_Nonnull fr_c) |
150 | 973 | { |
151 | 2.58k | for (uint32_t i = 0; i < fr_c->num_cons; ++i) { |
152 | 1.62k | if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) { |
153 | 13 | return i; |
154 | 13 | } |
155 | 1.62k | } |
156 | | |
157 | 960 | if (!realloc_friendconns(fr_c, fr_c->num_cons + 1)) { |
158 | 0 | return -1; |
159 | 0 | } |
160 | | |
161 | 960 | const int id = fr_c->num_cons; |
162 | 960 | ++fr_c->num_cons; |
163 | 960 | fr_c->conns[id] = empty_friend_conn; |
164 | | |
165 | 960 | return id; |
166 | 960 | } |
167 | | |
168 | | /** @brief Wipe a friend connection. |
169 | | * |
170 | | * @retval -1 on failure. |
171 | | * @retval 0 on success. |
172 | | */ |
173 | | static int wipe_friend_conn(Friend_Connections *_Nonnull fr_c, int friendcon_id) |
174 | 973 | { |
175 | 973 | if (!friendconn_id_valid(fr_c, friendcon_id)) { |
176 | 0 | return -1; |
177 | 0 | } |
178 | | |
179 | 973 | fr_c->conns[friendcon_id] = empty_friend_conn; |
180 | | |
181 | 973 | uint32_t i; |
182 | | |
183 | 1.93k | for (i = fr_c->num_cons; i != 0; --i) { |
184 | 1.48k | if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) { |
185 | 523 | break; |
186 | 523 | } |
187 | 1.48k | } |
188 | | |
189 | 973 | if (fr_c->num_cons != i) { |
190 | 520 | fr_c->num_cons = i; |
191 | 520 | realloc_friendconns(fr_c, fr_c->num_cons); |
192 | 520 | } |
193 | | |
194 | 973 | return 0; |
195 | 973 | } |
196 | | |
197 | | Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) |
198 | 872k | { |
199 | 872k | if (!friendconn_id_valid(fr_c, friendcon_id)) { |
200 | 127 | return nullptr; |
201 | 127 | } |
202 | | |
203 | 872k | return &fr_c->conns[friendcon_id]; |
204 | 872k | } |
205 | | |
206 | | /** |
207 | | * @return friendcon_id corresponding to the real public key on success. |
208 | | * @retval -1 on failure. |
209 | | */ |
210 | | int getfriend_conn_id_pk(const Friend_Connections *fr_c, const uint8_t *real_pk) |
211 | 1.38k | { |
212 | 3.82k | for (uint32_t i = 0; i < fr_c->num_cons; ++i) { |
213 | 2.74k | const Friend_Conn *friend_con = get_conn(fr_c, i); |
214 | | |
215 | 2.74k | if (friend_con != nullptr) { |
216 | 2.70k | if (pk_equal(friend_con->real_public_key, real_pk)) { |
217 | 296 | return i; |
218 | 296 | } |
219 | 2.70k | } |
220 | 2.74k | } |
221 | | |
222 | 1.08k | return -1; |
223 | 1.38k | } |
224 | | |
225 | | /** @brief Add a TCP relay associated to the friend. |
226 | | * |
227 | | * @retval -1 on failure. |
228 | | * @retval 0 on success. |
229 | | */ |
230 | | static int friend_add_tcp_relay(Friend_Connections *_Nonnull fr_c, int friendcon_id, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key) |
231 | 85 | { |
232 | 85 | IP_Port ipp_copy = *ip_port; |
233 | | |
234 | 85 | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
235 | | |
236 | 85 | if (friend_con == nullptr) { |
237 | 0 | return -1; |
238 | 0 | } |
239 | | |
240 | | /* Local ip and same pk means that they are hosting a TCP relay. */ |
241 | 85 | if (ip_is_local(&ipp_copy.ip) && pk_equal(friend_con->dht_temp_pk, public_key)) { |
242 | 0 | if (!net_family_is_unspec(friend_con->dht_ip_port.ip.family)) { |
243 | 0 | ipp_copy.ip = friend_con->dht_ip_port.ip; |
244 | 0 | } else { |
245 | 0 | friend_con->hosting_tcp_relay = false; |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | 85 | const uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS; |
250 | | |
251 | 2.11k | for (unsigned i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) { |
252 | 2.03k | if (!net_family_is_unspec(friend_con->tcp_relays[i].ip_port.ip.family) |
253 | 2.03k | && pk_equal(friend_con->tcp_relays[i].public_key, public_key)) { |
254 | 0 | friend_con->tcp_relays[i] = empty_node_format; |
255 | 0 | } |
256 | 2.03k | } |
257 | | |
258 | 85 | friend_con->tcp_relays[index].ip_port = ipp_copy; |
259 | 85 | memcpy(friend_con->tcp_relays[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
260 | 85 | ++friend_con->tcp_relay_counter; |
261 | | |
262 | 85 | return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, &ipp_copy, public_key); |
263 | 85 | } |
264 | | |
265 | | /** Connect to number saved relays for friend. */ |
266 | | static void connect_to_saved_tcp_relays(Friend_Connections *_Nonnull fr_c, int friendcon_id, unsigned int number) |
267 | 531 | { |
268 | 531 | const Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
269 | | |
270 | 531 | if (friend_con == nullptr) { |
271 | 0 | return; |
272 | 0 | } |
273 | | |
274 | 13.2k | for (unsigned i = 0; (i < FRIEND_MAX_STORED_TCP_RELAYS) && (number != 0); ++i) { |
275 | 12.7k | const uint16_t index = (friend_con->tcp_relay_counter - (i + 1)) % FRIEND_MAX_STORED_TCP_RELAYS; |
276 | | |
277 | 12.7k | if (!net_family_is_unspec(friend_con->tcp_relays[index].ip_port.ip.family)) { |
278 | 0 | if (add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, &friend_con->tcp_relays[index].ip_port, |
279 | 0 | friend_con->tcp_relays[index].public_key) == 0) { |
280 | 0 | --number; |
281 | 0 | } |
282 | 0 | } |
283 | 12.7k | } |
284 | 531 | } |
285 | | |
286 | | static unsigned int send_relays(Friend_Connections *_Nonnull fr_c, int friendcon_id) |
287 | 51.8k | { |
288 | 51.8k | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
289 | | |
290 | 51.8k | if (friend_con == nullptr) { |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | 51.8k | Node_format nodes[MAX_SHARED_RELAYS] = {{{0}}}; |
295 | 51.8k | uint8_t data[1024]; |
296 | | |
297 | 51.8k | const uint32_t n = copy_connected_tcp_relays_index(fr_c->net_crypto, nodes, MAX_SHARED_RELAYS, |
298 | 51.8k | friend_con->tcp_relay_share_index); |
299 | | |
300 | 51.8k | friend_con->tcp_relay_share_index += MAX_SHARED_RELAYS; |
301 | | |
302 | 51.8k | for (uint32_t i = 0; i < n; ++i) { |
303 | | /* Associated the relays being sent with this connection. |
304 | | * On receiving the peer will do the same which will establish the connection. */ |
305 | 0 | friend_add_tcp_relay(fr_c, friendcon_id, &nodes[i].ip_port, nodes[i].public_key); |
306 | 0 | } |
307 | | |
308 | 51.8k | int length = pack_nodes(fr_c->logger, data + 1, sizeof(data) - 1, nodes, n); |
309 | | |
310 | 51.8k | if (length <= 0) { |
311 | 51.8k | return 0; |
312 | 51.8k | } |
313 | | |
314 | 2 | data[0] = PACKET_ID_SHARE_RELAYS; |
315 | 2 | ++length; |
316 | | |
317 | 2 | if (write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, data, length, false) != -1) { |
318 | 0 | friend_con->share_relays_lastsent = mono_time_get(fr_c->mono_time); |
319 | 0 | return 1; |
320 | 0 | } |
321 | | |
322 | 2 | return 0; |
323 | 2 | } |
324 | | |
325 | | /** callback for recv TCP relay nodes. */ |
326 | | static int tcp_relay_node_callback(void *_Nonnull object, uint32_t number, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key) |
327 | 187 | { |
328 | 187 | Friend_Connections *fr_c = (Friend_Connections *)object; |
329 | 187 | const Friend_Conn *friend_con = get_conn(fr_c, number); |
330 | | |
331 | 187 | if (friend_con == nullptr) { |
332 | 0 | return -1; |
333 | 0 | } |
334 | | |
335 | 187 | if (friend_con->crypt_connection_id != -1) { |
336 | 85 | return friend_add_tcp_relay(fr_c, number, ip_port, public_key); |
337 | 85 | } |
338 | | |
339 | 102 | return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); |
340 | 187 | } |
341 | | |
342 | | static int friend_new_connection(Friend_Connections *_Nonnull fr_c, int friendcon_id); |
343 | | |
344 | | /** Callback for DHT ip_port changes. */ |
345 | | static void dht_ip_callback(void *_Nonnull object, int32_t number, const IP_Port *_Nonnull ip_port) |
346 | 2.04k | { |
347 | 2.04k | Friend_Connections *const fr_c = (Friend_Connections *)object; |
348 | 2.04k | Friend_Conn *const friend_con = get_conn(fr_c, number); |
349 | | |
350 | 2.04k | if (friend_con == nullptr) { |
351 | 0 | return; |
352 | 0 | } |
353 | | |
354 | 2.04k | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, true); |
355 | 2.04k | friend_con->dht_ip_port = *ip_port; |
356 | 2.04k | friend_con->dht_ip_port_lastrecv = mono_time_get(fr_c->mono_time); |
357 | | |
358 | 2.04k | if (friend_con->hosting_tcp_relay) { |
359 | 0 | friend_add_tcp_relay(fr_c, number, ip_port, friend_con->dht_temp_pk); |
360 | 0 | friend_con->hosting_tcp_relay = false; |
361 | 0 | } |
362 | 2.04k | } |
363 | | |
364 | | static void change_dht_pk(Friend_Connections *_Nonnull fr_c, int friendcon_id, const uint8_t *_Nonnull dht_public_key) |
365 | 532 | { |
366 | 532 | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
367 | | |
368 | 532 | if (friend_con == nullptr) { |
369 | 0 | return; |
370 | 0 | } |
371 | | |
372 | 532 | friend_con->dht_pk_lastrecv = mono_time_get(fr_c->mono_time); |
373 | | |
374 | 532 | if (friend_con->dht_lock_token > 0) { |
375 | 3 | if (dht_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock_token) != 0) { |
376 | 0 | LOGGER_ERROR(fr_c->logger, "a. Could not delete dht peer. Please report this."); |
377 | 0 | return; |
378 | 0 | } |
379 | 3 | friend_con->dht_lock_token = 0; |
380 | 3 | } |
381 | | |
382 | 532 | dht_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, fr_c, friendcon_id, &friend_con->dht_lock_token); |
383 | 532 | memcpy(friend_con->dht_temp_pk, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
384 | 532 | } |
385 | | |
386 | | static int handle_status(void *_Nonnull object, int id, bool status, void *_Nullable userdata) |
387 | 538 | { |
388 | 538 | Friend_Connections *const fr_c = (Friend_Connections *)object; |
389 | 538 | Friend_Conn *const friend_con = get_conn(fr_c, id); |
390 | | |
391 | 538 | if (friend_con == nullptr) { |
392 | 0 | return -1; |
393 | 0 | } |
394 | | |
395 | 538 | bool status_changed = false; |
396 | | |
397 | 538 | if (status) { /* Went online. */ |
398 | 502 | status_changed = true; |
399 | 502 | friend_con->status = FRIENDCONN_STATUS_CONNECTED; |
400 | 502 | friend_con->ping_lastrecv = mono_time_get(fr_c->mono_time); |
401 | 502 | friend_con->share_relays_lastsent = 0; |
402 | 502 | onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); |
403 | 502 | } else { /* Went offline. */ |
404 | 36 | if (friend_con->status != FRIENDCONN_STATUS_CONNECTING) { |
405 | 16 | status_changed = true; |
406 | 16 | friend_con->dht_pk_lastrecv = mono_time_get(fr_c->mono_time); |
407 | 16 | onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); |
408 | 16 | } |
409 | | |
410 | 36 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; |
411 | 36 | friend_con->crypt_connection_id = -1; |
412 | 36 | friend_con->hosting_tcp_relay = false; |
413 | 36 | } |
414 | | |
415 | 538 | if (status_changed) { |
416 | 518 | if (fr_c->global_status_callback != nullptr) { |
417 | 516 | fr_c->global_status_callback(fr_c->global_status_callback_object, id, status, userdata); |
418 | 516 | } |
419 | | |
420 | 1.55k | for (unsigned i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { |
421 | 1.03k | if (friend_con->callbacks[i].status_callback != nullptr) { |
422 | 525 | friend_con->callbacks[i].status_callback( |
423 | 525 | friend_con->callbacks[i].callback_object, |
424 | 525 | friend_con->callbacks[i].callback_id, status, userdata); |
425 | 525 | } |
426 | 1.03k | } |
427 | 518 | } |
428 | | |
429 | 538 | return 0; |
430 | 538 | } |
431 | | |
432 | | /** Callback for dht public key changes. */ |
433 | | static void dht_pk_callback(void *_Nonnull object, int32_t number, const uint8_t *_Nonnull dht_public_key, void *_Nullable userdata) |
434 | 630 | { |
435 | 630 | Friend_Connections *const fr_c = (Friend_Connections *)object; |
436 | 630 | Friend_Conn *friend_con = get_conn(fr_c, number); |
437 | | |
438 | 630 | if (friend_con == nullptr) { |
439 | 0 | return; |
440 | 0 | } |
441 | | |
442 | 630 | if (pk_equal(friend_con->dht_temp_pk, dht_public_key)) { |
443 | 127 | return; |
444 | 127 | } |
445 | | |
446 | 503 | change_dht_pk(fr_c, number, dht_public_key); |
447 | | |
448 | | /* if pk changed, create a new connection.*/ |
449 | 503 | if (friend_con->crypt_connection_id != -1) { |
450 | 2 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); |
451 | 2 | friend_con->crypt_connection_id = -1; |
452 | 2 | handle_status(object, number, false, userdata); /* Going offline. */ |
453 | | |
454 | | /* Re-fetch before dereferencing friend_con again below, |
455 | | * since handle_status can realloc or free the conns array it points into. */ |
456 | 2 | friend_con = get_conn(fr_c, number); |
457 | | |
458 | 2 | if (friend_con == nullptr) { |
459 | 0 | return; |
460 | 0 | } |
461 | 2 | } |
462 | | |
463 | 503 | onion_set_friend_dht_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); |
464 | 503 | } |
465 | | |
466 | | static int handle_packet(void *_Nonnull object, int id, const uint8_t *_Nonnull data, uint16_t length, void *_Nonnull userdata) |
467 | 88.7k | { |
468 | 88.7k | Friend_Connections *const fr_c = (Friend_Connections *)object; |
469 | | |
470 | 88.7k | if (length == 0) { |
471 | 0 | return -1; |
472 | 0 | } |
473 | | |
474 | 88.7k | Friend_Conn *friend_con = get_conn(fr_c, id); |
475 | | |
476 | 88.7k | if (friend_con == nullptr) { |
477 | 0 | return -1; |
478 | 0 | } |
479 | | |
480 | 88.7k | if (data[0] == PACKET_ID_FRIEND_REQUESTS) { |
481 | 0 | if (fr_c->fr_request_callback != nullptr) { |
482 | 0 | fr_c->fr_request_callback(fr_c->fr_request_object, friend_con->real_public_key, data, length, userdata); |
483 | 0 | } |
484 | |
|
485 | 0 | return 0; |
486 | 0 | } |
487 | | |
488 | 88.7k | if (data[0] == PACKET_ID_ALIVE) { |
489 | 694 | friend_con->ping_lastrecv = mono_time_get(fr_c->mono_time); |
490 | 694 | return 0; |
491 | 694 | } |
492 | | |
493 | 88.0k | if (data[0] == PACKET_ID_SHARE_RELAYS) { |
494 | 0 | Node_format nodes[MAX_SHARED_RELAYS]; |
495 | 0 | const int n = unpack_nodes(nodes, MAX_SHARED_RELAYS, nullptr, data + 1, length - 1, true); |
496 | |
|
497 | 0 | if (n == -1) { |
498 | 0 | return -1; |
499 | 0 | } |
500 | | |
501 | 0 | for (int j = 0; j < n; ++j) { |
502 | 0 | friend_add_tcp_relay(fr_c, id, &nodes[j].ip_port, nodes[j].public_key); |
503 | 0 | } |
504 | |
|
505 | 0 | return 0; |
506 | 0 | } |
507 | | |
508 | 264k | for (unsigned i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { |
509 | 176k | if (friend_con->callbacks[i].data_callback != nullptr) { |
510 | 88.9k | friend_con->callbacks[i].data_callback( |
511 | 88.9k | friend_con->callbacks[i].callback_object, |
512 | 88.9k | friend_con->callbacks[i].callback_id, data, length, userdata); |
513 | 88.9k | } |
514 | | |
515 | 176k | friend_con = get_conn(fr_c, id); |
516 | | |
517 | 176k | if (friend_con == nullptr) { |
518 | 0 | return -1; |
519 | 0 | } |
520 | 176k | } |
521 | | |
522 | 88.0k | return 0; |
523 | 88.0k | } |
524 | | |
525 | | static int handle_lossy_packet(void *_Nonnull object, int id, const uint8_t *_Nonnull data, uint16_t length, void *_Nonnull userdata) |
526 | 1.02k | { |
527 | 1.02k | const Friend_Connections *const fr_c = (const Friend_Connections *)object; |
528 | | |
529 | 1.02k | if (length == 0) { |
530 | 0 | return -1; |
531 | 0 | } |
532 | | |
533 | 1.02k | const Friend_Conn *friend_con = get_conn(fr_c, id); |
534 | | |
535 | 1.02k | if (friend_con == nullptr) { |
536 | 0 | return -1; |
537 | 0 | } |
538 | | |
539 | 3.08k | for (unsigned i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { |
540 | 2.05k | if (friend_con->callbacks[i].lossy_data_callback != nullptr) { |
541 | 1.53k | friend_con->callbacks[i].lossy_data_callback( |
542 | 1.53k | friend_con->callbacks[i].callback_object, |
543 | 1.53k | friend_con->callbacks[i].callback_id, data, length, userdata); |
544 | 1.53k | } |
545 | | |
546 | 2.05k | friend_con = get_conn(fr_c, id); |
547 | | |
548 | 2.05k | if (friend_con == nullptr) { |
549 | 0 | return -1; |
550 | 0 | } |
551 | 2.05k | } |
552 | | |
553 | 1.02k | return 0; |
554 | 1.02k | } |
555 | | |
556 | | static int handle_new_connections(void *_Nonnull object, const New_Connection *_Nonnull n_c) |
557 | 45 | { |
558 | 45 | Friend_Connections *const fr_c = (Friend_Connections *)object; |
559 | 45 | const int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); |
560 | 45 | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
561 | | |
562 | 45 | if (friend_con == nullptr) { |
563 | 11 | return -1; |
564 | 11 | } |
565 | | |
566 | 34 | if (friend_con->crypt_connection_id != -1) { |
567 | 0 | return -1; |
568 | 0 | } |
569 | | |
570 | 34 | const int id = accept_crypto_connection(fr_c->net_crypto, n_c); |
571 | | |
572 | 34 | if (id == -1) { |
573 | 0 | return -1; |
574 | 0 | } |
575 | | |
576 | 34 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); |
577 | 34 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); |
578 | 34 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); |
579 | 34 | friend_con->crypt_connection_id = id; |
580 | | |
581 | 34 | if (!net_family_is_ipv4(n_c->source.ip.family) && !net_family_is_ipv6(n_c->source.ip.family)) { |
582 | 0 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, &friend_con->dht_ip_port, false); |
583 | 34 | } else { |
584 | 34 | friend_con->dht_ip_port = n_c->source; |
585 | 34 | friend_con->dht_ip_port_lastrecv = mono_time_get(fr_c->mono_time); |
586 | 34 | } |
587 | | |
588 | 34 | if (!pk_equal(friend_con->dht_temp_pk, n_c->dht_public_key)) { |
589 | 29 | change_dht_pk(fr_c, friendcon_id, n_c->dht_public_key); |
590 | 29 | } |
591 | | |
592 | 34 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); |
593 | 34 | return 0; |
594 | 34 | } |
595 | | |
596 | | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) |
597 | 70.5k | { |
598 | 70.5k | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
599 | | |
600 | 70.5k | if (friend_con == nullptr) { |
601 | 0 | return -1; |
602 | 0 | } |
603 | | |
604 | 70.5k | if (friend_con->crypt_connection_id != -1) { |
605 | 70.0k | return -1; |
606 | 70.0k | } |
607 | | |
608 | | /* If dht_temp_pk does not contains a pk. */ |
609 | 543 | if (friend_con->dht_lock_token == 0) { |
610 | 0 | return -1; |
611 | 0 | } |
612 | | |
613 | 543 | const int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key, friend_con->dht_temp_pk); |
614 | | |
615 | 543 | if (id == -1) { |
616 | 0 | return -1; |
617 | 0 | } |
618 | | |
619 | 543 | friend_con->crypt_connection_id = id; |
620 | 543 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); |
621 | 543 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); |
622 | 543 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); |
623 | 543 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); |
624 | | |
625 | 543 | return 0; |
626 | 543 | } |
627 | | |
628 | | static int send_ping(const Friend_Connections *_Nonnull fr_c, int friendcon_id) |
629 | 712 | { |
630 | 712 | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
631 | | |
632 | 712 | if (friend_con == nullptr) { |
633 | 0 | return -1; |
634 | 0 | } |
635 | | |
636 | 712 | const uint8_t ping = PACKET_ID_ALIVE; |
637 | 712 | const int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), false); |
638 | | |
639 | 712 | if (ret != -1) { |
640 | 712 | friend_con->ping_lastsent = mono_time_get(fr_c->mono_time); |
641 | 712 | return 0; |
642 | 712 | } |
643 | | |
644 | 0 | return -1; |
645 | 712 | } |
646 | | |
647 | | /** @brief Increases lock_count for the connection with friendcon_id by 1. |
648 | | * |
649 | | * @retval 0 on success. |
650 | | * @retval -1 on failure. |
651 | | */ |
652 | | int friend_connection_lock(const Friend_Connections *fr_c, int friendcon_id) |
653 | 63 | { |
654 | 63 | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
655 | | |
656 | 63 | if (friend_con == nullptr) { |
657 | 0 | return -1; |
658 | 0 | } |
659 | | |
660 | 63 | ++friend_con->lock_count; |
661 | 63 | return 0; |
662 | 63 | } |
663 | | |
664 | | /** |
665 | | * @retval FRIENDCONN_STATUS_CONNECTED if the friend is connected. |
666 | | * @retval FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. |
667 | | * @retval FRIENDCONN_STATUS_NONE on failure. |
668 | | */ |
669 | | unsigned int friend_con_connected(const Friend_Connections *fr_c, int friendcon_id) |
670 | 1.45k | { |
671 | 1.45k | const Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
672 | | |
673 | 1.45k | if (friend_con == nullptr) { |
674 | 5 | return 0; |
675 | 5 | } |
676 | | |
677 | 1.44k | return friend_con->status; |
678 | 1.45k | } |
679 | | |
680 | | /** @brief Copy public keys associated to friendcon_id. |
681 | | * |
682 | | * @retval 0 on success. |
683 | | * @retval -1 on failure. |
684 | | */ |
685 | | int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, const Friend_Connections *fr_c, int friendcon_id) |
686 | 2.77k | { |
687 | 2.77k | const Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
688 | | |
689 | 2.77k | if (friend_con == nullptr) { |
690 | 0 | return -1; |
691 | 0 | } |
692 | | |
693 | 2.77k | if (real_pk != nullptr) { |
694 | 2.77k | memcpy(real_pk, friend_con->real_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
695 | 2.77k | } |
696 | | |
697 | 2.77k | if (dht_temp_pk != nullptr) { |
698 | 32 | memcpy(dht_temp_pk, friend_con->dht_temp_pk, CRYPTO_PUBLIC_KEY_SIZE); |
699 | 32 | } |
700 | | |
701 | 2.77k | return 0; |
702 | 2.77k | } |
703 | | |
704 | | /** Set temp dht key for connection. */ |
705 | | void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata) |
706 | 104 | { |
707 | 104 | dht_pk_callback(fr_c, friendcon_id, dht_temp_pk, userdata); |
708 | 104 | } |
709 | | |
710 | | /** @brief Set the callbacks for the friend connection. |
711 | | * @param index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we |
712 | | * want the callback to set in the array. |
713 | | * |
714 | | * @retval 0 on success. |
715 | | * @retval -1 on failure |
716 | | */ |
717 | | int friend_connection_callbacks(const Friend_Connections *fr_c, int friendcon_id, unsigned int index, |
718 | | fc_status_cb *status_callback, |
719 | | fc_data_cb *data_callback, |
720 | | fc_lossy_data_cb *lossy_data_callback, |
721 | | void *object, int number) |
722 | 1.04k | { |
723 | 1.04k | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
724 | | |
725 | 1.04k | if (friend_con == nullptr) { |
726 | 5 | return -1; |
727 | 5 | } |
728 | | |
729 | 1.03k | if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) { |
730 | 0 | return -1; |
731 | 0 | } |
732 | | |
733 | 1.03k | if (object != nullptr && (status_callback == nullptr || data_callback == nullptr || lossy_data_callback == nullptr)) { |
734 | 0 | LOGGER_ERROR(fr_c->logger, "non-null user data object but null callbacks"); |
735 | 0 | return -1; |
736 | 0 | } |
737 | | |
738 | 1.03k | friend_con->callbacks[index].status_callback = status_callback; |
739 | 1.03k | friend_con->callbacks[index].data_callback = data_callback; |
740 | 1.03k | friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; |
741 | | |
742 | 1.03k | friend_con->callbacks[index].callback_object = object; |
743 | 1.03k | friend_con->callbacks[index].callback_id = number; |
744 | | |
745 | 1.03k | return 0; |
746 | 1.03k | } |
747 | | |
748 | | /** Set global status callback for friend connections. */ |
749 | | void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object) |
750 | 3.58k | { |
751 | 3.58k | if (object != nullptr && global_status_callback == nullptr) { |
752 | 0 | LOGGER_ERROR(fr_c->logger, "non-null user data object but null callback"); |
753 | 0 | object = nullptr; |
754 | 0 | } |
755 | | |
756 | 3.58k | fr_c->global_status_callback = global_status_callback; |
757 | 3.58k | fr_c->global_status_callback_object = object; |
758 | 3.58k | } |
759 | | |
760 | | /** @brief return the crypt_connection_id for the connection. |
761 | | * |
762 | | * @return crypt_connection_id on success. |
763 | | * @retval -1 on failure. |
764 | | */ |
765 | | int friend_connection_crypt_connection_id(const Friend_Connections *fr_c, int friendcon_id) |
766 | 266k | { |
767 | 266k | const Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
768 | | |
769 | 266k | if (friend_con == nullptr) { |
770 | 0 | return -1; |
771 | 0 | } |
772 | | |
773 | 266k | return friend_con->crypt_connection_id; |
774 | 266k | } |
775 | | |
776 | | /** @brief Create a new friend connection. |
777 | | * If one to that real public key already exists, increase lock count and return it. |
778 | | * |
779 | | * @retval -1 on failure. |
780 | | * @return connection id on success. |
781 | | */ |
782 | | int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) |
783 | 973 | { |
784 | 973 | int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); |
785 | | |
786 | 973 | if (friendcon_id != -1) { |
787 | 0 | ++fr_c->conns[friendcon_id].lock_count; |
788 | 0 | return friendcon_id; |
789 | 0 | } |
790 | | |
791 | 973 | friendcon_id = create_friend_conn(fr_c); |
792 | | |
793 | 973 | if (friendcon_id == -1) { |
794 | 0 | return -1; |
795 | 0 | } |
796 | | |
797 | 973 | const int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); |
798 | | |
799 | 973 | if (onion_friendnum == -1) { |
800 | 0 | return -1; |
801 | 0 | } |
802 | | |
803 | 973 | Friend_Conn *const friend_con = &fr_c->conns[friendcon_id]; |
804 | | |
805 | 973 | friend_con->crypt_connection_id = -1; |
806 | 973 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; |
807 | 973 | memcpy(friend_con->real_public_key, real_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
808 | 973 | friend_con->onion_friendnum = onion_friendnum; |
809 | | |
810 | 973 | recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); |
811 | 973 | onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); |
812 | | |
813 | 973 | return friendcon_id; |
814 | 973 | } |
815 | | |
816 | | /** @brief Kill a friend connection. |
817 | | * |
818 | | * @retval -1 on failure. |
819 | | * @retval 0 on success. |
820 | | */ |
821 | | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) |
822 | 1.05k | { |
823 | 1.05k | Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
824 | | |
825 | 1.05k | if (friend_con == nullptr) { |
826 | 23 | return -1; |
827 | 23 | } |
828 | | |
829 | 1.03k | if (friend_con->lock_count > 0) { |
830 | 63 | --friend_con->lock_count; |
831 | 63 | return 0; |
832 | 63 | } |
833 | | |
834 | 973 | onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); |
835 | 973 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); |
836 | | |
837 | 973 | if (friend_con->dht_lock_token > 0) { |
838 | 529 | dht_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock_token); |
839 | 529 | friend_con->dht_lock_token = 0; |
840 | 529 | } |
841 | | |
842 | 973 | return wipe_friend_conn(fr_c, friendcon_id); |
843 | 1.03k | } |
844 | | |
845 | | /** @brief Set friend request callback. |
846 | | * |
847 | | * This function will be called every time a friend request packet is received. |
848 | | */ |
849 | | void set_friend_request_callback(Friend_Connections *fr_c, fr_request_cb *fr_request_callback, void *object) |
850 | 1.79k | { |
851 | 1.79k | fr_c->fr_request_callback = fr_request_callback; |
852 | 1.79k | fr_c->fr_request_object = object; |
853 | 1.79k | oniondata_registerhandler(fr_c->onion_c, CRYPTO_PACKET_FRIEND_REQ, fr_request_callback, object); |
854 | 1.79k | } |
855 | | |
856 | | /** @brief Send a Friend request packet. |
857 | | * |
858 | | * @retval -1 if failure. |
859 | | * @retval 0 if it sent the friend request directly to the friend. |
860 | | * @return the number of peers it was routed through if it did not send it directly. |
861 | | */ |
862 | | int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, |
863 | | uint16_t length) |
864 | 16.7k | { |
865 | | // TODO(Jfreegman): This max packet size is too large to be handled by receiving clients |
866 | | // when sent via the onion. We currently limit the length at a higher level, but |
867 | | // this bounds check should be fixed to represent the max size of a packet that |
868 | | // the onion client can handle. |
869 | 16.7k | if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) { |
870 | 0 | return -1; |
871 | 0 | } |
872 | | |
873 | 16.7k | const Friend_Conn *const friend_con = get_conn(fr_c, friendcon_id); |
874 | | |
875 | 16.7k | if (friend_con == nullptr) { |
876 | 0 | return -1; |
877 | 0 | } |
878 | | |
879 | 16.7k | const uint16_t packet_size = 1 + sizeof(nospam_num) + length; |
880 | 16.7k | VLA(uint8_t, packet, packet_size); |
881 | 16.7k | memcpy(packet + 1, &nospam_num, sizeof(nospam_num)); |
882 | 16.7k | memcpy(packet + 1 + sizeof(nospam_num), data, length); |
883 | | |
884 | 16.7k | if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { |
885 | 0 | packet[0] = PACKET_ID_FRIEND_REQUESTS; |
886 | 0 | return write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, packet, packet_size, |
887 | 0 | false) != -1 ? 1 : 0; |
888 | 0 | } |
889 | | |
890 | 16.7k | packet[0] = CRYPTO_PACKET_FRIEND_REQ; |
891 | 16.7k | const int num = send_onion_data(fr_c->onion_c, friend_con->onion_friendnum, packet, packet_size); |
892 | | |
893 | 16.7k | if (num <= 0) { |
894 | 16.4k | return -1; |
895 | 16.4k | } |
896 | | |
897 | 238 | return num; |
898 | 16.7k | } |
899 | | |
900 | | /** Create new friend_connections instance. */ |
901 | | Friend_Connections *new_friend_connections( |
902 | | const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Network *ns, |
903 | | Onion_Client *onion_c, DHT *dht, Net_Crypto *net_crypto, Networking_Core *net, |
904 | | bool local_discovery_enabled) |
905 | 1.84k | { |
906 | 1.84k | if (onion_c == nullptr) { |
907 | 0 | return nullptr; |
908 | 0 | } |
909 | | |
910 | 1.84k | Friend_Connections *const temp = (Friend_Connections *)mem_alloc(mem, sizeof(Friend_Connections)); |
911 | | |
912 | 1.84k | if (temp == nullptr) { |
913 | 2 | return nullptr; |
914 | 2 | } |
915 | | |
916 | 1.83k | temp->local_discovery_enabled = local_discovery_enabled; |
917 | | |
918 | 1.83k | if (temp->local_discovery_enabled) { |
919 | 1.48k | temp->broadcast = lan_discovery_init(mem, ns); |
920 | | |
921 | 1.48k | if (temp->broadcast == nullptr) { |
922 | 44 | LOGGER_ERROR(logger, "could not initialise LAN discovery"); |
923 | 44 | temp->local_discovery_enabled = false; |
924 | 44 | } |
925 | 1.48k | } |
926 | | |
927 | 1.83k | temp->mono_time = mono_time; |
928 | 1.83k | temp->mem = mem; |
929 | 1.83k | temp->logger = logger; |
930 | 1.83k | temp->dht = dht; |
931 | 1.83k | temp->net = net; |
932 | 1.83k | temp->net_crypto = net_crypto; |
933 | 1.83k | temp->onion_c = onion_c; |
934 | | // Don't include default port in port range |
935 | 1.83k | temp->next_lan_port = TOX_PORTRANGE_FROM + 1; |
936 | | |
937 | 1.83k | new_connection_handler(temp->net_crypto, &handle_new_connections, temp); |
938 | | |
939 | 1.83k | return temp; |
940 | 1.84k | } |
941 | | |
942 | | /** Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ |
943 | | static void lan_discovery(Friend_Connections *_Nonnull fr_c) |
944 | 2.23k | { |
945 | 2.23k | if (fr_c->last_lan_discovery + LAN_DISCOVERY_INTERVAL < mono_time_get(fr_c->mono_time)) { |
946 | 18 | if (fr_c->broadcast == nullptr) { |
947 | 0 | return; |
948 | 0 | } |
949 | 18 | const uint16_t first = fr_c->next_lan_port; |
950 | 18 | uint16_t last = first + PORTS_PER_DISCOVERY; |
951 | 18 | last = last > TOX_PORTRANGE_TO ? TOX_PORTRANGE_TO : last; |
952 | | |
953 | | // Always send to default port |
954 | 18 | lan_discovery_send(fr_c->net, fr_c->broadcast, dht_get_self_public_key(fr_c->dht), |
955 | 18 | net_htons(TOX_PORT_DEFAULT)); |
956 | | |
957 | | // And check some extra ports |
958 | 198 | for (uint16_t port = first; port < last; ++port) { |
959 | 180 | lan_discovery_send(fr_c->net, fr_c->broadcast, dht_get_self_public_key(fr_c->dht), net_htons(port)); |
960 | 180 | } |
961 | | |
962 | | // Don't include default port in port range |
963 | 18 | fr_c->next_lan_port = last != TOX_PORTRANGE_TO ? last : TOX_PORTRANGE_FROM + 1; |
964 | 18 | fr_c->last_lan_discovery = mono_time_get(fr_c->mono_time); |
965 | 18 | } |
966 | 2.23k | } |
967 | | |
968 | | /** main friend_connections loop. */ |
969 | | void do_friend_connections(Friend_Connections *fr_c, void *userdata) |
970 | 124k | { |
971 | 124k | const uint64_t temp_time = mono_time_get(fr_c->mono_time); |
972 | | |
973 | 309k | for (uint32_t i = 0; i < fr_c->num_cons; ++i) { |
974 | 184k | Friend_Conn *const friend_con = get_conn(fr_c, i); |
975 | | |
976 | 184k | if (friend_con != nullptr) { |
977 | 184k | if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { |
978 | 132k | if (friend_con->dht_pk_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { |
979 | 62.2k | if (friend_con->dht_lock_token > 0) { |
980 | 0 | dht_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock_token); |
981 | 0 | friend_con->dht_lock_token = 0; |
982 | 0 | memzero(friend_con->dht_temp_pk, CRYPTO_PUBLIC_KEY_SIZE); |
983 | 0 | } |
984 | 62.2k | } |
985 | | |
986 | 132k | if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { |
987 | 128k | friend_con->dht_ip_port.ip.family = net_family_unspec(); |
988 | 128k | } |
989 | | |
990 | 132k | if (friend_con->dht_lock_token > 0) { |
991 | 70.5k | if (friend_new_connection(fr_c, i) == 0) { |
992 | 531 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, &friend_con->dht_ip_port, false); |
993 | 531 | connect_to_saved_tcp_relays(fr_c, i, MAX_FRIEND_TCP_CONNECTIONS / 2); /* Only fill it half up. */ |
994 | 531 | } |
995 | 70.5k | } |
996 | 132k | } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { |
997 | 51.8k | if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { |
998 | 712 | send_ping(fr_c, i); |
999 | 712 | } |
1000 | | |
1001 | 51.8k | if (friend_con->share_relays_lastsent + SHARE_RELAYS_INTERVAL < temp_time) { |
1002 | 51.8k | send_relays(fr_c, i); |
1003 | 51.8k | } |
1004 | | |
1005 | 51.8k | if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { |
1006 | | /* If we stopped receiving ping packets, kill it. */ |
1007 | 8 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); |
1008 | 8 | friend_con->crypt_connection_id = -1; |
1009 | 8 | handle_status(fr_c, i, false, userdata); /* Going offline. */ |
1010 | 8 | } |
1011 | 51.8k | } |
1012 | 184k | } |
1013 | 184k | } |
1014 | | |
1015 | 124k | if (fr_c->local_discovery_enabled) { |
1016 | 2.23k | lan_discovery(fr_c); |
1017 | 2.23k | } |
1018 | 124k | } |
1019 | | |
1020 | | /** Free everything related with friend_connections. */ |
1021 | | void kill_friend_connections(Friend_Connections *fr_c) |
1022 | 1.84k | { |
1023 | 1.84k | if (fr_c == nullptr) { |
1024 | 8 | return; |
1025 | 8 | } |
1026 | | |
1027 | 2.60k | for (uint32_t i = 0; i < fr_c->num_cons; ++i) { |
1028 | 767 | kill_friend_connection(fr_c, i); |
1029 | 767 | } |
1030 | | |
1031 | | // there might be allocated NONE connections |
1032 | 1.83k | if (fr_c->conns != nullptr) { |
1033 | 0 | mem_delete(fr_c->mem, fr_c->conns); |
1034 | 0 | } |
1035 | | |
1036 | 1.83k | lan_discovery_kill(fr_c->broadcast); |
1037 | 1.83k | mem_delete(fr_c->mem, fr_c); |
1038 | 1.83k | } |