Coverage Report

Created: 2025-10-08 19:34

/work/toxcore/TCP_common.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2025 The TokTok team.
3
 * Copyright © 2014 Tox project.
4
 */
5
6
#include "TCP_common.h"
7
8
#include <string.h>
9
10
#include "attributes.h"
11
#include "ccompat.h"
12
#include "crypto_core.h"
13
#include "logger.h"
14
#include "mem.h"
15
#include "network.h"
16
17
void wipe_priority_list(const Memory *mem, TCP_Priority_List *p)
18
135
{
19
138
    while (p != nullptr) {
20
3
        TCP_Priority_List *pp = p;
21
3
        p = p->next;
22
3
        mem_delete(mem, pp->data);
23
3
        mem_delete(mem, pp);
24
3
    }
25
135
}
26
27
/**
28
 * @retval 0 if pending data was sent completely
29
 * @retval -1 if it wasn't
30
 */
31
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con)
32
29.6k
{
33
29.6k
    if (con->last_packet_length == 0) {
34
29.2k
        return 0;
35
29.2k
    }
36
37
410
    const uint16_t left = con->last_packet_length - con->last_packet_sent;
38
410
    const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port,
39
410
                             con->net_profile);
40
41
410
    if (len <= 0) {
42
347
        return -1;
43
347
    }
44
45
63
    if (len == left) {
46
63
        con->last_packet_length = 0;
47
63
        con->last_packet_sent = 0;
48
63
        return 0;
49
63
    }
50
51
0
    con->last_packet_sent += len;
52
0
    return -1;
53
63
}
54
55
/**
56
 * @retval 0 if pending data was sent completely
57
 * @retval -1 if it wasn't
58
 */
59
int send_pending_data(const Logger *logger, TCP_Connection *con)
60
29.6k
{
61
    /* finish sending current non-priority packet */
62
29.6k
    if (send_pending_data_nonpriority(logger, con) == -1) {
63
347
        return -1;
64
347
    }
65
66
29.2k
    TCP_Priority_List *p = con->priority_queue_start;
67
68
29.2k
    while (p != nullptr) {
69
346
        const uint16_t left = p->size - p->sent;
70
346
        const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port, con->net_profile);
71
72
346
        if (len != left) {
73
346
            if (len > 0) {
74
0
                p->sent += len;
75
0
            }
76
77
346
            break;
78
346
        }
79
80
0
        TCP_Priority_List *pp = p;
81
0
        p = p->next;
82
0
        mem_delete(con->mem, pp->data);
83
0
        mem_delete(con->mem, pp);
84
0
    }
85
86
29.2k
    con->priority_queue_start = p;
87
88
29.2k
    if (p == nullptr) {
89
28.9k
        con->priority_queue_end = nullptr;
90
28.9k
        return 0;
91
28.9k
    }
92
93
346
    return -1;
94
29.2k
}
95
96
/**
97
 * @retval false on failure (only if mem_alloc fails)
98
 * @retval true on success
99
 */
100
static bool add_priority(TCP_Connection *_Nonnull con, const uint8_t *_Nonnull packet, uint16_t size, uint16_t sent)
101
3
{
102
3
    TCP_Priority_List *p = con->priority_queue_end;
103
3
    TCP_Priority_List *new_list = (TCP_Priority_List *)mem_alloc(con->mem, sizeof(TCP_Priority_List));
104
105
3
    if (new_list == nullptr) {
106
0
        return false;
107
0
    }
108
109
3
    uint8_t *data = (uint8_t *)mem_balloc(con->mem, size);
110
111
3
    if (data == nullptr) {
112
0
        mem_delete(con->mem, new_list);
113
0
        return false;
114
0
    }
115
116
3
    memcpy(data, packet, size);
117
3
    new_list->data = data;
118
3
    new_list->size = size;
119
120
3
    new_list->next = nullptr;
121
3
    new_list->sent = sent;
122
123
3
    if (p != nullptr) {
124
1
        p->next = new_list;
125
2
    } else {
126
2
        con->priority_queue_start = new_list;
127
2
    }
128
129
3
    con->priority_queue_end = new_list;
130
3
    return true;
131
3
}
132
133
/**
134
 * @retval 1 on success.
135
 * @retval 0 if could not send packet.
136
 * @retval -1 on failure (connection must be killed).
137
 */
138
int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
139
                                       bool priority)
140
4.70k
{
141
4.70k
    if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) {
142
0
        return -1;
143
0
    }
144
145
4.70k
    bool sendpriority = true;
146
147
4.70k
    if (send_pending_data(logger, con) == -1) {
148
1
        if (priority) {
149
1
            sendpriority = false;
150
1
        } else {
151
0
            return 0;
152
0
        }
153
1
    }
154
155
4.70k
    const uint16_t packet_size = sizeof(uint16_t) + length + CRYPTO_MAC_SIZE;
156
4.70k
    VLA(uint8_t, packet, packet_size);
157
158
4.70k
    uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
159
4.70k
    memcpy(packet, &c_length, sizeof(uint16_t));
160
4.70k
    int len = encrypt_data_symmetric(con->mem, con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
161
162
4.70k
    if ((unsigned int)len != (packet_size - sizeof(uint16_t))) {
163
0
        return -1;
164
0
    }
165
166
4.70k
    if (priority) {
167
605
        len = sendpriority ? net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port,
168
604
                                      con->net_profile) : 0;
169
170
605
        if (len <= 0) {
171
3
            len = 0;
172
3
        }
173
174
605
        increment_nonce(con->sent_nonce);
175
176
605
        if ((unsigned int)len == packet_size) {
177
602
            return 1;
178
602
        }
179
180
3
        return add_priority(con, packet, packet_size, len) ? 1 : 0;
181
605
    }
182
183
4.09k
    len = net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port, con->net_profile);
184
185
4.09k
    if (len <= 0) {
186
7
        return 0;
187
7
    }
188
189
4.09k
    increment_nonce(con->sent_nonce);
190
191
4.09k
    if ((unsigned int)len == packet_size) {
192
4.09k
        return 1;
193
4.09k
    }
194
195
0
    memcpy(con->last_packet, packet, packet_size);
196
0
    con->last_packet_length = packet_size;
197
0
    con->last_packet_sent = len;
198
0
    return 1;
199
4.09k
}
200
201
/** @brief Read length bytes from socket.
202
 *
203
 * return length on success
204
 * return -1 on failure/no data in buffer.
205
 */
206
int read_tcp_packet(
207
    const Logger *logger, const Memory *mem, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port)
208
4.62k
{
209
4.62k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
210
211
4.62k
    if (count < length) {
212
179
        if (count != 0) {
213
            // Only log when there are some bytes available, as empty buffer
214
            // is a very common case and this spams our logs.
215
22
            LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
216
22
        }
217
179
        return -1;
218
179
    }
219
220
4.44k
    const int len = net_recv(ns, logger, sock, data, length, ip_port);
221
222
4.44k
    if (len != length) {
223
0
        LOGGER_ERROR(logger, "FAIL recv packet");
224
0
        return -1;
225
0
    }
226
227
4.44k
    return len;
228
4.44k
}
229
230
/** @brief Read the next two bytes in TCP stream then convert them to
231
 * length (host byte order).
232
 *
233
 * return length on success
234
 * return 0 if nothing has been read from socket.
235
 * return -1 on failure.
236
 */
237
static uint16_t read_tcp_length(const Logger *_Nonnull logger, const Network *_Nonnull ns, Socket sock, const IP_Port *_Nonnull ip_port)
238
28.8k
{
239
28.8k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
240
241
28.8k
    if (count >= sizeof(uint16_t)) {
242
4.31k
        uint8_t length_buf[sizeof(uint16_t)];
243
4.31k
        const int len = net_recv(ns, logger, sock, length_buf, sizeof(length_buf), ip_port);
244
245
4.31k
        if (len != sizeof(uint16_t)) {
246
0
            LOGGER_ERROR(logger, "FAIL recv packet");
247
0
            return 0;
248
0
        }
249
250
4.31k
        uint16_t length;
251
4.31k
        net_unpack_u16(length_buf, &length);
252
253
4.31k
        if (length > MAX_PACKET_SIZE) {
254
0
            LOGGER_ERROR(logger, "TCP packet too large: %d > %d", length, MAX_PACKET_SIZE);
255
0
            return -1;
256
0
        }
257
258
4.31k
        return length;
259
4.31k
    }
260
261
24.5k
    return 0;
262
28.8k
}
263
264
/**
265
 * @return length of received packet on success.
266
 * @retval 0 if could not read any packet.
267
 * @retval -1 on failure (connection must be killed).
268
 */
269
int read_packet_tcp_secure_connection(
270
    const Logger *logger, const Memory *mem, const Network *ns,
271
    Socket sock, uint16_t *next_packet_length,
272
    const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
273
    uint16_t max_len, const IP_Port *ip_port)
274
28.9k
{
275
28.9k
    if (*next_packet_length == 0) {
276
28.8k
        const uint16_t len = read_tcp_length(logger, ns, sock, ip_port);
277
278
28.8k
        if (len == (uint16_t) -1) {
279
0
            return -1;
280
0
        }
281
282
28.8k
        if (len == 0) {
283
24.5k
            return 0;
284
24.5k
        }
285
286
4.31k
        *next_packet_length = len;
287
4.31k
    }
288
289
4.33k
    if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) {
290
0
        LOGGER_DEBUG(logger, "packet too large");
291
0
        return -1;
292
0
    }
293
294
4.33k
    VLA(uint8_t, data_encrypted, (int) *next_packet_length);
295
4.33k
    const int len_packet = read_tcp_packet(logger, mem, ns, sock, data_encrypted, *next_packet_length, ip_port);
296
297
4.33k
    if (len_packet == -1) {
298
18
        return 0;
299
18
    }
300
301
4.31k
    if (len_packet != *next_packet_length) {
302
0
        LOGGER_WARNING(logger, "invalid packet length: %d, expected %d", len_packet, *next_packet_length);
303
0
        return 0;
304
0
    }
305
306
4.31k
    *next_packet_length = 0;
307
308
4.31k
    const int len = decrypt_data_symmetric(mem, shared_key, recv_nonce, data_encrypted, len_packet, data);
309
310
4.31k
    if (len + CRYPTO_MAC_SIZE != len_packet) {
311
0
        LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet);
312
0
        return -1;
313
0
    }
314
315
4.31k
    increment_nonce(recv_nonce);
316
317
4.31k
    return len;
318
4.31k
}