Skip to content

Commit 124ce65

Browse files
committed
test(TCP): Add regression test for TCP priority queue integrity.
This test ensures that multiple priority packets added to a `TCP_Connection` while the socket is busy are correctly queued in the linked list without dropping intermediate packets. Specifically, it protects against regressions where updating the tail pointer incorrectly (e.g., using the head pointer as a base for append) would result in data loss. This was identified as a risk in PR TokTok#2387.
1 parent f94a50d commit 124ce65

3 files changed

Lines changed: 124 additions & 0 deletions

File tree

toxcore/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,21 @@ cc_test(
911911
],
912912
)
913913

914+
cc_test(
915+
name = "TCP_common_test",
916+
size = "small",
917+
srcs = ["TCP_common_test.cc"],
918+
deps = [
919+
":TCP_common",
920+
":crypto_core",
921+
":logger",
922+
":os_memory",
923+
":os_random",
924+
"@com_google_googletest//:gtest",
925+
"@com_google_googletest//:gtest_main",
926+
],
927+
)
928+
914929
cc_library(
915930
name = "net_crypto",
916931
srcs = ["net_crypto.c"],

toxcore/TCP_common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include "network.h"
1919
#include "rng.h"
2020

21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
2125
typedef struct TCP_Priority_List TCP_Priority_List;
2226
struct TCP_Priority_List {
2327
TCP_Priority_List *_Nullable next;
@@ -114,4 +118,8 @@ int read_tcp_packet(const Logger *_Nonnull logger, const Memory *_Nonnull mem, c
114118
int read_packet_tcp_secure_connection(const Logger *_Nonnull logger, const Memory *_Nonnull mem, const Network *_Nonnull ns, Socket sock, uint16_t *_Nonnull next_packet_length,
115119
const uint8_t *_Nonnull shared_key, uint8_t *_Nonnull recv_nonce, uint8_t *_Nonnull data, uint16_t max_len, const IP_Port *_Nonnull ip_port);
116120

121+
#ifdef __cplusplus
122+
} /* extern "C" */
123+
#endif
124+
117125
#endif /* C_TOXCORE_TOXCORE_TCP_COMMON_H */

toxcore/TCP_common_test.cc

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include "TCP_common.h"
2+
3+
#include <gtest/gtest.h>
4+
5+
#include "logger.h"
6+
#include "os_memory.h"
7+
#include "os_random.h"
8+
9+
namespace {
10+
11+
// Mock net_send to simulate a full buffer (returns 0)
12+
// This forces packets into the priority queue.
13+
int mock_send(void *obj, Socket sock, const uint8_t *buf, size_t len)
14+
{
15+
(void)obj;
16+
(void)sock;
17+
(void)buf;
18+
(void)len;
19+
return 0;
20+
}
21+
22+
const Network_Funcs mock_funcs = {
23+
nullptr,
24+
nullptr,
25+
nullptr,
26+
nullptr,
27+
nullptr,
28+
nullptr,
29+
nullptr,
30+
nullptr,
31+
mock_send,
32+
nullptr,
33+
nullptr,
34+
nullptr,
35+
nullptr,
36+
nullptr,
37+
nullptr,
38+
nullptr,
39+
};
40+
41+
TEST(TCP_common, PriorityQueueOrderingAndIntegrity)
42+
{
43+
TCP_Connection con;
44+
memset(&con, 0, sizeof(con));
45+
con.mem = os_memory();
46+
con.rng = os_random();
47+
Network ns = {&mock_funcs, nullptr};
48+
con.ns = &ns;
49+
50+
Logger *logger = logger_new(con.mem);
51+
ASSERT_NE(logger, nullptr);
52+
53+
// Minimal initialization to make write_packet_tcp_secure_connection happy
54+
// It calls encrypt_data_symmetric which needs shared_key and sent_nonce
55+
memset(con.shared_key, 0x42, sizeof(con.shared_key));
56+
memset(con.sent_nonce, 0x12, sizeof(con.sent_nonce));
57+
58+
uint8_t data1[] = "packet1";
59+
uint8_t data2[] = "packet2";
60+
uint8_t data3[] = "packet3";
61+
62+
// First packet: will fail net_send (mocked to 0) and go to add_priority
63+
// Queue: [packet1]
64+
int ret1 = write_packet_tcp_secure_connection(logger, &con, data1, sizeof(data1), true);
65+
ASSERT_EQ(ret1, 1);
66+
ASSERT_NE(con.priority_queue_start, nullptr);
67+
ASSERT_EQ(con.priority_queue_start, con.priority_queue_end);
68+
69+
// Second packet: will go to add_priority
70+
// Queue: [packet1] -> [packet2]
71+
int ret2 = write_packet_tcp_secure_connection(logger, &con, data2, sizeof(data2), true);
72+
ASSERT_EQ(ret2, 1);
73+
ASSERT_NE(con.priority_queue_start->next, nullptr);
74+
ASSERT_EQ(con.priority_queue_start->next, con.priority_queue_end);
75+
76+
// Third packet: will go to add_priority
77+
// WITH BUG: Queue becomes [packet1] -> [packet3], packet2 is LOST
78+
// WITHOUT BUG: Queue: [packet1] -> [packet2] -> [packet3]
79+
int ret3 = write_packet_tcp_secure_connection(logger, &con, data3, sizeof(data3), true);
80+
ASSERT_EQ(ret3, 1);
81+
82+
// Verify integrity
83+
TCP_Priority_List *p = con.priority_queue_start;
84+
int count = 0;
85+
while (p) {
86+
count++;
87+
p = p->next;
88+
}
89+
90+
// This is where it will fail if the change in
91+
// https://github.com/TokTok/c-toxcore/pull/2387 is applied.
92+
// The count will be 2 instead of 3.
93+
EXPECT_EQ(count, 3)
94+
<< "Priority queue lost packets! (likely due to incorrect tail pointer usage)";
95+
96+
// Clean up
97+
wipe_priority_list(con.mem, con.priority_queue_start);
98+
logger_kill(logger);
99+
}
100+
101+
}

0 commit comments

Comments
 (0)