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