Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/TCP_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 © 2015 Tox project.
4
 */
5
6
/**
7
 * Handles TCP relay connections between two Tox clients.
8
 */
9
#include "TCP_connection.h"
10
11
#include <assert.h>
12
#include <string.h>
13
14
#include "DHT.h"
15
#include "TCP_client.h"
16
#include "attributes.h"
17
#include "ccompat.h"
18
#include "crypto_core.h"
19
#include "forwarding.h"
20
#include "logger.h"
21
#include "mem.h"
22
#include "mono_time.h"
23
#include "net_profile.h"
24
#include "network.h"
25
#include "util.h"
26
27
struct TCP_Connections {
28
    const Logger *_Nonnull logger;
29
    const Memory *_Nonnull mem;
30
    const Random *_Nonnull rng;
31
    Mono_Time *_Nonnull mono_time;
32
    const Network *_Nonnull ns;
33
    DHT *_Nonnull dht;
34
35
    uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
36
    uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
37
38
    TCP_Connection_to *_Nullable connections;
39
    uint32_t connections_length; /* Length of connections array. */
40
41
    TCP_con *_Nullable tcp_connections;
42
    uint32_t tcp_connections_length; /* Length of tcp_connections array. */
43
44
    tcp_data_cb *_Nullable tcp_data_callback;
45
    void *_Nullable tcp_data_callback_object;
46
47
    tcp_oob_cb *_Nullable tcp_oob_callback;
48
    void *_Nullable tcp_oob_callback_object;
49
50
    tcp_onion_cb *_Nullable tcp_onion_callback;
51
    void *_Nullable tcp_onion_callback_object;
52
53
    forwarded_response_cb *_Nullable tcp_forwarded_response_callback;
54
    void *_Nullable tcp_forwarded_response_callback_object;
55
56
    TCP_Proxy_Info proxy_info;
57
58
    bool onion_status;
59
    uint16_t onion_num_conns;
60
61
    /* Network profile for all TCP client packets. */
62
    Net_Profile *_Nullable net_profile;
63
};
64
65
static const TCP_Connection_to empty_tcp_connection_to = {0};
66
static const TCP_con empty_tcp_con = {0};
67
68
const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c)
69
8
{
70
8
    return tcp_c->self_public_key;
71
8
}
72
73
uint32_t tcp_connections_count(const TCP_Connections *tcp_c)
74
11.8k
{
75
11.8k
    return tcp_c->tcp_connections_length;
76
11.8k
}
77
78
/** @brief Set the size of the array to num.
79
 *
80
 * @retval -1 if mem_vrealloc fails.
81
 * @retval 0 if it succeeds.
82
 */
83
static int realloc_tcp_connection_to(const Memory *_Nonnull mem, TCP_Connection_to *_Nullable *array, size_t num)
84
1.13k
{
85
1.13k
    if (num == 0) {
86
288
        mem_delete(mem, *array);
87
288
        *array = nullptr;
88
288
        return 0;
89
288
    }
90
91
843
    TCP_Connection_to *temp_pointer =
92
843
        (TCP_Connection_to *)mem_vrealloc(mem, *array, num, sizeof(TCP_Connection_to));
93
94
843
    if (temp_pointer == nullptr) {
95
0
        return -1;
96
0
    }
97
98
843
    *array = temp_pointer;
99
100
843
    return 0;
101
843
}
102
103
static int realloc_tcp_con(const Memory *_Nonnull mem, TCP_con *_Nullable *array, size_t num)
104
97
{
105
97
    if (num == 0) {
106
2
        mem_delete(mem, *array);
107
2
        *array = nullptr;
108
2
        return 0;
109
2
    }
110
111
95
    TCP_con *temp_pointer = (TCP_con *)mem_vrealloc(mem, *array, num, sizeof(TCP_con));
112
113
95
    if (temp_pointer == nullptr) {
114
1
        return -1;
115
1
    }
116
117
94
    *array = temp_pointer;
118
119
94
    return 0;
120
95
}
121
122
/**
123
 * Return true if the connections_number is valid.
124
 */
125
static bool connections_number_is_valid(const TCP_Connections *_Nonnull tcp_c, int connections_number)
126
212k
{
127
212k
    if ((unsigned int)connections_number >= tcp_c->connections_length) {
128
104
        return false;
129
104
    }
130
131
212k
    if (tcp_c->connections == nullptr) {
132
0
        return false;
133
0
    }
134
135
212k
    return tcp_c->connections[connections_number].status != TCP_CONN_NONE;
136
212k
}
137
138
/**
139
 * Return true if the tcp_connections_number is valid.
140
 */
141
static bool tcp_connections_number_is_valid(const TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
142
91.4k
{
143
91.4k
    if ((uint32_t)tcp_connections_number >= tcp_c->tcp_connections_length) {
144
1
        return false;
145
1
    }
146
147
91.4k
    if (tcp_c->tcp_connections == nullptr) {
148
0
        return false;
149
0
    }
150
151
91.4k
    return tcp_c->tcp_connections[tcp_connections_number].status != TCP_CONN_NONE;
152
91.4k
}
153
154
/** @brief Create a new empty connection.
155
 *
156
 * return -1 on failure.
157
 * return connections_number on success.
158
 */
159
static int create_connection(TCP_Connections *_Nonnull tcp_c)
160
747
{
161
2.06k
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
162
1.35k
        if (tcp_c->connections[i].status == TCP_CONN_NONE) {
163
44
            return i;
164
44
        }
165
1.35k
    }
166
167
703
    int id = -1;
168
169
703
    if (realloc_tcp_connection_to(tcp_c->mem, &tcp_c->connections, tcp_c->connections_length + 1) == 0) {
170
703
        id = tcp_c->connections_length;
171
703
        ++tcp_c->connections_length;
172
703
        tcp_c->connections[id] = empty_tcp_connection_to;
173
703
    }
174
175
703
    return id;
176
747
}
177
178
/** @brief Create a new empty tcp connection.
179
 *
180
 * return -1 on failure.
181
 * return tcp_connections_number on success.
182
 */
183
static int create_tcp_connection(TCP_Connections *_Nonnull tcp_c)
184
95
{
185
125
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
186
30
        if (tcp_c->tcp_connections[i].status == TCP_CONN_NONE) {
187
0
            return i;
188
0
        }
189
30
    }
190
191
95
    int id = -1;
192
193
95
    if (realloc_tcp_con(tcp_c->mem, &tcp_c->tcp_connections, tcp_c->tcp_connections_length + 1) == 0) {
194
94
        id = tcp_c->tcp_connections_length;
195
94
        ++tcp_c->tcp_connections_length;
196
94
        tcp_c->tcp_connections[id] = empty_tcp_con;
197
94
    }
198
199
95
    return id;
200
95
}
201
202
/** @brief Wipe a connection.
203
 *
204
 * return -1 on failure.
205
 * return 0 on success.
206
 */
207
static int wipe_connection(TCP_Connections *_Nonnull tcp_c, int connections_number)
208
654
{
209
654
    if (!connections_number_is_valid(tcp_c, connections_number)) {
210
0
        return -1;
211
0
    }
212
213
654
    uint32_t i;
214
654
    tcp_c->connections[connections_number] = empty_tcp_connection_to;
215
216
1.25k
    for (i = tcp_c->connections_length; i != 0; --i) {
217
970
        if (tcp_c->connections[i - 1].status != TCP_CONN_NONE) {
218
366
            break;
219
366
        }
220
970
    }
221
222
654
    if (tcp_c->connections_length != i) {
223
428
        tcp_c->connections_length = i;
224
428
        if (realloc_tcp_connection_to(tcp_c->mem, &tcp_c->connections, tcp_c->connections_length) != 0) {
225
0
            return -1;
226
0
        }
227
428
    }
228
229
654
    return 0;
230
654
}
231
232
/** @brief Wipe a connection.
233
 *
234
 * return -1 on failure.
235
 * return 0 on success.
236
 */
237
static int wipe_tcp_connection(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
238
12
{
239
12
    if (!tcp_connections_number_is_valid(tcp_c, tcp_connections_number)) {
240
0
        return -1;
241
0
    }
242
243
12
    tcp_c->tcp_connections[tcp_connections_number] = empty_tcp_con;
244
245
12
    uint32_t i;
246
247
24
    for (i = tcp_c->tcp_connections_length; i != 0; --i) {
248
22
        if (tcp_c->tcp_connections[i - 1].status != TCP_CONN_NONE) {
249
10
            break;
250
10
        }
251
22
    }
252
253
12
    if (tcp_c->tcp_connections_length != i) {
254
2
        tcp_c->tcp_connections_length = i;
255
2
        if (realloc_tcp_con(tcp_c->mem, &tcp_c->tcp_connections, tcp_c->tcp_connections_length) != 0) {
256
0
            return -1;
257
0
        }
258
2
    }
259
260
12
    return 0;
261
12
}
262
263
static TCP_Connection_to *_Nullable get_connection(const TCP_Connections *_Nonnull tcp_c, int connections_number)
264
211k
{
265
211k
    if (!connections_number_is_valid(tcp_c, connections_number)) {
266
203
        return nullptr;
267
203
    }
268
269
211k
    return &tcp_c->connections[connections_number];
270
211k
}
271
272
static TCP_con *_Nullable get_tcp_connection(const TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
273
91.4k
{
274
91.4k
    if (!tcp_connections_number_is_valid(tcp_c, tcp_connections_number)) {
275
4
        return nullptr;
276
4
    }
277
278
91.3k
    return &tcp_c->tcp_connections[tcp_connections_number];
279
91.4k
}
280
281
uint32_t tcp_connected_relays_count(const TCP_Connections *tcp_c)
282
11.6k
{
283
11.6k
    uint32_t count = 0;
284
11.6k
    const uint32_t size = tcp_connections_count(tcp_c);
285
286
13.5k
    for (uint32_t i = 0; i < size; ++i) {
287
1.88k
        const TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
288
289
1.88k
        if (tcp_con == nullptr) {
290
0
            continue;
291
0
        }
292
293
1.88k
        if (tcp_con->status == TCP_CONN_CONNECTED) {
294
1.30k
            ++count;
295
1.30k
        }
296
1.88k
    }
297
298
11.6k
    return count;
299
11.6k
}
300
301
/** @brief Send a packet to the TCP connection.
302
 *
303
 * return -1 on failure.
304
 * return 0 on success.
305
 */
306
int send_packet_tcp_connection(const TCP_Connections *tcp_c, int connections_number, const uint8_t *packet,
307
                               uint16_t length)
308
73.6k
{
309
73.6k
    const TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
310
311
73.6k
    if (con_to == nullptr) {
312
1
        return -1;
313
1
    }
314
315
    // TODO(irungentoo): detect and kill bad relays.
316
    // TODO(irungentoo): thread safety?
317
73.6k
    int ret = -1;
318
319
73.6k
    bool limit_reached = false;
320
321
507k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
322
434k
        uint32_t tcp_con_num = con_to->connections[i].tcp_connection;
323
434k
        const uint8_t status = con_to->connections[i].status;
324
434k
        const uint8_t connection_id = con_to->connections[i].connection_id;
325
326
434k
        if (tcp_con_num > 0 && status == TCP_CONNECTIONS_STATUS_ONLINE) {
327
1.33k
            tcp_con_num -= 1;
328
1.33k
            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num);
329
330
1.33k
            if (tcp_con == nullptr) {
331
0
                continue;
332
0
            }
333
334
1.33k
            if (tcp_con->connection == nullptr) {
335
0
                LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_con_num);
336
0
                continue;
337
0
            }
338
1.33k
            ret = send_data(tcp_c->logger, tcp_con->connection, connection_id, packet, length);
339
340
1.33k
            if (ret == 0) {
341
0
                limit_reached = true;
342
0
            }
343
344
1.33k
            if (ret == 1) {
345
1.33k
                break;
346
1.33k
            }
347
1.33k
        }
348
434k
    }
349
350
73.6k
    if (ret == 1) {
351
1.33k
        return 0;
352
1.33k
    }
353
354
72.3k
    if (limit_reached) {
355
0
        return -1;
356
0
    }
357
358
72.3k
    bool sent_any = false;
359
360
    /* Send oob packets to all relays tied to the connection. */
361
505k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
362
433k
        uint32_t tcp_con_num = con_to->connections[i].tcp_connection;
363
433k
        const uint8_t status = con_to->connections[i].status;
364
365
433k
        if (tcp_con_num > 0 && status == TCP_CONNECTIONS_STATUS_REGISTERED) {
366
149
            tcp_con_num -= 1;
367
149
            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num);
368
369
149
            if (tcp_con == nullptr) {
370
0
                continue;
371
0
            }
372
373
149
            if (tcp_con->connection == nullptr) {
374
0
                LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_con_num);
375
0
                continue;
376
0
            }
377
149
            if (send_oob_packet(tcp_c->logger, tcp_con->connection, con_to->public_key, packet, length) == 1) {
378
149
                sent_any = true;
379
149
            }
380
149
        }
381
433k
    }
382
383
72.3k
    return sent_any ? 0 : -1;
384
72.3k
}
385
386
/** @brief Return a TCP connection number for use in send_tcp_onion_request.
387
 *
388
 * TODO(irungentoo): This number is just the index of an array that the elements
389
 * can change without warning.
390
 *
391
 * return TCP connection number on success.
392
 * return -1 on failure.
393
 */
394
int get_random_tcp_onion_conn_number(const TCP_Connections *tcp_c)
395
1.17k
{
396
1.17k
    const uint32_t r = random_u32(tcp_c->rng);
397
398
1.60k
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
399
915
        const uint32_t index = (i + r) % tcp_c->tcp_connections_length;
400
401
915
        if (tcp_c->tcp_connections[index].onion && tcp_c->tcp_connections[index].status == TCP_CONN_CONNECTED) {
402
493
            return index;
403
493
        }
404
915
    }
405
406
685
    return -1;
407
1.17k
}
408
409
/** @brief Return TCP connection number of active TCP connection with ip_port.
410
 *
411
 * return TCP connection number on success.
412
 * return -1 on failure.
413
 */
414
static int get_conn_number_by_ip_port(const TCP_Connections *_Nonnull tcp_c, const IP_Port *_Nonnull ip_port)
415
5
{
416
5
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
417
5
        if (tcp_c->tcp_connections[i].connection == nullptr) {
418
0
            LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %u", i);
419
0
            continue;
420
0
        }
421
5
        const IP_Port conn_ip_port = tcp_con_ip_port(tcp_c->tcp_connections[i].connection);
422
423
5
        if (ipport_equal(ip_port, &conn_ip_port) &&
424
5
                tcp_c->tcp_connections[i].status == TCP_CONN_CONNECTED) {
425
5
            return i;
426
5
        }
427
5
    }
428
429
0
    return -1;
430
5
}
431
432
/** @brief Put IP_Port of a random onion TCP connection in ip_port.
433
 *
434
 * return true on success.
435
 * return false on failure.
436
 */
437
bool tcp_get_random_conn_ip_port(const TCP_Connections *tcp_c, IP_Port *ip_port)
438
5
{
439
5
    const int index = get_random_tcp_onion_conn_number(tcp_c);
440
441
5
    if (index == -1) {
442
0
        return false;
443
0
    }
444
445
5
    if (tcp_c->tcp_connections[index].connection == nullptr) {
446
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
447
0
        return false;
448
0
    }
449
5
    *ip_port = tcp_con_ip_port(tcp_c->tcp_connections[index].connection);
450
5
    return true;
451
5
}
452
453
/** @brief Send an onion packet via the TCP relay corresponding to tcp_connections_number.
454
 *
455
 * return 0 on success.
456
 * return -1 on failure.
457
 */
458
int tcp_send_onion_request(TCP_Connections *tcp_c, uint32_t tcp_connections_number, const uint8_t *data,
459
                           uint16_t length)
460
6.55k
{
461
6.55k
    if (tcp_connections_number >= tcp_c->tcp_connections_length) {
462
0
        return -1;
463
0
    }
464
465
6.55k
    if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_CONNECTED) {
466
6.55k
        if (tcp_c->tcp_connections[tcp_connections_number].connection == nullptr) {
467
0
            LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_connections_number);
468
0
            return -1;
469
0
        }
470
6.55k
        const int ret = send_onion_request(tcp_c->logger, tcp_c->tcp_connections[tcp_connections_number].connection, data,
471
6.55k
                                           length);
472
473
6.55k
        if (ret == 1) {
474
6.55k
            return 0;
475
6.55k
        }
476
6.55k
    }
477
478
0
    return -1;
479
6.55k
}
480
481
/* Send a forward request to the TCP relay with IP_Port tcp_forwarder,
482
 * requesting to forward data via a chain of dht nodes starting with dht_node.
483
 * A chain_length of 0 means that dht_node is the final destination of data.
484
 *
485
 * return 0 on success.
486
 * return -1 on failure.
487
 */
488
int tcp_send_forward_request(const Logger *logger, TCP_Connections *tcp_c, const IP_Port *tcp_forwarder,
489
                             const IP_Port *dht_node,
490
                             const uint8_t *chain_keys, uint16_t chain_length,
491
                             const uint8_t *data, uint16_t data_length)
492
5
{
493
5
    const int index = get_conn_number_by_ip_port(tcp_c, tcp_forwarder);
494
495
5
    if (index == -1) {
496
0
        return -1;
497
0
    }
498
499
5
    if (chain_length == 0) {
500
1
        if (tcp_c->tcp_connections[index].connection == nullptr) {
501
0
            LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
502
0
            return -1;
503
0
        }
504
1
        return send_forward_request_tcp(logger, tcp_c->tcp_connections[index].connection, dht_node, data,
505
1
                                        data_length) == 1 ? 0 : -1;
506
1
    }
507
508
4
    const uint16_t len = forward_chain_packet_size(chain_length, data_length);
509
4
    VLA(uint8_t, packet, len);
510
511
4
    if (tcp_c->tcp_connections[index].connection == nullptr) {
512
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
513
0
        return -1;
514
0
    }
515
4
    return create_forward_chain_packet(chain_keys, chain_length, data, data_length, packet)
516
4
           && send_forward_request_tcp(logger, tcp_c->tcp_connections[index].connection, dht_node, packet, len) == 1 ? 0 : -1;
517
4
}
518
519
/** @brief Send an oob packet via the TCP relay corresponding to tcp_connections_number.
520
 *
521
 * return 0 on success.
522
 * return -1 on failure.
523
 */
524
int tcp_send_oob_packet(const TCP_Connections *tcp_c, unsigned int tcp_connections_number,
525
                        const uint8_t *public_key, const uint8_t *packet, uint16_t length)
526
52
{
527
52
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
528
529
52
    if (tcp_con == nullptr) {
530
0
        return -1;
531
0
    }
532
533
52
    if (tcp_con->status != TCP_CONN_CONNECTED) {
534
0
        return -1;
535
0
    }
536
537
52
    if (tcp_con->connection == nullptr) {
538
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
539
0
        return -1;
540
0
    }
541
52
    const int ret = send_oob_packet(tcp_c->logger, tcp_con->connection, public_key, packet, length);
542
543
52
    if (ret == 1) {
544
52
        return 0;
545
52
    }
546
547
0
    return -1;
548
52
}
549
550
static int find_tcp_connection_relay(const TCP_Connections *_Nonnull tcp_c, const uint8_t *_Nonnull relay_pk);
551
552
/** @brief Send an oob packet via the TCP relay corresponding to relay_pk.
553
 *
554
 * return 0 on success.
555
 * return -1 on failure.
556
 */
557
int tcp_send_oob_packet_using_relay(const TCP_Connections *tcp_c, const uint8_t *relay_pk, const uint8_t *public_key,
558
                                    const uint8_t *packet, uint16_t length)
559
2
{
560
2
    const int tcp_con_number = find_tcp_connection_relay(tcp_c, relay_pk);
561
562
2
    if (tcp_con_number < 0) {
563
0
        return -1;
564
0
    }
565
566
2
    return tcp_send_oob_packet(tcp_c, tcp_con_number, public_key, packet, length);
567
2
}
568
569
/** @brief Set the callback for TCP data packets. */
570
void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_data_cb *tcp_data_callback, void *object)
571
2.13k
{
572
2.13k
    tcp_c->tcp_data_callback = tcp_data_callback;
573
2.13k
    tcp_c->tcp_data_callback_object = object;
574
2.13k
}
575
576
/** @brief Set the callback for TCP oob data packets. */
577
void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_oob_cb *tcp_oob_callback, void *object)
578
2.13k
{
579
2.13k
    tcp_c->tcp_oob_callback = tcp_oob_callback;
580
2.13k
    tcp_c->tcp_oob_callback_object = object;
581
2.13k
}
582
583
/** @brief Set the callback for TCP onion packets. */
584
void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_onion_cb *tcp_onion_callback, void *object)
585
3.84k
{
586
3.84k
    tcp_c->tcp_onion_callback = tcp_onion_callback;
587
3.84k
    tcp_c->tcp_onion_callback_object = object;
588
3.84k
}
589
590
/** @brief Set the callback for TCP forwarding packets. */
591
void set_forwarding_packet_tcp_connection_callback(TCP_Connections *tcp_c,
592
        forwarded_response_cb *tcp_forwarded_response_callback,
593
        void *object)
594
20
{
595
20
    tcp_c->tcp_forwarded_response_callback = tcp_forwarded_response_callback;
596
20
    tcp_c->tcp_forwarded_response_callback_object = object;
597
20
}
598
599
/** @brief Encode tcp_connections_number as a custom ip_port.
600
 *
601
 * return ip_port.
602
 */
603
IP_Port tcp_connections_number_to_ip_port(unsigned int tcp_connections_number)
604
522
{
605
522
    IP_Port ip_port = {{{0}}};
606
522
    ip_port.ip.family = net_family_tcp_server();
607
522
    ip_port.ip.ip.v6.uint32[0] = tcp_connections_number;
608
522
    return ip_port;
609
522
}
610
611
/** @brief Decode ip_port created by tcp_connections_number_to_ip_port to tcp_connections_number.
612
 *
613
 * return true on success.
614
 * return false if ip_port is invalid.
615
 */
616
bool ip_port_to_tcp_connections_number(const IP_Port *ip_port, unsigned int *tcp_connections_number)
617
6.58k
{
618
6.58k
    *tcp_connections_number = ip_port->ip.ip.v6.uint32[0];
619
6.58k
    return net_family_is_tcp_server(ip_port->ip.family);
620
6.58k
}
621
622
/** @brief Find the TCP connection with public_key.
623
 *
624
 * return connections_number on success.
625
 * return -1 on failure.
626
 */
627
static int find_tcp_connection_to(const TCP_Connections *_Nonnull tcp_c, const uint8_t *_Nonnull public_key)
628
1.05k
{
629
2.83k
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
630
2.08k
        const TCP_Connection_to *con_to = get_connection(tcp_c, i);
631
632
2.08k
        if (con_to != nullptr) {
633
2.03k
            if (pk_equal(con_to->public_key, public_key)) {
634
304
                return i;
635
304
            }
636
2.03k
        }
637
2.08k
    }
638
639
749
    return -1;
640
1.05k
}
641
642
/** @brief Find the TCP connection to a relay with relay_pk.
643
 *
644
 * return connections_number on success.
645
 * return -1 on failure.
646
 */
647
static int find_tcp_connection_relay(const TCP_Connections *tcp_c, const uint8_t *relay_pk)
648
399
{
649
435
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
650
247
        const TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
651
652
247
        if (tcp_con != nullptr) {
653
247
            if (tcp_con->status == TCP_CONN_SLEEPING) {
654
0
                if (pk_equal(tcp_con->relay_pk, relay_pk)) {
655
0
                    return i;
656
0
                }
657
247
            } else {
658
247
                if (tcp_con->connection == nullptr) {
659
0
                    LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
660
0
                    return -1;
661
0
                }
662
247
                if (pk_equal(tcp_con_public_key(tcp_con->connection), relay_pk)) {
663
211
                    return i;
664
211
                }
665
247
            }
666
247
        }
667
247
    }
668
669
188
    return -1;
670
399
}
671
672
bool tcp_relay_is_valid(const TCP_Connections *tcp_c, const uint8_t *relay_pk)
673
102
{
674
102
    return find_tcp_connection_relay(tcp_c, relay_pk) != -1;
675
102
}
676
677
/** @brief Create a new TCP connection to public_key.
678
 *
679
 * public_key must be the counterpart to the secret key that the other peer used with `new_tcp_connections()`.
680
 *
681
 * id is the id in the callbacks for that connection.
682
 *
683
 * return connections_number on success.
684
 * return -1 on failure.
685
 */
686
int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id)
687
748
{
688
748
    if (find_tcp_connection_to(tcp_c, public_key) != -1) {
689
1
        return -1;
690
1
    }
691
692
747
    const int connections_number = create_connection(tcp_c);
693
694
747
    if (connections_number == -1) {
695
0
        return -1;
696
0
    }
697
698
747
    TCP_Connection_to *con_to = &tcp_c->connections[connections_number];
699
700
747
    con_to->status = TCP_CONN_VALID;
701
747
    memcpy(con_to->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
702
747
    con_to->id = id;
703
704
747
    return connections_number;
705
747
}
706
707
/**
708
 * @retval 0 on success.
709
 * @retval -1 on failure.
710
 */
711
int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)
712
654
{
713
654
    const TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
714
715
654
    if (con_to == nullptr) {
716
0
        return -1;
717
0
    }
718
719
4.57k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
720
3.92k
        if (con_to->connections[i].tcp_connection > 0) {
721
105
            const unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;
722
105
            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
723
724
105
            if (tcp_con == nullptr) {
725
0
                continue;
726
0
            }
727
728
105
            if (tcp_con->status == TCP_CONN_CONNECTED) {
729
105
                if (tcp_con->connection == nullptr) {
730
0
                    LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
731
0
                    continue;
732
0
                }
733
105
                send_disconnect_request(tcp_c->logger, tcp_con->connection, con_to->connections[i].connection_id);
734
105
            }
735
736
105
            if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {
737
103
                --tcp_con->lock_count;
738
739
103
                if (con_to->status == TCP_CONN_SLEEPING) {
740
0
                    --tcp_con->sleep_count;
741
0
                }
742
103
            }
743
105
        }
744
3.92k
    }
745
746
654
    return wipe_connection(tcp_c, connections_number);
747
654
}
748
749
/** @brief Set connection status.
750
 *
751
 * status of 1 means we are using the connection.
752
 * status of 0 means we are not using it.
753
 *
754
 * Unused tcp connections will be disconnected from but kept in case they are needed.
755
 *
756
 * return 0 on success.
757
 * return -1 on failure.
758
 */
759
int set_tcp_connection_to_status(const TCP_Connections *tcp_c, int connections_number, bool status)
760
84.6k
{
761
84.6k
    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
762
763
84.6k
    if (con_to == nullptr) {
764
150
        return -1;
765
150
    }
766
767
84.4k
    if (status) {
768
        /* Connection is unsleeping. */
769
10.7k
        if (con_to->status != TCP_CONN_SLEEPING) {
770
10.7k
            return -1;
771
10.7k
        }
772
773
49
        for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
774
42
            if (con_to->connections[i].tcp_connection > 0) {
775
0
                const unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;
776
0
                TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
777
778
0
                if (tcp_con == nullptr) {
779
0
                    continue;
780
0
                }
781
782
0
                if (tcp_con->status == TCP_CONN_SLEEPING) {
783
0
                    tcp_con->unsleep = true;
784
0
                }
785
0
            }
786
42
        }
787
788
7
        con_to->status = TCP_CONN_VALID;
789
7
        return 0;
790
10.7k
    }
791
792
    /* Connection is going to sleep. */
793
73.7k
    if (con_to->status != TCP_CONN_VALID) {
794
73.1k
        return -1;
795
73.1k
    }
796
797
3.82k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
798
3.27k
        if (con_to->connections[i].tcp_connection > 0) {
799
0
            const unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;
800
0
            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
801
802
0
            if (tcp_con == nullptr) {
803
0
                continue;
804
0
            }
805
806
0
            if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {
807
0
                ++tcp_con->sleep_count;
808
0
            }
809
0
        }
810
3.27k
    }
811
812
556
    con_to->status = TCP_CONN_SLEEPING;
813
556
    return 0;
814
73.7k
}
815
816
static bool tcp_connection_in_conn(const TCP_Connection_to *_Nonnull con_to, unsigned int tcp_connections_number)
817
326
{
818
1.49k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
819
1.29k
        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
820
132
            return true;
821
132
        }
822
1.29k
    }
823
824
194
    return false;
825
326
}
826
827
/**
828
 * @return index on success.
829
 * @retval -1 on failure.
830
 */
831
static int add_tcp_connection_to_conn(TCP_Connection_to *_Nonnull con_to, unsigned int tcp_connections_number)
832
129
{
833
129
    if (tcp_connection_in_conn(con_to, tcp_connections_number)) {
834
19
        return -1;
835
19
    }
836
837
110
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
838
110
        if (con_to->connections[i].tcp_connection == 0) {
839
110
            con_to->connections[i].tcp_connection = tcp_connections_number + 1;
840
110
            con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;
841
110
            con_to->connections[i].connection_id = 0;
842
110
            return i;
843
110
        }
844
110
    }
845
846
0
    return -1;
847
110
}
848
849
/**
850
 * @return index on success.
851
 * @retval -1 on failure.
852
 */
853
static int rm_tcp_connection_from_conn(TCP_Connection_to *_Nonnull con_to, unsigned int tcp_connections_number)
854
0
{
855
0
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
856
0
        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
857
0
            con_to->connections[i].tcp_connection = 0;
858
0
            con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;
859
0
            con_to->connections[i].connection_id = 0;
860
0
            return i;
861
0
        }
862
0
    }
863
864
0
    return -1;
865
0
}
866
867
/**
868
 * @return number of online connections on success.
869
 * @retval -1 on failure.
870
 */
871
static uint32_t online_tcp_connection_from_conn(const TCP_Connection_to *_Nonnull con_to)
872
48.8k
{
873
48.8k
    uint32_t count = 0;
874
875
341k
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
876
292k
        if (con_to->connections[i].tcp_connection > 0) {
877
6.23k
            if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {
878
6.23k
                ++count;
879
6.23k
            }
880
6.23k
        }
881
292k
    }
882
883
48.8k
    return count;
884
48.8k
}
885
886
/**
887
 * @return index on success.
888
 * @retval -1 on failure.
889
 */
890
static int set_tcp_connection_status(TCP_Connection_to *_Nonnull con_to, unsigned int tcp_connections_number, uint8_t status, uint8_t connection_id)
891
220
{
892
220
    for (uint32_t i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
893
220
        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
894
895
220
            if (con_to->connections[i].status == status) {
896
0
                return -1;
897
0
            }
898
899
220
            con_to->connections[i].status = status;
900
220
            con_to->connections[i].connection_id = connection_id;
901
220
            return i;
902
220
        }
903
220
    }
904
905
0
    return -1;
906
220
}
907
908
/** @brief Kill a TCP relay connection.
909
 *
910
 * return 0 on success.
911
 * return -1 on failure.
912
 */
913
int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)
914
12
{
915
12
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
916
917
12
    if (tcp_con == nullptr) {
918
0
        return -1;
919
0
    }
920
921
12
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
922
0
        TCP_Connection_to *con_to = get_connection(tcp_c, i);
923
924
0
        if (con_to != nullptr) {
925
0
            rm_tcp_connection_from_conn(con_to, tcp_connections_number);
926
0
        }
927
0
    }
928
929
12
    if (tcp_con->onion) {
930
0
        --tcp_c->onion_num_conns;
931
0
    }
932
933
12
    kill_tcp_connection(tcp_con->connection);
934
935
12
    return wipe_tcp_connection(tcp_c, tcp_connections_number);
936
12
}
937
938
static int reconnect_tcp_relay_connection(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
939
0
{
940
0
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
941
942
0
    if (tcp_con == nullptr) {
943
0
        return -1;
944
0
    }
945
946
0
    if (tcp_con->status == TCP_CONN_SLEEPING) {
947
0
        return -1;
948
0
    }
949
950
0
    if (tcp_con->connection == nullptr) {
951
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
952
0
        return -1;
953
0
    }
954
0
    const IP_Port ip_port = tcp_con_ip_port(tcp_con->connection);
955
0
    uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE];
956
0
    memcpy(relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
957
0
    kill_tcp_connection(tcp_con->connection);
958
0
    tcp_con->connection = new_tcp_connection(tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info,
959
0
                          tcp_c->net_profile);
960
961
0
    if (tcp_con->connection == nullptr) {
962
0
        kill_tcp_relay_connection(tcp_c, tcp_connections_number);
963
0
        return -1;
964
0
    }
965
966
0
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
967
0
        TCP_Connection_to *con_to = get_connection(tcp_c, i);
968
969
0
        if (con_to != nullptr) {
970
0
            set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0);
971
0
        }
972
0
    }
973
974
0
    if (tcp_con->onion) {
975
0
        --tcp_c->onion_num_conns;
976
0
        tcp_con->onion = false;
977
0
    }
978
979
0
    tcp_con->lock_count = 0;
980
0
    tcp_con->sleep_count = 0;
981
0
    tcp_con->connected_time = 0;
982
0
    tcp_con->status = TCP_CONN_VALID;
983
0
    tcp_con->unsleep = false;
984
985
0
    return 0;
986
0
}
987
988
static int sleep_tcp_relay_connection(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
989
0
{
990
0
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
991
992
0
    if (tcp_con == nullptr) {
993
0
        return -1;
994
0
    }
995
996
0
    if (tcp_con->status != TCP_CONN_CONNECTED) {
997
0
        return -1;
998
0
    }
999
1000
0
    if (tcp_con->lock_count != tcp_con->sleep_count) {
1001
0
        return -1;
1002
0
    }
1003
1004
0
    if (tcp_con->connection == nullptr) {
1005
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
1006
0
        return -1;
1007
0
    }
1008
0
    tcp_con->ip_port = tcp_con_ip_port(tcp_con->connection);
1009
0
    memcpy(tcp_con->relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
1010
1011
0
    kill_tcp_connection(tcp_con->connection);
1012
0
    tcp_con->connection = nullptr;
1013
1014
0
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
1015
0
        TCP_Connection_to *con_to = get_connection(tcp_c, i);
1016
1017
0
        if (con_to != nullptr) {
1018
0
            set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0);
1019
0
        }
1020
0
    }
1021
1022
0
    if (tcp_con->onion) {
1023
0
        --tcp_c->onion_num_conns;
1024
0
        tcp_con->onion = false;
1025
0
    }
1026
1027
0
    tcp_con->lock_count = 0;
1028
0
    tcp_con->sleep_count = 0;
1029
0
    tcp_con->connected_time = 0;
1030
0
    tcp_con->status = TCP_CONN_SLEEPING;
1031
0
    tcp_con->unsleep = false;
1032
1033
0
    return 0;
1034
0
}
1035
1036
static int unsleep_tcp_relay_connection(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
1037
0
{
1038
0
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1039
1040
0
    if (tcp_con == nullptr) {
1041
0
        return -1;
1042
0
    }
1043
1044
0
    if (tcp_con->status != TCP_CONN_SLEEPING) {
1045
0
        return -1;
1046
0
    }
1047
1048
0
    tcp_con->connection = new_tcp_connection(
1049
0
                              tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &tcp_con->ip_port,
1050
0
                              tcp_con->relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info, tcp_c->net_profile);
1051
1052
0
    if (tcp_con->connection == nullptr) {
1053
0
        kill_tcp_relay_connection(tcp_c, tcp_connections_number);
1054
0
        return -1;
1055
0
    }
1056
1057
0
    tcp_con->lock_count = 0;
1058
0
    tcp_con->sleep_count = 0;
1059
0
    tcp_con->connected_time = 0;
1060
0
    tcp_con->status = TCP_CONN_VALID;
1061
0
    tcp_con->unsleep = false;
1062
1063
0
    return 0;
1064
0
}
1065
1066
/** @brief Send a TCP routing request.
1067
 *
1068
 * return 0 on success.
1069
 * return -1 on failure.
1070
 */
1071
static int send_tcp_relay_routing_request(const TCP_Connections *_Nonnull tcp_c, int tcp_connections_number, const uint8_t *_Nonnull public_key)
1072
110
{
1073
110
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1074
1075
110
    if (tcp_con == nullptr) {
1076
0
        return -1;
1077
0
    }
1078
1079
110
    if (tcp_con->status == TCP_CONN_SLEEPING) {
1080
0
        return -1;
1081
0
    }
1082
1083
110
    if (tcp_con->connection == nullptr) {
1084
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
1085
0
        return -1;
1086
0
    }
1087
110
    if (send_routing_request(tcp_c->logger, tcp_con->connection, public_key) != 1) {
1088
0
        return -1;
1089
0
    }
1090
1091
110
    return 0;
1092
110
}
1093
1094
static int tcp_response_callback(void *_Nonnull object, uint8_t connection_id, const uint8_t *_Nonnull public_key)
1095
110
{
1096
110
    const TCP_Client_Connection *tcp_client_con = (const TCP_Client_Connection *)object;
1097
110
    const TCP_Connections *tcp_c = (const TCP_Connections *)tcp_con_custom_object(tcp_client_con);
1098
1099
110
    const unsigned int tcp_connections_number = tcp_con_custom_uint(tcp_client_con);
1100
110
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1101
1102
110
    if (tcp_con == nullptr) {
1103
0
        return -1;
1104
0
    }
1105
1106
110
    const int connections_number = find_tcp_connection_to(tcp_c, public_key);
1107
1108
110
    if (connections_number == -1) {
1109
0
        return -1;
1110
0
    }
1111
1112
110
    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
1113
1114
110
    if (con_to == nullptr) {
1115
0
        return -1;
1116
0
    }
1117
1118
110
    if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) {
1119
0
        return -1;
1120
0
    }
1121
1122
110
    if (tcp_con->connection == nullptr) {
1123
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
1124
0
        return -1;
1125
0
    }
1126
110
    set_tcp_connection_number(tcp_con->connection, connection_id, connections_number);
1127
1128
110
    return 0;
1129
110
}
1130
1131
static int tcp_status_callback(void *_Nonnull object, uint32_t number, uint8_t connection_id, uint8_t status)
1132
110
{
1133
110
    const TCP_Client_Connection *tcp_client_con = (const TCP_Client_Connection *)object;
1134
110
    const TCP_Connections *tcp_c = (const TCP_Connections *)tcp_con_custom_object(tcp_client_con);
1135
1136
110
    const unsigned int tcp_connections_number = tcp_con_custom_uint(tcp_client_con);
1137
110
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1138
110
    TCP_Connection_to *con_to = get_connection(tcp_c, number);
1139
1140
110
    if (con_to == nullptr || tcp_con == nullptr) {
1141
0
        return -1;
1142
0
    }
1143
1144
110
    if (status == 1) {
1145
2
        if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) {
1146
0
            return -1;
1147
0
        }
1148
1149
2
        --tcp_con->lock_count;
1150
1151
2
        if (con_to->status == TCP_CONN_SLEEPING) {
1152
0
            --tcp_con->sleep_count;
1153
0
        }
1154
108
    } else if (status == 2) {
1155
108
        if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1) {
1156
0
            return -1;
1157
0
        }
1158
1159
108
        ++tcp_con->lock_count;
1160
1161
108
        if (con_to->status == TCP_CONN_SLEEPING) {
1162
0
            ++tcp_con->sleep_count;
1163
0
        }
1164
108
    }
1165
1166
110
    return 0;
1167
110
}
1168
1169
static int tcp_conn_data_callback(void *_Nonnull object, uint32_t number, uint8_t connection_id, const uint8_t *_Nonnull data,
1170
                                  uint16_t length, void *_Nullable userdata)
1171
1.31k
{
1172
1.31k
    const TCP_Client_Connection *tcp_client_con = (TCP_Client_Connection *)object;
1173
1.31k
    if (length == 0) {
1174
0
        return -1;
1175
0
    }
1176
1177
1.31k
    TCP_Connections *tcp_c = (TCP_Connections *)tcp_con_custom_object(tcp_client_con);
1178
1179
1.31k
    const unsigned int tcp_connections_number = tcp_con_custom_uint(tcp_client_con);
1180
1.31k
    const TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1181
1182
1.31k
    if (tcp_con == nullptr) {
1183
0
        return -1;
1184
0
    }
1185
1186
1.31k
    const TCP_Connection_to *con_to = get_connection(tcp_c, number);
1187
1188
1.31k
    if (con_to == nullptr) {
1189
0
        return -1;
1190
0
    }
1191
1192
1.31k
    if (tcp_c->tcp_data_callback != nullptr) {
1193
1.31k
        tcp_c->tcp_data_callback(tcp_c->tcp_data_callback_object, con_to->id, data, length, userdata);
1194
1.31k
    }
1195
1196
1.31k
    return 0;
1197
1.31k
}
1198
1199
static int tcp_conn_oob_callback(void *_Nonnull object, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull data, uint16_t length, void *_Nonnull userdata)
1200
195
{
1201
195
    const TCP_Client_Connection *tcp_client_con = (const TCP_Client_Connection *)object;
1202
1203
195
    if (length == 0) {
1204
0
        return -1;
1205
0
    }
1206
1207
195
    TCP_Connections *tcp_c = (TCP_Connections *)tcp_con_custom_object(tcp_client_con);
1208
1209
195
    const unsigned int tcp_connections_number = tcp_con_custom_uint(tcp_client_con);
1210
195
    const TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1211
1212
195
    if (tcp_con == nullptr) {
1213
0
        return -1;
1214
0
    }
1215
1216
    /* TODO(irungentoo): optimize */
1217
195
    const int connections_number = find_tcp_connection_to(tcp_c, public_key);
1218
1219
195
    const TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
1220
1221
195
    if (con_to != nullptr && tcp_connection_in_conn(con_to, tcp_connections_number)) {
1222
110
        return tcp_conn_data_callback(object, connections_number, 0, data, length, userdata);
1223
110
    }
1224
1225
85
    if (tcp_c->tcp_oob_callback != nullptr) {
1226
85
        tcp_c->tcp_oob_callback(tcp_c->tcp_oob_callback_object, public_key, tcp_connections_number, data, length, userdata);
1227
85
    }
1228
1229
85
    return 0;
1230
195
}
1231
1232
static int tcp_onion_callback(void *_Nonnull object, const uint8_t *_Nonnull data, uint16_t length, void *_Nonnull userdata)
1233
6.53k
{
1234
6.53k
    TCP_Connections *tcp_c = (TCP_Connections *)object;
1235
1236
6.53k
    if (tcp_c->tcp_onion_callback != nullptr) {
1237
6.53k
        tcp_c->tcp_onion_callback(tcp_c->tcp_onion_callback_object, data, length, userdata);
1238
6.53k
    }
1239
1240
6.53k
    return 0;
1241
6.53k
}
1242
1243
static void tcp_forwarding_callback(void *_Nonnull object, const uint8_t *_Nonnull data, uint16_t length, void *_Nonnull userdata)
1244
5
{
1245
5
    TCP_Connections *tcp_c = (TCP_Connections *)object;
1246
1247
5
    if (tcp_c->tcp_forwarded_response_callback != nullptr) {
1248
5
        tcp_c->tcp_forwarded_response_callback(tcp_c->tcp_forwarded_response_callback_object, data, length, userdata);
1249
5
    }
1250
5
}
1251
1252
/** @brief Set callbacks for the TCP relay connection.
1253
 *
1254
 * return 0 on success.
1255
 * return -1 on failure.
1256
 */
1257
static int tcp_relay_set_callbacks(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
1258
60
{
1259
60
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1260
1261
60
    if (tcp_con == nullptr) {
1262
0
        return -1;
1263
0
    }
1264
1265
60
    TCP_Client_Connection *con = tcp_con->connection;
1266
1267
60
    tcp_con_set_custom_object(con, tcp_c);
1268
60
    tcp_con_set_custom_uint(con, tcp_connections_number);
1269
60
    onion_response_handler(con, &tcp_onion_callback, tcp_c);
1270
60
    forwarding_handler(con, &tcp_forwarding_callback, tcp_c);
1271
60
    routing_response_handler(con, &tcp_response_callback, con);
1272
60
    routing_status_handler(con, &tcp_status_callback, con);
1273
60
    routing_data_handler(con, &tcp_conn_data_callback, con);
1274
60
    oob_data_handler(con, &tcp_conn_oob_callback, con);
1275
1276
60
    return 0;
1277
60
}
1278
1279
static int tcp_relay_on_online(TCP_Connections *_Nonnull tcp_c, int tcp_connections_number)
1280
59
{
1281
59
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1282
1283
59
    if (tcp_con == nullptr) {
1284
0
        return -1;
1285
0
    }
1286
1287
59
    bool sent_any = false;
1288
1289
63
    for (uint32_t i = 0; i < tcp_c->connections_length; ++i) {
1290
4
        const TCP_Connection_to *con_to = get_connection(tcp_c, i);
1291
1292
4
        if (con_to != nullptr) {
1293
4
            if (tcp_connection_in_conn(con_to, tcp_connections_number)) {
1294
3
                if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) {
1295
3
                    sent_any = true;
1296
3
                }
1297
3
            }
1298
4
        }
1299
4
    }
1300
1301
59
    tcp_relay_set_callbacks(tcp_c, tcp_connections_number);
1302
59
    tcp_con->status = TCP_CONN_CONNECTED;
1303
1304
    /* If this connection isn't used by any connection, we don't need to wait for them to come online. */
1305
59
    if (sent_any) {
1306
3
        tcp_con->connected_time = mono_time_get(tcp_c->mono_time);
1307
56
    } else {
1308
56
        tcp_con->connected_time = 0;
1309
56
    }
1310
1311
59
    if (tcp_c->onion_status && tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) {
1312
53
        tcp_con->onion = true;
1313
53
        ++tcp_c->onion_num_conns;
1314
53
    }
1315
1316
59
    return 0;
1317
59
}
1318
1319
static int add_tcp_relay_instance(TCP_Connections *_Nonnull tcp_c, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull relay_pk)
1320
97
{
1321
97
    IP_Port ipp_copy = *ip_port;
1322
1323
97
    if (net_family_is_tcp_ipv4(ipp_copy.ip.family)) {
1324
3
        ipp_copy.ip.family = net_family_ipv4();
1325
94
    } else if (net_family_is_tcp_ipv6(ipp_copy.ip.family)) {
1326
0
        ipp_copy.ip.family = net_family_ipv6();
1327
0
    }
1328
1329
97
    if (!net_family_is_ipv4(ipp_copy.ip.family) && !net_family_is_ipv6(ipp_copy.ip.family)) {
1330
2
        return -1;
1331
2
    }
1332
1333
95
    const int tcp_connections_number = create_tcp_connection(tcp_c);
1334
1335
95
    if (tcp_connections_number == -1) {
1336
1
        return -1;
1337
1
    }
1338
1339
94
    TCP_con *tcp_con = &tcp_c->tcp_connections[tcp_connections_number];
1340
1341
94
    tcp_con->connection = new_tcp_connection(
1342
94
                              tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &ipp_copy,
1343
94
                              relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info, tcp_c->net_profile);
1344
1345
94
    if (tcp_con->connection == nullptr) {
1346
1
        return -1;
1347
1
    }
1348
1349
93
    tcp_con->status = TCP_CONN_VALID;
1350
1351
93
    return tcp_connections_number;
1352
94
}
1353
1354
/** @brief Add a TCP relay to the TCP_Connections instance.
1355
 *
1356
 * return 0 on success.
1357
 * return -1 on failure.
1358
 */
1359
int add_tcp_relay_global(TCP_Connections *tcp_c, const IP_Port *ip_port, const uint8_t *relay_pk)
1360
199
{
1361
199
    const int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk);
1362
1363
199
    if (tcp_connections_number != -1) {
1364
106
        return -1;
1365
106
    }
1366
1367
93
    if (add_tcp_relay_instance(tcp_c, ip_port, relay_pk) == -1) {
1368
3
        return -1;
1369
3
    }
1370
1371
90
    return 0;
1372
93
}
1373
1374
/** @brief Add a TCP relay tied to a connection.
1375
 *
1376
 * NOTE: This can only be used during the tcp_oob_callback.
1377
 *
1378
 * return 0 on success.
1379
 * return -1 on failure.
1380
 */
1381
int add_tcp_number_relay_connection(const TCP_Connections *tcp_c, int connections_number,
1382
                                    unsigned int tcp_connections_number)
1383
126
{
1384
126
    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
1385
1386
126
    if (con_to == nullptr) {
1387
0
        return -1;
1388
0
    }
1389
1390
126
    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1391
1392
126
    if (tcp_con == nullptr) {
1393
0
        return -1;
1394
0
    }
1395
1396
126
    if (con_to->status != TCP_CONN_SLEEPING && tcp_con->status == TCP_CONN_SLEEPING) {
1397
0
        tcp_con->unsleep = true;
1398
0
    }
1399
1400
126
    if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) {
1401
19
        return -1;
1402
19
    }
1403
1404
107
    if (tcp_con->status == TCP_CONN_CONNECTED) {
1405
107
        if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) {
1406
107
            tcp_con->connected_time = mono_time_get(tcp_c->mono_time);
1407
107
        }
1408
107
    }
1409
1410
107
    return 0;
1411
126
}
1412
1413
/** @brief Add a TCP relay tied to a connection.
1414
 *
1415
 * This should be called with the same relay by two peers who want to create a TCP connection with each other.
1416
 *
1417
 * return 0 on success.
1418
 * return -1 on failure.
1419
 */
1420
int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, const IP_Port *ip_port,
1421
                             const uint8_t *relay_pk)
1422
96
{
1423
96
    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
1424
1425
96
    if (con_to == nullptr) {
1426
0
        return -1;
1427
0
    }
1428
1429
96
    int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk);
1430
1431
96
    if (tcp_connections_number != -1) {
1432
92
        return add_tcp_number_relay_connection(tcp_c, connections_number, tcp_connections_number);
1433
92
    }
1434
1435
4
    if (online_tcp_connection_from_conn(con_to) >= RECOMMENDED_FRIEND_TCP_CONNECTIONS) {
1436
0
        return -1;
1437
0
    }
1438
1439
4
    tcp_connections_number = add_tcp_relay_instance(tcp_c, ip_port, relay_pk);
1440
1441
4
    const TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
1442
1443
4
    if (tcp_con == nullptr) {
1444
1
        return -1;
1445
1
    }
1446
1447
3
    if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) {
1448
0
        return -1;
1449
0
    }
1450
1451
3
    return 0;
1452
3
}
1453
1454
/**
1455
 * @return number of online tcp relays tied to the connection on success.
1456
 * @retval 0 on failure.
1457
 */
1458
uint32_t tcp_connection_to_online_tcp_relays(const TCP_Connections *tcp_c, int connections_number)
1459
48.8k
{
1460
48.8k
    const TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
1461
1462
48.8k
    if (con_to == nullptr) {
1463
0
        return 0;
1464
0
    }
1465
1466
48.8k
    return online_tcp_connection_from_conn(con_to);
1467
48.8k
}
1468
1469
/** @brief Copies the tcp relay from tcp connections designated by `idx` to `tcp_relay`.
1470
 *
1471
 * Returns true if the relay was successfully copied.
1472
 * Returns false if the connection index is invalid, or if the relay is not connected.
1473
 */
1474
static bool copy_tcp_relay_conn(const TCP_Connections *_Nonnull tcp_c, Node_format *_Nonnull tcp_relay, uint16_t idx)
1475
3.69k
{
1476
3.69k
    const TCP_con *tcp_con = get_tcp_connection(tcp_c, idx);
1477
1478
3.69k
    if (tcp_con == nullptr) {
1479
0
        return false;
1480
0
    }
1481
1482
3.69k
    if (tcp_con->status != TCP_CONN_CONNECTED) {
1483
4
        return false;
1484
4
    }
1485
1486
3.69k
    if (tcp_con->connection == nullptr) {
1487
0
        LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
1488
0
        return false;
1489
0
    }
1490
3.69k
    memcpy(tcp_relay->public_key, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
1491
3.69k
    tcp_relay->ip_port = tcp_con_ip_port(tcp_con->connection);
1492
1493
3.69k
    Family *const family = &tcp_relay->ip_port.ip.family;
1494
1495
3.69k
    if (net_family_is_ipv4(*family)) {
1496
3.69k
        *family = net_family_tcp_ipv4();
1497
3.69k
    } else if (net_family_is_ipv6(*family)) {
1498
0
        *family = net_family_tcp_ipv6();
1499
0
    }
1500
1501
3.69k
    return true;
1502
3.69k
}
1503
1504
/** @brief Copy a maximum of max_num TCP relays we are connected to to tcp_relays.
1505
 *
1506
 * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
1507
 *
1508
 * return number of relays copied to tcp_relays on success.
1509
 * return 0 on failure.
1510
 */
1511
uint32_t tcp_copy_connected_relays(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num)
1512
7.61k
{
1513
7.61k
    const uint32_t r = random_u32(tcp_c->rng);
1514
7.61k
    uint32_t copied = 0;
1515
1516
11.3k
    for (uint32_t i = 0; (i < tcp_c->tcp_connections_length) && (copied < max_num); ++i) {
1517
3.69k
        const uint16_t idx = (i + r) % tcp_c->tcp_connections_length;
1518
1519
3.69k
        if (copy_tcp_relay_conn(tcp_c, &tcp_relays[copied], idx)) {
1520
3.69k
            ++copied;
1521
3.69k
        }
1522
3.69k
    }
1523
1524
7.61k
    return copied;
1525
7.61k
}
1526
1527
uint32_t tcp_copy_connected_relays_index(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num,
1528
        uint32_t idx)
1529
51.8k
{
1530
51.8k
    if (tcp_c->tcp_connections_length == 0) {
1531
46.2k
        return 0;
1532
46.2k
    }
1533
1534
5.54k
    uint32_t copied = 0;
1535
5.54k
    const uint16_t num_to_copy = min_u16(max_num, tcp_c->tcp_connections_length);
1536
5.54k
    const uint16_t start = idx % tcp_c->tcp_connections_length;
1537
5.54k
    const uint16_t end = (start + num_to_copy) % tcp_c->tcp_connections_length;
1538
1539
5.54k
    for (uint16_t i = start; i != end; i = (i + 1) % tcp_c->tcp_connections_length) {
1540
0
        if (copy_tcp_relay_conn(tcp_c, &tcp_relays[copied], i)) {
1541
0
            ++copied;
1542
0
        }
1543
0
    }
1544
1545
5.54k
    return copied;
1546
51.8k
}
1547
1548
/** @brief Set if we want TCP_connection to allocate some connection for onion use.
1549
 *
1550
 * If status is 1, allocate some connections. if status is 0, don't.
1551
 *
1552
 * return 0 on success.
1553
 * return -1 on failure.
1554
 */
1555
int set_tcp_onion_status(TCP_Connections *tcp_c, bool status)
1556
6.25k
{
1557
6.25k
    if (tcp_c->onion_status == status) {
1558
5.74k
        return -1;
1559
5.74k
    }
1560
1561
508
    if (status) {
1562
529
        for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
1563
66
            TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
1564
1565
66
            if (tcp_con != nullptr) {
1566
65
                if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion) {
1567
0
                    ++tcp_c->onion_num_conns;
1568
0
                    tcp_con->onion = true;
1569
0
                }
1570
65
            }
1571
1572
66
            if (tcp_c->onion_num_conns >= NUM_ONION_TCP_CONNECTIONS) {
1573
0
                break;
1574
0
            }
1575
66
        }
1576
1577
463
        if (tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) {
1578
463
            const unsigned int wakeup = NUM_ONION_TCP_CONNECTIONS - tcp_c->onion_num_conns;
1579
1580
529
            for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
1581
66
                TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
1582
1583
66
                if (tcp_con != nullptr) {
1584
65
                    if (tcp_con->status == TCP_CONN_SLEEPING) {
1585
0
                        tcp_con->unsleep = true;
1586
0
                    }
1587
65
                }
1588
1589
66
                if (wakeup == 0) {
1590
0
                    break;
1591
0
                }
1592
66
            }
1593
463
        }
1594
1595
463
        tcp_c->onion_status = true;
1596
463
    } else {
1597
45
        for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
1598
0
            TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
1599
1600
0
            if (tcp_con != nullptr) {
1601
0
                if (tcp_con->onion) {
1602
0
                    --tcp_c->onion_num_conns;
1603
0
                    tcp_con->onion = false;
1604
0
                }
1605
0
            }
1606
0
        }
1607
1608
45
        tcp_c->onion_status = false;
1609
45
    }
1610
1611
508
    return 0;
1612
6.25k
}
1613
1614
/** @brief Returns a new TCP_Connections object associated with the secret_key.
1615
 *
1616
 * In order for others to connect to this instance `new_tcp_connection_to()` must be called with the
1617
 * public_key associated with secret_key.
1618
 *
1619
 * Returns NULL on failure.
1620
 */
1621
TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns,
1622
                                     Mono_Time *mono_time, const uint8_t *secret_key, const TCP_Proxy_Info *proxy_info, Net_Profile *tcp_np)
1623
2.14k
{
1624
2.14k
    assert(logger != nullptr);
1625
2.14k
    assert(mem != nullptr);
1626
2.14k
    assert(rng != nullptr);
1627
2.14k
    assert(ns != nullptr);
1628
2.14k
    assert(mono_time != nullptr);
1629
1630
2.14k
    if (secret_key == nullptr) {
1631
0
        return nullptr;
1632
0
    }
1633
1634
2.14k
    TCP_Connections *temp = (TCP_Connections *)mem_alloc(mem, sizeof(TCP_Connections));
1635
1636
2.14k
    if (temp == nullptr) {
1637
4
        return nullptr;
1638
4
    }
1639
1640
2.13k
    temp->net_profile = tcp_np;
1641
2.13k
    temp->logger = logger;
1642
2.13k
    temp->mem = mem;
1643
2.13k
    temp->rng = rng;
1644
2.13k
    temp->mono_time = mono_time;
1645
2.13k
    temp->ns = ns;
1646
1647
2.13k
    memcpy(temp->self_secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE);
1648
2.13k
    crypto_derive_public_key(temp->self_public_key, temp->self_secret_key);
1649
2.13k
    temp->proxy_info = *proxy_info;
1650
1651
2.13k
    return temp;
1652
2.14k
}
1653
1654
static void do_tcp_conns(const Logger *_Nonnull logger, TCP_Connections *_Nonnull tcp_c, void *_Nullable userdata)
1655
142k
{
1656
183k
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
1657
40.8k
        TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
1658
40.8k
        if (tcp_con == nullptr) {
1659
1
            continue;
1660
1
        }
1661
1662
40.9k
        if (tcp_con->status != TCP_CONN_SLEEPING) {
1663
40.9k
            if (tcp_con->connection == nullptr) {
1664
0
                LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
1665
0
                continue;
1666
0
            }
1667
40.9k
            do_tcp_connection(logger, tcp_c->mono_time, tcp_con->connection, userdata);
1668
1669
            /* callbacks can change TCP connection address. */
1670
40.9k
            tcp_con = get_tcp_connection(tcp_c, i);
1671
1672
            // Make sure the TCP connection wasn't dropped in any of the callbacks.
1673
40.9k
            assert(tcp_con != nullptr);
1674
1675
40.8k
            if (tcp_con->connection == nullptr) {
1676
0
                LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
1677
0
                continue;
1678
0
            }
1679
40.8k
            if (tcp_con_status(tcp_con->connection) == TCP_CLIENT_DISCONNECTED) {
1680
12
                if (tcp_con->status == TCP_CONN_CONNECTED) {
1681
0
                    reconnect_tcp_relay_connection(tcp_c, i);
1682
12
                } else {
1683
12
                    kill_tcp_relay_connection(tcp_c, i);
1684
12
                }
1685
1686
12
                continue;
1687
12
            }
1688
1689
40.8k
            if (tcp_con->connection == nullptr) {
1690
0
                LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
1691
0
                continue;
1692
0
            }
1693
40.8k
            if (tcp_con->status == TCP_CONN_VALID && tcp_con_status(tcp_con->connection) == TCP_CLIENT_CONFIRMED) {
1694
60
                tcp_relay_on_online(tcp_c, i);
1695
60
            }
1696
1697
40.8k
            if (tcp_con->status == TCP_CONN_CONNECTED
1698
40.8k
                    && !tcp_con->onion && tcp_con->lock_count > 0
1699
40.8k
                    && tcp_con->lock_count == tcp_con->sleep_count
1700
40.8k
                    && mono_time_is_timeout(tcp_c->mono_time, tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) {
1701
0
                sleep_tcp_relay_connection(tcp_c, i);
1702
0
            }
1703
40.8k
        }
1704
1705
40.8k
        if (tcp_con->status == TCP_CONN_SLEEPING && tcp_con->unsleep) {
1706
0
            unsleep_tcp_relay_connection(tcp_c, i);
1707
0
        }
1708
40.8k
    }
1709
142k
}
1710
1711
static void kill_nonused_tcp(TCP_Connections *_Nullable tcp_c)
1712
142k
{
1713
142k
    if (tcp_c == nullptr) {
1714
0
        return;
1715
0
    }
1716
1717
142k
    if (tcp_c->tcp_connections_length <= RECOMMENDED_FRIEND_TCP_CONNECTIONS) {
1718
142k
        return;
1719
142k
    }
1720
1721
102
    const uint32_t num_online = tcp_connected_relays_count(tcp_c);
1722
1723
102
    if (num_online <= RECOMMENDED_FRIEND_TCP_CONNECTIONS) {
1724
96
        return;
1725
96
    }
1726
1727
6
    const uint32_t max_kill_count = num_online - RECOMMENDED_FRIEND_TCP_CONNECTIONS;
1728
6
    uint32_t kill_count = 0;
1729
1730
6
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length && kill_count < max_kill_count; ++i) {
1731
0
        const TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
1732
1733
0
        if (tcp_con == nullptr) {
1734
0
            continue;
1735
0
        }
1736
1737
0
        if (tcp_con->status == TCP_CONN_CONNECTED) {
1738
0
            if (tcp_con->onion || tcp_con->lock_count > 0) {  // connection is in use so we skip it
1739
0
                continue;
1740
0
            }
1741
1742
0
            if (mono_time_is_timeout(tcp_c->mono_time, tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) {
1743
0
                kill_tcp_relay_connection(tcp_c, i);
1744
0
                ++kill_count;
1745
0
            }
1746
0
        }
1747
0
    }
1748
6
}
1749
1750
void do_tcp_connections(const Logger *logger, TCP_Connections *tcp_c, void *userdata)
1751
142k
{
1752
142k
    do_tcp_conns(logger, tcp_c, userdata);
1753
142k
    kill_nonused_tcp(tcp_c);
1754
142k
}
1755
1756
void kill_tcp_connections(TCP_Connections *tcp_c)
1757
2.13k
{
1758
2.13k
    if (tcp_c == nullptr) {
1759
0
        return;
1760
0
    }
1761
1762
2.21k
    for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
1763
82
        kill_tcp_connection(tcp_c->tcp_connections[i].connection);
1764
82
    }
1765
1766
2.13k
    crypto_memzero(tcp_c->self_secret_key, sizeof(tcp_c->self_secret_key));
1767
1768
2.13k
    mem_delete(tcp_c->mem, tcp_c->tcp_connections);
1769
2.13k
    mem_delete(tcp_c->mem, tcp_c->connections);
1770
2.13k
    mem_delete(tcp_c->mem, tcp_c);
1771
2.13k
}
1772