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