Coverage Report

Created: 2025-10-08 19:34

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