Squashed 'external/toxcore/c-toxcore/' changes from 1828c5356..c9cdae001

c9cdae001 fix(toxav): remove extra copy of video frame on encode
4f6d4546b test: Improve the fake network library.
a2581e700 refactor(toxcore): generate `Friend_Request` and `Dht_Nodes_Response`
2aaa11770 refactor(toxcore): use Tox_Memory in generated events
5c367452b test(toxcore): fix incorrect mutex in tox_scenario_get_time
8f92e710f perf: Add a timed limit of number of cookie requests.
695b6417a test: Add some more simulated network support.
815ae9ce9 test(toxcore): fix thread-safety in scenario framework
6d85c754e test(toxcore): add unit tests for net_crypto
9c22e79cc test(support): add SimulatedEnvironment for deterministic testing
f34fcb195 chore: Update windows Dockerfile to debian stable (trixie).
ece0e8980 fix(group_moderation): allow validating unsorted sanction list signatures
a4fa754d7 refactor: rename struct Packet to struct Net_Packet
d6f330f85 cleanup: Fix some warnings from coverity.
e206bffa2 fix(group_chats): fix sync packets reverting topics
0e4715598 test: Add new scenario testing framework.
668291f44 refactor(toxcore): decouple Network_Funcs from sockaddr via IP_Port
fc4396cef fix: potential division by zero in toxav and unsafe hex parsing
8e8b352ab refactor: Add nullable annotations to struct members.
7740bb421 refactor: decouple net_crypto from DHT
1936d4296 test: add benchmark for toxav audio and video
46bfdc2df fix: correct printf format specifiers for unsigned integers
REVERT: 1828c5356 fix(toxav): remove extra copy of video frame on encode

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: c9cdae001341e701fca980c9bb9febfeb95d2902
This commit is contained in:
Green Sky
2026-01-11 14:42:31 +01:00
parent e95f2cbb1c
commit 565efa4f39
328 changed files with 19057 additions and 13982 deletions

View File

@@ -26,8 +26,8 @@ cc_test(
srcs = ["test_util_test.cc"],
deps = [
":crypto_core",
":crypto_core_test_util",
":test_util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -118,19 +118,6 @@ cc_library(
],
)
cc_library(
name = "mem_test_util",
testonly = True,
srcs = ["mem_test_util.cc"],
hdrs = ["mem_test_util.hh"],
deps = [
":mem",
":os_memory",
":test_util",
":tox_memory",
],
)
cc_test(
name = "mem_test",
size = "small",
@@ -326,8 +313,8 @@ cc_test(
deps = [
":crypto_core",
":crypto_core_test_util",
":mem_test_util",
":util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -373,7 +360,7 @@ cc_library(
srcs = ["mono_time.c"],
hdrs = ["mono_time.h"],
visibility = [
"//c-toxcore/auto_tests:__pkg__",
"//c-toxcore/auto_tests:__subpackages__",
"//c-toxcore/other:__pkg__",
"//c-toxcore/other/bootstrap_daemon:__pkg__",
"//c-toxcore/testing:__pkg__",
@@ -388,13 +375,25 @@ cc_library(
],
)
cc_library(
name = "mono_time_test_util",
testonly = True,
srcs = ["mono_time_test_util.cc"],
hdrs = ["mono_time_test_util.hh"],
deps = [
":mono_time",
"//c-toxcore/testing/support",
],
)
cc_test(
name = "mono_time_test",
size = "small",
srcs = ["mono_time_test.cc"],
deps = [
":mem_test_util",
":mono_time",
":mono_time_test_util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -448,10 +447,11 @@ cc_library(
"network.h",
],
visibility = [
"//c-toxcore/auto_tests:__pkg__",
"//c-toxcore/auto_tests:__subpackages__",
"//c-toxcore/other:__pkg__",
"//c-toxcore/other/bootstrap_daemon:__pkg__",
"//c-toxcore/testing/fuzzing:__pkg__",
"//c-toxcore/testing/support:__pkg__",
"//c-toxcore/toxav:__pkg__",
],
deps = [
@@ -490,6 +490,7 @@ cc_test(
deps = [
":network",
":network_test_util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -527,9 +528,9 @@ cc_test(
srcs = ["ping_array_test.cc"],
deps = [
":crypto_core_test_util",
":mem_test_util",
":mono_time",
":ping_array",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -597,9 +598,13 @@ cc_library(
":DHT",
":crypto_core",
":crypto_core_test_util",
":logger",
":mono_time",
":net_crypto",
":network",
":network_test_util",
":test_util",
"//c-toxcore/testing/support",
],
)
@@ -613,11 +618,11 @@ cc_test(
":crypto_core",
":crypto_core_test_util",
":logger",
":mem_test_util",
":mono_time",
":network",
":network_test_util",
":test_util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -631,9 +636,8 @@ cc_fuzz_test(
corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"],
deps = [
":DHT",
":mem_test_util",
":net_profile",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/support",
],
)
@@ -689,8 +693,7 @@ cc_fuzz_test(
corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
deps = [
":forwarding",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/fuzzing:fuzz_tox",
"//c-toxcore/testing/support",
],
)
@@ -821,6 +824,25 @@ cc_test(
],
)
cc_test(
name = "TCP_client_test",
size = "small",
srcs = ["TCP_client_test.cc"],
deps = [
":TCP_client",
":TCP_common",
":crypto_core",
":logger",
":mono_time",
":net_profile",
":network",
":util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "net_crypto",
srcs = ["net_crypto.c"],
@@ -848,6 +870,44 @@ cc_library(
],
)
cc_test(
name = "net_crypto_test",
size = "small",
srcs = ["net_crypto_test.cc"],
deps = [
":DHT_test_util",
":crypto_core",
":logger",
":mono_time",
":net_crypto",
":net_profile",
":network",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "friend_connection_test",
size = "small",
srcs = ["friend_connection_test.cc"],
deps = [
":DHT_test_util",
":crypto_core",
":friend_connection",
":logger",
":mono_time",
":net_crypto",
":net_profile",
":network",
":onion_client",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_fuzz_test(
name = "net_crypto_fuzz_test",
size = "small",
@@ -857,12 +917,10 @@ cc_fuzz_test(
deps = [
":DHT",
":TCP_client",
":mem_test_util",
":net_crypto",
":net_profile",
":network",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/fuzzing:fuzz_tox",
"//c-toxcore/testing/support",
],
)
@@ -925,9 +983,10 @@ cc_test(
":crypto_core",
":group_announce",
":logger",
":mem_test_util",
":mono_time",
":mono_time_test_util",
":network",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -941,8 +1000,7 @@ cc_fuzz_test(
corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
deps = [
":group_announce",
":mem_test_util",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/support",
],
)
@@ -984,6 +1042,7 @@ cc_library(
":crypto_core",
":group_announce",
":group_onion_announce",
":list",
":logger",
":mem",
":mono_time",
@@ -998,6 +1057,42 @@ cc_library(
],
)
cc_test(
name = "onion_client_test",
size = "small",
srcs = ["onion_client_test.cc"],
deps = [
":DHT_test_util",
":crypto_core",
":logger",
":mono_time",
":net_crypto",
":net_profile",
":network",
":onion",
":onion_announce",
":onion_client",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_fuzz_test(
name = "onion_client_fuzz_test",
size = "small",
testonly = True,
srcs = ["onion_client_fuzz_test.cc"],
# corpus = ["//tools/toktok-fuzzer/corpus:onion_client_fuzz_test"],
deps = [
":DHT",
":net_crypto",
":net_profile",
":onion_client",
"//c-toxcore/testing/support",
],
)
cc_library(
name = "friend_connection",
srcs = ["friend_connection.c"],
@@ -1073,8 +1168,8 @@ cc_test(
":crypto_core_test_util",
":group_moderation",
":logger",
":mem_test_util",
":util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -1088,8 +1183,7 @@ cc_fuzz_test(
corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
deps = [
":group_moderation",
":mem_test_util",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/support",
],
)
@@ -1242,6 +1336,7 @@ cc_test(
":tox",
":tox_log_level",
":tox_options",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -1309,6 +1404,7 @@ cc_test(
":crypto_core",
":tox",
":tox_events",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@@ -1322,7 +1418,7 @@ cc_fuzz_test(
deps = [
":tox_dispatch",
":tox_events",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/support",
],
)

View File

@@ -56,8 +56,8 @@
#define KEYS_TIMEOUT 600
typedef struct DHT_Friend_Callback {
dht_ip_cb *ip_callback;
void *data;
dht_ip_cb *_Nullable ip_callback;
void *_Nullable data;
int32_t number;
} DHT_Friend_Callback;
@@ -87,17 +87,17 @@ const Node_format empty_node_format = {{0}};
static_assert(sizeof(empty_dht_friend.lock_flags) * 8 == DHT_FRIEND_MAX_LOCKS, "Bitfield size and number of locks don't match");
typedef struct Cryptopacket_Handler {
cryptopacket_handler_cb *function;
void *object;
cryptopacket_handler_cb *_Nullable function;
void *_Nullable object;
} Cryptopacket_Handler;
struct DHT {
const Logger *log;
const Network *ns;
Mono_Time *mono_time;
const Memory *mem;
const Random *rng;
Networking_Core *net;
const Logger *_Nonnull log;
const Network *_Nonnull ns;
Mono_Time *_Nonnull mono_time;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
Networking_Core *_Nonnull net;
bool hole_punching_enabled;
bool lan_discovery_enabled;
@@ -110,18 +110,18 @@ struct DHT {
uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
DHT_Friend *friends_list;
DHT_Friend *_Nullable friends_list;
uint16_t num_friends;
Node_format *loaded_nodes_list;
Node_format *_Nullable loaded_nodes_list;
uint32_t loaded_num_nodes;
unsigned int loaded_nodes_index;
Shared_Key_Cache *shared_keys_recv;
Shared_Key_Cache *shared_keys_sent;
Shared_Key_Cache *_Nonnull shared_keys_recv;
Shared_Key_Cache *_Nonnull shared_keys_sent;
struct Ping *ping;
Ping_Array *dht_ping_array;
struct Ping *_Nonnull ping;
Ping_Array *_Nonnull dht_ping_array;
uint64_t cur_time;
Cryptopacket_Handler cryptopackethandlers[256];
@@ -129,7 +129,7 @@ struct DHT {
Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];
unsigned int num_to_bootstrap;
dht_nodes_response_cb *nodes_response_callback;
dht_nodes_response_cb *_Nullable nodes_response_callback;
};
const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend)
@@ -855,9 +855,9 @@ static bool store_node_ok(const Client_data *_Nonnull client, uint64_t cur_time,
}
typedef struct Client_data_Cmp {
const Memory *mem;
const Memory *_Nonnull mem;
uint64_t cur_time;
const uint8_t *comp_public_key;
const uint8_t *_Nonnull comp_public_key;
} Client_data_Cmp;
static int client_data_cmp(const Client_data_Cmp *_Nonnull cmp, const Client_data *_Nonnull entry1, const Client_data *_Nonnull entry2)
@@ -2019,7 +2019,7 @@ static uint32_t foreach_ip_port(const DHT *_Nonnull dht, const DHT_Friend *_Nonn
static bool send_packet_to_friend(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, uint32_t *_Nonnull n, void *_Nonnull userdata)
{
const Packet *packet = (const Packet *)userdata;
const Net_Packet *packet = (const Net_Packet *)userdata;
const int retval = net_send_packet(dht->net, ip_port, *packet);
if ((uint32_t)retval == packet->length) {
@@ -2037,7 +2037,7 @@ static bool send_packet_to_friend(const DHT *_Nonnull dht, const IP_Port *_Nonnu
* @return ip for friend.
* @return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
*/
uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet *packet)
uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Net_Packet *packet)
{
const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
@@ -2053,7 +2053,7 @@ uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet
}
const DHT_Friend *const dht_friend = &dht->friends_list[num];
Packet packet_userdata = *packet; // Copy because it needs to be non-const.
Net_Packet packet_userdata = *packet; // Copy because it needs to be non-const.
return foreach_ip_port(dht, dht_friend, send_packet_to_friend, &packet_userdata);
}
@@ -2070,7 +2070,7 @@ static bool get_ip_port(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port
*
* @return number of nodes the packet was sent to.
*/
static uint32_t routeone_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Packet *_Nonnull packet)
static uint32_t routeone_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Net_Packet *_Nonnull packet)
{
const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
@@ -2119,7 +2119,7 @@ static int send_nat_ping(const DHT *_Nonnull dht, const uint8_t *_Nonnull public
assert(len <= UINT16_MAX);
uint32_t num = 0;
const Packet packet = {packet_data, (uint16_t)len};
const Net_Packet packet = {packet_data, (uint16_t)len};
if (type == 0) { /* If packet is request use many people to route it. */
num = route_to_friend(dht, public_key, &packet);
@@ -2515,14 +2515,16 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
dht->hole_punching_enabled = hole_punching_enabled;
dht->lan_discovery_enabled = lan_discovery_enabled;
dht->ping = ping_new(mem, mono_time, rng, dht, net);
struct Ping *temp_ping = ping_new(mem, mono_time, rng, dht, net);
if (dht->ping == nullptr) {
if (temp_ping == nullptr) {
LOGGER_ERROR(log, "failed to initialise ping");
kill_dht(dht);
return nullptr;
}
dht->ping = temp_ping;
networking_registerhandler(dht->net, NET_PACKET_NODES_REQUEST, &handle_nodes_request, dht);
networking_registerhandler(dht->net, NET_PACKET_NODES_RESPONSE, &handle_nodes_response, dht);
networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht);
@@ -2535,23 +2537,36 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
crypto_new_keypair(rng, dht->self_public_key, dht->self_secret_key);
dht->shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
dht->shared_keys_sent = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
Shared_Key_Cache *const temp_shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (dht->shared_keys_recv == nullptr || dht->shared_keys_sent == nullptr) {
if (temp_shared_keys_recv == nullptr) {
LOGGER_ERROR(log, "failed to initialise shared key cache");
kill_dht(dht);
return nullptr;
}
dht->dht_ping_array = ping_array_new(mem, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
dht->shared_keys_recv = temp_shared_keys_recv;
if (dht->dht_ping_array == nullptr) {
Shared_Key_Cache *const temp_shared_keys_sent = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (temp_shared_keys_sent == nullptr) {
LOGGER_ERROR(log, "failed to initialise shared key cache");
kill_dht(dht);
return nullptr;
}
dht->shared_keys_sent = temp_shared_keys_sent;
Ping_Array *const temp_ping_array = ping_array_new(mem, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
if (temp_ping_array == nullptr) {
LOGGER_ERROR(log, "failed to initialise ping array");
kill_dht(dht);
return nullptr;
}
dht->dht_ping_array = temp_ping_array;
for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {
uint8_t random_public_key_bytes[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t random_secret_key_bytes[CRYPTO_SECRET_KEY_SIZE];

View File

@@ -212,7 +212,7 @@ int unpack_nodes(Node_format *_Nonnull nodes, uint16_t max_num_nodes, uint16_t *
uint16_t length, bool tcp_enabled);
/*----------------------------------------------------------------------------------*/
typedef int cryptopacket_handler_cb(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull source_pubkey,
typedef int cryptopacket_handler_cb(void *_Nullable object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull source_pubkey,
const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata);
typedef struct DHT DHT;
@@ -398,7 +398,7 @@ int route_packet(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, co
* @return ip for friend.
* @return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
*/
uint32_t route_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Packet *_Nonnull packet);
uint32_t route_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Net_Packet *_Nonnull packet);
/** Function to handle crypto packets. */
void cryptopacket_registerhandler(DHT *_Nonnull dht, uint8_t byte, cryptopacket_handler_cb *_Nullable cb, void *_Nullable object);

View File

@@ -5,14 +5,18 @@
#include <cstring>
#include <vector>
#include "../testing/fuzzing/fuzz_support.hh"
#include "mem_test_util.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/simulated_environment.hh"
namespace {
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
void TestHandleRequest(Fuzz_Data &input)
{
const Test_Memory mem;
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
CONSUME_OR_RETURN(const uint8_t *self_public_key, input, CRYPTO_PUBLIC_KEY_SIZE);
CONSUME_OR_RETURN(const uint8_t *self_secret_key, input, CRYPTO_SECRET_KEY_SIZE);
@@ -20,7 +24,7 @@ void TestHandleRequest(Fuzz_Data &input)
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t request[MAX_CRYPTO_REQUEST_SIZE];
uint8_t request_id;
handle_request(mem, self_public_key, self_secret_key, public_key, request, &request_id,
handle_request(&c_mem, self_public_key, self_secret_key, public_key, request, &request_id,
input.data(), input.size());
}
@@ -34,8 +38,9 @@ void TestUnpackNodes(Fuzz_Data &input)
const int packed_count = unpack_nodes(
nodes, node_count, &processed_data_len, input.data(), input.size(), tcp_enabled);
if (packed_count > 0) {
const Memory *mem = os_memory();
Logger *logger = logger_new(mem);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Logger *logger = logger_new(&c_mem);
std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
const int packed_size
= pack_nodes(logger, packed.data(), packed.size(), nodes, packed_count);
@@ -63,6 +68,6 @@ void TestUnpackNodes(Fuzz_Data &input)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
fuzz_select_target<TestHandleRequest, TestUnpackNodes>(data, size);
tox::test::fuzz_select_target<TestHandleRequest, TestUnpackNodes>(data, size);
return 0;
}

View File

@@ -8,11 +8,11 @@
#include <cstring>
#include <random>
#include "../testing/support/public/simulated_environment.hh"
#include "DHT_test_util.hh"
#include "crypto_core.h"
#include "crypto_core_test_util.hh"
#include "logger.h"
#include "mem_test_util.hh"
#include "mono_time.h"
#include "network.h"
#include "network_test_util.hh"
@@ -25,6 +25,7 @@ using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::PrintToString;
using ::testing::UnorderedElementsAre;
using namespace tox::test;
using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
@@ -37,13 +38,14 @@ struct KeyPair {
TEST(IdClosest, KeyIsClosestToItself)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
PublicKey pk0 = random_pk(rng);
PublicKey pk0 = random_pk(&c_rng);
PublicKey pk1;
do {
// Get a random key that's not the same as pk0.
pk1 = random_pk(rng);
pk1 = random_pk(&c_rng);
} while (pk0 == pk1);
EXPECT_EQ(id_closest(pk0.data(), pk0.data(), pk1.data()), 1);
@@ -51,21 +53,23 @@ TEST(IdClosest, KeyIsClosestToItself)
TEST(IdClosest, IdenticalKeysAreSameDistance)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
PublicKey pk0 = random_pk(rng);
PublicKey pk1 = random_pk(rng);
PublicKey pk0 = random_pk(&c_rng);
PublicKey pk1 = random_pk(&c_rng);
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk1.data()), 0);
}
TEST(IdClosest, DistanceIsCommutative)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
PublicKey pk0 = random_pk(rng);
PublicKey pk1 = random_pk(rng);
PublicKey pk2 = random_pk(rng);
PublicKey pk0 = random_pk(&c_rng);
PublicKey pk1 = random_pk(&c_rng);
PublicKey pk2 = random_pk(&c_rng);
ASSERT_NE(pk1, pk2); // RNG can't produce the same random key twice
@@ -147,17 +151,18 @@ Node_format fill(Node_format v, PublicKey const &pk, IP_Port const &ip_port)
TEST(AddToList, AddsFirstKeysInOrder)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
// Make cmp_key the furthest away from 00000... as possible, so all initial inserts succeed.
PublicKey const cmp_pk{0xff, 0xff, 0xff, 0xff};
// Generate a bunch of other keys, sorted by distance from cmp_pk.
auto const keys
= sorted(array_of<20>(random_pk, rng), [&cmp_pk](auto const &pk1, auto const &pk2) {
= sorted(array_of<20>(random_pk, &c_rng), [&cmp_pk](auto const &pk1, auto const &pk2) {
return id_closest(cmp_pk.data(), pk1.data(), pk2.data()) == 1;
});
auto const ips = array_of<20>(increasing_ip_port(0, rng));
auto const ips = array_of<20>(increasing_ip_port(0, &c_rng));
std::vector<Node_format> nodes(4);
@@ -199,7 +204,7 @@ TEST(AddToList, AddsFirstKeysInOrder)
<< " nodes_list = " << PrintToString(nodes);
// Now shuffle each time we add a node, which should work fine.
std::mt19937 mt_rng;
std::minstd_rand mt_rng;
// Adding one that's closer will happen.
std::shuffle(nodes.begin(), nodes.end(), mt_rng);
@@ -249,16 +254,17 @@ TEST(AddToList, AddsFirstKeysInOrder)
TEST(AddToList, KeepsKeysInOrder)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
// Any random cmp_pk should work, as well as the smallest or (approximately) largest pk.
for (PublicKey const cmp_pk : {random_pk(rng), PublicKey{0x00}, PublicKey{0xff, 0xff}}) {
for (PublicKey const cmp_pk : {random_pk(&c_rng), PublicKey{0x00}, PublicKey{0xff, 0xff}}) {
auto const by_distance = [&cmp_pk](auto const &node1, auto const &node2) {
return id_closest(cmp_pk.data(), node1.public_key, node2.public_key) == 1;
};
// Generate a bunch of other keys, not sorted.
auto const nodes = vector_of(16, random_node_format, rng);
auto const nodes = vector_of(16, random_node_format, &c_rng);
std::vector<Node_format> node_list(4);
@@ -274,12 +280,13 @@ TEST(AddToList, KeepsKeysInOrder)
TEST(Request, CreateAndParse)
{
Test_Memory mem;
Test_Random rng;
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
auto c_rng = env.fake_random().get_c_random();
// Peers.
const KeyPair sender(rng);
const KeyPair receiver(rng);
const KeyPair sender(&c_rng);
const KeyPair receiver(&c_rng);
const uint8_t sent_pkt_id = CRYPTO_PACKET_FRIEND_REQ;
// Encoded packet.
@@ -292,33 +299,33 @@ TEST(Request, CreateAndParse)
// Request data: maximum payload is 918 bytes, so create a payload 1 byte larger than max.
std::vector<uint8_t> outgoing(919);
random_bytes(rng, outgoing.data(), outgoing.size());
random_bytes(&c_rng, outgoing.data(), outgoing.size());
EXPECT_LT(create_request(mem, rng, sender.pk.data(), sender.sk.data(), packet.data(),
EXPECT_LT(create_request(&c_mem, &c_rng, sender.pk.data(), sender.sk.data(), packet.data(),
receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id),
0);
// Pop one element so the payload is 918 bytes. Packing should now succeed.
outgoing.pop_back();
const int max_sent_length = create_request(mem, rng, sender.pk.data(), sender.sk.data(),
const int max_sent_length = create_request(&c_mem, &c_rng, sender.pk.data(), sender.sk.data(),
packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id);
ASSERT_GT(max_sent_length, 0); // success.
// Check that handle_request rejects packets larger than the maximum created packet size.
EXPECT_LT(handle_request(mem, receiver.pk.data(), receiver.sk.data(), pk.data(),
EXPECT_LT(handle_request(&c_mem, receiver.pk.data(), receiver.sk.data(), pk.data(),
incoming.data(), &recvd_pkt_id, packet.data(), max_sent_length + 1),
0);
// Now try all possible packet sizes from max (918) to 0.
while (!outgoing.empty()) {
// Pack:
const int sent_length = create_request(mem, rng, sender.pk.data(), sender.sk.data(),
const int sent_length = create_request(&c_mem, &c_rng, sender.pk.data(), sender.sk.data(),
packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id);
ASSERT_GT(sent_length, 0);
// Unpack:
const int recvd_length = handle_request(mem, receiver.pk.data(), receiver.sk.data(),
const int recvd_length = handle_request(&c_mem, receiver.pk.data(), receiver.sk.data(),
pk.data(), incoming.data(), &recvd_pkt_id, packet.data(), sent_length);
ASSERT_GE(recvd_length, 0);
@@ -331,24 +338,40 @@ TEST(Request, CreateAndParse)
TEST(AnnounceNodes, SetAndTest)
{
Test_Random rng;
Test_Memory mem;
Test_Network ns;
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
auto c_rng = env.fake_random().get_c_random();
Logger *log = logger_new(mem);
// Use FakeNetwork instead of Test_Network (which wrapped os_network)
// Create endpoint bound to virtual port
auto node = env.create_node(33445);
struct Network net_struct = node->c_network;
Logger *log = logger_new(&c_mem);
ASSERT_NE(log, nullptr);
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
Mono_Time *mono_time = mono_time_new(&c_mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
Ptr<Networking_Core> net(new_networking_no_udp(log, mem, ns));
// Hook up simulation clock to mono_time
mono_time_set_current_time_callback(
mono_time,
[](void *user_data) -> uint64_t {
auto *clock = static_cast<FakeClock *>(user_data);
return clock->current_time_ms();
},
&env.fake_clock());
Ptr<Networking_Core> net(new_networking_no_udp(log, &c_mem, &net_struct));
ASSERT_NE(net, nullptr);
Ptr<DHT> dht(new_dht(log, mem, rng, ns, mono_time, net.get(), true, true));
Ptr<DHT> dht(new_dht(log, &c_mem, &c_rng, &net_struct, mono_time, net.get(), true, true));
ASSERT_NE(dht, nullptr);
uint8_t pk_data[CRYPTO_PUBLIC_KEY_SIZE];
memcpy(pk_data, dht_get_self_public_key(dht.get()), sizeof(pk_data));
PublicKey self_pk(to_array(pk_data));
PublicKey pk1 = random_pk(rng);
PublicKey pk1 = random_pk(&c_rng);
ASSERT_NE(pk1, self_pk);
// Test with maximally close key to self
@@ -373,7 +396,7 @@ TEST(AnnounceNodes, SetAndTest)
EXPECT_EQ(
2, get_close_nodes(dht.get(), self_pk.data(), nodes, net_family_unspec(), true, true));
mono_time_free(mem, mono_time);
mono_time_free(&c_mem, mono_time);
logger_kill(log);
}

View File

@@ -1,14 +1,156 @@
#include "DHT_test_util.hh"
#include <cassert>
#include <cstring>
#include <iomanip>
#include "../testing/support/public/simulated_environment.hh"
#include "DHT.h"
#include "crypto_core.h"
#include "crypto_core_test_util.hh"
#include "network.h"
#include "network_test_util.hh"
using tox::test::FakeClock;
// --- Mock DHT Implementation ---
MockDHT::MockDHT(const Random *rng) { crypto_new_keypair(rng, self_public_key, self_secret_key); }
const uint8_t *MockDHT::get_shared_key(const uint8_t *pk)
{
std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE> pk_arr;
std::copy(pk, pk + CRYPTO_PUBLIC_KEY_SIZE, pk_arr.begin());
auto it = shared_keys.find(pk_arr);
if (it != shared_keys.end()) {
return it->second.data();
}
++computation_count;
// Compute new shared key
std::array<uint8_t, CRYPTO_SHARED_KEY_SIZE> sk;
encrypt_precompute(pk, self_secret_key, sk.data());
shared_keys[pk_arr] = sk;
return shared_keys[pk_arr].data();
}
const Net_Crypto_DHT_Funcs MockDHT::funcs = {
[](void *obj, const uint8_t *public_key) {
return static_cast<MockDHT *>(obj)->get_shared_key(public_key);
},
[](const void *obj) { return static_cast<const MockDHT *>(obj)->self_public_key; },
[](const void *obj) { return static_cast<const MockDHT *>(obj)->self_secret_key; },
};
// --- WrappedMockDHT Implementation ---
WrappedMockDHT::WrappedMockDHT(tox::test::SimulatedEnvironment &env, uint16_t port)
: node_(env.create_node(0))
, logger_(logger_new(&node_->c_memory), [](Logger *l) { logger_kill(l); })
, mono_time_(mono_time_new(
&node_->c_memory,
[](void *ud) -> uint64_t {
return static_cast<tox::test::FakeClock *>(ud)->current_time_ms();
},
&env.fake_clock()),
[mem = &node_->c_memory](Mono_Time *t) { mono_time_free(mem, t); })
, networking_(nullptr, [](Networking_Core *n) { kill_networking(n); })
, dht_(&node_->c_random)
{
// Setup Networking
IP ip;
ip_init(&ip, false);
unsigned int error = 0;
networking_.reset(new_networking_ex(
logger_.get(), &node_->c_memory, &node_->c_network, &ip, port, port + 1, &error));
assert(error == 0);
node_->endpoint = node_->node->get_primary_socket();
assert(node_->endpoint != nullptr);
assert(node_->endpoint->local_port() == port);
}
WrappedMockDHT::~WrappedMockDHT() = default;
IP_Port WrappedMockDHT::get_ip_port() const
{
IP_Port ip_port;
ip_port.ip = node_->node->ip;
ip_port.port = net_htons(node_->endpoint->local_port());
return ip_port;
}
void WrappedMockDHT::poll()
{
mono_time_update(mono_time_.get());
networking_poll(networking_.get(), nullptr);
}
const Net_Crypto_DHT_Funcs WrappedMockDHT::funcs = MockDHT::funcs;
// --- WrappedDHT Implementation ---
WrappedDHT::WrappedDHT(tox::test::SimulatedEnvironment &env, uint16_t port)
: node_(env.create_node(0))
, logger_(logger_new(&node_->c_memory), [](Logger *l) { logger_kill(l); })
, mono_time_(
mono_time_new(
&node_->c_memory,
[](void *ud) -> uint64_t { return static_cast<FakeClock *>(ud)->current_time_ms(); },
&env.fake_clock()),
[mem = &node_->c_memory](Mono_Time *t) { mono_time_free(mem, t); })
, networking_(nullptr, [](Networking_Core *n) { kill_networking(n); })
, dht_(nullptr, [](DHT *d) { kill_dht(d); })
{
// Setup Networking
IP ip;
ip_init(&ip, false);
unsigned int error = 0;
networking_.reset(new_networking_ex(
logger_.get(), &node_->c_memory, &node_->c_network, &ip, port, port + 1, &error));
assert(error == 0);
node_->endpoint = node_->node->get_primary_socket();
assert(node_->endpoint != nullptr);
assert(node_->endpoint->local_port() == port);
// Setup DHT
dht_.reset(new_dht(logger_.get(), &node_->c_memory, &node_->c_random, &node_->c_network,
mono_time_.get(), networking_.get(), true, true));
}
WrappedDHT::~WrappedDHT() = default;
const uint8_t *WrappedDHT::dht_public_key() const { return dht_get_self_public_key(dht_.get()); }
const uint8_t *WrappedDHT::dht_secret_key() const { return dht_get_self_secret_key(dht_.get()); }
IP_Port WrappedDHT::get_ip_port() const
{
IP_Port ip_port;
ip_port.ip = node_->node->ip;
ip_port.port = net_htons(node_->endpoint->local_port());
return ip_port;
}
void WrappedDHT::poll()
{
mono_time_update(mono_time_.get());
networking_poll(networking_.get(), nullptr);
do_dht(dht_.get());
}
const Net_Crypto_DHT_Funcs WrappedDHT::funcs = {
[](void *obj, const uint8_t *public_key) {
return dht_get_shared_key_sent(static_cast<DHT *>(obj), public_key);
},
[](const void *obj) { return dht_get_self_public_key(static_cast<const DHT *>(obj)); },
[](const void *obj) { return dht_get_self_secret_key(static_cast<const DHT *>(obj)); },
};
// --- Test Util Functions ---
Node_format random_node_format(const Random *rng)
{
Node_format node;

View File

@@ -1,12 +1,25 @@
#ifndef C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H
#define C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H
#include <array>
#include <functional>
#include <iosfwd>
#include <map>
#include <memory>
#include <vector>
#include "DHT.h"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net_crypto.h"
#include "test_util.hh"
namespace tox::test {
class SimulatedEnvironment;
struct ScopedToxSystem;
}
template <>
struct Deleter<DHT> : Function_Deleter<DHT, kill_dht> { };
@@ -16,4 +29,88 @@ std::ostream &operator<<(std::ostream &out, Node_format const &v);
Node_format random_node_format(const Random *rng);
// --- Mock DHT ---
struct MockDHT {
uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
// Cache for shared keys: Public Key -> Shared Key
std::map<std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>,
std::array<uint8_t, CRYPTO_SHARED_KEY_SIZE>>
shared_keys;
int computation_count = 0;
explicit MockDHT(const Random *rng);
const uint8_t *get_shared_key(const uint8_t *pk);
static const Net_Crypto_DHT_Funcs funcs;
};
// --- Mock DHT Wrapper ---
// Wraps a MockDHT instance and its dependencies (networking, etc.) within a SimulatedEnvironment
class WrappedMockDHT {
public:
WrappedMockDHT(tox::test::SimulatedEnvironment &env, uint16_t port);
MockDHT *get_dht() { return &dht_; }
const uint8_t *dht_public_key() const { return dht_.self_public_key; }
const uint8_t *dht_secret_key() const { return dht_.self_secret_key; }
int dht_computation_count() const { return dht_.computation_count; }
// Returns a valid IP_Port for this node in the simulation (Localhost IPv6)
IP_Port get_ip_port() const;
void poll();
tox::test::ScopedToxSystem &node() { return *node_; }
const tox::test::ScopedToxSystem &node() const { return *node_; }
Networking_Core *networking() { return networking_.get(); }
Mono_Time *mono_time() { return mono_time_.get(); }
Logger *logger() { return logger_.get(); }
~WrappedMockDHT();
static const Net_Crypto_DHT_Funcs funcs;
private:
std::unique_ptr<tox::test::ScopedToxSystem> node_;
std::unique_ptr<Logger, void (*)(Logger *)> logger_;
std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time_;
std::unique_ptr<Networking_Core, void (*)(Networking_Core *)> networking_;
MockDHT dht_;
};
// --- Real DHT Wrapper ---
// Wraps a DHT instance and its dependencies within a SimulatedEnvironment
class WrappedDHT {
public:
WrappedDHT(tox::test::SimulatedEnvironment &env, uint16_t port);
DHT *get_dht() { return dht_.get(); }
const uint8_t *dht_public_key() const;
const uint8_t *dht_secret_key() const;
// Returns a valid IP_Port for this node in the simulation (Localhost IPv6)
IP_Port get_ip_port() const;
void poll();
tox::test::ScopedToxSystem &node() { return *node_; }
const tox::test::ScopedToxSystem &node() const { return *node_; }
Networking_Core *networking() { return networking_.get(); }
Mono_Time *mono_time() { return mono_time_.get(); }
Logger *logger() { return logger_.get(); }
~WrappedDHT();
static const Net_Crypto_DHT_Funcs funcs;
private:
std::unique_ptr<tox::test::ScopedToxSystem> node_;
std::unique_ptr<Logger, void (*)(Logger *)> logger_;
std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time_;
std::unique_ptr<Networking_Core, void (*)(Networking_Core *)> networking_;
std::unique_ptr<DHT, void (*)(DHT *)> dht_;
};
#endif // C_TOXCORE_TOXCORE_DHT_TEST_UTIL_H

View File

@@ -47,6 +47,30 @@ static_assert(MAX_CONCURRENT_FILE_PIPES <= UINT8_MAX + 1,
static const Friend empty_friend = {{0}};
static const uint8_t *_Nullable nc_dht_get_shared_key_sent_wrapper(void *_Nonnull obj, const uint8_t *_Nonnull public_key)
{
DHT *dht = (DHT *)obj;
return dht_get_shared_key_sent(dht, public_key);
}
static const uint8_t *_Nonnull nc_dht_get_self_public_key_wrapper(const void *_Nonnull obj)
{
const DHT *dht = (const DHT *)obj;
return dht_get_self_public_key(dht);
}
static const uint8_t *_Nonnull nc_dht_get_self_secret_key_wrapper(const void *_Nonnull obj)
{
const DHT *dht = (const DHT *)obj;
return dht_get_self_secret_key(dht);
}
static const Net_Crypto_DHT_Funcs m_dht_funcs = {
nc_dht_get_shared_key_sent_wrapper,
nc_dht_get_self_public_key_wrapper,
nc_dht_get_self_secret_key_wrapper,
};
/**
* Determines if the friendnumber passed is valid in the Messenger object.
*
@@ -1555,7 +1579,7 @@ int send_file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber
* @return true if there's still work to do, false otherwise.
*
*/
static bool do_all_filetransfers(Messenger *_Nonnull m, int32_t friendnumber, void *_Nonnull userdata, uint32_t *_Nonnull free_slots)
static bool do_all_filetransfers(Messenger *_Nonnull m, int32_t friendnumber, void *_Nullable userdata, uint32_t *_Nonnull free_slots)
{
Friend *const friendcon = &m->friendlist[friendnumber];
@@ -3374,21 +3398,24 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->mem = mem;
m->rng = rng;
m->ns = ns;
m->forwarding = nullptr;
m->announce = nullptr;
m->tcp_server = nullptr;
m->fr = friendreq_new(mem);
if (m->fr == nullptr) {
Friend_Requests *fr = friendreq_new(mem);
if (fr == nullptr) {
mem_delete(mem, m);
return nullptr;
}
m->fr = fr;
m->log = logger_new(mem);
if (m->log == nullptr) {
Logger *log = logger_new(mem);
if (log == nullptr) {
friendreq_kill(m->fr);
mem_delete(mem, m);
return nullptr;
}
m->log = log;
logger_callback_log(m->log, options->log_callback, options->log_context, options->log_user_data);
@@ -3400,15 +3427,16 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
options->udp_disabled = true;
}
Networking_Core *net;
if (options->udp_disabled) {
m->net = new_networking_no_udp(m->log, m->mem, m->ns);
net = new_networking_no_udp(m->log, m->mem, m->ns);
} else {
IP ip;
ip_init(&ip, options->ipv6enabled);
m->net = new_networking_ex(m->log, m->mem, m->ns, &ip, options->port_range[0], options->port_range[1], &net_err);
net = new_networking_ex(m->log, m->mem, m->ns, &ip, options->port_range[0], options->port_range[1], &net_err);
}
if (m->net == nullptr) {
if (net == nullptr) {
friendreq_kill(m->fr);
if (error != nullptr && net_err == 1) {
@@ -3420,20 +3448,20 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->net = net;
m->dht = new_dht(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, options->hole_punching_enabled, options->local_discovery_enabled);
if (m->dht == nullptr) {
DHT *dht = new_dht(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, options->hole_punching_enabled, options->local_discovery_enabled);
if (dht == nullptr) {
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m);
return nullptr;
}
m->dht = dht;
m->tcp_np = netprof_new(m->log, mem);
if (m->tcp_np == nullptr) {
Net_Profile *tcp_np = netprof_new(m->log, mem);
if (tcp_np == nullptr) {
LOGGER_WARNING(m->log, "TCP netprof initialisation failed");
kill_dht(m->dht);
kill_networking(m->net);
@@ -3442,10 +3470,11 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->tcp_np = tcp_np;
m->net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, m->dht, &options->proxy_info, m->tcp_np);
Net_Crypto *net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, m->dht, &m_dht_funcs, &options->proxy_info, m->tcp_np);
if (m->net_crypto == nullptr) {
if (net_crypto == nullptr) {
LOGGER_WARNING(m->log, "net_crypto initialisation failed");
netprof_kill(mem, m->tcp_np);
@@ -3456,10 +3485,10 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->net_crypto = net_crypto;
m->group_announce = new_gca_list(m->mem);
if (m->group_announce == nullptr) {
GC_Announces_List *group_announce = new_gca_list(m->mem);
if (group_announce == nullptr) {
LOGGER_WARNING(m->log, "DHT group chats initialisation failed");
kill_net_crypto(m->net_crypto);
@@ -3471,35 +3500,33 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->group_announce = group_announce;
if (options->dht_announcements_enabled) {
m->forwarding = new_forwarding(m->log, m->mem, m->rng, m->mono_time, m->dht, m->net);
if (m->forwarding != nullptr) {
m->announce = new_announcements(m->log, m->mem, m->rng, m->mono_time, m->forwarding, m->dht, m->net);
} else {
m->announce = nullptr;
}
} else {
m->forwarding = nullptr;
m->announce = nullptr;
}
m->onion = new_onion(m->log, m->mem, m->mono_time, m->rng, m->dht, m->net);
m->onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht, m->net);
m->onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto, m->dht, m->net);
if (m->onion_c != nullptr) {
m->fr_c = new_friend_connections(m->log, m->mem, m->mono_time, m->ns, m->onion_c, m->dht, m->net_crypto, m->net, options->local_discovery_enabled);
Onion *onion = new_onion(m->log, m->mem, m->mono_time, m->rng, m->dht, m->net);
Onion_Announce *onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht, m->net);
Onion_Client *onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto, m->dht, m->net);
Friend_Connections *fr_c = nullptr;
if (onion_c != nullptr) {
fr_c = new_friend_connections(m->log, m->mem, m->mono_time, m->ns, onion_c, m->dht, m->net_crypto, m->net, options->local_discovery_enabled);
}
if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {
onion == nullptr || onion_a == nullptr || onion_c == nullptr || fr_c == nullptr) {
LOGGER_WARNING(m->log, "onion initialisation failed");
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
kill_onion_client(m->onion_c);
kill_onion(onion);
kill_onion_announce(onion_a);
kill_onion_client(onion_c);
kill_gca(m->group_announce);
kill_friend_connections(m->fr_c);
kill_friend_connections(fr_c);
kill_announcements(m->announce);
kill_forwarding(m->forwarding);
kill_net_crypto(m->net_crypto);
@@ -3511,12 +3538,15 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->onion = onion;
m->onion_a = onion_a;
m->onion_c = onion_c;
m->fr_c = fr_c;
gca_onion_init(m->group_announce, m->onion_a);
m->group_handler = new_dht_groupchats(m);
if (m->group_handler == nullptr) {
GC_Session *group_handler = new_dht_groupchats(m);
if (group_handler == nullptr) {
LOGGER_WARNING(m->log, "conferences initialisation failed");
kill_onion(m->onion);
@@ -3535,6 +3565,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
return nullptr;
}
m->group_handler = group_handler;
if (options->tcp_server_port != 0) {
m->tcp_server = new_tcp_server(m->log, m->mem, m->rng, m->ns, options->ipv6enabled, 1,

View File

@@ -241,28 +241,28 @@ typedef struct Friend {
} Friend;
struct Messenger {
Logger *_Nullable log;
Mono_Time *_Nullable mono_time;
const Memory *_Nullable mem;
const Random *_Nullable rng;
const Network *_Nullable ns;
Logger *_Nonnull log;
Mono_Time *_Nonnull mono_time;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
const Network *_Nonnull ns;
Networking_Core *_Nonnull net;
Net_Crypto *_Nonnull net_crypto;
Net_Profile *_Nullable tcp_np;
Net_Profile *_Nonnull tcp_np;
DHT *_Nonnull dht;
Forwarding *_Nullable forwarding;
Announcements *_Nullable announce;
Onion *_Nullable onion;
Onion_Announce *_Nullable onion_a;
Onion_Client *_Nullable onion_c;
Onion *_Nonnull onion;
Onion_Announce *_Nonnull onion_a;
Onion_Client *_Nonnull onion_c;
Friend_Connections *_Nullable fr_c;
Friend_Connections *_Nonnull fr_c;
TCP_Server *_Nullable tcp_server;
Friend_Requests *_Nullable fr;
Friend_Requests *_Nonnull fr;
uint8_t name[MAX_NAME_LENGTH];
uint16_t name_length;

View File

@@ -52,23 +52,23 @@ struct TCP_Client_Connection {
uint64_t ping_request_id;
TCP_Client_Conn connections[NUM_CLIENT_CONNECTIONS];
tcp_routing_response_cb *response_callback;
void *response_callback_object;
tcp_routing_status_cb *status_callback;
void *status_callback_object;
tcp_routing_data_cb *data_callback;
void *data_callback_object;
tcp_oob_data_cb *oob_data_callback;
void *oob_data_callback_object;
tcp_routing_response_cb *_Nullable response_callback;
void *_Nullable response_callback_object;
tcp_routing_status_cb *_Nullable status_callback;
void *_Nullable status_callback_object;
tcp_routing_data_cb *_Nullable data_callback;
void *_Nullable data_callback_object;
tcp_oob_data_cb *_Nullable oob_data_callback;
void *_Nullable oob_data_callback_object;
tcp_onion_response_cb *onion_callback;
void *onion_callback_object;
tcp_onion_response_cb *_Nullable onion_callback;
void *_Nullable onion_callback_object;
forwarded_response_cb *forwarded_response_callback;
void *forwarded_response_callback_object;
forwarded_response_cb *_Nullable forwarded_response_callback;
void *_Nullable forwarded_response_callback_object;
/* Can be used by user. */
void *custom_object;
void *_Nullable custom_object;
uint32_t custom_uint;
};
@@ -399,6 +399,11 @@ int send_data(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id,
return 0;
}
if (1 + length > MAX_PACKET_SIZE) {
LOGGER_ERROR(logger, "Packet length too long: %u", length);
return -1;
}
const uint16_t packet_size = 1 + length;
VLA(uint8_t, packet, packet_size);
packet[0] = con_id + NUM_RESERVED_PORTS;
@@ -541,6 +546,11 @@ int send_disconnect_request(const Logger *logger, TCP_Client_Connection *con, ui
*/
int send_onion_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *data, uint16_t length)
{
if (1 + length > MAX_PACKET_SIZE) {
LOGGER_ERROR(logger, "Packet length too long: %u", length);
return -1;
}
const uint16_t packet_size = 1 + length;
VLA(uint8_t, packet, packet_size);
packet[0] = TCP_PACKET_ONION_REQUEST;

View File

@@ -18,6 +18,10 @@
#include "net_profile.h"
#include "network.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TCP_CONNECTION_TIMEOUT 10
typedef enum TCP_Proxy_Type {
@@ -126,4 +130,8 @@ typedef int tcp_oob_data_cb(void *_Nonnull object, const uint8_t *_Nonnull publi
int send_oob_packet(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull data, uint16_t length);
void oob_data_handler(TCP_Client_Connection *_Nonnull con, tcp_oob_data_cb *_Nonnull oob_data_callback, void *_Nonnull object);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_TCP_CLIENT_H */

365
toxcore/TCP_client_test.cc Normal file
View File

@@ -0,0 +1,365 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "TCP_client.h"
// clang-format on
#include <gtest/gtest.h>
#include <vector>
#include "TCP_common.h"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net_profile.h"
#include "network.h"
#include "util.h"
namespace {
using namespace tox::test;
class TCPClientTest : public ::testing::Test {
protected:
SimulatedEnvironment env;
Mono_Time *create_mono_time(const Memory *mem)
{
Mono_Time *mt = mono_time_new(mem, nullptr, nullptr);
mono_time_set_current_time_callback(
mt,
[](void *user_data) -> uint64_t {
auto *clock = static_cast<FakeClock *>(user_data);
return clock->current_time_ms();
},
&env.fake_clock());
return mt;
}
static void log_cb(void *context, Logger_Level level, const char *file, uint32_t line,
const char *func, const char *message, void *userdata)
{
if (level > LOGGER_LEVEL_TRACE) {
fprintf(stderr, "[%d] %s:%u %s: %s\n", level, file, line, func, message);
}
}
static void net_profile_deleter(Net_Profile *p, const Memory *mem) { netprof_kill(mem, p); }
};
TEST_F(TCPClientTest, ConnectsToRelay)
{
auto server_node = env.create_node(33445);
auto client_node = env.create_node(0); // Ephemeral port
Logger *server_log = logger_new(&server_node->c_memory);
logger_callback_log(server_log, &TCPClientTest::log_cb, nullptr, nullptr);
Logger *client_log = logger_new(&client_node->c_memory);
logger_callback_log(client_log, &TCPClientTest::log_cb, nullptr, nullptr);
Mono_Time *client_time = create_mono_time(&client_node->c_memory);
// 1. Setup Server Socket
Socket server_sock
= net_socket(&server_node->c_network, net_family_ipv4(), TOX_SOCK_STREAM, TOX_PROTO_TCP);
ASSERT_TRUE(sock_valid(server_sock));
ASSERT_TRUE(set_socket_nonblock(&server_node->c_network, server_sock));
ASSERT_TRUE(bind_to_port(&server_node->c_network, server_sock, net_family_ipv4(), 33445));
ASSERT_EQ(0, net_listen(&server_node->c_network, server_sock, 5));
// Server Keys
uint8_t server_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t server_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&server_node->c_random, server_pk, server_sk);
// Client Keys
uint8_t client_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t client_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&client_node->c_random, client_pk, client_sk);
Net_Profile *client_profile = netprof_new(client_log, &client_node->c_memory);
// 2. Client connects to Server
IP_Port server_ip_port;
server_ip_port.ip = server_node->node->ip;
server_ip_port.port = net_htons(33445);
TCP_Client_Connection *client_conn = new_tcp_connection(client_log, &client_node->c_memory,
client_time, &client_node->c_random, &client_node->c_network, &server_ip_port, server_pk,
client_pk, client_sk, nullptr, client_profile);
ASSERT_NE(client_conn, nullptr);
// 3. Simulation Loop
bool connected = false;
Socket accepted_sock = net_invalid_socket();
uint64_t start_time = env.clock().current_time_ms();
while (env.clock().current_time_ms() - start_time < 5000) {
env.advance_time(10);
do_tcp_connection(client_log, client_time, client_conn, nullptr);
// Server accepts connection
if (!sock_valid(accepted_sock)) {
accepted_sock = net_accept(&server_node->c_network, server_sock);
if (sock_valid(accepted_sock)) {
fprintf(stderr, "Server accepted connection! Socket: %d\n", accepted_sock.value);
set_socket_nonblock(&server_node->c_network, accepted_sock);
}
}
// Server handles handshake
if (sock_valid(accepted_sock)) {
uint8_t buf[TCP_CLIENT_HANDSHAKE_SIZE];
IP_Port remote = {{{0}}};
int len = net_recv(
&server_node->c_network, server_log, accepted_sock, buf, sizeof(buf), &remote);
if (len > 0) {
fprintf(stderr, "Server received %d bytes\n", len);
}
if (len == TCP_CLIENT_HANDSHAKE_SIZE) {
// Verify client PK
EXPECT_EQ(0, memcmp(buf, client_pk, CRYPTO_PUBLIC_KEY_SIZE));
// Decrypt
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
encrypt_precompute(client_pk, server_sk, shared_key);
uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];
const uint8_t *nonce_ptr = buf + CRYPTO_PUBLIC_KEY_SIZE;
const uint8_t *ciphertext_ptr = buf + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE;
int res = decrypt_data_symmetric(&server_node->c_memory, shared_key, nonce_ptr,
ciphertext_ptr,
TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE),
plain);
if (res != TCP_HANDSHAKE_PLAIN_SIZE) {
fprintf(stderr, "Decryption failed: res=%d\n", res);
}
if (res == TCP_HANDSHAKE_PLAIN_SIZE) {
// Generate Response
// [Nonce (24)] [Encrypted (PK(32)+Nonce(24)+MAC(16))]
uint8_t resp_nonce[CRYPTO_NONCE_SIZE];
random_nonce(&server_node->c_random, resp_nonce);
uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t temp_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&server_node->c_random, temp_pk, temp_sk);
uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE];
memcpy(resp_plain, temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
random_nonce(&server_node->c_random, resp_plain + CRYPTO_PUBLIC_KEY_SIZE);
uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
memcpy(response, resp_nonce, CRYPTO_NONCE_SIZE);
encrypt_data_symmetric(&server_node->c_memory, shared_key,
resp_nonce, // nonce
resp_plain, // plain
TCP_HANDSHAKE_PLAIN_SIZE, // plain len
response + CRYPTO_NONCE_SIZE // dest
);
net_send(&server_node->c_network, server_log, accepted_sock, response,
sizeof(response), &remote, nullptr);
}
}
}
if (tcp_con_status(client_conn) == TCP_CLIENT_CONFIRMED) {
connected = true;
break;
}
}
EXPECT_TRUE(connected);
// Cleanup
kill_tcp_connection(client_conn);
net_profile_deleter(client_profile, &client_node->c_memory);
kill_sock(&server_node->c_network, server_sock);
if (sock_valid(accepted_sock))
kill_sock(&server_node->c_network, accepted_sock);
logger_kill(client_log);
logger_kill(server_log);
mono_time_free(&client_node->c_memory, client_time);
}
TEST_F(TCPClientTest, SendDataIntegerOverflow)
{
auto server_node = env.create_node(33446);
auto client_node = env.create_node(0);
Logger *server_log = logger_new(&server_node->c_memory);
logger_callback_log(server_log, &TCPClientTest::log_cb, nullptr, nullptr);
Logger *client_log = logger_new(&client_node->c_memory);
logger_callback_log(client_log, &TCPClientTest::log_cb, nullptr, nullptr);
Mono_Time *client_time = create_mono_time(&client_node->c_memory);
Socket server_sock
= net_socket(&server_node->c_network, net_family_ipv4(), TOX_SOCK_STREAM, TOX_PROTO_TCP);
ASSERT_TRUE(sock_valid(server_sock));
ASSERT_TRUE(set_socket_nonblock(&server_node->c_network, server_sock));
ASSERT_TRUE(bind_to_port(&server_node->c_network, server_sock, net_family_ipv4(), 33446));
ASSERT_EQ(0, net_listen(&server_node->c_network, server_sock, 5));
uint8_t server_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t server_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&server_node->c_random, server_pk, server_sk);
uint8_t client_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t client_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&client_node->c_random, client_pk, client_sk);
Net_Profile *client_profile = netprof_new(client_log, &client_node->c_memory);
IP_Port server_ip_port;
server_ip_port.ip = server_node->node->ip;
server_ip_port.port = net_htons(33446);
TCP_Client_Connection *client_conn = new_tcp_connection(client_log, &client_node->c_memory,
client_time, &client_node->c_random, &client_node->c_network, &server_ip_port, server_pk,
client_pk, client_sk, nullptr, client_profile);
ASSERT_NE(client_conn, nullptr);
bool connected = false;
Socket accepted_sock = net_invalid_socket();
uint64_t start_time = env.clock().current_time_ms();
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
uint8_t sent_nonce[CRYPTO_NONCE_SIZE] = {0};
uint8_t recv_nonce[CRYPTO_NONCE_SIZE] = {0};
// Helper to send encrypted packet from server to client
auto server_send_packet = [&](const uint8_t *data, uint16_t length) {
uint16_t packet_size = sizeof(uint16_t) + length + CRYPTO_MAC_SIZE;
std::vector<uint8_t> packet(packet_size);
uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
memcpy(packet.data(), &c_length, sizeof(uint16_t));
encrypt_data_symmetric(&server_node->c_memory, shared_key, sent_nonce, data, length,
packet.data() + sizeof(uint16_t));
increment_nonce(sent_nonce);
IP_Port remote = {{{0}}};
net_send(&server_node->c_network, server_log, accepted_sock, packet.data(), packet_size,
&remote, nullptr);
};
while (env.clock().current_time_ms() - start_time < 5000) {
env.advance_time(10);
do_tcp_connection(client_log, client_time, client_conn, nullptr);
if (!sock_valid(accepted_sock)) {
accepted_sock = net_accept(&server_node->c_network, server_sock);
if (sock_valid(accepted_sock)) {
set_socket_nonblock(&server_node->c_network, accepted_sock);
}
}
if (sock_valid(accepted_sock) && !connected) {
uint8_t buf[TCP_CLIENT_HANDSHAKE_SIZE];
IP_Port remote = {{{0}}};
int len = net_recv(
&server_node->c_network, server_log, accepted_sock, buf, sizeof(buf), &remote);
if (len == TCP_CLIENT_HANDSHAKE_SIZE) {
encrypt_precompute(client_pk, server_sk, shared_key);
uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];
if (decrypt_data_symmetric(&server_node->c_memory, shared_key,
buf + CRYPTO_PUBLIC_KEY_SIZE,
buf + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE),
plain)
== TCP_HANDSHAKE_PLAIN_SIZE) {
memcpy(recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE);
uint8_t resp_nonce[CRYPTO_NONCE_SIZE];
random_nonce(&server_node->c_random, resp_nonce);
memcpy(sent_nonce, resp_nonce, CRYPTO_NONCE_SIZE);
uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t temp_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&server_node->c_random, temp_pk, temp_sk);
uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE];
memcpy(resp_plain, temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
random_nonce(&server_node->c_random, resp_plain + CRYPTO_PUBLIC_KEY_SIZE);
// FIX: Save the nonce that client will use for receiving
memcpy(sent_nonce, resp_plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE);
uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
memcpy(response, resp_nonce, CRYPTO_NONCE_SIZE);
encrypt_data_symmetric(&server_node->c_memory, shared_key, resp_nonce,
resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + CRYPTO_NONCE_SIZE);
net_send(&server_node->c_network, server_log, accepted_sock, response,
sizeof(response), &remote, nullptr);
// FIX: Update shared key using Client's Ephemeral PK and Server's Ephemeral SK
encrypt_precompute(plain, temp_sk, shared_key);
}
}
}
if (tcp_con_status(client_conn) == TCP_CLIENT_CONFIRMED) {
connected = true;
break;
}
}
ASSERT_TRUE(connected);
// Establish sub-connection 0
uint8_t con_id = 0;
uint8_t other_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; // Dummy PK
// 1. Send Routing Response to set status=1
{
uint8_t packet[1 + 1 + CRYPTO_PUBLIC_KEY_SIZE];
packet[0] = TCP_PACKET_ROUTING_RESPONSE;
packet[1] = con_id + NUM_RESERVED_PORTS;
memcpy(packet + 2, other_pk, CRYPTO_PUBLIC_KEY_SIZE);
server_send_packet(packet, sizeof(packet));
}
// Pump loop to process packet
for (int i = 0; i < 10; ++i) {
env.advance_time(10);
do_tcp_connection(client_log, client_time, client_conn, nullptr);
}
// 2. Send Connection Notification to set status=2
{
uint8_t packet[1 + 1];
packet[0] = TCP_PACKET_CONNECTION_NOTIFICATION;
packet[1] = con_id + NUM_RESERVED_PORTS;
server_send_packet(packet, sizeof(packet));
}
// Pump loop to process packet
for (int i = 0; i < 10; ++i) {
env.advance_time(10);
do_tcp_connection(client_log, client_time, client_conn, nullptr);
}
// Now call send_data with 65535 bytes
std::vector<uint8_t> large_data(65535);
// This should trigger integer overflow: 1 + 65535 = 0. VLA(0). packet[0] write -> Crash/UB
send_data(client_log, client_conn, con_id, large_data.data(), 65535);
// Cleanup
kill_tcp_connection(client_conn);
net_profile_deleter(client_profile, &client_node->c_memory);
kill_sock(&server_node->c_network, server_sock);
if (sock_valid(accepted_sock))
kill_sock(&server_node->c_network, accepted_sock);
logger_kill(client_log);
logger_kill(server_log);
mono_time_free(&client_node->c_memory, client_time);
}
} // namespace

View File

@@ -25,33 +25,33 @@
#include "util.h"
struct TCP_Connections {
const Logger *logger;
const Memory *mem;
const Random *rng;
Mono_Time *mono_time;
const Network *ns;
DHT *dht;
const Logger *_Nonnull logger;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
Mono_Time *_Nonnull mono_time;
const Network *_Nonnull ns;
DHT *_Nonnull dht;
uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
TCP_Connection_to *connections;
TCP_Connection_to *_Nullable connections;
uint32_t connections_length; /* Length of connections array. */
TCP_con *tcp_connections;
TCP_con *_Nullable tcp_connections;
uint32_t tcp_connections_length; /* Length of tcp_connections array. */
tcp_data_cb *tcp_data_callback;
void *tcp_data_callback_object;
tcp_data_cb *_Nullable tcp_data_callback;
void *_Nullable tcp_data_callback_object;
tcp_oob_cb *tcp_oob_callback;
void *tcp_oob_callback_object;
tcp_oob_cb *_Nullable tcp_oob_callback;
void *_Nullable tcp_oob_callback_object;
tcp_onion_cb *tcp_onion_callback;
void *tcp_onion_callback_object;
tcp_onion_cb *_Nullable tcp_onion_callback;
void *_Nullable tcp_onion_callback_object;
forwarded_response_cb *tcp_forwarded_response_callback;
void *tcp_forwarded_response_callback_object;
forwarded_response_cb *_Nullable tcp_forwarded_response_callback;
void *_Nullable tcp_forwarded_response_callback_object;
TCP_Proxy_Info proxy_info;
@@ -59,7 +59,7 @@ struct TCP_Connections {
uint16_t onion_num_conns;
/* Network profile for all TCP client packets. */
Net_Profile *net_profile;
Net_Profile *_Nullable net_profile;
};
static const TCP_Connection_to empty_tcp_connection_to = {0};
@@ -80,7 +80,7 @@ uint32_t tcp_connections_count(const TCP_Connections *tcp_c)
* @retval -1 if mem_vrealloc fails.
* @retval 0 if it succeeds.
*/
static int realloc_tcp_connection_to(const Memory *_Nonnull mem, TCP_Connection_to *_Nullable *_Nonnull array, size_t num)
static int realloc_tcp_connection_to(const Memory *_Nonnull mem, TCP_Connection_to *_Nullable *array, size_t num)
{
if (num == 0) {
mem_delete(mem, *array);
@@ -100,7 +100,7 @@ static int realloc_tcp_connection_to(const Memory *_Nonnull mem, TCP_Connection_
return 0;
}
static int realloc_tcp_con(const Memory *_Nonnull mem, TCP_con *_Nullable *_Nonnull array, size_t num)
static int realloc_tcp_con(const Memory *_Nonnull mem, TCP_con *_Nullable *array, size_t num)
{
if (num == 0) {
mem_delete(mem, *array);
@@ -331,6 +331,10 @@ int send_packet_tcp_connection(const TCP_Connections *tcp_c, int connections_num
continue;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_con_num);
continue;
}
ret = send_data(tcp_c->logger, tcp_con->connection, connection_id, packet, length);
if (ret == 0) {
@@ -366,6 +370,10 @@ int send_packet_tcp_connection(const TCP_Connections *tcp_c, int connections_num
continue;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_con_num);
continue;
}
if (send_oob_packet(tcp_c->logger, tcp_con->connection, con_to->public_key, packet, length) == 1) {
sent_any = true;
}
@@ -406,6 +414,10 @@ int get_random_tcp_onion_conn_number(const TCP_Connections *tcp_c)
static int get_conn_number_by_ip_port(const TCP_Connections *_Nonnull tcp_c, const IP_Port *_Nonnull ip_port)
{
for (uint32_t i = 0; i < tcp_c->tcp_connections_length; ++i) {
if (tcp_c->tcp_connections[i].connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %u", i);
continue;
}
const IP_Port conn_ip_port = tcp_con_ip_port(tcp_c->tcp_connections[i].connection);
if (ipport_equal(ip_port, &conn_ip_port) &&
@@ -430,6 +442,10 @@ bool tcp_get_random_conn_ip_port(const TCP_Connections *tcp_c, IP_Port *ip_port)
return false;
}
if (tcp_c->tcp_connections[index].connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
return false;
}
*ip_port = tcp_con_ip_port(tcp_c->tcp_connections[index].connection);
return true;
}
@@ -447,6 +463,10 @@ int tcp_send_onion_request(TCP_Connections *tcp_c, uint32_t tcp_connections_numb
}
if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_CONNECTED) {
if (tcp_c->tcp_connections[tcp_connections_number].connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection number %u", tcp_connections_number);
return -1;
}
const int ret = send_onion_request(tcp_c->logger, tcp_c->tcp_connections[tcp_connections_number].connection, data,
length);
@@ -477,6 +497,10 @@ int tcp_send_forward_request(const Logger *logger, TCP_Connections *tcp_c, const
}
if (chain_length == 0) {
if (tcp_c->tcp_connections[index].connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
return -1;
}
return send_forward_request_tcp(logger, tcp_c->tcp_connections[index].connection, dht_node, data,
data_length) == 1 ? 0 : -1;
}
@@ -484,6 +508,10 @@ int tcp_send_forward_request(const Logger *logger, TCP_Connections *tcp_c, const
const uint16_t len = forward_chain_packet_size(chain_length, data_length);
VLA(uint8_t, packet, len);
if (tcp_c->tcp_connections[index].connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for connection index %d", index);
return -1;
}
return create_forward_chain_packet(chain_keys, chain_length, data, data_length, packet)
&& send_forward_request_tcp(logger, tcp_c->tcp_connections[index].connection, dht_node, packet, len) == 1 ? 0 : -1;
}
@@ -506,6 +534,10 @@ int tcp_send_oob_packet(const TCP_Connections *tcp_c, unsigned int tcp_connectio
return -1;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
const int ret = send_oob_packet(tcp_c->logger, tcp_con->connection, public_key, packet, length);
if (ret == 1) {
@@ -623,6 +655,10 @@ static int find_tcp_connection_relay(const TCP_Connections *tcp_c, const uint8_t
return i;
}
} else {
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
if (pk_equal(tcp_con_public_key(tcp_con->connection), relay_pk)) {
return i;
}
@@ -690,6 +726,10 @@ int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)
}
if (tcp_con->status == TCP_CONN_CONNECTED) {
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
continue;
}
send_disconnect_request(tcp_c->logger, tcp_con->connection, con_to->connections[i].connection_id);
}
@@ -907,6 +947,10 @@ static int reconnect_tcp_relay_connection(TCP_Connections *_Nonnull tcp_c, int t
return -1;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
const IP_Port ip_port = tcp_con_ip_port(tcp_con->connection);
uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE];
memcpy(relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
@@ -957,6 +1001,10 @@ static int sleep_tcp_relay_connection(TCP_Connections *_Nonnull tcp_c, int tcp_c
return -1;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
tcp_con->ip_port = tcp_con_ip_port(tcp_con->connection);
memcpy(tcp_con->relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
@@ -1032,6 +1080,10 @@ static int send_tcp_relay_routing_request(const TCP_Connections *_Nonnull tcp_c,
return -1;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
if (send_routing_request(tcp_c->logger, tcp_con->connection, public_key) != 1) {
return -1;
}
@@ -1067,6 +1119,10 @@ static int tcp_response_callback(void *_Nonnull object, uint8_t connection_id, c
return -1;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return -1;
}
set_tcp_connection_number(tcp_con->connection, connection_id, connections_number);
return 0;
@@ -1427,6 +1483,10 @@ static bool copy_tcp_relay_conn(const TCP_Connections *_Nonnull tcp_c, Node_form
return false;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(tcp_c->logger, "TCP connection is null for tcp_con");
return false;
}
memcpy(tcp_relay->public_key, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE);
tcp_relay->ip_port = tcp_con_ip_port(tcp_con->connection);
@@ -1600,6 +1660,10 @@ static void do_tcp_conns(const Logger *_Nonnull logger, TCP_Connections *_Nonnul
}
if (tcp_con->status != TCP_CONN_SLEEPING) {
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
continue;
}
do_tcp_connection(logger, tcp_c->mono_time, tcp_con->connection, userdata);
/* callbacks can change TCP connection address. */
@@ -1608,6 +1672,10 @@ static void do_tcp_conns(const Logger *_Nonnull logger, TCP_Connections *_Nonnul
// Make sure the TCP connection wasn't dropped in any of the callbacks.
assert(tcp_con != nullptr);
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
continue;
}
if (tcp_con_status(tcp_con->connection) == TCP_CLIENT_DISCONNECTED) {
if (tcp_con->status == TCP_CONN_CONNECTED) {
reconnect_tcp_relay_connection(tcp_c, i);
@@ -1618,6 +1686,10 @@ static void do_tcp_conns(const Logger *_Nonnull logger, TCP_Connections *_Nonnul
continue;
}
if (tcp_con->connection == nullptr) {
LOGGER_ERROR(logger, "TCP connection is null for tcp_con");
continue;
}
if (tcp_con->status == TCP_CONN_VALID && tcp_con_status(tcp_con->connection) == TCP_CLIENT_CONFIRMED) {
tcp_relay_on_online(tcp_c, i);
}

View File

@@ -64,18 +64,18 @@ typedef struct TCP_Secure_Connection {
static const TCP_Secure_Connection empty_tcp_secure_connection = {{nullptr}};
struct TCP_Server {
const Logger *logger;
const Memory *mem;
const Random *rng;
const Network *ns;
Onion *onion;
Forwarding *forwarding;
const Logger *_Nonnull logger;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
const Network *_Nonnull ns;
Onion *_Nullable onion;
Forwarding *_Nullable forwarding;
#ifdef TCP_SERVER_USE_EPOLL
int efd;
uint64_t last_run_pinged;
#endif /* TCP_SERVER_USE_EPOLL */
Socket *socks_listening;
Socket *_Nullable socks_listening;
unsigned int num_listening_socks;
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
@@ -85,7 +85,7 @@ struct TCP_Server {
TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMING_CONNECTIONS];
uint16_t unconfirmed_connection_queue_index;
TCP_Secure_Connection *accepted_connection_array;
TCP_Secure_Connection *_Nullable accepted_connection_array;
uint32_t size_accepted_connections;
uint32_t num_accepted_connections;
@@ -94,7 +94,7 @@ struct TCP_Server {
BS_List accepted_key_list;
/* Network profile for all TCP server packets. */
Net_Profile *net_profile;
Net_Profile *_Nullable net_profile;
};
static_assert(sizeof(TCP_Server) < 7 * 1024 * 1024,

View File

@@ -19,6 +19,10 @@
#include "network.h"
#include "onion.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_INCOMING_CONNECTIONS 256
#define TCP_MAX_BACKLOG MAX_INCOMING_CONNECTIONS
@@ -51,4 +55,9 @@ void kill_tcp_server(TCP_Server *_Nullable tcp_server);
* Returns null if `tcp_server` is null.
*/
const Net_Profile *_Nullable tcp_server_get_net_profile(const TCP_Server *_Nullable tcp_server);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_TCP_SERVER_H */

View File

@@ -51,22 +51,22 @@ uint8_t announce_response_of_request_type(uint8_t request_type)
typedef struct Announce_Entry {
uint64_t store_until;
uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t *data;
uint8_t *_Nullable data;
uint32_t length;
} Announce_Entry;
struct Announcements {
const Logger *log;
const Memory *mem;
const Random *rng;
Forwarding *forwarding;
const Mono_Time *mono_time;
DHT *dht;
Networking_Core *net;
const uint8_t *public_key;
const uint8_t *secret_key;
const Logger *_Nonnull log;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
Forwarding *_Nonnull forwarding;
const Mono_Time *_Nonnull mono_time;
DHT *_Nonnull dht;
Networking_Core *_Nonnull net;
const uint8_t *_Nonnull public_key;
const uint8_t *_Nonnull secret_key;
Shared_Key_Cache *shared_keys;
Shared_Key_Cache *_Nonnull shared_keys;
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
int32_t synch_offset;
@@ -328,6 +328,10 @@ static int create_reply_plain_data_search_request(Announcements *_Nonnull announ
} else {
*p = 1;
++p;
if (stored->data == nullptr) {
LOGGER_ERROR(announce->log, "Stored data is null for public key.");
return -1;
}
crypto_sha256(p, stored->data, stored->length);
p += CRYPTO_SHA256_SIZE;
}
@@ -462,6 +466,10 @@ static int create_reply_plain_store_announce_request(Announcements *_Nonnull ann
}
uint8_t stored_hash[CRYPTO_SHA256_SIZE];
if (stored->data == nullptr) {
LOGGER_ERROR(announce->log, "Stored data is null for public key.");
return -1;
}
crypto_sha256(stored_hash, stored->data, stored->length);
if (!crypto_sha256_eq(announcement, stored_hash)) {
@@ -635,11 +643,12 @@ Announcements *new_announcements(const Logger *log, const Memory *mem, const Ran
announce->public_key = dht_get_self_public_key(announce->dht);
announce->secret_key = dht_get_self_secret_key(announce->dht);
new_hmac_key(announce->rng, announce->hmac_key);
announce->shared_keys = shared_key_cache_new(log, mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (announce->shared_keys == nullptr) {
Shared_Key_Cache *const shared_keys = shared_key_cache_new(log, mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (shared_keys == nullptr) {
mem_delete(announce->mem, announce);
return nullptr;
}
announce->shared_keys = shared_keys;
announce->start_time = mono_time_get(announce->mono_time);

View File

@@ -13,7 +13,7 @@
#include "logger.h"
struct Bin_Pack {
uint8_t *bytes;
uint8_t *_Nullable bytes;
uint32_t bytes_size;
uint32_t bytes_pos;
cmp_ctx_t ctx;

View File

@@ -13,9 +13,9 @@
#include "mem.h"
struct Bin_Unpack {
const Memory *mem;
const Memory *_Nonnull mem;
const uint8_t *bytes;
const uint8_t *_Nonnull bytes;
uint32_t bytes_size;
cmp_ctx_t ctx;
};

View File

@@ -1,4 +1,7 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "crypto_core.h"
// clang-format on
#include <gtest/gtest.h>
@@ -7,7 +10,6 @@
#include <vector>
#include "crypto_core_test_util.hh"
#include "mem_test_util.hh"
namespace {
@@ -17,29 +19,31 @@ using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
using Signature = std::array<uint8_t, CRYPTO_SIGNATURE_SIZE>;
using Nonce = std::array<uint8_t, CRYPTO_NONCE_SIZE>;
using tox::test::SimulatedEnvironment;
TEST(PkEqual, TwoRandomIdsAreNotEqual)
{
std::mt19937 rng;
std::uniform_int_distribution<unsigned short> dist{0, UINT8_MAX};
SimulatedEnvironment env;
auto &rng = env.fake_random();
uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE];
std::generate(std::begin(pk1), std::end(pk1), [&]() { return dist(rng); });
std::generate(std::begin(pk2), std::end(pk2), [&]() { return dist(rng); });
rng.bytes(pk1, sizeof(pk1));
rng.bytes(pk2, sizeof(pk2));
EXPECT_FALSE(pk_equal(pk1, pk2));
}
TEST(PkEqual, IdCopyMakesKeysEqual)
{
std::mt19937 rng;
std::uniform_int_distribution<unsigned short> dist{0, UINT8_MAX};
SimulatedEnvironment env;
auto &rng = env.fake_random();
uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE] = {0};
std::generate(std::begin(pk1), std::end(pk1), [&]() { return dist(rng); });
rng.bytes(pk1, sizeof(pk1));
pk_copy(pk2, pk1);
@@ -48,20 +52,21 @@ TEST(PkEqual, IdCopyMakesKeysEqual)
TEST(CryptoCore, EncryptLargeData)
{
Test_Memory mem;
Test_Random rng;
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
auto c_rng = env.fake_random().get_c_random();
Nonce nonce{};
PublicKey pk;
SecretKey sk;
crypto_new_keypair(rng, pk.data(), sk.data());
crypto_new_keypair(&c_rng, pk.data(), sk.data());
// 100 MiB of data (all zeroes, doesn't matter what's inside).
std::vector<uint8_t> plain(100 * 1024 * 1024);
std::vector<uint8_t> encrypted(plain.size() + CRYPTO_MAC_SIZE);
encrypt_data(
mem, pk.data(), sk.data(), nonce.data(), plain.data(), plain.size(), encrypted.data());
&c_mem, pk.data(), sk.data(), nonce.data(), plain.data(), plain.size(), encrypted.data());
}
TEST(CryptoCore, IncrementNonce)
@@ -99,12 +104,13 @@ TEST(CryptoCore, IncrementNonceNumber)
TEST(CryptoCore, Signatures)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
Extended_Public_Key pk;
Extended_Secret_Key sk;
EXPECT_TRUE(create_extended_keypair(&pk, &sk, rng));
EXPECT_TRUE(create_extended_keypair(&pk, &sk, &c_rng));
std::vector<uint8_t> message{0};
message.clear();
@@ -117,16 +123,17 @@ TEST(CryptoCore, Signatures)
EXPECT_TRUE(crypto_signature_verify(
signature.data(), message.data(), message.size(), get_sig_pk(&pk)));
message.push_back(random_u08(rng));
message.push_back(random_u08(&c_rng));
}
}
TEST(CryptoCore, Hmac)
{
Test_Random rng;
SimulatedEnvironment env;
auto c_rng = env.fake_random().get_c_random();
HmacKey sk;
new_hmac_key(rng, sk.data());
new_hmac_key(&c_rng, sk.data());
std::vector<uint8_t> message{0};
message.clear();
@@ -137,7 +144,7 @@ TEST(CryptoCore, Hmac)
crypto_hmac(auth.data(), sk.data(), message.data(), message.size());
EXPECT_TRUE(crypto_hmac_verify(auth.data(), sk.data(), message.data(), message.size()));
message.push_back(random_u08(rng));
message.push_back(random_u08(&c_rng));
}
}

View File

@@ -5,25 +5,6 @@
#include "crypto_core.h"
#include "test_util.hh"
#include "tox_random_impl.h"
Tox_Random_Funcs const Random_Class::vtable = {
Method<tox_random_bytes_cb, Random_Class>::invoke<&Random_Class::random_bytes>,
Method<tox_random_uniform_cb, Random_Class>::invoke<&Random_Class::random_uniform>,
};
Random_Class::~Random_Class() = default;
void Test_Random::random_bytes(void *obj, uint8_t *bytes, uint32_t length)
{
std::generate(bytes, &bytes[length], std::ref(lcg));
}
uint32_t Test_Random::random_uniform(void *obj, uint32_t upper_bound)
{
std::uniform_int_distribution<uint32_t> distrib(0, upper_bound);
return distrib(lcg);
}
PublicKey random_pk(const Random *rng)
{

View File

@@ -4,41 +4,9 @@
#include <algorithm>
#include <array>
#include <iosfwd>
#include <random>
#include "crypto_core.h"
#include "test_util.hh"
#include "tox_random_impl.h"
struct Random_Class {
static Tox_Random_Funcs const vtable;
Tox_Random const self;
operator Tox_Random const *() const { return &self; }
Random_Class(Random_Class const &) = default;
Random_Class()
: self{&vtable, this}
{
}
virtual ~Random_Class();
virtual tox_random_bytes_cb random_bytes = 0;
virtual tox_random_uniform_cb random_uniform = 0;
};
/**
* A very simple, fast, and deterministic PRNG just for testing.
*
* We generally don't want to use system_random(), since it's a
* cryptographically secure PRNG and we don't need that in unit tests.
*/
class Test_Random : public Random_Class {
std::minstd_rand lcg;
void random_bytes(void *obj, uint8_t *bytes, uint32_t length) override;
uint32_t random_uniform(void *obj, uint32_t upper_bound) override;
};
struct PublicKey : private std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE> {
using Base = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -86,7 +86,7 @@ Tox_Event_Conference_Connected *tox_event_conference_connected_new(const Memory
void tox_event_conference_connected_free(Tox_Event_Conference_Connected *conference_connected, const Memory *mem)
{
if (conference_connected != nullptr) {
tox_event_conference_connected_destruct(conference_connected, mem);
tox_event_conference_connected_destruct((Tox_Event_Conference_Connected * _Nonnull)conference_connected, mem);
}
mem_delete(mem, conference_connected);
}
@@ -124,11 +124,8 @@ bool tox_event_conference_connected_unpack(
return tox_event_conference_connected_unpack_into(*event, bu);
}
static Tox_Event_Conference_Connected *tox_event_conference_connected_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Connected *tox_event_conference_connected_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -153,7 +150,8 @@ void tox_events_handle_conference_connected(
Tox *tox, uint32_t conference_number,
void *user_data)
{
Tox_Event_Conference_Connected *conference_connected = tox_event_conference_connected_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Connected *conference_connected = tox_event_conference_connected_alloc(state);
if (conference_connected == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -55,11 +54,11 @@ Tox_Conference_Type tox_event_conference_invite_get_type(const Tox_Event_Confere
}
static bool tox_event_conference_invite_set_cookie(Tox_Event_Conference_Invite *_Nonnull conference_invite,
const uint8_t *_Nullable cookie, uint32_t cookie_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable cookie, uint32_t cookie_length)
{
assert(conference_invite != nullptr);
if (conference_invite->cookie != nullptr) {
free(conference_invite->cookie);
mem_delete(mem, conference_invite->cookie);
conference_invite->cookie = nullptr;
conference_invite->cookie_length = 0;
}
@@ -69,7 +68,7 @@ static bool tox_event_conference_invite_set_cookie(Tox_Event_Conference_Invite *
return true;
}
uint8_t *cookie_copy = (uint8_t *)malloc(cookie_length);
uint8_t *cookie_copy = (uint8_t *)mem_balloc(mem, cookie_length);
if (cookie_copy == nullptr) {
return false;
@@ -99,7 +98,7 @@ static void tox_event_conference_invite_construct(Tox_Event_Conference_Invite *_
}
static void tox_event_conference_invite_destruct(Tox_Event_Conference_Invite *_Nonnull conference_invite, const Memory *_Nonnull mem)
{
free(conference_invite->cookie);
mem_delete(mem, conference_invite->cookie);
}
bool tox_event_conference_invite_pack(
@@ -150,7 +149,7 @@ Tox_Event_Conference_Invite *tox_event_conference_invite_new(const Memory *mem)
void tox_event_conference_invite_free(Tox_Event_Conference_Invite *conference_invite, const Memory *mem)
{
if (conference_invite != nullptr) {
tox_event_conference_invite_destruct(conference_invite, mem);
tox_event_conference_invite_destruct((Tox_Event_Conference_Invite * _Nonnull)conference_invite, mem);
}
mem_delete(mem, conference_invite);
}
@@ -188,11 +187,8 @@ bool tox_event_conference_invite_unpack(
return tox_event_conference_invite_unpack_into(*event, bu);
}
static Tox_Event_Conference_Invite *tox_event_conference_invite_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Invite *tox_event_conference_invite_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -217,7 +213,8 @@ void tox_events_handle_conference_invite(
Tox *tox, uint32_t friend_number, Tox_Conference_Type type, const uint8_t *cookie, size_t length,
void *user_data)
{
Tox_Event_Conference_Invite *conference_invite = tox_event_conference_invite_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Invite *conference_invite = tox_event_conference_invite_alloc(state);
if (conference_invite == nullptr) {
return;
@@ -225,5 +222,5 @@ void tox_events_handle_conference_invite(
tox_event_conference_invite_set_friend_number(conference_invite, friend_number);
tox_event_conference_invite_set_type(conference_invite, type);
tox_event_conference_invite_set_cookie(conference_invite, cookie, length);
tox_event_conference_invite_set_cookie(conference_invite, state->mem, cookie, length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -67,11 +66,11 @@ Tox_Message_Type tox_event_conference_message_get_type(const Tox_Event_Conferenc
}
static bool tox_event_conference_message_set_message(Tox_Event_Conference_Message *_Nonnull conference_message,
const uint8_t *_Nullable message, uint32_t message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(conference_message != nullptr);
if (conference_message->message != nullptr) {
free(conference_message->message);
mem_delete(mem, conference_message->message);
conference_message->message = nullptr;
conference_message->message_length = 0;
}
@@ -81,7 +80,7 @@ static bool tox_event_conference_message_set_message(Tox_Event_Conference_Messag
return true;
}
uint8_t *message_copy = (uint8_t *)malloc(message_length);
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
return false;
@@ -111,7 +110,7 @@ static void tox_event_conference_message_construct(Tox_Event_Conference_Message
}
static void tox_event_conference_message_destruct(Tox_Event_Conference_Message *_Nonnull conference_message, const Memory *_Nonnull mem)
{
free(conference_message->message);
mem_delete(mem, conference_message->message);
}
bool tox_event_conference_message_pack(
@@ -164,7 +163,7 @@ Tox_Event_Conference_Message *tox_event_conference_message_new(const Memory *mem
void tox_event_conference_message_free(Tox_Event_Conference_Message *conference_message, const Memory *mem)
{
if (conference_message != nullptr) {
tox_event_conference_message_destruct(conference_message, mem);
tox_event_conference_message_destruct((Tox_Event_Conference_Message * _Nonnull)conference_message, mem);
}
mem_delete(mem, conference_message);
}
@@ -202,11 +201,8 @@ bool tox_event_conference_message_unpack(
return tox_event_conference_message_unpack_into(*event, bu);
}
static Tox_Event_Conference_Message *tox_event_conference_message_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Message *tox_event_conference_message_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -231,7 +227,8 @@ void tox_events_handle_conference_message(
Tox *tox, uint32_t conference_number, uint32_t peer_number, Tox_Message_Type type, const uint8_t *message, size_t length,
void *user_data)
{
Tox_Event_Conference_Message *conference_message = tox_event_conference_message_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Message *conference_message = tox_event_conference_message_alloc(state);
if (conference_message == nullptr) {
return;
@@ -240,5 +237,5 @@ void tox_events_handle_conference_message(
tox_event_conference_message_set_conference_number(conference_message, conference_number);
tox_event_conference_message_set_peer_number(conference_message, peer_number);
tox_event_conference_message_set_type(conference_message, type);
tox_event_conference_message_set_message(conference_message, message, length);
tox_event_conference_message_set_message(conference_message, state->mem, message, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -86,7 +86,7 @@ Tox_Event_Conference_Peer_List_Changed *tox_event_conference_peer_list_changed_n
void tox_event_conference_peer_list_changed_free(Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed, const Memory *mem)
{
if (conference_peer_list_changed != nullptr) {
tox_event_conference_peer_list_changed_destruct(conference_peer_list_changed, mem);
tox_event_conference_peer_list_changed_destruct((Tox_Event_Conference_Peer_List_Changed * _Nonnull)conference_peer_list_changed, mem);
}
mem_delete(mem, conference_peer_list_changed);
}
@@ -124,11 +124,8 @@ bool tox_event_conference_peer_list_changed_unpack(
return tox_event_conference_peer_list_changed_unpack_into(*event, bu);
}
static Tox_Event_Conference_Peer_List_Changed *tox_event_conference_peer_list_changed_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Peer_List_Changed *tox_event_conference_peer_list_changed_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -153,7 +150,8 @@ void tox_events_handle_conference_peer_list_changed(
Tox *tox, uint32_t conference_number,
void *user_data)
{
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed = tox_event_conference_peer_list_changed_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed = tox_event_conference_peer_list_changed_alloc(state);
if (conference_peer_list_changed == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_conference_peer_name_get_peer_number(const Tox_Event_Conferen
}
static bool tox_event_conference_peer_name_set_name(Tox_Event_Conference_Peer_Name *_Nonnull conference_peer_name,
const uint8_t *_Nullable name, uint32_t name_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable name, uint32_t name_length)
{
assert(conference_peer_name != nullptr);
if (conference_peer_name->name != nullptr) {
free(conference_peer_name->name);
mem_delete(mem, conference_peer_name->name);
conference_peer_name->name = nullptr;
conference_peer_name->name_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_conference_peer_name_set_name(Tox_Event_Conference_Peer_Na
return true;
}
uint8_t *name_copy = (uint8_t *)malloc(name_length);
uint8_t *name_copy = (uint8_t *)mem_balloc(mem, name_length);
if (name_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_conference_peer_name_construct(Tox_Event_Conference_Peer_N
}
static void tox_event_conference_peer_name_destruct(Tox_Event_Conference_Peer_Name *_Nonnull conference_peer_name, const Memory *_Nonnull mem)
{
free(conference_peer_name->name);
mem_delete(mem, conference_peer_name->name);
}
bool tox_event_conference_peer_name_pack(
@@ -148,7 +147,7 @@ Tox_Event_Conference_Peer_Name *tox_event_conference_peer_name_new(const Memory
void tox_event_conference_peer_name_free(Tox_Event_Conference_Peer_Name *conference_peer_name, const Memory *mem)
{
if (conference_peer_name != nullptr) {
tox_event_conference_peer_name_destruct(conference_peer_name, mem);
tox_event_conference_peer_name_destruct((Tox_Event_Conference_Peer_Name * _Nonnull)conference_peer_name, mem);
}
mem_delete(mem, conference_peer_name);
}
@@ -186,11 +185,8 @@ bool tox_event_conference_peer_name_unpack(
return tox_event_conference_peer_name_unpack_into(*event, bu);
}
static Tox_Event_Conference_Peer_Name *tox_event_conference_peer_name_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Peer_Name *tox_event_conference_peer_name_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_conference_peer_name(
Tox *tox, uint32_t conference_number, uint32_t peer_number, const uint8_t *name, size_t length,
void *user_data)
{
Tox_Event_Conference_Peer_Name *conference_peer_name = tox_event_conference_peer_name_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Peer_Name *conference_peer_name = tox_event_conference_peer_name_alloc(state);
if (conference_peer_name == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_conference_peer_name(
tox_event_conference_peer_name_set_conference_number(conference_peer_name, conference_number);
tox_event_conference_peer_name_set_peer_number(conference_peer_name, peer_number);
tox_event_conference_peer_name_set_name(conference_peer_name, name, length);
tox_event_conference_peer_name_set_name(conference_peer_name, state->mem, name, length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_conference_title_get_peer_number(const Tox_Event_Conference_T
}
static bool tox_event_conference_title_set_title(Tox_Event_Conference_Title *_Nonnull conference_title,
const uint8_t *_Nullable title, uint32_t title_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable title, uint32_t title_length)
{
assert(conference_title != nullptr);
if (conference_title->title != nullptr) {
free(conference_title->title);
mem_delete(mem, conference_title->title);
conference_title->title = nullptr;
conference_title->title_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_conference_title_set_title(Tox_Event_Conference_Title *_No
return true;
}
uint8_t *title_copy = (uint8_t *)malloc(title_length);
uint8_t *title_copy = (uint8_t *)mem_balloc(mem, title_length);
if (title_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_conference_title_construct(Tox_Event_Conference_Title *_No
}
static void tox_event_conference_title_destruct(Tox_Event_Conference_Title *_Nonnull conference_title, const Memory *_Nonnull mem)
{
free(conference_title->title);
mem_delete(mem, conference_title->title);
}
bool tox_event_conference_title_pack(
@@ -148,7 +147,7 @@ Tox_Event_Conference_Title *tox_event_conference_title_new(const Memory *mem)
void tox_event_conference_title_free(Tox_Event_Conference_Title *conference_title, const Memory *mem)
{
if (conference_title != nullptr) {
tox_event_conference_title_destruct(conference_title, mem);
tox_event_conference_title_destruct((Tox_Event_Conference_Title * _Nonnull)conference_title, mem);
}
mem_delete(mem, conference_title);
}
@@ -186,11 +185,8 @@ bool tox_event_conference_title_unpack(
return tox_event_conference_title_unpack_into(*event, bu);
}
static Tox_Event_Conference_Title *tox_event_conference_title_alloc(void *_Nonnull user_data)
static Tox_Event_Conference_Title *tox_event_conference_title_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_conference_title(
Tox *tox, uint32_t conference_number, uint32_t peer_number, const uint8_t *title, size_t length,
void *user_data)
{
Tox_Event_Conference_Title *conference_title = tox_event_conference_title_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Conference_Title *conference_title = tox_event_conference_title_alloc(state);
if (conference_title == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_conference_title(
tox_event_conference_title_set_conference_number(conference_title, conference_number);
tox_event_conference_title_set_peer_number(conference_title, peer_number);
tox_event_conference_title_set_title(conference_title, title, length);
tox_event_conference_title_set_title(conference_title, state->mem, title, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2022-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -15,7 +15,6 @@
#include "../tox.h"
#include "../tox_event.h"
#include "../tox_events.h"
#include "../tox_private.h"
/*****************************************************
*
@@ -32,49 +31,62 @@ struct Tox_Event_Dht_Nodes_Response {
static bool tox_event_dht_nodes_response_set_public_key(Tox_Event_Dht_Nodes_Response *_Nonnull dht_nodes_response, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE])
{
assert(dht_nodes_response != nullptr);
memcpy(dht_nodes_response->public_key, public_key, TOX_PUBLIC_KEY_SIZE);
return true;
}
const uint8_t *_Nonnull tox_event_dht_nodes_response_get_public_key(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
const uint8_t *tox_event_dht_nodes_response_get_public_key(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
assert(dht_nodes_response != nullptr);
return dht_nodes_response->public_key;
}
static bool tox_event_dht_nodes_response_set_ip(Tox_Event_Dht_Nodes_Response *_Nonnull dht_nodes_response, const char *_Nonnull ip, uint32_t ip_length, const Memory *_Nonnull mem)
static bool tox_event_dht_nodes_response_set_ip(Tox_Event_Dht_Nodes_Response *_Nonnull dht_nodes_response,
const Memory *_Nonnull mem, const uint8_t *_Nullable ip, uint32_t ip_length)
{
assert(dht_nodes_response != nullptr);
if (dht_nodes_response->ip != nullptr) {
mem_delete(mem, dht_nodes_response->ip);
dht_nodes_response->ip = nullptr;
dht_nodes_response->ip_length = 0;
}
uint8_t *ip_tmp = (uint8_t *)mem_balloc(mem, ip_length + 1);
if (ip == nullptr) {
assert(ip_length == 0);
return true;
}
if (ip_tmp == nullptr) {
uint8_t *ip_copy = (uint8_t *)mem_balloc(mem, ip_length + 1);
if (ip_copy == nullptr) {
return false;
}
memcpy(ip_tmp, ip, ip_length + 1);
dht_nodes_response->ip = ip_tmp;
memcpy(ip_copy, ip, ip_length);
ip_copy[ip_length] = 0;
dht_nodes_response->ip = ip_copy;
dht_nodes_response->ip_length = ip_length;
return true;
}
uint32_t tox_event_dht_nodes_response_get_ip_length(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
assert(dht_nodes_response != nullptr);
return dht_nodes_response->ip_length;
}
const uint8_t *tox_event_dht_nodes_response_get_ip(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
assert(dht_nodes_response != nullptr);
return dht_nodes_response->ip;
}
static bool tox_event_dht_nodes_response_set_port(Tox_Event_Dht_Nodes_Response *_Nonnull dht_nodes_response, uint16_t port)
static void tox_event_dht_nodes_response_set_port(Tox_Event_Dht_Nodes_Response *_Nonnull dht_nodes_response, uint16_t port)
{
assert(dht_nodes_response != nullptr);
dht_nodes_response->port = port;
return true;
}
uint16_t tox_event_dht_nodes_response_get_port(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
assert(dht_nodes_response != nullptr);
return dht_nodes_response->port;
}
@@ -102,6 +114,7 @@ bool tox_event_dht_nodes_response_pack(
static bool tox_event_dht_nodes_response_unpack_into(Tox_Event_Dht_Nodes_Response *_Nonnull event, Bin_Unpack *_Nonnull bu)
{
assert(event != nullptr);
if (!bin_unpack_array_fixed(bu, 3, nullptr)) {
return false;
}
@@ -111,8 +124,13 @@ static bool tox_event_dht_nodes_response_unpack_into(Tox_Event_Dht_Nodes_Respons
&& bin_unpack_u16(bu, &event->port);
}
const Tox_Event_Dht_Nodes_Response *tox_event_get_dht_nodes_response(
const Tox_Event *event)
/*****************************************************
*
* :: new/free/add/get/size/unpack
*
*****************************************************/
const Tox_Event_Dht_Nodes_Response *tox_event_get_dht_nodes_response(const Tox_Event *event)
{
return event->type == TOX_EVENT_DHT_NODES_RESPONSE ? event->data.dht_nodes_response : nullptr;
}
@@ -133,7 +151,7 @@ Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_new(const Memory *mem
void tox_event_dht_nodes_response_free(Tox_Event_Dht_Nodes_Response *dht_nodes_response, const Memory *mem)
{
if (dht_nodes_response != nullptr) {
tox_event_dht_nodes_response_destruct(dht_nodes_response, mem);
tox_event_dht_nodes_response_destruct((Tox_Event_Dht_Nodes_Response * _Nonnull)dht_nodes_response, mem);
}
mem_delete(mem, dht_nodes_response);
}
@@ -160,6 +178,8 @@ static Tox_Event_Dht_Nodes_Response *tox_events_add_dht_nodes_response(Tox_Event
bool tox_event_dht_nodes_response_unpack(
Tox_Event_Dht_Nodes_Response **event, Bin_Unpack *bu, const Memory *mem)
{
assert(event != nullptr);
assert(*event == nullptr);
*event = tox_event_dht_nodes_response_new(mem);
if (*event == nullptr) {
@@ -169,11 +189,8 @@ bool tox_event_dht_nodes_response_unpack(
return tox_event_dht_nodes_response_unpack_into(*event, bu);
}
static Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_alloc(void *_Nonnull user_data)
static Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -195,18 +212,17 @@ static Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_alloc(void *_N
*****************************************************/
void tox_events_handle_dht_nodes_response(
Tox *tox, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
const char *ip, uint32_t ip_length, uint16_t port, void *user_data)
Tox *tox, const uint8_t *public_key, const char *ip, uint32_t ip_length, uint16_t port,
void *user_data)
{
Tox_Event_Dht_Nodes_Response *dht_nodes_response = tox_event_dht_nodes_response_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Dht_Nodes_Response *dht_nodes_response = tox_event_dht_nodes_response_alloc(state);
if (dht_nodes_response == nullptr) {
return;
}
const Tox_System *sys = tox_get_system(tox);
tox_event_dht_nodes_response_set_public_key(dht_nodes_response, public_key);
tox_event_dht_nodes_response_set_ip(dht_nodes_response, ip, ip_length, sys->mem);
tox_event_dht_nodes_response_set_ip(dht_nodes_response, state->mem, (const uint8_t *)ip, ip_length);
tox_event_dht_nodes_response_set_port(dht_nodes_response, port);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -133,7 +133,7 @@ Tox_Event_File_Chunk_Request *tox_event_file_chunk_request_new(const Memory *mem
void tox_event_file_chunk_request_free(Tox_Event_File_Chunk_Request *file_chunk_request, const Memory *mem)
{
if (file_chunk_request != nullptr) {
tox_event_file_chunk_request_destruct(file_chunk_request, mem);
tox_event_file_chunk_request_destruct((Tox_Event_File_Chunk_Request * _Nonnull)file_chunk_request, mem);
}
mem_delete(mem, file_chunk_request);
}
@@ -171,11 +171,8 @@ bool tox_event_file_chunk_request_unpack(
return tox_event_file_chunk_request_unpack_into(*event, bu);
}
static Tox_Event_File_Chunk_Request *tox_event_file_chunk_request_alloc(void *_Nonnull user_data)
static Tox_Event_File_Chunk_Request *tox_event_file_chunk_request_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -200,7 +197,8 @@ void tox_events_handle_file_chunk_request(
Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,
void *user_data)
{
Tox_Event_File_Chunk_Request *file_chunk_request = tox_event_file_chunk_request_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_File_Chunk_Request *file_chunk_request = tox_event_file_chunk_request_alloc(state);
if (file_chunk_request == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -77,11 +76,11 @@ uint64_t tox_event_file_recv_get_file_size(const Tox_Event_File_Recv *file_recv)
}
static bool tox_event_file_recv_set_filename(Tox_Event_File_Recv *_Nonnull file_recv,
const uint8_t *_Nullable filename, uint32_t filename_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable filename, uint32_t filename_length)
{
assert(file_recv != nullptr);
if (file_recv->filename != nullptr) {
free(file_recv->filename);
mem_delete(mem, file_recv->filename);
file_recv->filename = nullptr;
file_recv->filename_length = 0;
}
@@ -91,7 +90,7 @@ static bool tox_event_file_recv_set_filename(Tox_Event_File_Recv *_Nonnull file_
return true;
}
uint8_t *filename_copy = (uint8_t *)malloc(filename_length);
uint8_t *filename_copy = (uint8_t *)mem_balloc(mem, filename_length);
if (filename_copy == nullptr) {
return false;
@@ -121,7 +120,7 @@ static void tox_event_file_recv_construct(Tox_Event_File_Recv *_Nonnull file_rec
}
static void tox_event_file_recv_destruct(Tox_Event_File_Recv *_Nonnull file_recv, const Memory *_Nonnull mem)
{
free(file_recv->filename);
mem_delete(mem, file_recv->filename);
}
bool tox_event_file_recv_pack(
@@ -176,7 +175,7 @@ Tox_Event_File_Recv *tox_event_file_recv_new(const Memory *mem)
void tox_event_file_recv_free(Tox_Event_File_Recv *file_recv, const Memory *mem)
{
if (file_recv != nullptr) {
tox_event_file_recv_destruct(file_recv, mem);
tox_event_file_recv_destruct((Tox_Event_File_Recv * _Nonnull)file_recv, mem);
}
mem_delete(mem, file_recv);
}
@@ -214,11 +213,8 @@ bool tox_event_file_recv_unpack(
return tox_event_file_recv_unpack_into(*event, bu);
}
static Tox_Event_File_Recv *tox_event_file_recv_alloc(void *_Nonnull user_data)
static Tox_Event_File_Recv *tox_event_file_recv_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -243,7 +239,8 @@ void tox_events_handle_file_recv(
Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t file_size, const uint8_t *filename, size_t filename_length,
void *user_data)
{
Tox_Event_File_Recv *file_recv = tox_event_file_recv_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_File_Recv *file_recv = tox_event_file_recv_alloc(state);
if (file_recv == nullptr) {
return;
@@ -253,5 +250,5 @@ void tox_events_handle_file_recv(
tox_event_file_recv_set_file_number(file_recv, file_number);
tox_event_file_recv_set_kind(file_recv, kind);
tox_event_file_recv_set_file_size(file_recv, file_size);
tox_event_file_recv_set_filename(file_recv, filename, filename_length);
tox_event_file_recv_set_filename(file_recv, state->mem, filename, filename_length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -65,11 +64,11 @@ uint64_t tox_event_file_recv_chunk_get_position(const Tox_Event_File_Recv_Chunk
}
static bool tox_event_file_recv_chunk_set_data(Tox_Event_File_Recv_Chunk *_Nonnull file_recv_chunk,
const uint8_t *_Nullable data, uint32_t data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable data, uint32_t data_length)
{
assert(file_recv_chunk != nullptr);
if (file_recv_chunk->data != nullptr) {
free(file_recv_chunk->data);
mem_delete(mem, file_recv_chunk->data);
file_recv_chunk->data = nullptr;
file_recv_chunk->data_length = 0;
}
@@ -79,7 +78,7 @@ static bool tox_event_file_recv_chunk_set_data(Tox_Event_File_Recv_Chunk *_Nonnu
return true;
}
uint8_t *data_copy = (uint8_t *)malloc(data_length);
uint8_t *data_copy = (uint8_t *)mem_balloc(mem, data_length);
if (data_copy == nullptr) {
return false;
@@ -109,7 +108,7 @@ static void tox_event_file_recv_chunk_construct(Tox_Event_File_Recv_Chunk *_Nonn
}
static void tox_event_file_recv_chunk_destruct(Tox_Event_File_Recv_Chunk *_Nonnull file_recv_chunk, const Memory *_Nonnull mem)
{
free(file_recv_chunk->data);
mem_delete(mem, file_recv_chunk->data);
}
bool tox_event_file_recv_chunk_pack(
@@ -162,7 +161,7 @@ Tox_Event_File_Recv_Chunk *tox_event_file_recv_chunk_new(const Memory *mem)
void tox_event_file_recv_chunk_free(Tox_Event_File_Recv_Chunk *file_recv_chunk, const Memory *mem)
{
if (file_recv_chunk != nullptr) {
tox_event_file_recv_chunk_destruct(file_recv_chunk, mem);
tox_event_file_recv_chunk_destruct((Tox_Event_File_Recv_Chunk * _Nonnull)file_recv_chunk, mem);
}
mem_delete(mem, file_recv_chunk);
}
@@ -200,11 +199,8 @@ bool tox_event_file_recv_chunk_unpack(
return tox_event_file_recv_chunk_unpack_into(*event, bu);
}
static Tox_Event_File_Recv_Chunk *tox_event_file_recv_chunk_alloc(void *_Nonnull user_data)
static Tox_Event_File_Recv_Chunk *tox_event_file_recv_chunk_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -229,7 +225,8 @@ void tox_events_handle_file_recv_chunk(
Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, size_t length,
void *user_data)
{
Tox_Event_File_Recv_Chunk *file_recv_chunk = tox_event_file_recv_chunk_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_File_Recv_Chunk *file_recv_chunk = tox_event_file_recv_chunk_alloc(state);
if (file_recv_chunk == nullptr) {
return;
@@ -238,5 +235,5 @@ void tox_events_handle_file_recv_chunk(
tox_event_file_recv_chunk_set_friend_number(file_recv_chunk, friend_number);
tox_event_file_recv_chunk_set_file_number(file_recv_chunk, file_number);
tox_event_file_recv_chunk_set_position(file_recv_chunk, position);
tox_event_file_recv_chunk_set_data(file_recv_chunk, data, length);
tox_event_file_recv_chunk_set_data(file_recv_chunk, state->mem, data, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -121,7 +121,7 @@ Tox_Event_File_Recv_Control *tox_event_file_recv_control_new(const Memory *mem)
void tox_event_file_recv_control_free(Tox_Event_File_Recv_Control *file_recv_control, const Memory *mem)
{
if (file_recv_control != nullptr) {
tox_event_file_recv_control_destruct(file_recv_control, mem);
tox_event_file_recv_control_destruct((Tox_Event_File_Recv_Control * _Nonnull)file_recv_control, mem);
}
mem_delete(mem, file_recv_control);
}
@@ -159,11 +159,8 @@ bool tox_event_file_recv_control_unpack(
return tox_event_file_recv_control_unpack_into(*event, bu);
}
static Tox_Event_File_Recv_Control *tox_event_file_recv_control_alloc(void *_Nonnull user_data)
static Tox_Event_File_Recv_Control *tox_event_file_recv_control_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -188,7 +185,8 @@ void tox_events_handle_file_recv_control(
Tox *tox, uint32_t friend_number, uint32_t file_number, Tox_File_Control control,
void *user_data)
{
Tox_Event_File_Recv_Control *file_recv_control = tox_event_file_recv_control_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_File_Recv_Control *file_recv_control = tox_event_file_recv_control_alloc(state);
if (file_recv_control == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Friend_Connection_Status *tox_event_friend_connection_status_new(const
void tox_event_friend_connection_status_free(Tox_Event_Friend_Connection_Status *friend_connection_status, const Memory *mem)
{
if (friend_connection_status != nullptr) {
tox_event_friend_connection_status_destruct(friend_connection_status, mem);
tox_event_friend_connection_status_destruct((Tox_Event_Friend_Connection_Status * _Nonnull)friend_connection_status, mem);
}
mem_delete(mem, friend_connection_status);
}
@@ -145,11 +145,8 @@ bool tox_event_friend_connection_status_unpack(
return tox_event_friend_connection_status_unpack_into(*event, bu);
}
static Tox_Event_Friend_Connection_Status *tox_event_friend_connection_status_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Connection_Status *tox_event_friend_connection_status_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_friend_connection_status(
Tox *tox, uint32_t friend_number, Tox_Connection connection_status,
void *user_data)
{
Tox_Event_Friend_Connection_Status *friend_connection_status = tox_event_friend_connection_status_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Connection_Status *friend_connection_status = tox_event_friend_connection_status_alloc(state);
if (friend_connection_status == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -41,11 +40,11 @@ uint32_t tox_event_friend_lossless_packet_get_friend_number(const Tox_Event_Frie
}
static bool tox_event_friend_lossless_packet_set_data(Tox_Event_Friend_Lossless_Packet *_Nonnull friend_lossless_packet,
const uint8_t *_Nullable data, uint32_t data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable data, uint32_t data_length)
{
assert(friend_lossless_packet != nullptr);
if (friend_lossless_packet->data != nullptr) {
free(friend_lossless_packet->data);
mem_delete(mem, friend_lossless_packet->data);
friend_lossless_packet->data = nullptr;
friend_lossless_packet->data_length = 0;
}
@@ -55,7 +54,7 @@ static bool tox_event_friend_lossless_packet_set_data(Tox_Event_Friend_Lossless_
return true;
}
uint8_t *data_copy = (uint8_t *)malloc(data_length);
uint8_t *data_copy = (uint8_t *)mem_balloc(mem, data_length);
if (data_copy == nullptr) {
return false;
@@ -85,7 +84,7 @@ static void tox_event_friend_lossless_packet_construct(Tox_Event_Friend_Lossless
}
static void tox_event_friend_lossless_packet_destruct(Tox_Event_Friend_Lossless_Packet *_Nonnull friend_lossless_packet, const Memory *_Nonnull mem)
{
free(friend_lossless_packet->data);
mem_delete(mem, friend_lossless_packet->data);
}
bool tox_event_friend_lossless_packet_pack(
@@ -134,7 +133,7 @@ Tox_Event_Friend_Lossless_Packet *tox_event_friend_lossless_packet_new(const Mem
void tox_event_friend_lossless_packet_free(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet, const Memory *mem)
{
if (friend_lossless_packet != nullptr) {
tox_event_friend_lossless_packet_destruct(friend_lossless_packet, mem);
tox_event_friend_lossless_packet_destruct((Tox_Event_Friend_Lossless_Packet * _Nonnull)friend_lossless_packet, mem);
}
mem_delete(mem, friend_lossless_packet);
}
@@ -172,11 +171,8 @@ bool tox_event_friend_lossless_packet_unpack(
return tox_event_friend_lossless_packet_unpack_into(*event, bu);
}
static Tox_Event_Friend_Lossless_Packet *tox_event_friend_lossless_packet_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Lossless_Packet *tox_event_friend_lossless_packet_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -201,12 +197,13 @@ void tox_events_handle_friend_lossless_packet(
Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
void *user_data)
{
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet = tox_event_friend_lossless_packet_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet = tox_event_friend_lossless_packet_alloc(state);
if (friend_lossless_packet == nullptr) {
return;
}
tox_event_friend_lossless_packet_set_friend_number(friend_lossless_packet, friend_number);
tox_event_friend_lossless_packet_set_data(friend_lossless_packet, data, length);
tox_event_friend_lossless_packet_set_data(friend_lossless_packet, state->mem, data, length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -41,11 +40,11 @@ uint32_t tox_event_friend_lossy_packet_get_friend_number(const Tox_Event_Friend_
}
static bool tox_event_friend_lossy_packet_set_data(Tox_Event_Friend_Lossy_Packet *_Nonnull friend_lossy_packet,
const uint8_t *_Nullable data, uint32_t data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable data, uint32_t data_length)
{
assert(friend_lossy_packet != nullptr);
if (friend_lossy_packet->data != nullptr) {
free(friend_lossy_packet->data);
mem_delete(mem, friend_lossy_packet->data);
friend_lossy_packet->data = nullptr;
friend_lossy_packet->data_length = 0;
}
@@ -55,7 +54,7 @@ static bool tox_event_friend_lossy_packet_set_data(Tox_Event_Friend_Lossy_Packet
return true;
}
uint8_t *data_copy = (uint8_t *)malloc(data_length);
uint8_t *data_copy = (uint8_t *)mem_balloc(mem, data_length);
if (data_copy == nullptr) {
return false;
@@ -85,7 +84,7 @@ static void tox_event_friend_lossy_packet_construct(Tox_Event_Friend_Lossy_Packe
}
static void tox_event_friend_lossy_packet_destruct(Tox_Event_Friend_Lossy_Packet *_Nonnull friend_lossy_packet, const Memory *_Nonnull mem)
{
free(friend_lossy_packet->data);
mem_delete(mem, friend_lossy_packet->data);
}
bool tox_event_friend_lossy_packet_pack(
@@ -134,7 +133,7 @@ Tox_Event_Friend_Lossy_Packet *tox_event_friend_lossy_packet_new(const Memory *m
void tox_event_friend_lossy_packet_free(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet, const Memory *mem)
{
if (friend_lossy_packet != nullptr) {
tox_event_friend_lossy_packet_destruct(friend_lossy_packet, mem);
tox_event_friend_lossy_packet_destruct((Tox_Event_Friend_Lossy_Packet * _Nonnull)friend_lossy_packet, mem);
}
mem_delete(mem, friend_lossy_packet);
}
@@ -172,11 +171,8 @@ bool tox_event_friend_lossy_packet_unpack(
return tox_event_friend_lossy_packet_unpack_into(*event, bu);
}
static Tox_Event_Friend_Lossy_Packet *tox_event_friend_lossy_packet_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Lossy_Packet *tox_event_friend_lossy_packet_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -201,12 +197,13 @@ void tox_events_handle_friend_lossy_packet(
Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
void *user_data)
{
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet = tox_event_friend_lossy_packet_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet = tox_event_friend_lossy_packet_alloc(state);
if (friend_lossy_packet == nullptr) {
return;
}
tox_event_friend_lossy_packet_set_friend_number(friend_lossy_packet, friend_number);
tox_event_friend_lossy_packet_set_data(friend_lossy_packet, data, length);
tox_event_friend_lossy_packet_set_data(friend_lossy_packet, state->mem, data, length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -55,11 +54,11 @@ Tox_Message_Type tox_event_friend_message_get_type(const Tox_Event_Friend_Messag
}
static bool tox_event_friend_message_set_message(Tox_Event_Friend_Message *_Nonnull friend_message,
const uint8_t *_Nullable message, uint32_t message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(friend_message != nullptr);
if (friend_message->message != nullptr) {
free(friend_message->message);
mem_delete(mem, friend_message->message);
friend_message->message = nullptr;
friend_message->message_length = 0;
}
@@ -69,7 +68,7 @@ static bool tox_event_friend_message_set_message(Tox_Event_Friend_Message *_Nonn
return true;
}
uint8_t *message_copy = (uint8_t *)malloc(message_length);
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
return false;
@@ -99,7 +98,7 @@ static void tox_event_friend_message_construct(Tox_Event_Friend_Message *_Nonnul
}
static void tox_event_friend_message_destruct(Tox_Event_Friend_Message *_Nonnull friend_message, const Memory *_Nonnull mem)
{
free(friend_message->message);
mem_delete(mem, friend_message->message);
}
bool tox_event_friend_message_pack(
@@ -150,7 +149,7 @@ Tox_Event_Friend_Message *tox_event_friend_message_new(const Memory *mem)
void tox_event_friend_message_free(Tox_Event_Friend_Message *friend_message, const Memory *mem)
{
if (friend_message != nullptr) {
tox_event_friend_message_destruct(friend_message, mem);
tox_event_friend_message_destruct((Tox_Event_Friend_Message * _Nonnull)friend_message, mem);
}
mem_delete(mem, friend_message);
}
@@ -188,11 +187,8 @@ bool tox_event_friend_message_unpack(
return tox_event_friend_message_unpack_into(*event, bu);
}
static Tox_Event_Friend_Message *tox_event_friend_message_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Message *tox_event_friend_message_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -217,7 +213,8 @@ void tox_events_handle_friend_message(
Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message, size_t length,
void *user_data)
{
Tox_Event_Friend_Message *friend_message = tox_event_friend_message_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Message *friend_message = tox_event_friend_message_alloc(state);
if (friend_message == nullptr) {
return;
@@ -225,5 +222,5 @@ void tox_events_handle_friend_message(
tox_event_friend_message_set_friend_number(friend_message, friend_number);
tox_event_friend_message_set_type(friend_message, type);
tox_event_friend_message_set_message(friend_message, message, length);
tox_event_friend_message_set_message(friend_message, state->mem, message, length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -41,11 +40,11 @@ uint32_t tox_event_friend_name_get_friend_number(const Tox_Event_Friend_Name *fr
}
static bool tox_event_friend_name_set_name(Tox_Event_Friend_Name *_Nonnull friend_name,
const uint8_t *_Nullable name, uint32_t name_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable name, uint32_t name_length)
{
assert(friend_name != nullptr);
if (friend_name->name != nullptr) {
free(friend_name->name);
mem_delete(mem, friend_name->name);
friend_name->name = nullptr;
friend_name->name_length = 0;
}
@@ -55,7 +54,7 @@ static bool tox_event_friend_name_set_name(Tox_Event_Friend_Name *_Nonnull frien
return true;
}
uint8_t *name_copy = (uint8_t *)malloc(name_length);
uint8_t *name_copy = (uint8_t *)mem_balloc(mem, name_length);
if (name_copy == nullptr) {
return false;
@@ -85,7 +84,7 @@ static void tox_event_friend_name_construct(Tox_Event_Friend_Name *_Nonnull frie
}
static void tox_event_friend_name_destruct(Tox_Event_Friend_Name *_Nonnull friend_name, const Memory *_Nonnull mem)
{
free(friend_name->name);
mem_delete(mem, friend_name->name);
}
bool tox_event_friend_name_pack(
@@ -134,7 +133,7 @@ Tox_Event_Friend_Name *tox_event_friend_name_new(const Memory *mem)
void tox_event_friend_name_free(Tox_Event_Friend_Name *friend_name, const Memory *mem)
{
if (friend_name != nullptr) {
tox_event_friend_name_destruct(friend_name, mem);
tox_event_friend_name_destruct((Tox_Event_Friend_Name * _Nonnull)friend_name, mem);
}
mem_delete(mem, friend_name);
}
@@ -172,11 +171,8 @@ bool tox_event_friend_name_unpack(
return tox_event_friend_name_unpack_into(*event, bu);
}
static Tox_Event_Friend_Name *tox_event_friend_name_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Name *tox_event_friend_name_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -201,12 +197,13 @@ void tox_events_handle_friend_name(
Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length,
void *user_data)
{
Tox_Event_Friend_Name *friend_name = tox_event_friend_name_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Name *friend_name = tox_event_friend_name_alloc(state);
if (friend_name == nullptr) {
return;
}
tox_event_friend_name_set_friend_number(friend_name, friend_number);
tox_event_friend_name_set_name(friend_name, name, length);
tox_event_friend_name_set_name(friend_name, state->mem, name, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -105,7 +105,7 @@ Tox_Event_Friend_Read_Receipt *tox_event_friend_read_receipt_new(const Memory *m
void tox_event_friend_read_receipt_free(Tox_Event_Friend_Read_Receipt *friend_read_receipt, const Memory *mem)
{
if (friend_read_receipt != nullptr) {
tox_event_friend_read_receipt_destruct(friend_read_receipt, mem);
tox_event_friend_read_receipt_destruct((Tox_Event_Friend_Read_Receipt * _Nonnull)friend_read_receipt, mem);
}
mem_delete(mem, friend_read_receipt);
}
@@ -143,11 +143,8 @@ bool tox_event_friend_read_receipt_unpack(
return tox_event_friend_read_receipt_unpack_into(*event, bu);
}
static Tox_Event_Friend_Read_Receipt *tox_event_friend_read_receipt_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Read_Receipt *tox_event_friend_read_receipt_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -172,7 +169,8 @@ void tox_events_handle_friend_read_receipt(
Tox *tox, uint32_t friend_number, uint32_t message_id,
void *user_data)
{
Tox_Event_Friend_Read_Receipt *friend_read_receipt = tox_event_friend_read_receipt_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Read_Receipt *friend_read_receipt = tox_event_friend_read_receipt_alloc(state);
if (friend_read_receipt == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2022-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -15,7 +15,6 @@
#include "../tox.h"
#include "../tox_event.h"
#include "../tox_events.h"
#include "../tox_private.h"
/*****************************************************
*
@@ -29,10 +28,9 @@ struct Tox_Event_Friend_Request {
uint32_t message_length;
};
static bool tox_event_friend_request_set_public_key(Tox_Event_Friend_Request *_Nonnull friend_request, const uint8_t *_Nonnull public_key)
static bool tox_event_friend_request_set_public_key(Tox_Event_Friend_Request *_Nonnull friend_request, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE])
{
assert(friend_request != nullptr);
memcpy(friend_request->public_key, public_key, TOX_PUBLIC_KEY_SIZE);
return true;
}
@@ -42,16 +40,21 @@ const uint8_t *tox_event_friend_request_get_public_key(const Tox_Event_Friend_Re
return friend_request->public_key;
}
static bool tox_event_friend_request_set_message(Tox_Event_Friend_Request *_Nonnull friend_request, const uint8_t *_Nonnull message, uint32_t message_length, const Memory *_Nonnull mem)
static bool tox_event_friend_request_set_message(Tox_Event_Friend_Request *_Nonnull friend_request,
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(friend_request != nullptr);
if (friend_request->message != nullptr) {
mem_delete(mem, friend_request->message);
friend_request->message = nullptr;
friend_request->message_length = 0;
}
if (message == nullptr) {
assert(message_length == 0);
return true;
}
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
@@ -106,8 +109,13 @@ static bool tox_event_friend_request_unpack_into(Tox_Event_Friend_Request *_Nonn
&& bin_unpack_bin(bu, &event->message, &event->message_length);
}
const Tox_Event_Friend_Request *tox_event_get_friend_request(
const Tox_Event *event)
/*****************************************************
*
* :: new/free/add/get/size/unpack
*
*****************************************************/
const Tox_Event_Friend_Request *tox_event_get_friend_request(const Tox_Event *event)
{
return event->type == TOX_EVENT_FRIEND_REQUEST ? event->data.friend_request : nullptr;
}
@@ -128,7 +136,7 @@ Tox_Event_Friend_Request *tox_event_friend_request_new(const Memory *mem)
void tox_event_friend_request_free(Tox_Event_Friend_Request *friend_request, const Memory *mem)
{
if (friend_request != nullptr) {
tox_event_friend_request_destruct(friend_request, mem);
tox_event_friend_request_destruct((Tox_Event_Friend_Request * _Nonnull)friend_request, mem);
}
mem_delete(mem, friend_request);
}
@@ -166,11 +174,8 @@ bool tox_event_friend_request_unpack(
return tox_event_friend_request_unpack_into(*event, bu);
}
static Tox_Event_Friend_Request *tox_event_friend_request_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Request *tox_event_friend_request_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -191,17 +196,17 @@ static Tox_Event_Friend_Request *tox_event_friend_request_alloc(void *_Nonnull u
*
*****************************************************/
void tox_events_handle_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
void *user_data)
void tox_events_handle_friend_request(
Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
void *user_data)
{
Tox_Event_Friend_Request *friend_request = tox_event_friend_request_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Request *friend_request = tox_event_friend_request_alloc(state);
if (friend_request == nullptr) {
return;
}
const Tox_System *sys = tox_get_system(tox);
tox_event_friend_request_set_public_key(friend_request, public_key);
tox_event_friend_request_set_message(friend_request, message, length, sys->mem);
tox_event_friend_request_set_message(friend_request, state->mem, message, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Friend_Status *tox_event_friend_status_new(const Memory *mem)
void tox_event_friend_status_free(Tox_Event_Friend_Status *friend_status, const Memory *mem)
{
if (friend_status != nullptr) {
tox_event_friend_status_destruct(friend_status, mem);
tox_event_friend_status_destruct((Tox_Event_Friend_Status * _Nonnull)friend_status, mem);
}
mem_delete(mem, friend_status);
}
@@ -145,11 +145,8 @@ bool tox_event_friend_status_unpack(
return tox_event_friend_status_unpack_into(*event, bu);
}
static Tox_Event_Friend_Status *tox_event_friend_status_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Status *tox_event_friend_status_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_friend_status(
Tox *tox, uint32_t friend_number, Tox_User_Status status,
void *user_data)
{
Tox_Event_Friend_Status *friend_status = tox_event_friend_status_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Status *friend_status = tox_event_friend_status_alloc(state);
if (friend_status == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -41,11 +40,11 @@ uint32_t tox_event_friend_status_message_get_friend_number(const Tox_Event_Frien
}
static bool tox_event_friend_status_message_set_message(Tox_Event_Friend_Status_Message *_Nonnull friend_status_message,
const uint8_t *_Nullable message, uint32_t message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(friend_status_message != nullptr);
if (friend_status_message->message != nullptr) {
free(friend_status_message->message);
mem_delete(mem, friend_status_message->message);
friend_status_message->message = nullptr;
friend_status_message->message_length = 0;
}
@@ -55,7 +54,7 @@ static bool tox_event_friend_status_message_set_message(Tox_Event_Friend_Status_
return true;
}
uint8_t *message_copy = (uint8_t *)malloc(message_length);
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
return false;
@@ -85,7 +84,7 @@ static void tox_event_friend_status_message_construct(Tox_Event_Friend_Status_Me
}
static void tox_event_friend_status_message_destruct(Tox_Event_Friend_Status_Message *_Nonnull friend_status_message, const Memory *_Nonnull mem)
{
free(friend_status_message->message);
mem_delete(mem, friend_status_message->message);
}
bool tox_event_friend_status_message_pack(
@@ -134,7 +133,7 @@ Tox_Event_Friend_Status_Message *tox_event_friend_status_message_new(const Memor
void tox_event_friend_status_message_free(Tox_Event_Friend_Status_Message *friend_status_message, const Memory *mem)
{
if (friend_status_message != nullptr) {
tox_event_friend_status_message_destruct(friend_status_message, mem);
tox_event_friend_status_message_destruct((Tox_Event_Friend_Status_Message * _Nonnull)friend_status_message, mem);
}
mem_delete(mem, friend_status_message);
}
@@ -172,11 +171,8 @@ bool tox_event_friend_status_message_unpack(
return tox_event_friend_status_message_unpack_into(*event, bu);
}
static Tox_Event_Friend_Status_Message *tox_event_friend_status_message_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Status_Message *tox_event_friend_status_message_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -201,12 +197,13 @@ void tox_events_handle_friend_status_message(
Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length,
void *user_data)
{
Tox_Event_Friend_Status_Message *friend_status_message = tox_event_friend_status_message_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Status_Message *friend_status_message = tox_event_friend_status_message_alloc(state);
if (friend_status_message == nullptr) {
return;
}
tox_event_friend_status_message_set_friend_number(friend_status_message, friend_number);
tox_event_friend_status_message_set_message(friend_status_message, message, length);
tox_event_friend_status_message_set_message(friend_status_message, state->mem, message, length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -105,7 +105,7 @@ Tox_Event_Friend_Typing *tox_event_friend_typing_new(const Memory *mem)
void tox_event_friend_typing_free(Tox_Event_Friend_Typing *friend_typing, const Memory *mem)
{
if (friend_typing != nullptr) {
tox_event_friend_typing_destruct(friend_typing, mem);
tox_event_friend_typing_destruct((Tox_Event_Friend_Typing * _Nonnull)friend_typing, mem);
}
mem_delete(mem, friend_typing);
}
@@ -143,11 +143,8 @@ bool tox_event_friend_typing_unpack(
return tox_event_friend_typing_unpack_into(*event, bu);
}
static Tox_Event_Friend_Typing *tox_event_friend_typing_alloc(void *_Nonnull user_data)
static Tox_Event_Friend_Typing *tox_event_friend_typing_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -172,7 +169,8 @@ void tox_events_handle_friend_typing(
Tox *tox, uint32_t friend_number, bool typing,
void *user_data)
{
Tox_Event_Friend_Typing *friend_typing = tox_event_friend_typing_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Friend_Typing *friend_typing = tox_event_friend_typing_alloc(state);
if (friend_typing == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_group_custom_packet_get_peer_id(const Tox_Event_Group_Custom_
}
static bool tox_event_group_custom_packet_set_data(Tox_Event_Group_Custom_Packet *_Nonnull group_custom_packet,
const uint8_t *_Nullable data, uint32_t data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable data, uint32_t data_length)
{
assert(group_custom_packet != nullptr);
if (group_custom_packet->data != nullptr) {
free(group_custom_packet->data);
mem_delete(mem, group_custom_packet->data);
group_custom_packet->data = nullptr;
group_custom_packet->data_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_group_custom_packet_set_data(Tox_Event_Group_Custom_Packet
return true;
}
uint8_t *data_copy = (uint8_t *)malloc(data_length);
uint8_t *data_copy = (uint8_t *)mem_balloc(mem, data_length);
if (data_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_group_custom_packet_construct(Tox_Event_Group_Custom_Packe
}
static void tox_event_group_custom_packet_destruct(Tox_Event_Group_Custom_Packet *_Nonnull group_custom_packet, const Memory *_Nonnull mem)
{
free(group_custom_packet->data);
mem_delete(mem, group_custom_packet->data);
}
bool tox_event_group_custom_packet_pack(
@@ -148,7 +147,7 @@ Tox_Event_Group_Custom_Packet *tox_event_group_custom_packet_new(const Memory *m
void tox_event_group_custom_packet_free(Tox_Event_Group_Custom_Packet *group_custom_packet, const Memory *mem)
{
if (group_custom_packet != nullptr) {
tox_event_group_custom_packet_destruct(group_custom_packet, mem);
tox_event_group_custom_packet_destruct((Tox_Event_Group_Custom_Packet * _Nonnull)group_custom_packet, mem);
}
mem_delete(mem, group_custom_packet);
}
@@ -186,11 +185,8 @@ bool tox_event_group_custom_packet_unpack(
return tox_event_group_custom_packet_unpack_into(*event, bu);
}
static Tox_Event_Group_Custom_Packet *tox_event_group_custom_packet_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Custom_Packet *tox_event_group_custom_packet_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_group_custom_packet(
Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t data_length,
void *user_data)
{
Tox_Event_Group_Custom_Packet *group_custom_packet = tox_event_group_custom_packet_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Custom_Packet *group_custom_packet = tox_event_group_custom_packet_alloc(state);
if (group_custom_packet == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_group_custom_packet(
tox_event_group_custom_packet_set_group_number(group_custom_packet, group_number);
tox_event_group_custom_packet_set_peer_id(group_custom_packet, peer_id);
tox_event_group_custom_packet_set_data(group_custom_packet, data, data_length);
tox_event_group_custom_packet_set_data(group_custom_packet, state->mem, data, data_length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_group_custom_private_packet_get_peer_id(const Tox_Event_Group
}
static bool tox_event_group_custom_private_packet_set_data(Tox_Event_Group_Custom_Private_Packet *_Nonnull group_custom_private_packet,
const uint8_t *_Nullable data, uint32_t data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable data, uint32_t data_length)
{
assert(group_custom_private_packet != nullptr);
if (group_custom_private_packet->data != nullptr) {
free(group_custom_private_packet->data);
mem_delete(mem, group_custom_private_packet->data);
group_custom_private_packet->data = nullptr;
group_custom_private_packet->data_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_group_custom_private_packet_set_data(Tox_Event_Group_Custo
return true;
}
uint8_t *data_copy = (uint8_t *)malloc(data_length);
uint8_t *data_copy = (uint8_t *)mem_balloc(mem, data_length);
if (data_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_group_custom_private_packet_construct(Tox_Event_Group_Cust
}
static void tox_event_group_custom_private_packet_destruct(Tox_Event_Group_Custom_Private_Packet *_Nonnull group_custom_private_packet, const Memory *_Nonnull mem)
{
free(group_custom_private_packet->data);
mem_delete(mem, group_custom_private_packet->data);
}
bool tox_event_group_custom_private_packet_pack(
@@ -148,7 +147,7 @@ Tox_Event_Group_Custom_Private_Packet *tox_event_group_custom_private_packet_new
void tox_event_group_custom_private_packet_free(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet, const Memory *mem)
{
if (group_custom_private_packet != nullptr) {
tox_event_group_custom_private_packet_destruct(group_custom_private_packet, mem);
tox_event_group_custom_private_packet_destruct((Tox_Event_Group_Custom_Private_Packet * _Nonnull)group_custom_private_packet, mem);
}
mem_delete(mem, group_custom_private_packet);
}
@@ -186,11 +185,8 @@ bool tox_event_group_custom_private_packet_unpack(
return tox_event_group_custom_private_packet_unpack_into(*event, bu);
}
static Tox_Event_Group_Custom_Private_Packet *tox_event_group_custom_private_packet_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Custom_Private_Packet *tox_event_group_custom_private_packet_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_group_custom_private_packet(
Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t data_length,
void *user_data)
{
Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet = tox_event_group_custom_private_packet_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet = tox_event_group_custom_private_packet_alloc(state);
if (group_custom_private_packet == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_group_custom_private_packet(
tox_event_group_custom_private_packet_set_group_number(group_custom_private_packet, group_number);
tox_event_group_custom_private_packet_set_peer_id(group_custom_private_packet, peer_id);
tox_event_group_custom_private_packet_set_data(group_custom_private_packet, data, data_length);
tox_event_group_custom_private_packet_set_data(group_custom_private_packet, state->mem, data, data_length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -43,11 +42,11 @@ uint32_t tox_event_group_invite_get_friend_number(const Tox_Event_Group_Invite *
}
static bool tox_event_group_invite_set_invite_data(Tox_Event_Group_Invite *_Nonnull group_invite,
const uint8_t *_Nullable invite_data, uint32_t invite_data_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable invite_data, uint32_t invite_data_length)
{
assert(group_invite != nullptr);
if (group_invite->invite_data != nullptr) {
free(group_invite->invite_data);
mem_delete(mem, group_invite->invite_data);
group_invite->invite_data = nullptr;
group_invite->invite_data_length = 0;
}
@@ -57,7 +56,7 @@ static bool tox_event_group_invite_set_invite_data(Tox_Event_Group_Invite *_Nonn
return true;
}
uint8_t *invite_data_copy = (uint8_t *)malloc(invite_data_length);
uint8_t *invite_data_copy = (uint8_t *)mem_balloc(mem, invite_data_length);
if (invite_data_copy == nullptr) {
return false;
@@ -80,11 +79,11 @@ const uint8_t *tox_event_group_invite_get_invite_data(const Tox_Event_Group_Invi
}
static bool tox_event_group_invite_set_group_name(Tox_Event_Group_Invite *_Nonnull group_invite,
const uint8_t *_Nullable group_name, uint32_t group_name_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable group_name, uint32_t group_name_length)
{
assert(group_invite != nullptr);
if (group_invite->group_name != nullptr) {
free(group_invite->group_name);
mem_delete(mem, group_invite->group_name);
group_invite->group_name = nullptr;
group_invite->group_name_length = 0;
}
@@ -94,7 +93,7 @@ static bool tox_event_group_invite_set_group_name(Tox_Event_Group_Invite *_Nonnu
return true;
}
uint8_t *group_name_copy = (uint8_t *)malloc(group_name_length);
uint8_t *group_name_copy = (uint8_t *)mem_balloc(mem, group_name_length);
if (group_name_copy == nullptr) {
return false;
@@ -124,8 +123,8 @@ static void tox_event_group_invite_construct(Tox_Event_Group_Invite *_Nonnull gr
}
static void tox_event_group_invite_destruct(Tox_Event_Group_Invite *_Nonnull group_invite, const Memory *_Nonnull mem)
{
free(group_invite->invite_data);
free(group_invite->group_name);
mem_delete(mem, group_invite->invite_data);
mem_delete(mem, group_invite->group_name);
}
bool tox_event_group_invite_pack(
@@ -176,7 +175,7 @@ Tox_Event_Group_Invite *tox_event_group_invite_new(const Memory *mem)
void tox_event_group_invite_free(Tox_Event_Group_Invite *group_invite, const Memory *mem)
{
if (group_invite != nullptr) {
tox_event_group_invite_destruct(group_invite, mem);
tox_event_group_invite_destruct((Tox_Event_Group_Invite * _Nonnull)group_invite, mem);
}
mem_delete(mem, group_invite);
}
@@ -214,11 +213,8 @@ bool tox_event_group_invite_unpack(
return tox_event_group_invite_unpack_into(*event, bu);
}
static Tox_Event_Group_Invite *tox_event_group_invite_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Invite *tox_event_group_invite_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -243,13 +239,14 @@ void tox_events_handle_group_invite(
Tox *tox, uint32_t friend_number, const uint8_t *invite_data, size_t invite_data_length, const uint8_t *group_name, size_t group_name_length,
void *user_data)
{
Tox_Event_Group_Invite *group_invite = tox_event_group_invite_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Invite *group_invite = tox_event_group_invite_alloc(state);
if (group_invite == nullptr) {
return;
}
tox_event_group_invite_set_friend_number(group_invite, friend_number);
tox_event_group_invite_set_invite_data(group_invite, invite_data, invite_data_length);
tox_event_group_invite_set_group_name(group_invite, group_name, group_name_length);
tox_event_group_invite_set_invite_data(group_invite, state->mem, invite_data, invite_data_length);
tox_event_group_invite_set_group_name(group_invite, state->mem, group_name, group_name_length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Group_Join_Fail *tox_event_group_join_fail_new(const Memory *mem)
void tox_event_group_join_fail_free(Tox_Event_Group_Join_Fail *group_join_fail, const Memory *mem)
{
if (group_join_fail != nullptr) {
tox_event_group_join_fail_destruct(group_join_fail, mem);
tox_event_group_join_fail_destruct((Tox_Event_Group_Join_Fail * _Nonnull)group_join_fail, mem);
}
mem_delete(mem, group_join_fail);
}
@@ -145,11 +145,8 @@ bool tox_event_group_join_fail_unpack(
return tox_event_group_join_fail_unpack_into(*event, bu);
}
static Tox_Event_Group_Join_Fail *tox_event_group_join_fail_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Join_Fail *tox_event_group_join_fail_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_group_join_fail(
Tox *tox, uint32_t group_number, Tox_Group_Join_Fail fail_type,
void *user_data)
{
Tox_Event_Group_Join_Fail *group_join_fail = tox_event_group_join_fail_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Join_Fail *group_join_fail = tox_event_group_join_fail_alloc(state);
if (group_join_fail == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -68,11 +67,11 @@ Tox_Message_Type tox_event_group_message_get_message_type(const Tox_Event_Group_
}
static bool tox_event_group_message_set_message(Tox_Event_Group_Message *_Nonnull group_message,
const uint8_t *_Nullable message, uint32_t message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(group_message != nullptr);
if (group_message->message != nullptr) {
free(group_message->message);
mem_delete(mem, group_message->message);
group_message->message = nullptr;
group_message->message_length = 0;
}
@@ -82,7 +81,7 @@ static bool tox_event_group_message_set_message(Tox_Event_Group_Message *_Nonnul
return true;
}
uint8_t *message_copy = (uint8_t *)malloc(message_length);
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
return false;
@@ -123,7 +122,7 @@ static void tox_event_group_message_construct(Tox_Event_Group_Message *_Nonnull
}
static void tox_event_group_message_destruct(Tox_Event_Group_Message *_Nonnull group_message, const Memory *_Nonnull mem)
{
free(group_message->message);
mem_delete(mem, group_message->message);
}
bool tox_event_group_message_pack(
@@ -178,7 +177,7 @@ Tox_Event_Group_Message *tox_event_group_message_new(const Memory *mem)
void tox_event_group_message_free(Tox_Event_Group_Message *group_message, const Memory *mem)
{
if (group_message != nullptr) {
tox_event_group_message_destruct(group_message, mem);
tox_event_group_message_destruct((Tox_Event_Group_Message * _Nonnull)group_message, mem);
}
mem_delete(mem, group_message);
}
@@ -216,11 +215,8 @@ bool tox_event_group_message_unpack(
return tox_event_group_message_unpack_into(*event, bu);
}
static Tox_Event_Group_Message *tox_event_group_message_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Message *tox_event_group_message_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -245,7 +241,8 @@ void tox_events_handle_group_message(
Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type message_type, const uint8_t *message, size_t message_length, uint32_t message_id,
void *user_data)
{
Tox_Event_Group_Message *group_message = tox_event_group_message_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Message *group_message = tox_event_group_message_alloc(state);
if (group_message == nullptr) {
return;
@@ -254,6 +251,6 @@ void tox_events_handle_group_message(
tox_event_group_message_set_group_number(group_message, group_number);
tox_event_group_message_set_peer_id(group_message, peer_id);
tox_event_group_message_set_message_type(group_message, message_type);
tox_event_group_message_set_message(group_message, message, message_length);
tox_event_group_message_set_message(group_message, state->mem, message, message_length);
tox_event_group_message_set_message_id(group_message, message_id);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -135,7 +135,7 @@ Tox_Event_Group_Moderation *tox_event_group_moderation_new(const Memory *mem)
void tox_event_group_moderation_free(Tox_Event_Group_Moderation *group_moderation, const Memory *mem)
{
if (group_moderation != nullptr) {
tox_event_group_moderation_destruct(group_moderation, mem);
tox_event_group_moderation_destruct((Tox_Event_Group_Moderation * _Nonnull)group_moderation, mem);
}
mem_delete(mem, group_moderation);
}
@@ -173,11 +173,8 @@ bool tox_event_group_moderation_unpack(
return tox_event_group_moderation_unpack_into(*event, bu);
}
static Tox_Event_Group_Moderation *tox_event_group_moderation_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Moderation *tox_event_group_moderation_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -202,7 +199,8 @@ void tox_events_handle_group_moderation(
Tox *tox, uint32_t group_number, uint32_t source_peer_id, uint32_t target_peer_id, Tox_Group_Mod_Event mod_type,
void *user_data)
{
Tox_Event_Group_Moderation *group_moderation = tox_event_group_moderation_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Moderation *group_moderation = tox_event_group_moderation_alloc(state);
if (group_moderation == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -41,11 +40,11 @@ uint32_t tox_event_group_password_get_group_number(const Tox_Event_Group_Passwor
}
static bool tox_event_group_password_set_password(Tox_Event_Group_Password *_Nonnull group_password,
const uint8_t *_Nullable password, uint32_t password_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable password, uint32_t password_length)
{
assert(group_password != nullptr);
if (group_password->password != nullptr) {
free(group_password->password);
mem_delete(mem, group_password->password);
group_password->password = nullptr;
group_password->password_length = 0;
}
@@ -55,7 +54,7 @@ static bool tox_event_group_password_set_password(Tox_Event_Group_Password *_Non
return true;
}
uint8_t *password_copy = (uint8_t *)malloc(password_length);
uint8_t *password_copy = (uint8_t *)mem_balloc(mem, password_length);
if (password_copy == nullptr) {
return false;
@@ -85,7 +84,7 @@ static void tox_event_group_password_construct(Tox_Event_Group_Password *_Nonnul
}
static void tox_event_group_password_destruct(Tox_Event_Group_Password *_Nonnull group_password, const Memory *_Nonnull mem)
{
free(group_password->password);
mem_delete(mem, group_password->password);
}
bool tox_event_group_password_pack(
@@ -134,7 +133,7 @@ Tox_Event_Group_Password *tox_event_group_password_new(const Memory *mem)
void tox_event_group_password_free(Tox_Event_Group_Password *group_password, const Memory *mem)
{
if (group_password != nullptr) {
tox_event_group_password_destruct(group_password, mem);
tox_event_group_password_destruct((Tox_Event_Group_Password * _Nonnull)group_password, mem);
}
mem_delete(mem, group_password);
}
@@ -172,11 +171,8 @@ bool tox_event_group_password_unpack(
return tox_event_group_password_unpack_into(*event, bu);
}
static Tox_Event_Group_Password *tox_event_group_password_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Password *tox_event_group_password_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -201,12 +197,13 @@ void tox_events_handle_group_password(
Tox *tox, uint32_t group_number, const uint8_t *password, size_t password_length,
void *user_data)
{
Tox_Event_Group_Password *group_password = tox_event_group_password_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Password *group_password = tox_event_group_password_alloc(state);
if (group_password == nullptr) {
return;
}
tox_event_group_password_set_group_number(group_password, group_number);
tox_event_group_password_set_password(group_password, password, password_length);
tox_event_group_password_set_password(group_password, state->mem, password, password_length);
}

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -69,11 +68,11 @@ Tox_Group_Exit_Type tox_event_group_peer_exit_get_exit_type(const Tox_Event_Grou
}
static bool tox_event_group_peer_exit_set_name(Tox_Event_Group_Peer_Exit *_Nonnull group_peer_exit,
const uint8_t *_Nullable name, uint32_t name_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable name, uint32_t name_length)
{
assert(group_peer_exit != nullptr);
if (group_peer_exit->name != nullptr) {
free(group_peer_exit->name);
mem_delete(mem, group_peer_exit->name);
group_peer_exit->name = nullptr;
group_peer_exit->name_length = 0;
}
@@ -83,7 +82,7 @@ static bool tox_event_group_peer_exit_set_name(Tox_Event_Group_Peer_Exit *_Nonnu
return true;
}
uint8_t *name_copy = (uint8_t *)malloc(name_length);
uint8_t *name_copy = (uint8_t *)mem_balloc(mem, name_length);
if (name_copy == nullptr) {
return false;
@@ -106,11 +105,11 @@ const uint8_t *tox_event_group_peer_exit_get_name(const Tox_Event_Group_Peer_Exi
}
static bool tox_event_group_peer_exit_set_part_message(Tox_Event_Group_Peer_Exit *_Nonnull group_peer_exit,
const uint8_t *_Nullable part_message, uint32_t part_message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable part_message, uint32_t part_message_length)
{
assert(group_peer_exit != nullptr);
if (group_peer_exit->part_message != nullptr) {
free(group_peer_exit->part_message);
mem_delete(mem, group_peer_exit->part_message);
group_peer_exit->part_message = nullptr;
group_peer_exit->part_message_length = 0;
}
@@ -120,7 +119,7 @@ static bool tox_event_group_peer_exit_set_part_message(Tox_Event_Group_Peer_Exit
return true;
}
uint8_t *part_message_copy = (uint8_t *)malloc(part_message_length);
uint8_t *part_message_copy = (uint8_t *)mem_balloc(mem, part_message_length);
if (part_message_copy == nullptr) {
return false;
@@ -150,8 +149,8 @@ static void tox_event_group_peer_exit_construct(Tox_Event_Group_Peer_Exit *_Nonn
}
static void tox_event_group_peer_exit_destruct(Tox_Event_Group_Peer_Exit *_Nonnull group_peer_exit, const Memory *_Nonnull mem)
{
free(group_peer_exit->name);
free(group_peer_exit->part_message);
mem_delete(mem, group_peer_exit->name);
mem_delete(mem, group_peer_exit->part_message);
}
bool tox_event_group_peer_exit_pack(
@@ -206,7 +205,7 @@ Tox_Event_Group_Peer_Exit *tox_event_group_peer_exit_new(const Memory *mem)
void tox_event_group_peer_exit_free(Tox_Event_Group_Peer_Exit *group_peer_exit, const Memory *mem)
{
if (group_peer_exit != nullptr) {
tox_event_group_peer_exit_destruct(group_peer_exit, mem);
tox_event_group_peer_exit_destruct((Tox_Event_Group_Peer_Exit * _Nonnull)group_peer_exit, mem);
}
mem_delete(mem, group_peer_exit);
}
@@ -244,11 +243,8 @@ bool tox_event_group_peer_exit_unpack(
return tox_event_group_peer_exit_unpack_into(*event, bu);
}
static Tox_Event_Group_Peer_Exit *tox_event_group_peer_exit_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Peer_Exit *tox_event_group_peer_exit_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -273,7 +269,8 @@ void tox_events_handle_group_peer_exit(
Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Group_Exit_Type exit_type, const uint8_t *name, size_t name_length, const uint8_t *part_message, size_t part_message_length,
void *user_data)
{
Tox_Event_Group_Peer_Exit *group_peer_exit = tox_event_group_peer_exit_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Peer_Exit *group_peer_exit = tox_event_group_peer_exit_alloc(state);
if (group_peer_exit == nullptr) {
return;
@@ -282,6 +279,6 @@ void tox_events_handle_group_peer_exit(
tox_event_group_peer_exit_set_group_number(group_peer_exit, group_number);
tox_event_group_peer_exit_set_peer_id(group_peer_exit, peer_id);
tox_event_group_peer_exit_set_exit_type(group_peer_exit, exit_type);
tox_event_group_peer_exit_set_name(group_peer_exit, name, name_length);
tox_event_group_peer_exit_set_part_message(group_peer_exit, part_message, part_message_length);
tox_event_group_peer_exit_set_name(group_peer_exit, state->mem, name, name_length);
tox_event_group_peer_exit_set_part_message(group_peer_exit, state->mem, part_message, part_message_length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -105,7 +105,7 @@ Tox_Event_Group_Peer_Join *tox_event_group_peer_join_new(const Memory *mem)
void tox_event_group_peer_join_free(Tox_Event_Group_Peer_Join *group_peer_join, const Memory *mem)
{
if (group_peer_join != nullptr) {
tox_event_group_peer_join_destruct(group_peer_join, mem);
tox_event_group_peer_join_destruct((Tox_Event_Group_Peer_Join * _Nonnull)group_peer_join, mem);
}
mem_delete(mem, group_peer_join);
}
@@ -143,11 +143,8 @@ bool tox_event_group_peer_join_unpack(
return tox_event_group_peer_join_unpack_into(*event, bu);
}
static Tox_Event_Group_Peer_Join *tox_event_group_peer_join_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Peer_Join *tox_event_group_peer_join_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -172,7 +169,8 @@ void tox_events_handle_group_peer_join(
Tox *tox, uint32_t group_number, uint32_t peer_id,
void *user_data)
{
Tox_Event_Group_Peer_Join *group_peer_join = tox_event_group_peer_join_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Peer_Join *group_peer_join = tox_event_group_peer_join_alloc(state);
if (group_peer_join == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -105,7 +105,7 @@ Tox_Event_Group_Peer_Limit *tox_event_group_peer_limit_new(const Memory *mem)
void tox_event_group_peer_limit_free(Tox_Event_Group_Peer_Limit *group_peer_limit, const Memory *mem)
{
if (group_peer_limit != nullptr) {
tox_event_group_peer_limit_destruct(group_peer_limit, mem);
tox_event_group_peer_limit_destruct((Tox_Event_Group_Peer_Limit * _Nonnull)group_peer_limit, mem);
}
mem_delete(mem, group_peer_limit);
}
@@ -143,11 +143,8 @@ bool tox_event_group_peer_limit_unpack(
return tox_event_group_peer_limit_unpack_into(*event, bu);
}
static Tox_Event_Group_Peer_Limit *tox_event_group_peer_limit_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Peer_Limit *tox_event_group_peer_limit_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -172,7 +169,8 @@ void tox_events_handle_group_peer_limit(
Tox *tox, uint32_t group_number, uint32_t peer_limit,
void *user_data)
{
Tox_Event_Group_Peer_Limit *group_peer_limit = tox_event_group_peer_limit_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Peer_Limit *group_peer_limit = tox_event_group_peer_limit_alloc(state);
if (group_peer_limit == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_group_peer_name_get_peer_id(const Tox_Event_Group_Peer_Name *
}
static bool tox_event_group_peer_name_set_name(Tox_Event_Group_Peer_Name *_Nonnull group_peer_name,
const uint8_t *_Nullable name, uint32_t name_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable name, uint32_t name_length)
{
assert(group_peer_name != nullptr);
if (group_peer_name->name != nullptr) {
free(group_peer_name->name);
mem_delete(mem, group_peer_name->name);
group_peer_name->name = nullptr;
group_peer_name->name_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_group_peer_name_set_name(Tox_Event_Group_Peer_Name *_Nonnu
return true;
}
uint8_t *name_copy = (uint8_t *)malloc(name_length);
uint8_t *name_copy = (uint8_t *)mem_balloc(mem, name_length);
if (name_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_group_peer_name_construct(Tox_Event_Group_Peer_Name *_Nonn
}
static void tox_event_group_peer_name_destruct(Tox_Event_Group_Peer_Name *_Nonnull group_peer_name, const Memory *_Nonnull mem)
{
free(group_peer_name->name);
mem_delete(mem, group_peer_name->name);
}
bool tox_event_group_peer_name_pack(
@@ -148,7 +147,7 @@ Tox_Event_Group_Peer_Name *tox_event_group_peer_name_new(const Memory *mem)
void tox_event_group_peer_name_free(Tox_Event_Group_Peer_Name *group_peer_name, const Memory *mem)
{
if (group_peer_name != nullptr) {
tox_event_group_peer_name_destruct(group_peer_name, mem);
tox_event_group_peer_name_destruct((Tox_Event_Group_Peer_Name * _Nonnull)group_peer_name, mem);
}
mem_delete(mem, group_peer_name);
}
@@ -186,11 +185,8 @@ bool tox_event_group_peer_name_unpack(
return tox_event_group_peer_name_unpack_into(*event, bu);
}
static Tox_Event_Group_Peer_Name *tox_event_group_peer_name_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Peer_Name *tox_event_group_peer_name_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_group_peer_name(
Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t name_length,
void *user_data)
{
Tox_Event_Group_Peer_Name *group_peer_name = tox_event_group_peer_name_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Peer_Name *group_peer_name = tox_event_group_peer_name_alloc(state);
if (group_peer_name == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_group_peer_name(
tox_event_group_peer_name_set_group_number(group_peer_name, group_number);
tox_event_group_peer_name_set_peer_id(group_peer_name, peer_id);
tox_event_group_peer_name_set_name(group_peer_name, name, name_length);
tox_event_group_peer_name_set_name(group_peer_name, state->mem, name, name_length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -121,7 +121,7 @@ Tox_Event_Group_Peer_Status *tox_event_group_peer_status_new(const Memory *mem)
void tox_event_group_peer_status_free(Tox_Event_Group_Peer_Status *group_peer_status, const Memory *mem)
{
if (group_peer_status != nullptr) {
tox_event_group_peer_status_destruct(group_peer_status, mem);
tox_event_group_peer_status_destruct((Tox_Event_Group_Peer_Status * _Nonnull)group_peer_status, mem);
}
mem_delete(mem, group_peer_status);
}
@@ -159,11 +159,8 @@ bool tox_event_group_peer_status_unpack(
return tox_event_group_peer_status_unpack_into(*event, bu);
}
static Tox_Event_Group_Peer_Status *tox_event_group_peer_status_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Peer_Status *tox_event_group_peer_status_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -188,7 +185,8 @@ void tox_events_handle_group_peer_status(
Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_User_Status status,
void *user_data)
{
Tox_Event_Group_Peer_Status *group_peer_status = tox_event_group_peer_status_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Peer_Status *group_peer_status = tox_event_group_peer_status_alloc(state);
if (group_peer_status == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Group_Privacy_State *tox_event_group_privacy_state_new(const Memory *m
void tox_event_group_privacy_state_free(Tox_Event_Group_Privacy_State *group_privacy_state, const Memory *mem)
{
if (group_privacy_state != nullptr) {
tox_event_group_privacy_state_destruct(group_privacy_state, mem);
tox_event_group_privacy_state_destruct((Tox_Event_Group_Privacy_State * _Nonnull)group_privacy_state, mem);
}
mem_delete(mem, group_privacy_state);
}
@@ -145,11 +145,8 @@ bool tox_event_group_privacy_state_unpack(
return tox_event_group_privacy_state_unpack_into(*event, bu);
}
static Tox_Event_Group_Privacy_State *tox_event_group_privacy_state_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Privacy_State *tox_event_group_privacy_state_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_group_privacy_state(
Tox *tox, uint32_t group_number, Tox_Group_Privacy_State privacy_state,
void *user_data)
{
Tox_Event_Group_Privacy_State *group_privacy_state = tox_event_group_privacy_state_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Privacy_State *group_privacy_state = tox_event_group_privacy_state_alloc(state);
if (group_privacy_state == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -68,11 +67,11 @@ Tox_Message_Type tox_event_group_private_message_get_message_type(const Tox_Even
}
static bool tox_event_group_private_message_set_message(Tox_Event_Group_Private_Message *_Nonnull group_private_message,
const uint8_t *_Nullable message, uint32_t message_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable message, uint32_t message_length)
{
assert(group_private_message != nullptr);
if (group_private_message->message != nullptr) {
free(group_private_message->message);
mem_delete(mem, group_private_message->message);
group_private_message->message = nullptr;
group_private_message->message_length = 0;
}
@@ -82,7 +81,7 @@ static bool tox_event_group_private_message_set_message(Tox_Event_Group_Private_
return true;
}
uint8_t *message_copy = (uint8_t *)malloc(message_length);
uint8_t *message_copy = (uint8_t *)mem_balloc(mem, message_length);
if (message_copy == nullptr) {
return false;
@@ -123,7 +122,7 @@ static void tox_event_group_private_message_construct(Tox_Event_Group_Private_Me
}
static void tox_event_group_private_message_destruct(Tox_Event_Group_Private_Message *_Nonnull group_private_message, const Memory *_Nonnull mem)
{
free(group_private_message->message);
mem_delete(mem, group_private_message->message);
}
bool tox_event_group_private_message_pack(
@@ -178,7 +177,7 @@ Tox_Event_Group_Private_Message *tox_event_group_private_message_new(const Memor
void tox_event_group_private_message_free(Tox_Event_Group_Private_Message *group_private_message, const Memory *mem)
{
if (group_private_message != nullptr) {
tox_event_group_private_message_destruct(group_private_message, mem);
tox_event_group_private_message_destruct((Tox_Event_Group_Private_Message * _Nonnull)group_private_message, mem);
}
mem_delete(mem, group_private_message);
}
@@ -216,11 +215,8 @@ bool tox_event_group_private_message_unpack(
return tox_event_group_private_message_unpack_into(*event, bu);
}
static Tox_Event_Group_Private_Message *tox_event_group_private_message_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Private_Message *tox_event_group_private_message_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -245,7 +241,8 @@ void tox_events_handle_group_private_message(
Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type message_type, const uint8_t *message, size_t message_length, uint32_t message_id,
void *user_data)
{
Tox_Event_Group_Private_Message *group_private_message = tox_event_group_private_message_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Private_Message *group_private_message = tox_event_group_private_message_alloc(state);
if (group_private_message == nullptr) {
return;
@@ -254,6 +251,6 @@ void tox_events_handle_group_private_message(
tox_event_group_private_message_set_group_number(group_private_message, group_number);
tox_event_group_private_message_set_peer_id(group_private_message, peer_id);
tox_event_group_private_message_set_message_type(group_private_message, message_type);
tox_event_group_private_message_set_message(group_private_message, message, message_length);
tox_event_group_private_message_set_message(group_private_message, state->mem, message, message_length);
tox_event_group_private_message_set_message_id(group_private_message, message_id);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -86,7 +86,7 @@ Tox_Event_Group_Self_Join *tox_event_group_self_join_new(const Memory *mem)
void tox_event_group_self_join_free(Tox_Event_Group_Self_Join *group_self_join, const Memory *mem)
{
if (group_self_join != nullptr) {
tox_event_group_self_join_destruct(group_self_join, mem);
tox_event_group_self_join_destruct((Tox_Event_Group_Self_Join * _Nonnull)group_self_join, mem);
}
mem_delete(mem, group_self_join);
}
@@ -124,11 +124,8 @@ bool tox_event_group_self_join_unpack(
return tox_event_group_self_join_unpack_into(*event, bu);
}
static Tox_Event_Group_Self_Join *tox_event_group_self_join_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Self_Join *tox_event_group_self_join_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -153,7 +150,8 @@ void tox_events_handle_group_self_join(
Tox *tox, uint32_t group_number,
void *user_data)
{
Tox_Event_Group_Self_Join *group_self_join = tox_event_group_self_join_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Self_Join *group_self_join = tox_event_group_self_join_alloc(state);
if (group_self_join == nullptr) {
return;

View File

@@ -1,11 +1,10 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../attributes.h"
@@ -53,11 +52,11 @@ uint32_t tox_event_group_topic_get_peer_id(const Tox_Event_Group_Topic *group_to
}
static bool tox_event_group_topic_set_topic(Tox_Event_Group_Topic *_Nonnull group_topic,
const uint8_t *_Nullable topic, uint32_t topic_length)
const Memory *_Nonnull mem, const uint8_t *_Nullable topic, uint32_t topic_length)
{
assert(group_topic != nullptr);
if (group_topic->topic != nullptr) {
free(group_topic->topic);
mem_delete(mem, group_topic->topic);
group_topic->topic = nullptr;
group_topic->topic_length = 0;
}
@@ -67,7 +66,7 @@ static bool tox_event_group_topic_set_topic(Tox_Event_Group_Topic *_Nonnull grou
return true;
}
uint8_t *topic_copy = (uint8_t *)malloc(topic_length);
uint8_t *topic_copy = (uint8_t *)mem_balloc(mem, topic_length);
if (topic_copy == nullptr) {
return false;
@@ -97,7 +96,7 @@ static void tox_event_group_topic_construct(Tox_Event_Group_Topic *_Nonnull grou
}
static void tox_event_group_topic_destruct(Tox_Event_Group_Topic *_Nonnull group_topic, const Memory *_Nonnull mem)
{
free(group_topic->topic);
mem_delete(mem, group_topic->topic);
}
bool tox_event_group_topic_pack(
@@ -148,7 +147,7 @@ Tox_Event_Group_Topic *tox_event_group_topic_new(const Memory *mem)
void tox_event_group_topic_free(Tox_Event_Group_Topic *group_topic, const Memory *mem)
{
if (group_topic != nullptr) {
tox_event_group_topic_destruct(group_topic, mem);
tox_event_group_topic_destruct((Tox_Event_Group_Topic * _Nonnull)group_topic, mem);
}
mem_delete(mem, group_topic);
}
@@ -186,11 +185,8 @@ bool tox_event_group_topic_unpack(
return tox_event_group_topic_unpack_into(*event, bu);
}
static Tox_Event_Group_Topic *tox_event_group_topic_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Topic *tox_event_group_topic_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -215,7 +211,8 @@ void tox_events_handle_group_topic(
Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, size_t topic_length,
void *user_data)
{
Tox_Event_Group_Topic *group_topic = tox_event_group_topic_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Topic *group_topic = tox_event_group_topic_alloc(state);
if (group_topic == nullptr) {
return;
@@ -223,5 +220,5 @@ void tox_events_handle_group_topic(
tox_event_group_topic_set_group_number(group_topic, group_number);
tox_event_group_topic_set_peer_id(group_topic, peer_id);
tox_event_group_topic_set_topic(group_topic, topic, topic_length);
tox_event_group_topic_set_topic(group_topic, state->mem, topic, topic_length);
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Group_Topic_Lock *tox_event_group_topic_lock_new(const Memory *mem)
void tox_event_group_topic_lock_free(Tox_Event_Group_Topic_Lock *group_topic_lock, const Memory *mem)
{
if (group_topic_lock != nullptr) {
tox_event_group_topic_lock_destruct(group_topic_lock, mem);
tox_event_group_topic_lock_destruct((Tox_Event_Group_Topic_Lock * _Nonnull)group_topic_lock, mem);
}
mem_delete(mem, group_topic_lock);
}
@@ -145,11 +145,8 @@ bool tox_event_group_topic_lock_unpack(
return tox_event_group_topic_lock_unpack_into(*event, bu);
}
static Tox_Event_Group_Topic_Lock *tox_event_group_topic_lock_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Topic_Lock *tox_event_group_topic_lock_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_group_topic_lock(
Tox *tox, uint32_t group_number, Tox_Group_Topic_Lock topic_lock,
void *user_data)
{
Tox_Event_Group_Topic_Lock *group_topic_lock = tox_event_group_topic_lock_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Topic_Lock *group_topic_lock = tox_event_group_topic_lock_alloc(state);
if (group_topic_lock == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -107,7 +107,7 @@ Tox_Event_Group_Voice_State *tox_event_group_voice_state_new(const Memory *mem)
void tox_event_group_voice_state_free(Tox_Event_Group_Voice_State *group_voice_state, const Memory *mem)
{
if (group_voice_state != nullptr) {
tox_event_group_voice_state_destruct(group_voice_state, mem);
tox_event_group_voice_state_destruct((Tox_Event_Group_Voice_State * _Nonnull)group_voice_state, mem);
}
mem_delete(mem, group_voice_state);
}
@@ -145,11 +145,8 @@ bool tox_event_group_voice_state_unpack(
return tox_event_group_voice_state_unpack_into(*event, bu);
}
static Tox_Event_Group_Voice_State *tox_event_group_voice_state_alloc(void *_Nonnull user_data)
static Tox_Event_Group_Voice_State *tox_event_group_voice_state_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -174,7 +171,8 @@ void tox_events_handle_group_voice_state(
Tox *tox, uint32_t group_number, Tox_Group_Voice_State voice_state,
void *user_data)
{
Tox_Event_Group_Voice_State *group_voice_state = tox_event_group_voice_state_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Group_Voice_State *group_voice_state = tox_event_group_voice_state_alloc(state);
if (group_voice_state == nullptr) {
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
@@ -88,7 +88,7 @@ Tox_Event_Self_Connection_Status *tox_event_self_connection_status_new(const Mem
void tox_event_self_connection_status_free(Tox_Event_Self_Connection_Status *self_connection_status, const Memory *mem)
{
if (self_connection_status != nullptr) {
tox_event_self_connection_status_destruct(self_connection_status, mem);
tox_event_self_connection_status_destruct((Tox_Event_Self_Connection_Status * _Nonnull)self_connection_status, mem);
}
mem_delete(mem, self_connection_status);
}
@@ -126,11 +126,8 @@ bool tox_event_self_connection_status_unpack(
return tox_event_self_connection_status_unpack_into(*event, bu);
}
static Tox_Event_Self_Connection_Status *tox_event_self_connection_status_alloc(void *_Nonnull user_data)
static Tox_Event_Self_Connection_Status *tox_event_self_connection_status_alloc(Tox_Events_State *_Nonnull state)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
@@ -155,7 +152,8 @@ void tox_events_handle_self_connection_status(
Tox *tox, Tox_Connection connection_status,
void *user_data)
{
Tox_Event_Self_Connection_Status *self_connection_status = tox_event_self_connection_status_alloc(user_data);
Tox_Events_State *state = tox_events_alloc(user_data);
Tox_Event_Self_Connection_Status *self_connection_status = tox_event_self_connection_status_alloc(state);
if (self_connection_status == nullptr) {
return;

View File

@@ -18,12 +18,12 @@
#include "timed_auth.h"
struct Forwarding {
const Logger *log;
const Memory *mem;
const Random *rng;
DHT *dht;
const Mono_Time *mono_time;
Networking_Core *net;
const Logger *_Nonnull log;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
DHT *_Nonnull dht;
const Mono_Time *_Nonnull mono_time;
Networking_Core *_Nonnull net;
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];

View File

@@ -5,11 +5,21 @@
#include <memory>
#include <optional>
#include "../testing/fuzzing/fuzz_support.hh"
#include "../testing/fuzzing/fuzz_tox.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/fuzz_helpers.hh"
#include "../testing/support/public/simulated_environment.hh"
namespace {
using tox::test::configure_fuzz_memory_source;
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
constexpr uint16_t SIZE_IP_PORT = SIZE_IP6 + sizeof(uint16_t);
template <typename T>
using Ptr = std::unique_ptr<T, void (*)(T *)>;
std::optional<std::tuple<IP_Port, IP_Port, const uint8_t *, size_t>> prepare(Fuzz_Data &input)
{
CONSUME_OR_RETURN_VAL(const uint8_t *ipp_packed, input, SIZE_IP_PORT, std::nullopt);
@@ -43,16 +53,18 @@ void TestSendForwardRequest(Fuzz_Data &input)
}
const auto [ipp, forwarder, data, data_size] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
SimulatedEnvironment env;
auto node = env.create_node(ipp.port);
configure_fuzz_memory_source(env.fake_memory(), input);
const Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
const Ptr<Logger> logger(logger_new(&node->c_memory), logger_kill);
if (logger == nullptr) {
return;
}
const Ptr<Networking_Core> net(new_networking_ex(logger.get(), sys.mem.get(), sys.ns.get(),
&ipp.ip, ipp.port, ipp.port + 100, nullptr),
const Ptr<Networking_Core> net(
new_networking_ex(logger.get(), &node->c_memory, &node->c_network, &ipp.ip, ipp.port,
ipp.port + 100, nullptr),
kill_networking);
if (net == nullptr) {
return;
@@ -72,16 +84,18 @@ void TestForwardReply(Fuzz_Data &input)
}
const auto [ipp, forwarder, data, data_size] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
SimulatedEnvironment env;
auto node = env.create_node(ipp.port);
configure_fuzz_memory_source(env.fake_memory(), input);
const Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
const Ptr<Logger> logger(logger_new(&node->c_memory), logger_kill);
if (logger == nullptr) {
return;
}
const Ptr<Networking_Core> net(new_networking_ex(logger.get(), sys.mem.get(), sys.ns.get(),
&ipp.ip, ipp.port, ipp.port + 100, nullptr),
const Ptr<Networking_Core> net(
new_networking_ex(logger.get(), &node->c_memory, &node->c_network, &ipp.ip, ipp.port,
ipp.port + 100, nullptr),
kill_networking);
if (net == nullptr) {
return;
@@ -95,6 +109,6 @@ void TestForwardReply(Fuzz_Data &input)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
fuzz_select_target<TestSendForwardRequest, TestForwardReply>(data, size);
tox::test::fuzz_select_target<TestSendForwardRequest, TestForwardReply>(data, size);
return 0;
}

View File

@@ -29,11 +29,11 @@
#define PORTS_PER_DISCOVERY 10
typedef struct Friend_Conn_Callbacks {
fc_status_cb *status_callback;
fc_data_cb *data_callback;
fc_lossy_data_cb *lossy_data_callback;
fc_status_cb *_Nullable status_callback;
fc_data_cb *_Nullable data_callback;
fc_lossy_data_cb *_Nullable lossy_data_callback;
void *callback_object;
void *_Nullable callback_object;
int callback_id;
} Friend_Conn_Callbacks;
@@ -68,23 +68,23 @@ struct Friend_Conn {
static const Friend_Conn empty_friend_conn = {0};
struct Friend_Connections {
const Mono_Time *mono_time;
const Memory *mem;
const Logger *logger;
Networking_Core *net;
Net_Crypto *net_crypto;
DHT *dht;
Broadcast_Info *broadcast;
Onion_Client *onion_c;
const Mono_Time *_Nonnull mono_time;
const Memory *_Nonnull mem;
const Logger *_Nonnull logger;
Networking_Core *_Nonnull net;
Net_Crypto *_Nonnull net_crypto;
DHT *_Nonnull dht;
Broadcast_Info *_Nullable broadcast;
Onion_Client *_Nonnull onion_c;
Friend_Conn *conns;
Friend_Conn *_Nullable conns;
uint32_t num_cons;
fr_request_cb *fr_request_callback;
void *fr_request_object;
fr_request_cb *_Nullable fr_request_callback;
void *_Nullable fr_request_object;
global_status_cb *global_status_callback;
void *global_status_callback_object;
global_status_cb *_Nullable global_status_callback;
void *_Nullable global_status_callback_object;
uint64_t last_lan_discovery;
uint16_t next_lan_port;
@@ -351,10 +351,6 @@ static void dht_ip_callback(void *_Nonnull object, int32_t number, const IP_Port
return;
}
if (friend_con->crypt_connection_id == -1) {
friend_new_connection(fr_c, number);
}
set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, true);
friend_con->dht_ip_port = *ip_port;
friend_con->dht_ip_port_lastrecv = mono_time_get(fr_c->mono_time);
@@ -387,7 +383,7 @@ static void change_dht_pk(Friend_Connections *_Nonnull fr_c, int friendcon_id, c
memcpy(friend_con->dht_temp_pk, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE);
}
static int handle_status(void *_Nonnull object, int id, bool status, void *_Nonnull userdata)
static int handle_status(void *_Nonnull object, int id, bool status, void *_Nullable userdata)
{
Friend_Connections *const fr_c = (Friend_Connections *)object;
Friend_Conn *const friend_con = get_conn(fr_c, id);
@@ -434,7 +430,7 @@ static int handle_status(void *_Nonnull object, int id, bool status, void *_Nonn
}
/** Callback for dht public key changes. */
static void dht_pk_callback(void *_Nonnull object, int32_t number, const uint8_t *_Nonnull dht_public_key, void *_Nonnull userdata)
static void dht_pk_callback(void *_Nonnull object, int32_t number, const uint8_t *_Nonnull dht_public_key, void *_Nullable userdata)
{
Friend_Connections *const fr_c = (Friend_Connections *)object;
Friend_Conn *const friend_con = get_conn(fr_c, number);
@@ -456,7 +452,6 @@ static void dht_pk_callback(void *_Nonnull object, int32_t number, const uint8_t
handle_status(object, number, false, userdata); /* Going offline. */
}
friend_new_connection(fr_c, number);
onion_set_friend_dht_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key);
}
@@ -940,6 +935,9 @@ Friend_Connections *new_friend_connections(
static void lan_discovery(Friend_Connections *_Nonnull fr_c)
{
if (fr_c->last_lan_discovery + LAN_DISCOVERY_INTERVAL < mono_time_get(fr_c->mono_time)) {
if (fr_c->broadcast == nullptr) {
return;
}
const uint16_t first = fr_c->next_lan_port;
uint16_t last = first + PORTS_PER_DISCOVERY;
last = last > TOX_PORTRANGE_TO ? TOX_PORTRANGE_TO : last;

View File

@@ -51,6 +51,10 @@ typedef enum Friendconn_Status {
FRIENDCONN_STATUS_CONNECTED,
} Friendconn_Status;
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Friend_Connections Friend_Connections;
Net_Crypto *_Nonnull friendconn_net_crypto(const Friend_Connections *_Nonnull fr_c);
@@ -82,7 +86,7 @@ unsigned int friend_con_connected(const Friend_Connections *_Nonnull fr_c, int f
*/
int get_friendcon_public_keys(uint8_t *_Nullable real_pk, uint8_t *_Nullable dht_temp_pk, const Friend_Connections *_Nonnull fr_c, int friendcon_id);
/** Set temp dht key for connection. */
void set_dht_temp_pk(Friend_Connections *_Nonnull fr_c, int friendcon_id, const uint8_t *_Nonnull dht_temp_pk, void *_Nonnull userdata);
void set_dht_temp_pk(Friend_Connections *_Nonnull fr_c, int friendcon_id, const uint8_t *_Nonnull dht_temp_pk, void *_Nullable userdata);
typedef int global_status_cb(void *_Nullable object, int friendcon_id, bool status, void *_Nullable userdata);
@@ -141,7 +145,7 @@ typedef int fr_request_cb(
*
* This function will be called every time a friend request packet is received.
*/
void set_friend_request_callback(Friend_Connections *_Nonnull fr_c, fr_request_cb *_Nonnull fr_request_callback, void *_Nonnull object);
void set_friend_request_callback(Friend_Connections *_Nonnull fr_c, fr_request_cb *_Nullable fr_request_callback, void *_Nullable object);
/** Create new friend_connections instance. */
Friend_Connections *_Nullable new_friend_connections(const Logger *_Nonnull logger, const Memory *_Nonnull mem, const Mono_Time *_Nonnull mono_time, const Network *_Nonnull ns,
@@ -149,7 +153,7 @@ Friend_Connections *_Nullable new_friend_connections(const Logger *_Nonnull logg
bool local_discovery_enabled);
/** main friend_connections loop. */
void do_friend_connections(Friend_Connections *_Nonnull fr_c, void *_Nonnull userdata);
void do_friend_connections(Friend_Connections *_Nonnull fr_c, void *_Nullable userdata);
/** Free everything related with friend_connections. */
void kill_friend_connections(Friend_Connections *_Nullable fr_c);
@@ -159,4 +163,8 @@ Friend_Conn *_Nullable get_conn(const Friend_Connections *_Nonnull fr_c, int fri
int friend_conn_get_onion_friendnum(const Friend_Conn *_Nonnull fc);
const IP_Port *_Nullable friend_conn_get_dht_ip_port(const Friend_Conn *_Nonnull fc);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_FRIEND_CONNECTION_H */

View File

@@ -0,0 +1,180 @@
#include "friend_connection.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <vector>
#include "../testing/support/public/simulated_environment.hh"
#include "DHT_test_util.hh"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net_crypto.h"
#include "net_profile.h"
#include "network.h"
#include "onion_client.h"
namespace {
using namespace tox::test;
// --- Helper Class ---
template <typename DHTWrapper>
class FriendConnTestNode {
public:
FriendConnTestNode(SimulatedEnvironment &env, uint16_t port)
: dht_wrapper_(env, port)
, net_profile_(netprof_new(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory),
[mem = &dht_wrapper_.node().c_memory](Net_Profile *p) { netprof_kill(mem, p); })
, net_crypto_(nullptr, [](Net_Crypto *c) { kill_net_crypto(c); })
, onion_client_(nullptr, [](Onion_Client *c) { kill_onion_client(c); })
, friend_connections_(nullptr, [](Friend_Connections *c) { kill_friend_connections(c); })
{
logger_callback_log(
dht_wrapper_.logger(),
[](void *context, Logger_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *userdata) {
fprintf(stderr, "[%d] %s:%u: %s: %s\n", level, file, line, func, message);
},
nullptr, nullptr);
// Setup NetCrypto
TCP_Proxy_Info proxy_info = {{0}, TCP_PROXY_NONE};
net_crypto_.reset(new_net_crypto(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
&dht_wrapper_.node().c_random, &dht_wrapper_.node().c_network, dht_wrapper_.mono_time(),
dht_wrapper_.networking(), dht_wrapper_.get_dht(), &DHTWrapper::funcs, &proxy_info,
net_profile_.get()));
new_keys(net_crypto_.get());
// Setup Onion Client
onion_client_.reset(new_onion_client(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
&dht_wrapper_.node().c_random, dht_wrapper_.mono_time(), net_crypto_.get(),
dht_wrapper_.get_dht(), dht_wrapper_.networking()));
// Setup Friend Connections
friend_connections_.reset(
new_friend_connections(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
dht_wrapper_.mono_time(), &dht_wrapper_.node().c_network, onion_client_.get(),
dht_wrapper_.get_dht(), net_crypto_.get(), dht_wrapper_.networking(), true));
}
Friend_Connections *get_friend_connections() { return friend_connections_.get(); }
Onion_Client *get_onion_client() { return onion_client_.get(); }
Net_Crypto *get_net_crypto() { return net_crypto_.get(); }
DHT *get_dht() { return dht_wrapper_.get_dht(); }
const uint8_t *dht_public_key() const { return dht_wrapper_.dht_public_key(); }
const uint8_t *real_public_key() const { return nc_get_self_public_key(net_crypto_.get()); }
const Random *get_random() { return &dht_wrapper_.node().c_random; }
IP_Port get_ip_port() const { return dht_wrapper_.get_ip_port(); }
void poll()
{
dht_wrapper_.poll();
do_net_crypto(net_crypto_.get(), nullptr);
do_onion_client(onion_client_.get());
do_friend_connections(friend_connections_.get(), nullptr);
}
~FriendConnTestNode();
private:
DHTWrapper dht_wrapper_;
std::unique_ptr<Net_Profile, std::function<void(Net_Profile *)>> net_profile_;
std::unique_ptr<Net_Crypto, void (*)(Net_Crypto *)> net_crypto_;
std::unique_ptr<Onion_Client, void (*)(Onion_Client *)> onion_client_;
std::unique_ptr<Friend_Connections, void (*)(Friend_Connections *)> friend_connections_;
};
template <typename DHTWrapper>
FriendConnTestNode<DHTWrapper>::~FriendConnTestNode() = default;
using FriendConnNode = FriendConnTestNode<WrappedDHT>;
class FriendConnectionTest : public ::testing::Test {
protected:
SimulatedEnvironment env;
};
TEST_F(FriendConnectionTest, CreationAndDestruction)
{
FriendConnNode alice(env, 33445);
EXPECT_NE(alice.get_friend_connections(), nullptr);
}
TEST_F(FriendConnectionTest, AddKillConnection)
{
FriendConnNode alice(env, 33445);
uint8_t friend_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t friend_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(alice.get_random(), friend_pk, friend_sk);
// Add Connection
int conn_id = new_friend_connection(alice.get_friend_connections(), friend_pk);
EXPECT_NE(conn_id, -1);
// Verify status (should be connecting or none initially, but ID is valid)
EXPECT_NE(
friend_con_connected(alice.get_friend_connections(), conn_id), FRIENDCONN_STATUS_NONE);
// Kill Connection
EXPECT_EQ(kill_friend_connection(alice.get_friend_connections(), conn_id), 0);
}
TEST_F(FriendConnectionTest, ConnectTwoNodes)
{
FriendConnNode alice(env, 33445);
FriendConnNode bob(env, 33446);
// Alice adds Bob as friend
int alice_conn_id
= new_friend_connection(alice.get_friend_connections(), bob.real_public_key());
ASSERT_NE(alice_conn_id, -1);
// Bob adds Alice as friend
int bob_conn_id = new_friend_connection(bob.get_friend_connections(), alice.real_public_key());
ASSERT_NE(bob_conn_id, -1);
// Helper to inject peer info into DHT and trigger connection
auto inject_peer = [](FriendConnNode &self, const FriendConnNode &peer, int conn_id) {
// 1. Tell DHT where the peer is (IP/Port + DHT Public Key)
IP_Port peer_ip = peer.get_ip_port();
addto_lists(self.get_dht(), &peer_ip, peer.dht_public_key());
// 2. Tell friend_connection the peer's DHT Public Key (normally found via Onion)
set_dht_temp_pk(self.get_friend_connections(), conn_id, peer.dht_public_key(), nullptr);
};
inject_peer(alice, bob, alice_conn_id);
inject_peer(bob, alice, bob_conn_id);
auto start = env.clock().current_time_ms();
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) { // 5 seconds timeout
alice.poll();
bob.poll();
env.advance_time(10);
if (friend_con_connected(alice.get_friend_connections(), alice_conn_id)
== FRIENDCONN_STATUS_CONNECTED
&& friend_con_connected(bob.get_friend_connections(), bob_conn_id)
== FRIENDCONN_STATUS_CONNECTED) {
connected = true;
break;
}
}
EXPECT_TRUE(connected) << "Alice and Bob failed to connect";
}
} // namespace

View File

@@ -36,15 +36,15 @@ struct Received_Requests {
};
struct Friend_Requests {
const Memory *mem;
const Memory *_Nonnull mem;
uint32_t nospam;
fr_friend_request_cb *handle_friendrequest;
fr_friend_request_cb *_Nullable handle_friendrequest;
uint8_t handle_friendrequest_isset;
void *handle_friendrequest_object;
void *_Nullable handle_friendrequest_object;
filter_function_cb *filter_function;
void *filter_function_userdata;
filter_function_cb *_Nullable filter_function;
void *_Nullable filter_function_userdata;
struct Received_Requests received;
};

View File

@@ -35,14 +35,14 @@ typedef void fr_friend_request_cb(void *_Nonnull object, const uint8_t *_Nonnull
void *_Nullable user_data);
/** Set the function that will be executed when a friend request for us is received. */
void callback_friendrequest(Friend_Requests *_Nonnull fr, fr_friend_request_cb *_Nonnull function, void *_Nonnull object);
void callback_friendrequest(Friend_Requests *_Nonnull fr, fr_friend_request_cb *_Nullable function, void *_Nullable object);
typedef int filter_function_cb(void *_Nonnull object, const uint8_t *_Nonnull public_key);
/** @brief Set the function used to check if a friend request should be displayed to the user or not.
* It must return 0 if the request is ok (anything else if it is bad).
*/
void set_filter_function(Friend_Requests *_Nonnull fr, filter_function_cb *_Nonnull function, void *_Nonnull userdata);
void set_filter_function(Friend_Requests *_Nonnull fr, filter_function_cb *_Nullable function, void *_Nullable userdata);
/** Sets up friendreq packet handlers. */
void friendreq_init(Friend_Requests *_Nonnull fr, Friend_Connections *_Nonnull fr_c);

View File

@@ -87,7 +87,7 @@ typedef struct Group_Peer {
uint16_t bottom_lossy_number;
uint16_t top_lossy_number;
void *object;
void *_Nullable object;
} Group_Peer;
typedef struct Groupchat_Connection {
@@ -112,10 +112,10 @@ typedef struct Group_c {
bool need_send_name;
bool title_fresh;
Group_Peer *group;
Group_Peer *_Nullable group;
uint32_t numpeers;
Group_Peer *frozen;
Group_Peer *_Nullable frozen;
uint32_t numfrozen;
uint32_t maxfrozen;
@@ -140,31 +140,31 @@ typedef struct Group_c {
uint32_t num_introducer_connections;
void *object;
void *_Nullable object;
peer_on_join_cb *peer_on_join;
peer_on_leave_cb *peer_on_leave;
group_on_delete_cb *group_on_delete;
peer_on_join_cb *_Nullable peer_on_join;
peer_on_leave_cb *_Nullable peer_on_leave;
group_on_delete_cb *_Nullable group_on_delete;
} Group_c;
struct Group_Chats {
const Memory *mem;
const Mono_Time *mono_time;
const Memory *_Nonnull mem;
const Mono_Time *_Nonnull mono_time;
Messenger *m;
Friend_Connections *fr_c;
Messenger *_Nonnull m;
Friend_Connections *_Nonnull fr_c;
Group_c *chats;
Group_c *_Nullable chats;
uint16_t num_chats;
g_conference_invite_cb *invite_callback;
g_conference_connected_cb *connected_callback;
g_conference_message_cb *message_callback;
peer_name_cb *peer_name_callback;
peer_list_changed_cb *peer_list_changed_callback;
title_cb *title_callback;
g_conference_invite_cb *_Nullable invite_callback;
g_conference_connected_cb *_Nullable connected_callback;
g_conference_message_cb *_Nullable message_callback;
peer_name_cb *_Nullable peer_name_callback;
peer_list_changed_cb *_Nullable peer_list_changed_callback;
title_cb *_Nullable title_callback;
lossy_packet_cb *lossy_packethandlers[256];
lossy_packet_cb *_Nullable lossy_packethandlers[256];
};
static const Group_c empty_group_c = {0};

View File

@@ -5,11 +5,15 @@
#include <memory>
#include <vector>
#include "../testing/fuzzing/fuzz_support.hh"
#include "mem_test_util.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/simulated_environment.hh"
namespace {
using tox::test::FakeClock;
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
void TestUnpackAnnouncesList(Fuzz_Data &input)
{
CONSUME1_OR_RETURN(const uint8_t, max_count, input);
@@ -19,8 +23,9 @@ void TestUnpackAnnouncesList(Fuzz_Data &input)
// TODO(iphydf): How do we know the packed size?
CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
Test_Memory mem;
Logger *logger = logger_new(mem);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Logger *logger = logger_new(&c_mem);
if (gca_unpack_announces_list(logger, input.data(), input.size(), announces.data(), max_count)
!= -1) {
// Always allocate at least something to avoid passing nullptr to functions below.
@@ -39,8 +44,9 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
// TODO(iphydf): How do we know the packed size?
CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
Test_Memory mem;
Logger *logger = logger_new(mem);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Logger *logger = logger_new(&c_mem);
if (gca_unpack_public_announce(logger, input.data(), input.size(), &public_announce) != -1) {
// Always allocate at least something to avoid passing nullptr to functions below.
std::vector<uint8_t> packed(packed_size + 1);
@@ -51,17 +57,22 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
void TestDoGca(Fuzz_Data &input)
{
Test_Memory mem;
std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(mem), logger_kill);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(&c_mem), logger_kill);
uint64_t clock = 1;
std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
mono_time_new(
mem, [](void *user_data) { return *static_cast<uint64_t *>(user_data); }, &clock),
[mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
&c_mem,
[](void *user_data) -> uint64_t {
return static_cast<FakeClock *>(user_data)->current_time_ms();
},
&env.fake_clock()),
[c_mem](Mono_Time *ptr) { mono_time_free(&c_mem, ptr); });
assert(mono_time != nullptr);
std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(
new_gca_list(mem), kill_gca);
std::unique_ptr<GC_Announces_List, std::function<void(GC_Announces_List *)>> gca(
new_gca_list(&c_mem), [](GC_Announces_List *ptr) { kill_gca(ptr); });
assert(gca != nullptr);
while (!input.empty()) {
@@ -73,14 +84,14 @@ void TestDoGca(Fuzz_Data &input)
CONSUME_OR_RETURN(const uint8_t *data, input, length);
GC_Public_Announce public_announce;
if (gca_unpack_public_announce(logger.get(), data, length, &public_announce) != -1) {
gca_add_announce(mem, mono_time.get(), gca.get(), &public_announce);
gca_add_announce(&c_mem, mono_time.get(), gca.get(), &public_announce);
}
break;
}
case 1: {
// Advance the time by a number of tox_iteration_intervals.
CONSUME1_OR_RETURN(const uint8_t, iterations, input);
clock += iterations * 20;
env.fake_clock().advance(iterations * 20);
// Do an iteration.
do_gca(mono_time.get(), gca.get());
break;
@@ -111,6 +122,7 @@ void TestDoGca(Fuzz_Data &input)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
fuzz_select_target<TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca>(data, size);
tox::test::fuzz_select_target<TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca>(
data, size);
return 0;
}

View File

@@ -1,20 +1,26 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "group_announce.h"
// clang-format on
#include <gtest/gtest.h>
#include "DHT.h"
#include "crypto_core.h"
#include "logger.h"
#include "mem_test_util.hh"
#include "mono_time.h"
#include "mono_time_test_util.hh"
#include "network.h"
namespace {
using tox::test::FakeClock;
using tox::test::SimulatedEnvironment;
struct Announces : ::testing::Test {
protected:
Test_Memory mem_;
uint64_t clock_ = 1000;
SimulatedEnvironment env;
Tox_Memory c_mem_;
Mono_Time *mono_time_ = nullptr;
GC_Announces_List *gca_ = nullptr;
GC_Announce _ann1;
@@ -22,24 +28,24 @@ protected:
void SetUp() override
{
mono_time_ = mono_time_new(mem_, nullptr, nullptr);
c_mem_ = env.fake_memory().get_c_memory();
mono_time_ = mono_time_new(&c_mem_, nullptr, nullptr);
ASSERT_NE(mono_time_, nullptr);
mono_time_set_current_time_callback(
mono_time_, [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
&clock_);
gca_ = new_gca_list(mem_);
setup_fake_clock(mono_time_, env.fake_clock());
gca_ = new_gca_list(&c_mem_);
ASSERT_NE(gca_, nullptr);
}
~Announces() override
{
kill_gca(gca_);
mono_time_free(mem_, mono_time_);
mono_time_free(&c_mem_, mono_time_);
}
void advance_clock(uint64_t increment)
{
clock_ += increment;
env.fake_clock().advance(increment);
mono_time_update(mono_time_);
}
};
@@ -54,10 +60,10 @@ TEST_F(Announces, CanBeCreatedAndDeleted)
{
GC_Public_Announce ann{};
ann.chat_public_key[0] = 0x88;
ASSERT_NE(gca_add_announce(mem_, mono_time_, gca_, &ann), nullptr);
ASSERT_NE(gca_add_announce(&c_mem_, mono_time_, gca_, &ann), nullptr);
#ifndef __clang__
ASSERT_EQ(gca_add_announce(mem_, mono_time_, gca_, nullptr), nullptr);
ASSERT_EQ(gca_add_announce(mem_, mono_time_, nullptr, &ann), nullptr);
ASSERT_EQ(gca_add_announce(&c_mem_, mono_time_, gca_, nullptr), nullptr);
ASSERT_EQ(gca_add_announce(&c_mem_, mono_time_, nullptr, &ann), nullptr);
#endif
}
@@ -67,7 +73,7 @@ TEST_F(Announces, AnnouncesCanTimeOut)
ASSERT_EQ(gca_->root_announces, nullptr);
GC_Public_Announce ann{};
ann.chat_public_key[0] = 0xae;
ASSERT_NE(gca_add_announce(mem_, mono_time_, gca_, &ann), nullptr);
ASSERT_NE(gca_add_announce(&c_mem_, mono_time_, gca_, &ann), nullptr);
ASSERT_NE(gca_->root_announces, nullptr);
ASSERT_EQ(gca_->root_announces->chat_id[0], 0xae);
@@ -95,9 +101,9 @@ TEST_F(Announces, AnnouncesGetAndCleanup)
ann2.chat_public_key[0] = 0x92;
ann2.base_announce.peer_public_key[0] = 0x7c;
ASSERT_NE(gca_add_announce(mem_, mono_time_, gca_, &ann1), nullptr);
ASSERT_NE(gca_add_announce(mem_, mono_time_, gca_, &ann2), nullptr);
ASSERT_NE(gca_add_announce(mem_, mono_time_, gca_, &ann2), nullptr);
ASSERT_NE(gca_add_announce(&c_mem_, mono_time_, gca_, &ann1), nullptr);
ASSERT_NE(gca_add_announce(&c_mem_, mono_time_, gca_, &ann2), nullptr);
ASSERT_NE(gca_add_announce(&c_mem_, mono_time_, gca_, &ann2), nullptr);
uint8_t empty_pk[ENC_PUBLIC_KEY_SIZE] = {0};
@@ -117,13 +123,15 @@ TEST_F(Announces, AnnouncesGetAndCleanup)
struct AnnouncesPack : ::testing::Test {
protected:
SimulatedEnvironment env;
Tox_Memory c_mem_;
std::vector<GC_Announce> announces_;
Test_Memory mem_;
Logger *logger_ = nullptr;
void SetUp() override
{
logger_ = logger_new(mem_);
c_mem_ = env.fake_memory().get_c_memory();
logger_ = logger_new(&c_mem_);
ASSERT_NE(logger_, nullptr);
// Add an announce without TCP relay.

View File

@@ -1069,6 +1069,10 @@ static bool prune_gc_mod_list(GC_Chat *_Nonnull chat)
bool pruned_mod = false;
for (uint16_t i = 0; i < chat->moderation.num_mods; ++i) {
if (chat->moderation.mod_list[i] == nullptr) {
LOGGER_ERROR(chat->log, "Moderator list contains a null entry at index %u", i);
continue;
}
if (get_peer_number_of_sig_pk(chat, chat->moderation.mod_list[i]) == -1) {
memcpy(public_sig_key, chat->moderation.mod_list[i], SIG_PUBLIC_KEY_SIZE);
@@ -1622,6 +1626,9 @@ static bool send_lossless_group_packet(const GC_Chat *_Nonnull chat, GC_Connecti
}
if (length > MAX_GC_PACKET_CHUNK_SIZE) {
if (data == nullptr) {
return false;
}
return gcc_send_lossless_packet_fragments(chat, gconn, data, length, packet_type);
}
@@ -1719,6 +1726,9 @@ static bool unpack_gc_sync_announce(GC_Chat *_Nonnull chat, const uint8_t *_Nonn
uint32_t added_tcp_relays = 0;
for (uint8_t i = 0; i < announce.tcp_relays_count; ++i) {
if (chat->tcp_conn == nullptr) {
return false;
}
const int add_tcp_result = add_tcp_relay_connection(chat->tcp_conn, new_gconn->tcp_connection_num,
&announce.tcp_relays[i].ip_port,
announce.tcp_relays[i].public_key);
@@ -1733,6 +1743,9 @@ static bool unpack_gc_sync_announce(GC_Chat *_Nonnull chat, const uint8_t *_Nonn
}
if (!announce.ip_port_is_set && added_tcp_relays == 0) {
if (chat->tcp_conn == nullptr) {
return false;
}
gcc_mark_for_deletion(new_gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
LOGGER_ERROR(chat->log, "Sync error: Invalid peer connection info");
return false;
@@ -1760,6 +1773,9 @@ static int handle_gc_sync_response(const GC_Session *_Nonnull c, GC_Chat *_Nonnu
uint16_t length, void *_Nullable userdata)
{
if (length > 0) {
if (data == nullptr) {
return -1;
}
if (!unpack_gc_sync_announce(chat, data, length)) {
return -1;
}
@@ -2187,7 +2203,7 @@ static bool send_gc_invite_response_reject(const GC_Chat *_Nonnull chat, GC_Conn
* Return -3 if we fail to send an invite response.
* Return -4 if peer_number does not designate a valid peer.
*/
static int handle_gc_invite_request(GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nullable data, uint16_t length)
static int handle_gc_invite_request(GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data, uint16_t length)
{
if (chat->shared_state.version == 0) { // we aren't synced yet; ignore request
return 0;
@@ -3825,10 +3841,12 @@ static bool handle_gc_topic_validate(const GC_Chat *_Nonnull chat, const GC_Peer
}
}
if (topic_info->version == chat->shared_state.topic_lock) {
// always accept topic on initial connection
if (!mono_time_is_timeout(chat->mono_time, chat->time_connected, GC_PING_TIMEOUT)) {
return true;
if (topic_info->version == chat->shared_state.topic_lock ||
!mono_time_is_timeout(chat->mono_time, chat->time_connected, GC_PING_TIMEOUT)) {
if (chat->topic_prev_checksum == topic_info->checksum &&
!mono_time_is_timeout(chat->mono_time, chat->topic_time_set, GC_CONFIRMED_PEER_TIMEOUT)) {
LOGGER_DEBUG(chat->log, "Topic reversion (probable sync error)");
return false;
}
return true;
@@ -7241,13 +7259,15 @@ static bool init_gc_tcp_connection(const GC_Session *_Nonnull c, GC_Chat *_Nonnu
{
const Messenger *m = c->messenger;
chat->tcp_conn = new_tcp_connections(chat->log, chat->mem, chat->rng, m->ns, chat->mono_time, chat->self_secret_key.enc,
&m->options.proxy_info, c->tcp_np);
TCP_Connections *tcp_conn = new_tcp_connections(chat->log, chat->mem, chat->rng, m->ns, chat->mono_time, chat->self_secret_key.enc,
&m->options.proxy_info, c->tcp_np);
if (chat->tcp_conn == nullptr) {
if (tcp_conn == nullptr) {
return false;
}
chat->tcp_conn = tcp_conn;
add_tcp_relays_to_chat(c, chat);
set_packet_tcp_connection_callback(chat->tcp_conn, &handle_gc_tcp_packet, c->messenger);

View File

@@ -541,7 +541,7 @@ void do_gc(GC_Session *_Nonnull c, void *_Nullable userdata);
* Make sure that DHT is initialized before calling this.
* Returns a NULL pointer on failure.
*/
GC_Session *_Nullable new_dht_groupchats(Messenger *_Nullable m);
GC_Session *_Nullable new_dht_groupchats(Messenger *_Nonnull m);
/** @brief Cleans up groupchat structures and calls `gc_group_exit()` for every group chat */
void kill_dht_groupchats(GC_Session *_Nullable c);
/** @brief Loads a previously saved group and attempts to join it.
@@ -680,7 +680,7 @@ bool gc_send_message_ack(const GC_Chat *_Nonnull chat, GC_Connection *_Nonnull g
*
* @retval true if packet is successfully handled.
*/
bool handle_gc_lossless_helper(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nullable data,
bool handle_gc_lossless_helper(const GC_Session *_Nonnull c, GC_Chat *_Nonnull chat, uint32_t peer_number, const uint8_t *_Nonnull data,
uint16_t length, uint8_t packet_type, void *_Nullable userdata);
/** @brief Handles an invite accept packet.
*

View File

@@ -276,7 +276,7 @@ typedef struct GC_Chat {
IP_Port self_ip_port;
Networking_Core *_Nonnull net;
TCP_Connections *_Nullable tcp_conn;
TCP_Connections *_Nonnull tcp_conn;
uint64_t last_checked_tcp_relays;
Group_Handshake_Join_Type join_type;
@@ -380,8 +380,8 @@ typedef void gc_rejected_cb(const Messenger *_Nonnull m, uint32_t group_number,
typedef struct GC_Session {
Messenger *_Nonnull messenger;
GC_Chat *_Nullable chats;
Net_Profile *_Nullable tcp_np;
struct GC_Announces_List *_Nullable announces_list;
Net_Profile *_Nonnull tcp_np;
struct GC_Announces_List *_Nonnull announces_list;
uint32_t chats_index;

View File

@@ -452,13 +452,15 @@ int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer
/* peer number can change from peer add operations in packet handlers */
peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
gconn = get_gc_connection(chat, peer_number);
GC_Connection *new_gconn = get_gc_connection(chat, peer_number);
if (gconn == nullptr) {
if (new_gconn == nullptr) {
mem_delete(chat->mem, payload);
return 0;
}
gconn = new_gconn;
gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
gconn->last_chunk_id = 0;
@@ -510,7 +512,14 @@ static bool process_recv_array_entry(const GC_Session *_Nonnull c, GC_Chat *_Non
uint8_t sender_pk[ENC_PUBLIC_KEY_SIZE];
memcpy(sender_pk, get_enc_key(&gconn->addr.public_key), ENC_PUBLIC_KEY_SIZE);
const bool ret = handle_gc_lossless_helper(c, chat, peer_number, array_entry->data, array_entry->data_length,
const uint8_t *data = array_entry->data;
// TODO(iphydf): This is ugly. We should probably change all the handlers to accept nullable.
const uint8_t empty_data[1] = { 0 };
if (data == nullptr) {
data = empty_data;
}
const bool ret = handle_gc_lossless_helper(c, chat, peer_number, data, array_entry->data_length,
array_entry->packet_type, userdata);
/* peer number can change from peer add operations in packet handlers */
@@ -612,6 +621,9 @@ bool gcc_send_packet(const GC_Chat *chat, GC_Connection *gconn, const uint8_t *p
}
}
if (chat->tcp_conn == nullptr) {
return false;
}
const int ret = send_packet_tcp_connection(chat->tcp_conn, gconn->tcp_connection_num, packet, length);
return ret == 0 || direct_send_attempt;
}
@@ -682,7 +694,9 @@ void gcc_mark_for_deletion(GC_Connection *gconn, TCP_Connections *tcp_conn, Grou
gconn->pending_delete = true;
gconn->exit_info.exit_type = type;
kill_tcp_connection_to(tcp_conn, gconn->tcp_connection_num);
if (tcp_conn != nullptr) {
kill_tcp_connection_to(tcp_conn, gconn->tcp_connection_num);
}
if (length > 0 && length <= MAX_GC_PART_MESSAGE_SIZE && part_message != nullptr) {
memcpy(gconn->exit_info.part_message, part_message, length);

View File

@@ -439,7 +439,7 @@ int sanctions_list_unpack(Mod_Sanction *_Nonnull sanctions, Mod_Sanction_Creds *
* Return true on success.
*/
static bool sanctions_list_make_hash(const Memory *_Nonnull mem, const Mod_Sanction *_Nullable sanctions, uint32_t new_version, uint16_t num_sanctions,
uint8_t *_Nonnull hash)
bool sort, uint8_t *_Nonnull hash)
{
if (num_sanctions == 0 || sanctions == nullptr) {
memzero(hash, MOD_SANCTION_HASH_SIZE);
@@ -464,7 +464,9 @@ static bool sanctions_list_make_hash(const Memory *_Nonnull mem, const Mod_Sanct
memcpy(&data[i * SIGNATURE_SIZE], sanctions[i].signature, SIGNATURE_SIZE);
}
qsort(data, num_sanctions, SIGNATURE_SIZE, compare_signatures);
if (sort) {
qsort(data, num_sanctions, SIGNATURE_SIZE, compare_signatures);
}
memcpy(&data[sig_data_size], &new_version, sizeof(uint32_t));
crypto_sha256(hash, data, data_buf_size);
@@ -524,7 +526,7 @@ bool sanctions_list_make_creds(Moderation *_Nonnull moderation)
uint8_t hash[MOD_SANCTION_HASH_SIZE];
if (!sanctions_list_make_hash(moderation->mem, moderation->sanctions, moderation->sanctions_creds.version,
moderation->num_sanctions, hash)) {
moderation->num_sanctions, true, hash)) {
moderation->sanctions_creds = old_creds;
return false;
}
@@ -563,15 +565,23 @@ static bool sanctions_creds_validate(const Moderation *_Nonnull moderation, cons
uint8_t hash[MOD_SANCTION_HASH_SIZE];
if (!sanctions_list_make_hash(moderation->mem, sanctions, creds->version, num_sanctions, hash)) {
if (!sanctions_list_make_hash(moderation->mem, sanctions, creds->version, num_sanctions, true, hash)) {
return false;
}
if (memcmp(hash, creds->hash, MOD_SANCTION_HASH_SIZE) != 0) {
LOGGER_WARNING(moderation->log, "Invalid credentials hash");
return false;
}
/* Some older/other clients might not sort the signatures.
* Try calculating the hash without sorting.
*/
if (!sanctions_list_make_hash(moderation->mem, sanctions, creds->version, num_sanctions, false, hash)) {
return false;
}
if (memcmp(hash, creds->hash, MOD_SANCTION_HASH_SIZE) != 0) {
LOGGER_WARNING(moderation->log, "Invalid credentials hash");
return false;
}
}
if (creds->checksum != sanctions_creds_get_checksum(creds)) {
LOGGER_WARNING(moderation->log, "Invalid credentials checksum");
return false;
@@ -684,6 +694,9 @@ static bool sanctions_list_remove_index(Moderation *_Nonnull moderation, uint16_
}
/* Operate on a copy of the list in case something goes wrong. */
if (moderation->sanctions == nullptr) {
return false;
}
Mod_Sanction *sanctions_copy = sanctions_list_copy(moderation->mem, moderation->sanctions, moderation->num_sanctions);
if (sanctions_copy == nullptr) {
@@ -782,6 +795,9 @@ bool sanctions_list_add_entry(Moderation *_Nonnull moderation, const Mod_Sanctio
Mod_Sanction *sanctions_copy = nullptr;
if (moderation->num_sanctions > 0) {
if (moderation->sanctions == nullptr) {
return false;
}
sanctions_copy = sanctions_list_copy(moderation->mem, moderation->sanctions, moderation->num_sanctions);
if (sanctions_copy == nullptr) {

View File

@@ -1,15 +1,19 @@
#include "group_moderation.h"
#include "../testing/fuzzing/fuzz_support.hh"
#include "mem_test_util.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/simulated_environment.hh"
namespace {
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
void TestModListUnpack(Fuzz_Data &input)
{
CONSUME1_OR_RETURN(const uint16_t, num_mods, input);
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
mod_list_unpack(&mods, input.data(), input.size(), num_mods);
mod_list_cleanup(&mods);
}
@@ -34,7 +38,7 @@ void TestSanctionCredsUnpack(Fuzz_Data &input)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
fuzz_select_target<TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack>(
data, size);
tox::test::fuzz_select_target<TestModListUnpack, TestSanctionsListUnpack,
TestSanctionCredsUnpack>(data, size);
return 0;
}

View File

@@ -1,4 +1,7 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "group_moderation.h"
// clang-format on
#include <gtest/gtest.h>
@@ -10,17 +13,18 @@
#include "crypto_core.h"
#include "crypto_core_test_util.hh"
#include "logger.h"
#include "mem_test_util.hh"
#include "util.h"
namespace {
using tox::test::SimulatedEnvironment;
using ModerationHash = std::array<uint8_t, MOD_MODERATION_HASH_SIZE>;
TEST(ModList, PackedSizeOfEmptyModListIsZero)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
EXPECT_EQ(mod_list_packed_size(&mods), 0);
uint8_t byte = 1;
@@ -30,16 +34,18 @@ TEST(ModList, PackedSizeOfEmptyModListIsZero)
TEST(ModList, UnpackingZeroSizeArrayIsNoop)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
const uint8_t byte = 1;
EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0);
}
TEST(ModList, AddRemoveMultipleMods)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
uint8_t sig_pk1[32] = {1};
uint8_t sig_pk2[32] = {2};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1));
@@ -51,8 +57,9 @@ TEST(ModList, AddRemoveMultipleMods)
TEST(ModList, PackingAndUnpackingList)
{
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
std::vector<uint8_t> packed(mod_list_packed_size(&mods));
@@ -60,7 +67,7 @@ TEST(ModList, PackingAndUnpackingList)
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
Moderation mods2{mem};
Moderation mods2{&c_mem};
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size());
EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data()));
}
@@ -68,14 +75,15 @@ TEST(ModList, PackingAndUnpackingList)
TEST(ModList, UnpackingTooManyModsFails)
{
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
std::vector<uint8_t> packed(mod_list_packed_size(&mods));
mod_list_pack(&mods, packed.data());
Moderation mods2{mem};
Moderation mods2{&c_mem};
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1);
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
}
@@ -84,45 +92,50 @@ TEST(ModList, UnpackingFromEmptyBufferFails)
{
std::vector<uint8_t> packed(1);
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
EXPECT_EQ(mod_list_unpack(&mods, packed.data(), 0, 1), -1);
}
TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
{
Test_Memory mem;
Test_Random rng;
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
auto c_rng = env.fake_random().get_c_random();
Moderation mods{mem};
Moderation mods{&c_mem};
// Fill with random data, check that it's zeroed.
ModerationHash hash;
random_bytes(rng, hash.data(), hash.size());
random_bytes(&c_rng, hash.data(), hash.size());
EXPECT_TRUE(mod_list_make_hash(&mods, hash.data()));
EXPECT_EQ(hash, ModerationHash{});
}
TEST(ModList, RemoveIndexFromEmptyModListFails)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
EXPECT_FALSE(mod_list_remove_index(&mods, 0));
EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX));
}
TEST(ModList, RemoveEntryFromEmptyModListFails)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
uint8_t sig_pk[32] = {0};
EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk));
}
TEST(ModList, ModListRemoveIndex)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
uint8_t sig_pk[32] = {1};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
EXPECT_TRUE(mod_list_remove_index(&mods, 0));
@@ -130,23 +143,26 @@ TEST(ModList, ModListRemoveIndex)
TEST(ModList, CleanupOnEmptyModsIsNoop)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
mod_list_cleanup(&mods);
}
TEST(ModList, EmptyModListCannotVerifyAnySigPk)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
uint8_t sig_pk[32] = {1};
EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
}
TEST(ModList, ModListAddVerifyRemoveSigPK)
{
Test_Memory mem;
Moderation mods{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods{&c_mem};
uint8_t sig_pk[32] = {1};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk));
@@ -156,8 +172,9 @@ TEST(ModList, ModListAddVerifyRemoveSigPK)
TEST(ModList, ModListHashCheck)
{
Test_Memory mem;
Moderation mods1{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mods1{&c_mem};
uint8_t sig_pk1[32] = {1};
std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1;
@@ -179,8 +196,9 @@ TEST(SanctionsList, PackingIntoUndersizedBufferFails)
TEST(SanctionsList, PackUnpackSanctionsCreds)
{
Test_Memory mem;
Moderation mod{mem};
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Moderation mod{&c_mem};
std::array<uint8_t, MOD_SANCTIONS_CREDS_SIZE> packed;
EXPECT_EQ(sanctions_creds_pack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
EXPECT_EQ(
@@ -189,20 +207,30 @@ TEST(SanctionsList, PackUnpackSanctionsCreds)
struct SanctionsListMod : ::testing::Test {
protected:
SimulatedEnvironment env;
Tox_Memory c_mem_;
Tox_Random c_rng_;
Extended_Public_Key pk;
Extended_Secret_Key sk;
Test_Random rng;
Test_Memory mem;
Logger *log = logger_new(mem);
Moderation mod{mem};
Logger *log = nullptr;
Moderation mod;
Mod_Sanction sanctions[2] = {};
const uint8_t sanctioned_pk1[32] = {1};
const uint8_t sanctioned_pk2[32] = {2};
SanctionsListMod()
: c_mem_(env.fake_memory().get_c_memory())
, c_rng_(env.fake_random().get_c_random())
, mod{&c_mem_}
{
}
void SetUp() override
{
ASSERT_TRUE(create_extended_keypair(&pk, &sk, rng));
log = logger_new(&c_mem_);
ASSERT_TRUE(create_extended_keypair(&pk, &sk, &c_rng_));
mod.log = log;

View File

@@ -59,7 +59,7 @@ static int find(const BS_List *_Nonnull list, const uint8_t *_Nonnull data)
// closest match is found if we move back to where we have already been
while (true) {
const int r = list->cmp_callback(data, (const void *_Nonnull)(list->data + list->element_size * i), list->element_size);
const int r = list->cmp_callback(data, list->data + list->element_size * i, list->element_size);
if (r == 0) {
return i;

View File

@@ -18,11 +18,11 @@
#include "mem.h"
struct Logger {
const Memory *mem;
const Memory *_Nonnull mem;
logger_cb *callback;
void *context;
void *userdata;
logger_cb *_Nullable callback;
void *_Nullable context;
void *_Nullable userdata;
};
/*

View File

@@ -1,29 +0,0 @@
#include "mem_test_util.hh"
#include <cstdlib>
#include "test_util.hh"
#include "tox_memory_impl.h"
Tox_Memory_Funcs const Memory_Class::vtable = {
Method<tox_memory_malloc_cb, Memory_Class>::invoke<&Memory_Class::malloc>,
Method<tox_memory_realloc_cb, Memory_Class>::invoke<&Memory_Class::realloc>,
Method<tox_memory_dealloc_cb, Memory_Class>::invoke<&Memory_Class::dealloc>,
};
Memory_Class::~Memory_Class() = default;
void *Test_Memory::malloc(void *obj, uint32_t size)
{
return mem->funcs->malloc_callback(mem->user_data, size);
}
void *Test_Memory::realloc(void *obj, void *ptr, uint32_t size)
{
return mem->funcs->realloc_callback(mem->user_data, ptr, size);
}
void Test_Memory::dealloc(void *obj, void *ptr)
{
return mem->funcs->dealloc_callback(mem->user_data, ptr);
}

View File

@@ -1,39 +0,0 @@
#ifndef C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
#define C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
#include "mem.h"
#include "os_memory.h"
#include "test_util.hh"
#include "tox_memory_impl.h"
struct Memory_Class {
static Tox_Memory_Funcs const vtable;
Tox_Memory const self;
operator Tox_Memory const *() const { return &self; }
Memory_Class(Memory_Class const &) = default;
Memory_Class()
: self{&vtable, this}
{
}
virtual ~Memory_Class();
virtual tox_memory_malloc_cb malloc = 0;
virtual tox_memory_realloc_cb realloc = 0;
virtual tox_memory_dealloc_cb dealloc = 0;
};
/**
* Base test Memory class that just forwards to os_memory. Can be
* subclassed to override individual (or all) functions.
*/
class Test_Memory : public Memory_Class {
const Tox_Memory *mem = REQUIRE_NOT_NULL(os_memory());
void *malloc(void *obj, uint32_t size) override;
void *realloc(void *obj, void *ptr, uint32_t size) override;
void dealloc(void *obj, void *ptr) override;
};
#endif // C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H

View File

@@ -43,12 +43,12 @@ struct Mono_Time {
uint64_t base_time;
#ifndef ESP_PLATFORM
/* protect `time` from concurrent access */
pthread_rwlock_t *time_update_lock;
/** protect @ref cur_time from concurrent access */
pthread_rwlock_t *_Nonnull time_update_lock;
#endif /* ESP_PLATFORM */
mono_time_current_time_cb *current_time_callback;
void *user_data;
mono_time_current_time_cb *_Nonnull current_time_callback;
void *_Nullable user_data;
};
static uint64_t timespec_to_u64(struct timespec clock_mono)
@@ -116,7 +116,7 @@ Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_t
}
#ifndef ESP_PLATFORM
pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t));
pthread_rwlock_t *const rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t));
if (rwlock == nullptr) {
mem_delete(mem, mono_time);

View File

@@ -1,80 +1,92 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "mono_time.h"
// clang-format on
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
#include "mem_test_util.hh"
#include "mono_time_test_util.hh"
namespace {
TEST(MonoTime, UnixTimeIncreasesOverTime)
using tox::test::FakeClock;
using tox::test::SimulatedEnvironment;
TEST(MonoTime, TimeIncreasesWhenAdvanced)
{
Test_Memory mem;
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Mono_Time *mono_time = mono_time_new(&c_mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
setup_fake_clock(mono_time, env.fake_clock());
mono_time_update(mono_time);
uint64_t const start = mono_time_get(mono_time);
while (start == mono_time_get(mono_time)) {
mono_time_update(mono_time);
}
// Advance 10 seconds to ensure we definitely cross second boundaries and see an increase
env.fake_clock().advance(10000);
mono_time_update(mono_time);
uint64_t const end = mono_time_get(mono_time);
EXPECT_GT(end, start);
EXPECT_EQ(end, start + 10);
mono_time_free(mem, mono_time);
mono_time_free(&c_mem, mono_time);
}
TEST(MonoTime, IsTimeout)
{
Test_Memory mem;
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Mono_Time *mono_time = mono_time_new(&c_mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
setup_fake_clock(mono_time, env.fake_clock());
mono_time_update(mono_time); // Ensure start is consistent with fake clock
uint64_t const start = mono_time_get(mono_time);
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 1));
while (start == mono_time_get(mono_time)) {
mono_time_update(mono_time);
}
env.fake_clock().advance(2000); // 2 seconds
mono_time_update(mono_time);
EXPECT_TRUE(mono_time_is_timeout(mono_time, start, 1));
mono_time_free(mem, mono_time);
mono_time_free(&c_mem, mono_time);
}
TEST(MonoTime, IsTimeoutReal)
TEST(MonoTime, IsTimeoutWithIntermediateUpdates)
{
Test_Memory mem;
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Mono_Time *mono_time = mono_time_new(&c_mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
setup_fake_clock(mono_time, env.fake_clock());
mono_time_update(mono_time);
uint64_t const start = mono_time_get(mono_time);
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 5));
const uint64_t before_sleep = mono_time_get(mono_time);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
env.fake_clock().advance(100);
mono_time_update(mono_time);
const uint64_t after_sleep = mono_time_get(mono_time);
// should still not have timed out (5sec) after sleeping ~100ms
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 5))
<< "before sleep: " << before_sleep << ", after sleep: " << after_sleep;
// Should not have timed out (5sec) after 100ms
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 5));
mono_time_free(mem, mono_time);
env.fake_clock().advance(5000);
mono_time_update(mono_time);
EXPECT_TRUE(mono_time_is_timeout(mono_time, start, 5));
mono_time_free(&c_mem, mono_time);
}
TEST(MonoTime, CustomTime)
{
Test_Memory mem;
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
SimulatedEnvironment env;
auto c_mem = env.fake_memory().get_c_memory();
Mono_Time *mono_time = mono_time_new(&c_mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
uint64_t test_time = current_time_monotonic(mono_time) + 42137;
uint64_t test_time = 123456;
mono_time_set_current_time_callback(
mono_time, [](void *user_data) { return *static_cast<uint64_t *>(user_data); }, &test_time);
mono_time_update(mono_time);
@@ -84,13 +96,12 @@ TEST(MonoTime, CustomTime)
uint64_t const start = mono_time_get(mono_time);
test_time += 7000;
mono_time_update(mono_time);
EXPECT_EQ(mono_time_get(mono_time) - start, 7);
EXPECT_EQ(mono_time_get(mono_time) - start, 7);
EXPECT_EQ(current_time_monotonic(mono_time), test_time);
mono_time_free(mem, mono_time);
mono_time_free(&c_mem, mono_time);
}
} // namespace

View File

@@ -0,0 +1,13 @@
#include "mono_time_test_util.hh"
using tox::test::FakeClock;
void setup_fake_clock(Mono_Time *mono_time, FakeClock &clock)
{
mono_time_set_current_time_callback(
mono_time,
[](void *user_data) -> uint64_t {
return static_cast<FakeClock *>(user_data)->current_time_ms();
},
&clock);
}

View File

@@ -0,0 +1,9 @@
#ifndef C_TOXCORE_TOXCORE_MONO_TIME_TEST_UTIL_HH
#define C_TOXCORE_TOXCORE_MONO_TIME_TEST_UTIL_HH
#include "../testing/support/doubles/fake_clock.hh"
#include "mono_time.h"
void setup_fake_clock(Mono_Time *mono_time, tox::test::FakeClock &clock);
#endif // C_TOXCORE_TOXCORE_MONO_TIME_TEST_UTIL_HH

View File

@@ -13,7 +13,7 @@
#include <pthread.h>
#include <string.h>
#include "DHT.h"
#include "DHT.h" // Node_format
#include "LAN_discovery.h"
#include "TCP_client.h"
#include "TCP_connection.h"
@@ -35,7 +35,7 @@ typedef struct Packet_Data {
} Packet_Data;
typedef struct Packets_Array {
Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE];
Packet_Data *_Nullable buffer[CRYPTO_PACKET_BUFFER_SIZE];
uint32_t buffer_start;
uint32_t buffer_end; /* packet numbers in array: `{buffer_start, buffer_end)` */
} Packets_Array;
@@ -66,7 +66,7 @@ typedef struct Crypto_Connection {
uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */
uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */
uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint8_t *_Nullable temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint16_t temp_packet_length;
uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */
uint32_t temp_packet_num_sent;
@@ -81,16 +81,16 @@ typedef struct Crypto_Connection {
Packets_Array send_array;
Packets_Array recv_array;
connection_status_cb *connection_status_callback;
void *connection_status_callback_object;
connection_status_cb *_Nullable connection_status_callback;
void *_Nullable connection_status_callback_object;
int connection_status_callback_id;
connection_data_cb *connection_data_callback;
void *connection_data_callback_object;
connection_data_cb *_Nullable connection_data_callback;
void *_Nullable connection_data_callback_object;
int connection_data_callback_id;
connection_lossy_data_cb *connection_lossy_data_callback;
void *connection_lossy_data_callback_object;
connection_lossy_data_cb *_Nullable connection_lossy_data_callback;
void *_Nullable connection_lossy_data_callback_object;
int connection_lossy_data_callback_id;
uint64_t last_request_packet_sent;
@@ -124,25 +124,27 @@ typedef struct Crypto_Connection {
bool maximum_speed_reached;
dht_pk_cb *dht_pk_callback;
void *dht_pk_callback_object;
dht_pk_cb *_Nullable dht_pk_callback;
void *_Nullable dht_pk_callback_object;
uint32_t dht_pk_callback_number;
} Crypto_Connection;
static const Crypto_Connection empty_crypto_connection = {{0}};
struct Net_Crypto {
const Logger *log;
const Memory *mem;
const Random *rng;
Mono_Time *mono_time;
const Network *ns;
const Logger *_Nonnull log;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
Mono_Time *_Nonnull mono_time;
const Network *_Nonnull ns;
Networking_Core *net;
DHT *dht;
TCP_Connections *tcp_c;
void *_Nonnull dht;
const Net_Crypto_DHT_Funcs *_Nonnull dht_funcs;
Crypto_Connection *crypto_connections;
TCP_Connections *_Nonnull tcp_c;
Crypto_Connection *_Nullable crypto_connections;
uint32_t crypto_connections_length; /* Length of connections array. */
@@ -153,13 +155,17 @@ struct Net_Crypto {
/* The secret key used for cookies */
uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE];
new_connection_cb *new_connection_callback;
void *new_connection_callback_object;
new_connection_cb *_Nullable new_connection_callback;
void *_Nullable new_connection_callback_object;
/* The current optimal sleep time */
uint32_t current_sleep_time;
BS_List ip_port_list;
/* Rate limiter for cookie requests */
uint64_t cookie_request_last_time;
uint32_t cookie_request_tokens;
};
const uint8_t *nc_get_self_public_key(const Net_Crypto *c)
@@ -202,6 +208,11 @@ static bool crypt_connection_id_is_valid(const Net_Crypto *_Nonnull c, int crypt
#define COOKIE_REQUEST_LENGTH (uint16_t)(1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE)
#define COOKIE_RESPONSE_LENGTH (uint16_t)(1 + CRYPTO_NONCE_SIZE + COOKIE_LENGTH + sizeof(uint64_t) + CRYPTO_MAC_SIZE)
/** Maximum number of tokens in the bucket for cookie request rate limiting. */
#define COOKIE_REQUEST_MAX_TOKENS 10
/** Interval in milliseconds to generate one token for cookie request rate limiting. */
#define COOKIE_REQUEST_TOKEN_INTERVAL 100
/** @brief Create a cookie request packet and put it in packet.
*
* dht_public_key is the dht public key of the other
@@ -218,12 +229,16 @@ static int create_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
memzero(plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE);
memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t));
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
const uint8_t *tmp_shared_key = c->dht_funcs->get_shared_key_sent(c->dht, dht_public_key);
if (tmp_shared_key == nullptr) {
LOGGER_ERROR(c->log, "Failed to get shared key for cookie request");
return -1;
}
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
uint8_t nonce[CRYPTO_NONCE_SIZE];
random_nonce(c->rng, nonce);
packet[0] = NET_PACKET_COOKIE_REQUEST;
memcpy(packet + 1, dht_get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE);
memcpy(packet + 1, c->dht_funcs->get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE);
memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
const int len = encrypt_data_symmetric(c->mem, shared_key, nonce, plain, sizeof(plain),
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
@@ -330,12 +345,17 @@ static int handle_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
}
memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE);
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
const uint8_t *tmp_shared_key = c->dht_funcs->get_shared_key_sent(c->dht, dht_public_key);
if (tmp_shared_key == nullptr) {
LOGGER_ERROR(c->log, "Failed to get shared key for cookie response");
return -1;
}
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
const int len = decrypt_data_symmetric(c->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE,
request_plain);
if (len != COOKIE_REQUEST_PLAIN_LENGTH) {
return -1;
}
@@ -347,7 +367,32 @@ static int handle_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
static int udp_handle_cookie_request(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length,
void *_Nullable userdata)
{
const Net_Crypto *c = (const Net_Crypto *)object;
Net_Crypto *c = (Net_Crypto *)object;
const uint64_t current_time = mono_time_get_ms(c->mono_time);
// Add 1 token every 100ms
const uint64_t new_tokens = (current_time - c->cookie_request_last_time) / COOKIE_REQUEST_TOKEN_INTERVAL;
if (new_tokens > 0) {
c->cookie_request_tokens += new_tokens;
if (c->cookie_request_tokens > COOKIE_REQUEST_MAX_TOKENS) {
c->cookie_request_tokens = COOKIE_REQUEST_MAX_TOKENS;
// Full bucket, reset time anchor to now so we stop accumulating until consumed
c->cookie_request_last_time = current_time;
} else {
// Advance time anchor by the exact time consumed to generate these tokens
// to preserve the remainder (precision)
c->cookie_request_last_time += new_tokens * COOKIE_REQUEST_TOKEN_INTERVAL;
}
}
if (c->cookie_request_tokens == 0) {
return 0;
}
--c->cookie_request_tokens;
uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH];
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE];
@@ -505,16 +550,19 @@ static bool handle_crypto_handshake(const Net_Crypto *_Nonnull c, uint8_t *_Nonn
uint8_t *_Nonnull dht_public_key, uint8_t *_Nonnull cookie, const uint8_t *_Nonnull packet, uint16_t length, const uint8_t *_Nullable expected_real_pk)
{
if (length != HANDSHAKE_PACKET_LENGTH) {
LOGGER_WARNING(c->log, "Handshake length mismatch: %u != %u", length, (unsigned int)HANDSHAKE_PACKET_LENGTH);
return false;
}
uint8_t cookie_plain[COOKIE_DATA_LENGTH];
if (open_cookie(c->mem, c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) {
LOGGER_WARNING(c->log, "Failed to open cookie");
return false;
}
if (expected_real_pk != nullptr && !pk_equal(cookie_plain, expected_real_pk)) {
LOGGER_WARNING(c->log, "Expected real pk mismatch");
return false;
}
@@ -527,10 +575,12 @@ static bool handle_crypto_handshake(const Net_Crypto *_Nonnull c, uint8_t *_Nonn
HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain);
if (len != sizeof(plain)) {
LOGGER_WARNING(c->log, "Failed to decrypt handshake data");
return false;
}
if (!crypto_sha512_eq(cookie_hash, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE)) {
LOGGER_WARNING(c->log, "Cookie hash mismatch");
return false;
}
@@ -2240,7 +2290,7 @@ uint32_t copy_connected_tcp_relays_index(const Net_Crypto *c, Node_format *tcp_r
return tcp_copy_connected_relays_index(c->tcp_c, tcp_relays, num, idx);
}
static void do_tcp(Net_Crypto *_Nonnull c, void *_Nonnull userdata)
static void do_tcp(Net_Crypto *_Nonnull c, void *_Nullable userdata)
{
do_tcp_connections(c->log, c->tcp_c, userdata);
@@ -2911,9 +2961,9 @@ void load_secret_key(Net_Crypto *c, const uint8_t *sk)
* Sets all the global connection variables to their default values.
*/
Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
Mono_Time *mono_time, Networking_Core *net, DHT *dht, const TCP_Proxy_Info *proxy_info, Net_Profile *tcp_np)
Mono_Time *mono_time, Networking_Core *net, void *dht, const Net_Crypto_DHT_Funcs *dht_funcs, const TCP_Proxy_Info *proxy_info, Net_Profile *tcp_np)
{
if (dht == nullptr) {
if (dht == nullptr || dht_funcs == nullptr || dht_funcs->get_shared_key_sent == nullptr || dht_funcs->get_self_public_key == nullptr || dht_funcs->get_self_secret_key == nullptr) {
return nullptr;
}
@@ -2930,18 +2980,21 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
temp->ns = ns;
temp->net = net;
temp->tcp_c = new_tcp_connections(log, mem, rng, ns, mono_time, dht_get_self_secret_key(dht), proxy_info, tcp_np);
temp->dht = dht;
temp->dht_funcs = dht_funcs;
if (temp->tcp_c == nullptr) {
TCP_Connections *const tcp_c = new_tcp_connections(log, mem, rng, ns, mono_time, dht_funcs->get_self_secret_key(dht), proxy_info, tcp_np);
if (tcp_c == nullptr) {
mem_delete(mem, temp);
return nullptr;
}
temp->tcp_c = tcp_c;
set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp);
set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp);
temp->dht = dht;
new_keys(temp);
new_symmetric_key(rng, temp->secret_symmetric_key);
@@ -2954,6 +3007,9 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
bs_list_init(&temp->ip_port_list, mem, sizeof(IP_Port), 8, ipport_cmp_handler);
temp->cookie_request_tokens = COOKIE_REQUEST_MAX_TOKENS;
temp->cookie_request_last_time = mono_time_get_ms(mono_time);
return temp;
}
@@ -3020,3 +3076,13 @@ void kill_net_crypto(Net_Crypto *c)
crypto_memzero(c, sizeof(Net_Crypto));
mem_delete(mem, c);
}
void nc_testonly_get_secrets(const Net_Crypto *c, int conn_id, uint8_t *shared_key, uint8_t *sent_nonce, uint8_t *recv_nonce)
{
const Crypto_Connection *conn = get_crypto_connection(c, conn_id);
if (conn != nullptr) {
memcpy(shared_key, conn->shared_key, CRYPTO_SHARED_KEY_SIZE);
memcpy(sent_nonce, conn->sent_nonce, CRYPTO_NONCE_SIZE);
memcpy(recv_nonce, conn->recv_nonce, CRYPTO_NONCE_SIZE);
}
}

View File

@@ -9,7 +9,7 @@
#ifndef C_TOXCORE_TOXCORE_NET_CRYPTO_H
#define C_TOXCORE_TOXCORE_NET_CRYPTO_H
#include "DHT.h"
#include "DHT.h" // Node_format
#include "TCP_client.h"
#include "TCP_connection.h"
#include "attributes.h"
@@ -24,6 +24,16 @@
extern "C" {
#endif
typedef const uint8_t *_Nullable nc_dht_get_shared_key_sent_cb(void *_Nonnull obj, const uint8_t *_Nonnull public_key);
typedef const uint8_t *_Nonnull nc_dht_get_self_public_key_cb(const void *_Nonnull obj);
typedef const uint8_t *_Nonnull nc_dht_get_self_secret_key_cb(const void *_Nonnull obj);
typedef struct Net_Crypto_DHT_Funcs {
nc_dht_get_shared_key_sent_cb *_Nonnull get_shared_key_sent;
nc_dht_get_self_public_key_cb *_Nonnull get_self_public_key;
nc_dht_get_self_secret_key_cb *_Nonnull get_self_secret_key;
} Net_Crypto_DHT_Funcs;
/*** Crypto payloads. */
/*** Ranges. */
@@ -133,7 +143,7 @@ typedef struct New_Connection {
uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer. */
uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */
uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */
uint8_t *_Nullable cookie;
uint8_t *_Nonnull cookie;
uint8_t cookie_length;
} New_Connection;
@@ -369,7 +379,7 @@ void load_secret_key(Net_Crypto *_Nonnull c, const uint8_t *_Nonnull sk);
* Sets all the global connection variables to their default values.
*/
Net_Crypto *_Nullable new_net_crypto(const Logger *_Nonnull log, const Memory *_Nonnull mem, const Random *_Nonnull rng, const Network *_Nonnull ns, Mono_Time *_Nonnull mono_time,
Networking_Core *_Nonnull net, DHT *_Nonnull dht,
Networking_Core *_Nonnull net, void *_Nonnull dht, const Net_Crypto_DHT_Funcs *_Nonnull dht_funcs,
const TCP_Proxy_Info *_Nonnull proxy_info, Net_Profile *_Nonnull tcp_np);
/** return the optimal interval in ms for running do_net_crypto. */
@@ -378,6 +388,10 @@ uint32_t crypto_run_interval(const Net_Crypto *_Nonnull c);
/** Main loop. */
void do_net_crypto(Net_Crypto *_Nonnull c, void *_Nullable userdata);
void kill_net_crypto(Net_Crypto *_Nullable c);
/** Unit test support functions. Do not use outside tests. */
void nc_testonly_get_secrets(const Net_Crypto *_Nonnull c, int conn_id, uint8_t *_Nonnull shared_key, uint8_t *_Nonnull sent_nonce, uint8_t *_Nonnull recv_nonce);
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -6,8 +6,9 @@
#include <memory>
#include <optional>
#include "../testing/fuzzing/fuzz_support.hh"
#include "../testing/fuzzing/fuzz_tox.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/fuzz_helpers.hh"
#include "../testing/support/public/simulated_environment.hh"
#include "DHT.h"
#include "TCP_client.h"
#include "net_profile.h"
@@ -15,11 +16,19 @@
namespace {
using tox::test::configure_fuzz_memory_source;
using tox::test::FakeClock;
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
template <typename T>
using Ptr = std::unique_ptr<T, void (*)(T *)>;
std::optional<std::tuple<IP_Port, uint8_t>> prepare(Fuzz_Data &input)
{
IP_Port ipp;
ip_init(&ipp.ip, true);
ipp.port = 33445;
ipp.port = net_htons(33445);
CONSUME_OR_RETURN_VAL(const uint8_t *iterations_packed, input, 1, std::nullopt);
uint8_t iterations = *iterations_packed;
@@ -27,6 +36,14 @@ std::optional<std::tuple<IP_Port, uint8_t>> prepare(Fuzz_Data &input)
return {{ipp, iterations}};
}
static constexpr Net_Crypto_DHT_Funcs dht_funcs = {
[](void *dht, const uint8_t *public_key) {
return dht_get_shared_key_sent(static_cast<DHT *>(dht), public_key);
},
[](const void *dht) { return dht_get_self_public_key(static_cast<const DHT *>(dht)); },
[](const void *dht) { return dht_get_self_secret_key(static_cast<const DHT *>(dht)); },
};
void TestNetCrypto(Fuzz_Data &input)
{
const auto prep = prepare(input);
@@ -35,16 +52,19 @@ void TestNetCrypto(Fuzz_Data &input)
}
const auto [ipp, iterations] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
SimulatedEnvironment env;
env.fake_clock().advance(1000000000); // Start clock high to match legacy behavior
auto node = env.create_node(ipp.port);
configure_fuzz_memory_source(env.fake_memory(), input);
const Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
const Ptr<Logger> logger(logger_new(&node->c_memory), logger_kill);
if (logger == nullptr) {
return;
}
const Ptr<Networking_Core> net(new_networking_ex(logger.get(), sys.mem.get(), sys.ns.get(),
&ipp.ip, ipp.port, ipp.port + 100, nullptr),
const Ptr<Networking_Core> net(
new_networking_ex(logger.get(), &node->c_memory, &node->c_network, &ipp.ip, ipp.port,
ipp.port + 100, nullptr),
kill_networking);
if (net == nullptr) {
return;
@@ -52,21 +72,23 @@ void TestNetCrypto(Fuzz_Data &input)
const std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
mono_time_new(
sys.mem.get(), [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
&sys.clock),
[mem = sys.mem.get()](Mono_Time *ptr) { mono_time_free(mem, ptr); });
&node->c_memory,
[](void *user_data) { return static_cast<FakeClock *>(user_data)->current_time_ms(); },
&env.fake_clock()),
[&node](Mono_Time *ptr) { mono_time_free(&node->c_memory, ptr); });
if (mono_time == nullptr) {
return;
}
const Ptr<DHT> dht(new_dht(logger.get(), sys.mem.get(), sys.rng.get(), sys.ns.get(),
const Ptr<DHT> dht(new_dht(logger.get(), &node->c_memory, &node->c_random, &node->c_network,
mono_time.get(), net.get(), false, false),
kill_dht);
if (dht == nullptr) {
return;
}
Net_Profile *tcp_np = netprof_new(logger.get(), sys.mem.get());
Net_Profile *tcp_np = netprof_new(logger.get(), &node->c_memory);
if (tcp_np == nullptr) {
return;
@@ -75,11 +97,11 @@ void TestNetCrypto(Fuzz_Data &input)
const TCP_Proxy_Info proxy_info = {0};
const Ptr<Net_Crypto> net_crypto(
new_net_crypto(logger.get(), sys.mem.get(), sys.rng.get(), sys.ns.get(), mono_time.get(),
net.get(), dht.get(), &proxy_info, tcp_np),
new_net_crypto(logger.get(), &node->c_memory, &node->c_random, &node->c_network,
mono_time.get(), net.get(), dht.get(), &dht_funcs, &proxy_info, tcp_np),
kill_net_crypto);
if (net_crypto == nullptr) {
netprof_kill(sys.mem.get(), tcp_np);
netprof_kill(&node->c_memory, tcp_np);
return;
}
@@ -87,11 +109,11 @@ void TestNetCrypto(Fuzz_Data &input)
networking_poll(net.get(), nullptr);
do_dht(dht.get());
do_net_crypto(net_crypto.get(), nullptr);
// "Sleep"
sys.clock += System::BOOTSTRAP_ITERATION_INTERVAL;
env.advance_time(200);
}
netprof_kill(sys.mem.get(), tcp_np);
netprof_kill(&node->c_memory, tcp_np);
}
} // namespace
@@ -99,6 +121,6 @@ void TestNetCrypto(Fuzz_Data &input)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
fuzz_select_target<TestNetCrypto>(data, size);
tox::test::fuzz_select_target<TestNetCrypto>(data, size);
return 0;
}

577
toxcore/net_crypto_test.cc Normal file
View File

@@ -0,0 +1,577 @@
#include "net_crypto.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <random>
#include <vector>
#include "../testing/support/public/simulated_environment.hh"
#include "DHT_test_util.hh"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net_profile.h"
#include "network.h"
namespace {
using namespace tox::test;
// --- Helper Class ---
template <typename DHTWrapper>
class TestNode {
public:
TestNode(SimulatedEnvironment &env, uint16_t port, bool enable_trace = false)
: dht_wrapper_(env, port)
, net_profile_(netprof_new(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory),
[mem = &dht_wrapper_.node().c_memory](Net_Profile *p) { netprof_kill(mem, p); })
, net_crypto_(nullptr, [](Net_Crypto *c) { kill_net_crypto(c); })
, trace_enabled_(enable_trace)
{
// Setup Logger to stderr
logger_callback_log(
dht_wrapper_.logger(),
[](void *context, Logger_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *) {
auto *self = static_cast<TestNode *>(context);
if (self->trace_enabled_ || level >= LOGGER_LEVEL_DEBUG) {
fprintf(stderr, "[%d] %s:%u %s: %s\n", level, file, line, func, message);
}
},
this, nullptr);
// 3. Setup NetCrypto
TCP_Proxy_Info proxy_info = {{0}, TCP_PROXY_NONE};
net_crypto_.reset(new_net_crypto(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
&dht_wrapper_.node().c_random, &dht_wrapper_.node().c_network, dht_wrapper_.mono_time(),
dht_wrapper_.networking(), dht_wrapper_.get_dht(), &DHTWrapper::funcs, &proxy_info,
net_profile_.get()));
// 4. Register Callbacks
new_connection_handler(net_crypto_.get(), &TestNode::static_new_connection_cb, this);
}
Net_Crypto *get_net_crypto() { return net_crypto_.get(); }
const uint8_t *dht_public_key() const { return dht_wrapper_.dht_public_key(); }
const uint8_t *real_public_key() const { return nc_get_self_public_key(net_crypto_.get()); }
int dht_computation_count() const { return dht_wrapper_.dht_computation_count(); }
const Memory *get_memory() const { return &dht_wrapper_.node().c_memory; }
IP_Port get_ip_port() const { return dht_wrapper_.get_ip_port(); }
void poll()
{
dht_wrapper_.poll();
do_net_crypto(net_crypto_.get(), nullptr);
}
// -- High Level Operations --
// Initiates a connection to 'other'. Returns the connection ID.
template <typename OtherDHTWrapper>
int connect_to(TestNode<OtherDHTWrapper> &other)
{
int id = new_crypto_connection(
net_crypto_.get(), other.real_public_key(), other.dht_public_key());
if (id == -1)
return -1;
// "Cheating" by telling net_crypto the direct IP immediately
IP_Port addr = other.get_ip_port();
set_direct_ip_port(net_crypto_.get(), id, &addr, true);
// Setup monitoring for this connection
setup_connection_callbacks(id);
return id;
}
// Sends data to the connected peer (assuming only 1 for simplicity or last connected)
bool send_data(int conn_id, const std::vector<uint8_t> &data)
{
if (data.empty())
return false;
return write_cryptpacket(net_crypto_.get(), conn_id, data.data(), data.size(), false) != -1;
}
void send_direct_packet(const IP_Port &dest, const std::vector<uint8_t> &data)
{
if (data.empty())
return;
sendpacket(dht_wrapper_.networking(), &dest, data.data(), data.size());
}
// -- Observability --
bool is_connected(int conn_id) const
{
if (conn_id < 0 || conn_id >= static_cast<int>(connections_.size()))
return false;
return connections_[conn_id].connected;
}
const std::vector<uint8_t> &get_last_received_data(int conn_id) const
{
if (conn_id < 0 || conn_id >= static_cast<int>(connections_.size()))
return empty_vector_;
return connections_[conn_id].received_data;
}
// Helper to get the ID assigned to a peer by Public Key (for the acceptor side)
int get_connection_id_by_pk(const uint8_t *pk) { return last_accepted_id_; }
~TestNode();
private:
DHTWrapper dht_wrapper_;
struct ConnectionState {
bool connected = false;
std::vector<uint8_t> received_data;
};
// We map connection IDs to state. connection IDs are small ints.
std::vector<ConnectionState> connections_{128};
int last_accepted_id_ = -1;
std::vector<uint8_t> empty_vector_;
void setup_connection_callbacks(int id)
{
if (id >= static_cast<int>(connections_.size()))
connections_.resize(id + 1);
connection_status_handler(
net_crypto_.get(), id, &TestNode::static_connection_status_cb, this, id);
connection_data_handler(
net_crypto_.get(), id, &TestNode::static_connection_data_cb, this, id);
}
// -- Static Callbacks --
static int static_new_connection_cb(void *object, const New_Connection *n_c)
{
auto *self = static_cast<TestNode *>(object);
int id = accept_crypto_connection(self->net_crypto_.get(), n_c);
if (id != -1) {
self->last_accepted_id_ = id;
self->setup_connection_callbacks(id);
}
return id; // Return ID on success
}
static int static_connection_status_cb(void *object, int id, bool status, void *userdata)
{
auto *self = static_cast<TestNode *>(object);
if (id < static_cast<int>(self->connections_.size())) {
self->connections_[id].connected = status;
}
return 0;
}
static int static_connection_data_cb(
void *object, int id, const uint8_t *data, uint16_t length, void *userdata)
{
auto *self = static_cast<TestNode *>(object);
if (id < static_cast<int>(self->connections_.size())) {
self->connections_[id].received_data.assign(data, data + length);
}
return 0;
}
// Use std::function for the deleter to allow capturing memory pointer
std::unique_ptr<Net_Profile, std::function<void(Net_Profile *)>> net_profile_;
std::unique_ptr<Net_Crypto, void (*)(Net_Crypto *)> net_crypto_;
bool trace_enabled_ = false;
};
template <typename DHTWrapper>
TestNode<DHTWrapper>::~TestNode() = default;
using NetCryptoNode = TestNode<WrappedMockDHT>;
using RealDHTNode = TestNode<WrappedDHT>;
class NetCryptoTest : public ::testing::Test {
protected:
SimulatedEnvironment env;
};
TEST_F(NetCryptoTest, EndToEndDataExchange)
{
NetCryptoNode alice(env, 33445);
NetCryptoNode bob(env, 33446);
// 1. Alice initiates connection to Bob
int alice_conn_id = alice.connect_to(bob);
ASSERT_NE(alice_conn_id, -1);
// 2. Run simulation until connected
auto start = env.clock().current_time_ms();
int bob_conn_id = -1;
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) {
alice.poll();
bob.poll();
env.advance_time(10); // 10ms steps
bob_conn_id = bob.get_connection_id_by_pk(alice.real_public_key());
if (alice.is_connected(alice_conn_id) && bob_conn_id != -1
&& bob.is_connected(bob_conn_id)) {
connected = true;
break;
}
}
ASSERT_TRUE(connected) << "Failed to establish connection within timeout";
// 3. Exchange Data
// Packet ID must be in custom range (160+)
std::vector<uint8_t> message = {160, 'H', 'e', 'l', 'l', 'o'};
EXPECT_TRUE(alice.send_data(alice_conn_id, message));
start = env.clock().current_time_ms();
bool data_received = false;
while ((env.clock().current_time_ms() - start) < 1000) {
alice.poll();
bob.poll();
env.advance_time(10);
if (bob.get_last_received_data(bob_conn_id) == message) {
data_received = true;
break;
}
}
EXPECT_TRUE(data_received) << "Bob did not receive the correct data";
}
TEST_F(NetCryptoTest, ConnectionTimeout)
{
NetCryptoNode alice(env, 33445);
NetCryptoNode bob(env, 33446);
// Alice tries to connect to Bob
int alice_conn_id = alice.connect_to(bob);
ASSERT_NE(alice_conn_id, -1);
// Filter: Drop ALL packets from Bob to Alice
env.simulation().net().add_filter([&](tox::test::Packet &p) {
// Drop if destination is Alice (33445)
if (net_ntohs(p.to.port) == 33445) {
return false;
}
return true;
});
// Run simulation for longer than timeout (approx 8-10s)
auto start = env.clock().current_time_ms();
bool timeout_detected = false;
// expect Alice to kill the connection after MAX_NUM_SENDPACKET_TRIES * INTERVAL (8*1s=8s).
//
// Run for 15 seconds to be safe
while ((env.clock().current_time_ms() - start) < 15000) {
alice.poll();
bob.poll();
env.advance_time(100);
bool direct;
if (!crypto_connection_status(alice.get_net_crypto(), alice_conn_id, &direct, nullptr)) {
timeout_detected = true;
break;
}
}
EXPECT_TRUE(timeout_detected) << "Alice should have killed the timed-out connection";
}
TEST_F(NetCryptoTest, DataLossAndRetransmission)
{
bool dropped = false;
NetCryptoNode alice(env, 33445);
NetCryptoNode bob(env, 33446);
int alice_conn_id = alice.connect_to(bob);
ASSERT_NE(alice_conn_id, -1);
// Establish connection
auto start = env.clock().current_time_ms();
int bob_conn_id = -1;
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) {
alice.poll();
bob.poll();
env.advance_time(10);
bob_conn_id = bob.get_connection_id_by_pk(alice.real_public_key());
if (alice.is_connected(alice_conn_id) && bob_conn_id != -1
&& bob.is_connected(bob_conn_id)) {
connected = true;
break;
}
}
ASSERT_TRUE(connected);
// Configure network to drop the next packet from Alice
// NET_PACKET_CRYPTO_DATA is 0x1b
// We want to drop the *first* data packet sent.
env.simulation().net().add_filter([&](tox::test::Packet &p) {
if (!dropped && net_ntohs(p.to.port) == 33446 && p.data.size() > 0
&& p.data[0] == NET_PACKET_CRYPTO_DATA) {
dropped = true;
return false; // Drop it
}
return true;
});
std::vector<uint8_t> message = {161, 'R', 'e', 't', 'r', 'y'};
alice.send_data(alice_conn_id, message);
// Alice needs to detect packet loss and retransmit.
// Timeout for retransmission is tricky, it depends on RTT estimation.
// Default RTT is 1s.
start = env.clock().current_time_ms();
bool data_received = false;
while ((env.clock().current_time_ms() - start) < 5000) {
alice.poll();
bob.poll();
env.advance_time(50); // coarser steps
if (bob.get_last_received_data(bob_conn_id) == message) {
data_received = true;
break;
}
}
EXPECT_TRUE(dropped) << "Packet filter failed to target the data packet";
EXPECT_TRUE(data_received) << "Bob failed to receive data after retransmission";
}
TEST_F(NetCryptoTest, CookieRequestCPUExhaustion)
{
NetCryptoNode victim(env, 33445);
NetCryptoNode attacker(env, 33446);
// Cookie Request Packet Length
// From net_crypto.c:
// #define COOKIE_REQUEST_LENGTH (uint16_t)(1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE +
// COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) 1 + 32 + 24 + (32 * 2 + 8) + 16 = 145
const int TEST_COOKIE_REQUEST_LENGTH = 145;
// Send enough packets to trigger rate limiting
const int NUM_PACKETS = 50;
std::minstd_rand rng(42);
std::uniform_int_distribution<uint8_t> dist;
auto gen = [&]() { return dist(rng); };
for (int i = 0; i < NUM_PACKETS; ++i) {
std::vector<uint8_t> packet(TEST_COOKIE_REQUEST_LENGTH);
packet[0] = NET_PACKET_COOKIE_REQUEST;
// Random public key at offset 1 (size 32)
std::generate(packet.begin() + 1, packet.begin() + 1 + CRYPTO_PUBLIC_KEY_SIZE, gen);
// Fill the rest with random data just to be safe
std::generate(packet.begin() + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet.end(), gen);
attacker.send_direct_packet(victim.get_ip_port(), packet);
// Advance time to allow network delivery
env.advance_time(1);
victim.poll();
}
// Verify that the victim performed some computations (as it must for the first few packets)
// but filtered out the majority of the flood due to rate limiting.
int computations = victim.dht_computation_count();
EXPECT_GT(computations, 0) << "Should handle at least some packets";
EXPECT_LT(computations, NUM_PACKETS) << "Victim performed expensive shared key computations "
"for ALL packets! CPU exhaustion mitigation failed.";
}
TEST_F(NetCryptoTest, CookieRequestRateLimiting)
{
NetCryptoNode victim(env, 33445);
NetCryptoNode attacker(env, 33446);
const int TEST_COOKIE_REQUEST_LENGTH = 145;
std::minstd_rand rng(42);
std::uniform_int_distribution<uint8_t> dist;
auto gen = [&]() { return dist(rng); };
auto send_packet = [&]() {
std::vector<uint8_t> packet(TEST_COOKIE_REQUEST_LENGTH);
packet[0] = NET_PACKET_COOKIE_REQUEST;
std::generate(packet.begin() + 1, packet.begin() + 1 + CRYPTO_PUBLIC_KEY_SIZE, gen);
std::generate(packet.begin() + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet.end(), gen);
attacker.send_direct_packet(victim.get_ip_port(), packet);
env.advance_time(1); // Network delivery
victim.poll();
};
// 1. Initial Burst: Consume all 10 tokens
int initial_computations = victim.dht_computation_count();
for (int i = 0; i < 10; ++i) {
send_packet();
}
int burst_computations = victim.dht_computation_count();
EXPECT_EQ(burst_computations - initial_computations, 10)
<< "Should accept initial burst of 10 packets";
// 2. Verify Limit Reached: 11th packet should be dropped
send_packet();
EXPECT_EQ(victim.dht_computation_count(), burst_computations) << "Should drop 11th packet";
// 3. Partial Refill Check: Advance 80ms (total < 100ms since empty)
env.advance_time(80);
send_packet();
EXPECT_EQ(victim.dht_computation_count(), burst_computations)
<< "Should drop packet before 100ms refill";
// 4. Full Refill Check: Advance to > 100ms
env.advance_time(20);
send_packet();
EXPECT_EQ(victim.dht_computation_count(), burst_computations + 1)
<< "Should accept packet after 100ms refill";
}
TEST_F(NetCryptoTest, HandleRequestPacketOOB)
{
NetCryptoNode alice(env, 33445);
NetCryptoNode bob(env, 33446);
// 1. Establish connection
int alice_conn_id = alice.connect_to(bob);
ASSERT_NE(alice_conn_id, -1);
auto start = env.clock().current_time_ms();
int bob_conn_id = -1;
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) {
alice.poll();
bob.poll();
env.advance_time(10);
bob_conn_id = bob.get_connection_id_by_pk(alice.real_public_key());
if (alice.is_connected(alice_conn_id) && bob_conn_id != -1
&& bob.is_connected(bob_conn_id)) {
connected = true;
break;
}
}
ASSERT_TRUE(connected);
// 2. Alice sends many packets to populate her send_array.
std::vector<uint8_t> dummy_data(50, 'A');
for (int i = 0; i < 300; ++i) {
dummy_data[0] = 160 + (i % 30); // Valid packet ID range
alice.send_data(alice_conn_id, dummy_data);
}
alice.poll(); // Process sends
// 3. Construct the malicious packet.
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
uint8_t alice_sent_nonce[CRYPTO_NONCE_SIZE];
uint8_t alice_recv_nonce[CRYPTO_NONCE_SIZE];
// Retrieve secrets
nc_testonly_get_secrets(
alice.get_net_crypto(), alice_conn_id, shared_key, alice_sent_nonce, alice_recv_nonce);
// Use Alice's recv_nonce (which Bob uses to encrypt)
uint8_t nonce[CRYPTO_NONCE_SIZE];
memcpy(nonce, alice_recv_nonce, CRYPTO_NONCE_SIZE);
// Payload: [PACKET_ID_REQUEST (1), 255]
// The length of 2 will trigger the OOB read when n wraps around.
uint8_t plaintext[] = {PACKET_ID_REQUEST, 255};
uint16_t plaintext_len = sizeof(plaintext);
uint16_t packet_size = 1 + sizeof(uint16_t) + plaintext_len + CRYPTO_MAC_SIZE;
std::vector<uint8_t> malicious_packet(packet_size);
malicious_packet[0] = NET_PACKET_CRYPTO_DATA;
memcpy(&malicious_packet[1], nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t));
int len = encrypt_data_symmetric(
alice.get_memory(), shared_key, nonce, plaintext, plaintext_len, &malicious_packet[3]);
ASSERT_EQ(len, plaintext_len + CRYPTO_MAC_SIZE);
// 4. Inject the packet
tox::test::Packet p;
p.to = alice.get_ip_port();
p.data = malicious_packet;
p.from = bob.get_ip_port();
env.simulation().net().send_packet(p);
// 5. Trigger processing - Expect ASAN/UBSAN failure if vulnerable
alice.poll();
}
// Test with Real DHT (but fake network) to ensure integration works
TEST_F(NetCryptoTest, EndToEndDataExchange_RealDHT)
{
RealDHTNode alice(env, 33445);
RealDHTNode bob(env, 33446);
// 1. Alice initiates connection to Bob
int alice_conn_id = alice.connect_to(bob);
ASSERT_NE(alice_conn_id, -1);
// 2. Run simulation until connected
auto start = env.clock().current_time_ms();
int bob_conn_id = -1;
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) {
alice.poll();
bob.poll();
env.advance_time(10); // 10ms steps
bob_conn_id = bob.get_connection_id_by_pk(alice.real_public_key());
if (alice.is_connected(alice_conn_id) && bob_conn_id != -1
&& bob.is_connected(bob_conn_id)) {
connected = true;
break;
}
}
ASSERT_TRUE(connected) << "Failed to establish connection within timeout";
// 3. Exchange Data
// Packet ID must be in custom range (160+)
std::vector<uint8_t> message = {160, 'H', 'e', 'l', 'l', 'o'};
EXPECT_TRUE(alice.send_data(alice_conn_id, message));
start = env.clock().current_time_ms();
bool data_received = false;
while ((env.clock().current_time_ms() - start) < 1000) {
alice.poll();
bob.poll();
env.advance_time(10);
if (bob.get_last_received_data(bob_conn_id) == message) {
data_received = true;
break;
}
}
EXPECT_TRUE(data_received) << "Bob did not receive the correct data";
}
} // namespace

View File

@@ -282,6 +282,7 @@ static const Family family_tcp_ipv6 = {TCP_INET6};
static const Family family_tox_tcp_ipv4 = {TOX_TCP_INET};
static const Family family_tox_tcp_ipv6 = {TOX_TCP_INET6};
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static const Family *make_tox_family(int family)
{
switch (family) {
@@ -298,6 +299,7 @@ static const Family *make_tox_family(int family)
return nullptr;
}
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
static void get_ip4(IP4 *_Nonnull result, const struct in_addr *_Nonnull addr)
{
@@ -472,10 +474,48 @@ bool sock_valid(Socket sock)
return sock.value != invalid_socket.value;
}
struct Network_Addr {
typedef struct Network_Addr {
struct sockaddr_storage addr;
size_t size;
};
} Network_Addr;
static void ip_port_to_network_addr(const IP_Port *ip_port, Network_Addr *addr)
{
addr->size = 0;
if (net_family_is_ipv4(ip_port->ip.family)) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr->addr;
addr->size = sizeof(struct sockaddr_in);
addr4->sin_family = AF_INET;
fill_addr4(&ip_port->ip.ip.v4, &addr4->sin_addr);
addr4->sin_port = ip_port->port;
} else if (net_family_is_ipv6(ip_port->ip.family)) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr->addr;
addr->size = sizeof(struct sockaddr_in6);
addr6->sin6_family = AF_INET6;
fill_addr6(&ip_port->ip.ip.v6, &addr6->sin6_addr);
addr6->sin6_port = ip_port->port;
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
}
}
static bool network_addr_to_ip_port(const Network_Addr *addr, IP_Port *ip_port)
{
if (addr->addr.ss_family == AF_INET) {
const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr->addr;
ip_port->ip.family = net_family_ipv4();
get_ip4(&ip_port->ip.ip.v4, &addr_in->sin_addr);
ip_port->port = addr_in->sin_port;
return true;
} else if (addr->addr.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr->addr;
ip_port->ip.family = net_family_ipv6();
get_ip6(&ip_port->ip.ip.v6, &addr_in6->sin6_addr);
ip_port->port = addr_in6->sin6_port;
return true;
}
return false;
}
static int sys_close(void *_Nonnull obj, Socket sock)
{
@@ -491,9 +531,14 @@ static Socket sys_accept(void *_Nonnull obj, Socket sock)
return net_socket_from_native(accept(net_socket_to_native(sock), nullptr, nullptr));
}
static int sys_bind(void *_Nonnull obj, Socket sock, const Network_Addr *_Nonnull addr)
static int sys_bind(void *_Nonnull obj, Socket sock, const IP_Port *_Nonnull addr)
{
return bind(net_socket_to_native(sock), (const struct sockaddr *)&addr->addr, addr->size);
Network_Addr naddr;
ip_port_to_network_addr(addr, &naddr);
if (naddr.size == 0) {
return -1;
}
return bind(net_socket_to_native(sock), (const struct sockaddr *)&naddr.addr, naddr.size);
}
static int sys_listen(void *_Nonnull obj, Socket sock, int backlog)
@@ -501,9 +546,14 @@ static int sys_listen(void *_Nonnull obj, Socket sock, int backlog)
return listen(net_socket_to_native(sock), backlog);
}
static int sys_connect(void *_Nonnull obj, Socket sock, const Network_Addr *_Nonnull addr)
static int sys_connect(void *_Nonnull obj, Socket sock, const IP_Port *_Nonnull addr)
{
return connect(net_socket_to_native(sock), (const struct sockaddr *)&addr->addr, addr->size);
Network_Addr naddr;
ip_port_to_network_addr(addr, &naddr);
if (naddr.size == 0) {
return -1;
}
return connect(net_socket_to_native(sock), (const struct sockaddr *)&naddr.addr, naddr.size);
}
static int sys_recvbuf(void *_Nonnull obj, Socket sock)
@@ -529,16 +579,28 @@ static int sys_send(void *_Nonnull obj, Socket sock, const uint8_t *_Nonnull buf
return send(net_socket_to_native(sock), (const char *)buf, len, MSG_NOSIGNAL);
}
static int sys_sendto(void *_Nonnull obj, Socket sock, const uint8_t *_Nonnull buf, size_t len, const Network_Addr *_Nonnull addr)
static int sys_sendto(void *_Nonnull obj, Socket sock, const uint8_t *_Nonnull buf, size_t len, const IP_Port *_Nonnull addr)
{
return sendto(net_socket_to_native(sock), (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size);
Network_Addr naddr;
ip_port_to_network_addr(addr, &naddr);
if (naddr.size == 0) {
return -1;
}
return sendto(net_socket_to_native(sock), (const char *)buf, len, 0, (const struct sockaddr *)&naddr.addr, naddr.size);
}
static int sys_recvfrom(void *_Nonnull obj, Socket sock, uint8_t *_Nonnull buf, size_t len, Network_Addr *_Nonnull addr)
static int sys_recvfrom(void *_Nonnull obj, Socket sock, uint8_t *_Nonnull buf, size_t len, IP_Port *_Nonnull addr)
{
socklen_t size = addr->size;
const int ret = recvfrom(net_socket_to_native(sock), (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size);
addr->size = size;
Network_Addr naddr = {{0}};
socklen_t addrlen = sizeof(naddr.addr);
const int ret = recvfrom(net_socket_to_native(sock), (char *)buf, len, 0, (struct sockaddr *)&naddr.addr, &addrlen);
naddr.size = addrlen;
if (ret >= 0) {
if (!network_addr_to_ip_port(&naddr, addr)) {
// Ignore packets from unknown families
return -1;
}
}
return ret;
}
@@ -576,14 +638,13 @@ static int sys_setsockopt(void *_Nonnull obj, Socket sock, int level, int optnam
// sets and fills an array of addrs for address
// returns the number of entries in addrs
static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const char *_Nonnull address, int family, int sock_type, Network_Addr **_Nonnull addrs)
static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const char *_Nonnull address, int family, int sock_type, IP_Port *_Nullable *_Nonnull addrs)
{
assert(addrs != nullptr);
struct addrinfo hints = {0};
hints.ai_family = family;
// different platforms favour a different field
// hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
hints.ai_socktype = sock_type;
@@ -599,7 +660,7 @@ static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const
return 0;
}
const int32_t max_count = INT32_MAX / sizeof(Network_Addr);
const int32_t max_count = INT32_MAX / sizeof(IP_Port);
// we count number of "valid" results
int result = 0;
@@ -613,7 +674,7 @@ static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const
assert(max_count >= result);
Network_Addr *tmp_addrs = (Network_Addr *)mem_valloc(mem, result, sizeof(Network_Addr));
IP_Port *tmp_addrs = (IP_Port *)mem_valloc(mem, result, sizeof(IP_Port));
if (tmp_addrs == nullptr) {
freeaddrinfo(infos);
return 0;
@@ -623,21 +684,18 @@ static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const
int i = 0;
for (struct addrinfo *walker = infos; walker != nullptr; walker = walker->ai_next) {
if (walker->ai_family == family || family == AF_UNSPEC) {
tmp_addrs[i].size = sizeof(struct sockaddr_storage);
tmp_addrs[i].addr.ss_family = walker->ai_family;
Network_Addr naddr;
naddr.size = walker->ai_addrlen;
memcpy(&naddr.addr, walker->ai_addr, walker->ai_addrlen);
// according to spec, storage is supposed to be large enough (and source shows they are)
// storage is 128 bytes
assert(walker->ai_addrlen <= tmp_addrs[i].size);
memcpy(&tmp_addrs[i].addr, walker->ai_addr, walker->ai_addrlen);
tmp_addrs[i].size = walker->ai_addrlen;
++i;
if (network_addr_to_ip_port(&naddr, &tmp_addrs[i])) {
++i;
}
}
}
assert(i == result);
// Correct the count if conversion failed for some reason
result = i;
freeaddrinfo(infos);
@@ -647,7 +705,7 @@ static int sys_getaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, const
return result;
}
static int sys_freeaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, Network_Addr *_Nonnull addrs)
static int sys_freeaddrinfo(void *_Nonnull obj, const Memory *_Nonnull mem, IP_Port *_Nonnull addrs)
{
if (addrs == nullptr) {
return 0;
@@ -728,9 +786,9 @@ int net_send(const Network *ns, const Logger *log,
return res;
}
static int net_sendto(const Network *_Nonnull ns, Socket sock, const uint8_t *_Nonnull buf, size_t len, const Network_Addr *_Nonnull addr, const IP_Port *_Nonnull ip_port)
static int net_sendto(const Network *_Nonnull ns, Socket sock, const uint8_t *_Nonnull buf, size_t len, const IP_Port *_Nonnull ip_port)
{
return ns->funcs->sendto(ns->obj, sock, buf, len, addr);
return ns->funcs->sendto(ns->obj, sock, buf, len, ip_port);
}
int net_recv(const Network *ns, const Logger *log,
@@ -741,7 +799,7 @@ int net_recv(const Network *ns, const Logger *log,
return res;
}
static int net_recvfrom(const Network *_Nonnull ns, Socket sock, uint8_t *_Nonnull buf, size_t len, Network_Addr *_Nonnull addr)
static int net_recvfrom(const Network *_Nonnull ns, Socket sock, uint8_t *_Nonnull buf, size_t len, IP_Port *_Nonnull addr)
{
return ns->funcs->recvfrom(ns->obj, sock, buf, len, addr);
}
@@ -751,7 +809,7 @@ int net_listen(const Network *ns, Socket sock, int backlog)
return ns->funcs->listen(ns->obj, sock, backlog);
}
static int net_bind(const Network *_Nonnull ns, Socket sock, const Network_Addr *_Nonnull addr)
static int net_bind(const Network *_Nonnull ns, Socket sock, const IP_Port *_Nonnull addr)
{
return ns->funcs->bind(ns->obj, sock, addr);
}
@@ -807,22 +865,22 @@ bool set_socket_dualstack(const Network *ns, Socket sock)
}
typedef struct Packet_Handler {
packet_handler_cb *function;
void *object;
packet_handler_cb *_Nullable function;
void *_Nullable object;
} Packet_Handler;
struct Networking_Core {
const Logger *log;
const Memory *mem;
const Logger *_Nonnull log;
const Memory *_Nonnull mem;
Packet_Handler packethandlers[256];
const Network *ns;
const Network *_Nonnull ns;
Family family;
uint16_t port;
/* Our UDP socket. */
Socket sock;
Net_Profile *udp_net_profile;
Net_Profile *_Nullable udp_net_profile;
};
Family net_family(const Networking_Core *net)
@@ -838,7 +896,7 @@ uint16_t net_port(const Networking_Core *net)
/* Basic network functions:
*/
int net_send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packet)
int net_send_packet(const Networking_Core *net, const IP_Port *ip_port, Net_Packet packet)
{
IP_Port ipp_copy = *ip_port;
@@ -880,31 +938,7 @@ int net_send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet p
ipp_copy.ip.ip.v6 = ip6;
}
Network_Addr addr;
if (net_family_is_ipv4(ipp_copy.ip.family)) {
struct sockaddr_in *const addr4 = (struct sockaddr_in *)&addr.addr;
addr.size = sizeof(struct sockaddr_in);
addr4->sin_family = AF_INET;
addr4->sin_port = ipp_copy.port;
fill_addr4(&ipp_copy.ip.ip.v4, &addr4->sin_addr);
} else if (net_family_is_ipv6(ipp_copy.ip.family)) {
struct sockaddr_in6 *const addr6 = (struct sockaddr_in6 *)&addr.addr;
addr.size = sizeof(struct sockaddr_in6);
addr6->sin6_family = AF_INET6;
addr6->sin6_port = ipp_copy.port;
fill_addr6(&ipp_copy.ip.ip.v6, &addr6->sin6_addr);
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
} else {
LOGGER_ERROR(net->log, "unknown address type: %d", ipp_copy.ip.family.value);
return -1;
}
const long res = net_sendto(net->ns, net->sock, packet.data, packet.length, &addr, &ipp_copy);
const long res = net_sendto(net->ns, net->sock, packet.data, packet.length, &ipp_copy);
net_log_data(net->log, "O=>", packet.data, packet.length, ip_port, res);
assert(res <= INT_MAX);
@@ -923,7 +957,7 @@ int net_send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet p
*/
int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length)
{
const Packet packet = {data, length};
const Net_Packet packet = {data, length};
return net_send_packet(net, ip_port, packet);
}
@@ -935,11 +969,9 @@ int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t
static int receivepacket(const Network *_Nonnull ns, const Logger *_Nonnull log, Socket sock, IP_Port *_Nonnull ip_port, uint8_t *_Nonnull data, uint32_t *_Nonnull length)
{
memset(ip_port, 0, sizeof(IP_Port));
Network_Addr addr = {{0}};
addr.size = sizeof(addr.addr);
*length = 0;
const int fail_or_len = net_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, &addr);
const int fail_or_len = net_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, ip_port);
if (fail_or_len < 0) {
const int error = net_error();
@@ -954,38 +986,9 @@ static int receivepacket(const Network *_Nonnull ns, const Logger *_Nonnull log,
*length = (uint32_t)fail_or_len;
if (addr.addr.ss_family == AF_INET) {
const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr.addr;
const Family *const family = make_tox_family(addr_in->sin_family);
assert(family != nullptr);
if (family == nullptr) {
return -1;
}
ip_port->ip.family = *family;
get_ip4(&ip_port->ip.ip.v4, &addr_in->sin_addr);
ip_port->port = addr_in->sin_port;
} else if (addr.addr.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr.addr;
const Family *const family = make_tox_family(addr_in6->sin6_family);
assert(family != nullptr);
if (family == nullptr) {
return -1;
}
ip_port->ip.family = *family;
get_ip6(&ip_port->ip.ip.v6, &addr_in6->sin6_addr);
ip_port->port = addr_in6->sin6_port;
if (ipv6_ipv4_in_v6(&ip_port->ip.ip.v6)) {
ip_port->ip.family = net_family_ipv4();
ip_port->ip.ip.v4.uint32 = ip_port->ip.ip.v6.uint32[3];
}
} else {
return -1;
if (net_family_is_ipv6(ip_port->ip.family) && ipv6_ipv4_in_v6(&ip_port->ip.ip.v6)) {
ip_port->ip.family = net_family_ipv4();
ip_port->ip.ip.v4.uint32 = ip_port->ip.ip.v6.uint32[3];
}
net_log_data(log, "=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
@@ -1080,7 +1083,7 @@ Networking_Core *new_networking_ex(
Net_Profile *np = netprof_new(log, mem);
if (np == nullptr) {
free(temp);
mem_delete(mem, temp);
return nullptr;
}
@@ -1153,29 +1156,13 @@ Networking_Core *new_networking_ex(
/* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
uint16_t *portptr = nullptr;
Network_Addr addr = {{0}};
IP_Port addr;
ip_init(&addr.ip, net_family_is_ipv6(temp->family));
if (net_family_is_ipv4(temp->family)) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
addr.size = sizeof(struct sockaddr_in);
addr4->sin_family = AF_INET;
addr4->sin_port = 0;
fill_addr4(&ip->ip.v4, &addr4->sin_addr);
portptr = &addr4->sin_port;
} else if (net_family_is_ipv6(temp->family)) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
addr.size = sizeof(struct sockaddr_in6);
addr6->sin6_family = AF_INET6;
addr6->sin6_port = 0;
fill_addr6(&ip->ip.v6, &addr6->sin6_addr);
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
portptr = &addr6->sin6_port;
if (net_family_is_ipv4(temp->family) || net_family_is_ipv6(temp->family)) {
ip_copy(&addr.ip, ip);
addr.port = 0;
portptr = &addr.port;
} else {
mem_delete(mem, temp);
return nullptr;
@@ -1747,7 +1734,7 @@ static bool addr_resolve(const Network *_Nonnull ns, const Memory *_Nonnull mem,
const Family tox_family = to->family;
const int family = make_family(tox_family);
Network_Addr *addrs = nullptr;
IP_Port *addrs = nullptr;
const int rc = ns->funcs->getaddrinfo(ns->obj, mem, address, family, 0, &addrs);
// Lookup failed / empty.
@@ -1766,39 +1753,23 @@ static bool addr_resolve(const Network *_Nonnull ns, const Memory *_Nonnull mem,
bool done = false;
for (int i = 0; i < rc && !done; ++i) {
switch (addrs[i].addr.ss_family) {
case AF_INET: {
if (addrs[i].addr.ss_family == family) { /* AF_INET requested, done */
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
get_ip4(&to->ip.v4, &addr->sin_addr);
result = TOX_ADDR_RESOLVE_INET;
done = true;
} else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
get_ip4(&ip4.ip.v4, &addr->sin_addr);
result |= TOX_ADDR_RESOLVE_INET;
}
break; /* switch */
if (net_family_is_ipv4(addrs[i].ip.family)) {
if (addrs[i].ip.family.value == to->family.value) { /* AF_INET requested, done */
ip_copy(to, &addrs[i].ip);
result = TOX_ADDR_RESOLVE_INET;
done = true;
} else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */
ip_copy(&ip4, &addrs[i].ip);
result |= TOX_ADDR_RESOLVE_INET;
}
case AF_INET6: {
if (addrs[i].addr.ss_family == family) { /* AF_INET6 requested, done */
if (addrs[i].size == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr;
get_ip6(&to->ip.v6, &addr->sin6_addr);
result = TOX_ADDR_RESOLVE_INET6;
done = true;
}
} else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */
if (addrs[i].size == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr;
get_ip6(&ip6.ip.v6, &addr->sin6_addr);
result |= TOX_ADDR_RESOLVE_INET6;
}
}
break; /* switch */
} else if (net_family_is_ipv6(addrs[i].ip.family)) {
if (addrs[i].ip.family.value == to->family.value) { /* AF_INET6 requested, done */
ip_copy(to, &addrs[i].ip);
result = TOX_ADDR_RESOLVE_INET6;
done = true;
} else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */
ip_copy(&ip6, &addrs[i].ip);
result |= TOX_ADDR_RESOLVE_INET6;
}
}
}
@@ -1846,23 +1817,7 @@ const char *net_err_connect_to_string(Net_Err_Connect err)
bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port, Net_Err_Connect *err)
{
Network_Addr addr = {{0}};
if (net_family_is_ipv4(ip_port->ip.family)) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
addr.size = sizeof(struct sockaddr_in);
addr4->sin_family = AF_INET;
fill_addr4(&ip_port->ip.ip.v4, &addr4->sin_addr);
addr4->sin_port = ip_port->port;
} else if (net_family_is_ipv6(ip_port->ip.family)) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
addr.size = sizeof(struct sockaddr_in6);
addr6->sin6_family = AF_INET6;
fill_addr6(&ip_port->ip.ip.v6, &addr6->sin6_addr);
addr6->sin6_port = ip_port->port;
} else {
if (!(net_family_is_ipv4(ip_port->ip.family) || net_family_is_ipv6(ip_port->ip.family))) {
Ip_Ntoa ip_str;
LOGGER_ERROR(log, "cannot connect to %s:%d which is neither IPv4 nor IPv6",
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port));
@@ -1882,7 +1837,7 @@ bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket
net_socket_to_native(sock), net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port));
errno = 0;
if (ns->funcs->connect(ns->obj, sock, &addr) == -1) {
if (ns->funcs->connect(ns->obj, sock, ip_port) == -1) {
const int error = net_error();
// Non-blocking socket: "Operation in progress" means it's connecting.
@@ -1946,7 +1901,7 @@ int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP
}
// It's not an IP address, so now we try doing a DNS lookup.
Network_Addr *addrs = nullptr;
IP_Port *addrs = nullptr;
const int rc = ns->funcs->getaddrinfo(ns->obj, mem, node, AF_UNSPEC, type, &addrs);
// Lookup failed / empty.
@@ -1956,62 +1911,8 @@ int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP
assert(addrs != nullptr);
// Used to avoid calloc parameter overflow
const size_t max_count = min_u64(SIZE_MAX, INT32_MAX) / sizeof(IP_Port);
size_t count = 0;
for (int i = 0; i < rc && count < max_count; ++i) {
if (addrs[i].addr.ss_family != AF_INET && addrs[i].addr.ss_family != AF_INET6) {
continue;
}
++count;
}
assert(count <= max_count);
if (count == 0) {
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return 0;
}
IP_Port *ip_port = (IP_Port *)mem_valloc(mem, count, sizeof(IP_Port));
if (ip_port == nullptr) {
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
*res = nullptr;
return -1;
}
*res = ip_port;
for (int i = 0; i < rc && count < max_count; ++i) {
if (addrs[i].addr.ss_family == AF_INET) {
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
ip_port->ip.ip.v4.uint32 = addr->sin_addr.s_addr;
} else if (addrs[i].addr.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)&addrs[i].addr;
memcpy(ip_port->ip.ip.v6.uint8, addr->sin6_addr.s6_addr, sizeof(IP6));
} else {
continue;
}
const Family *const family = make_tox_family(addrs[i].addr.ss_family);
assert(family != nullptr);
if (family == nullptr) {
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return -1;
}
ip_port->ip.family = *family;
++ip_port;
}
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return count;
*res = addrs;
return rc;
}
void net_freeipport(const Memory *mem, IP_Port *ip_ports)
@@ -2021,24 +1922,18 @@ void net_freeipport(const Memory *mem, IP_Port *ip_ports)
bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port)
{
Network_Addr addr = {{0}};
IP_Port addr;
ip_init(&addr.ip, net_family_is_ipv6(family));
addr.ip.family = family;
if (net_family_is_ipv4(family)) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
addr.size = sizeof(struct sockaddr_in);
addr4->sin_family = AF_INET;
addr4->sin_port = net_htons(port);
} else if (net_family_is_ipv6(family)) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
addr.size = sizeof(struct sockaddr_in6);
addr6->sin6_family = AF_INET6;
addr6->sin6_port = net_htons(port);
addr.ip.ip.v4.uint32 = 0;
} else {
return false;
memset(addr.ip.ip.v6.uint8, 0, 16);
}
addr.port = net_htons(port);
return net_bind(ns, sock, &addr) == 0;
}

View File

@@ -23,35 +23,68 @@
extern "C" {
#endif
/**
* @brief Wrapper for sockaddr_storage and size.
*/
typedef struct Network_Addr Network_Addr;
typedef bitwise int Socket_Value;
typedef struct Socket {
Socket_Value value;
} Socket;
#define SIZE_IP4 4
#define SIZE_IP6 16
#define SIZE_IP (1 + SIZE_IP6)
#define SIZE_PORT 2
#define SIZE_IPPORT (SIZE_IP + SIZE_PORT)
typedef struct Family {
uint8_t value;
} Family;
typedef union IP4 {
uint32_t uint32;
uint16_t uint16[2];
uint8_t uint8[4];
} IP4;
typedef union IP6 {
uint8_t uint8[16];
uint16_t uint16[8];
uint32_t uint32[4];
uint64_t uint64[2];
} IP6;
typedef union IP_Union {
IP4 v4;
IP6 v6;
} IP_Union;
typedef struct IP {
Family family;
IP_Union ip;
} IP;
typedef struct IP_Port {
IP ip;
uint16_t port;
} IP_Port;
int net_socket_to_native(Socket sock);
Socket net_socket_from_native(int sock);
typedef int net_close_cb(void *_Nullable obj, Socket sock);
typedef Socket net_accept_cb(void *_Nullable obj, Socket sock);
typedef int net_bind_cb(void *_Nullable obj, Socket sock, const Network_Addr *_Nonnull addr);
typedef int net_bind_cb(void *_Nullable obj, Socket sock, const IP_Port *_Nonnull addr);
typedef int net_listen_cb(void *_Nullable obj, Socket sock, int backlog);
typedef int net_connect_cb(void *_Nullable obj, Socket sock, const Network_Addr *_Nonnull addr);
typedef int net_connect_cb(void *_Nullable obj, Socket sock, const IP_Port *_Nonnull addr);
typedef int net_recvbuf_cb(void *_Nullable obj, Socket sock);
typedef int net_recv_cb(void *_Nullable obj, Socket sock, uint8_t *_Nonnull buf, size_t len);
typedef int net_recvfrom_cb(void *_Nullable obj, Socket sock, uint8_t *_Nonnull buf, size_t len, Network_Addr *_Nonnull addr);
typedef int net_recvfrom_cb(void *_Nullable obj, Socket sock, uint8_t *_Nonnull buf, size_t len, IP_Port *_Nonnull addr);
typedef int net_send_cb(void *_Nullable obj, Socket sock, const uint8_t *_Nonnull buf, size_t len);
typedef int net_sendto_cb(void *_Nullable obj, Socket sock, const uint8_t *_Nonnull buf, size_t len, const Network_Addr *_Nonnull addr);
typedef int net_sendto_cb(void *_Nullable obj, Socket sock, const uint8_t *_Nonnull buf, size_t len, const IP_Port *_Nonnull addr);
typedef Socket net_socket_cb(void *_Nullable obj, int domain, int type, int proto);
typedef int net_socket_nonblock_cb(void *_Nullable obj, Socket sock, bool nonblock);
typedef int net_getsockopt_cb(void *_Nullable obj, Socket sock, int level, int optname, void *_Nonnull optval, size_t *_Nonnull optlen);
typedef int net_setsockopt_cb(void *_Nullable obj, Socket sock, int level, int optname, const void *_Nonnull optval, size_t optlen);
typedef int net_getaddrinfo_cb(void *_Nullable obj, const Memory *_Nonnull mem, const char *_Nonnull address, int family, int protocol, Network_Addr *_Nullable *_Nonnull addrs);
typedef int net_freeaddrinfo_cb(void *_Nullable obj, const Memory *_Nonnull mem, Network_Addr *_Nullable addrs);
typedef int net_getaddrinfo_cb(void *_Nullable obj, const Memory *_Nonnull mem, const char *_Nonnull address, int family, int protocol, IP_Port *_Nullable *_Nonnull addrs);
typedef int net_freeaddrinfo_cb(void *_Nullable obj, const Memory *_Nonnull mem, IP_Port *_Nullable addrs);
/** @brief Functions wrapping POSIX network functions.
*
@@ -84,10 +117,6 @@ typedef struct Network {
const Network *_Nullable os_network(void);
typedef struct Family {
uint8_t value;
} Family;
bool net_family_is_unspec(Family family);
bool net_family_is_ipv4(Family family);
bool net_family_is_ipv6(Family family);
@@ -182,46 +211,12 @@ typedef enum Net_Packet_Type {
#define TCP_INET6 (TOX_AF_INET6 + 3)
#define TCP_SERVER_FAMILY (TOX_AF_INET6 + 4)
#define SIZE_IP4 4
#define SIZE_IP6 16
#define SIZE_IP (1 + SIZE_IP6)
#define SIZE_PORT 2
#define SIZE_IPPORT (SIZE_IP + SIZE_PORT)
typedef union IP4 {
uint32_t uint32;
uint16_t uint16[2];
uint8_t uint8[4];
} IP4;
IP4 get_ip4_loopback(void);
IP4 get_ip4_broadcast(void);
typedef union IP6 {
uint8_t uint8[16];
uint16_t uint16[8];
uint32_t uint32[4];
uint64_t uint64[2];
} IP6;
IP6 get_ip6_loopback(void);
IP6 get_ip6_broadcast(void);
typedef union IP_Union {
IP4 v4;
IP6 v6;
} IP_Union;
typedef struct IP {
Family family;
IP_Union ip;
} IP;
typedef struct IP_Port {
IP ip;
uint16_t port;
} IP_Port;
Socket net_socket(const Network *_Nonnull ns, Family domain, int type, int protocol);
/**
@@ -450,15 +445,15 @@ bool set_socket_dualstack(const Network *_Nonnull ns, Socket sock);
*
* Use `net_send_packet` to send it to an IP/port endpoint.
*/
typedef struct Packet {
typedef struct Net_Packet {
const uint8_t *_Nonnull data;
uint16_t length;
} Packet;
} Net_Packet;
/**
* Function to send a network packet to a given IP/port.
*/
int net_send_packet(const Networking_Core *_Nonnull net, const IP_Port *_Nonnull ip_port, Packet packet);
int net_send_packet(const Networking_Core *_Nonnull net, const IP_Port *_Nonnull ip_port, Net_Packet packet);
/**
* Function to send packet(data) of length length to ip_port.

View File

@@ -1,4 +1,7 @@
// clang-format off
#include "../testing/support/public/simulated_environment.hh"
#include "network.h"
// clang-format on
#include <gtest/gtest.h>
@@ -6,11 +9,13 @@
namespace {
TEST(TestUtil, ProducesNonNullNetwork)
TEST(SimulatedEnvironment, ProducesNonNullNetwork)
{
Test_Network net;
const Network *ns = net;
EXPECT_NE(ns, nullptr);
tox::test::SimulatedEnvironment env;
auto node = env.create_node(0);
struct Network net = node->c_network;
EXPECT_NE(net.funcs, nullptr);
EXPECT_NE(net.obj, nullptr);
}
TEST(IpNtoa, DoesntWriteOutOfBounds)

View File

@@ -7,87 +7,6 @@
#include "network.h"
#include "test_util.hh"
Network_Funcs const Network_Class::vtable = {
Method<net_close_cb, Network_Class>::invoke<&Network_Class::close>,
Method<net_accept_cb, Network_Class>::invoke<&Network_Class::accept>,
Method<net_bind_cb, Network_Class>::invoke<&Network_Class::bind>,
Method<net_listen_cb, Network_Class>::invoke<&Network_Class::listen>,
Method<net_connect_cb, Network_Class>::invoke<&Network_Class::connect>,
Method<net_recvbuf_cb, Network_Class>::invoke<&Network_Class::recvbuf>,
Method<net_recv_cb, Network_Class>::invoke<&Network_Class::recv>,
Method<net_recvfrom_cb, Network_Class>::invoke<&Network_Class::recvfrom>,
Method<net_send_cb, Network_Class>::invoke<&Network_Class::send>,
Method<net_sendto_cb, Network_Class>::invoke<&Network_Class::sendto>,
Method<net_socket_cb, Network_Class>::invoke<&Network_Class::socket>,
Method<net_socket_nonblock_cb, Network_Class>::invoke<&Network_Class::socket_nonblock>,
Method<net_getsockopt_cb, Network_Class>::invoke<&Network_Class::getsockopt>,
Method<net_setsockopt_cb, Network_Class>::invoke<&Network_Class::setsockopt>,
Method<net_getaddrinfo_cb, Network_Class>::invoke<&Network_Class::getaddrinfo>,
Method<net_freeaddrinfo_cb, Network_Class>::invoke<&Network_Class::freeaddrinfo>,
};
int Test_Network::close(void *obj, Socket sock) { return net->funcs->close(net->obj, sock); }
Socket Test_Network::accept(void *obj, Socket sock) { return net->funcs->accept(net->obj, sock); }
int Test_Network::bind(void *obj, Socket sock, const Network_Addr *addr)
{
return net->funcs->bind(net->obj, sock, addr);
}
int Test_Network::listen(void *obj, Socket sock, int backlog)
{
return net->funcs->listen(net->obj, sock, backlog);
}
int Test_Network::connect(void *obj, Socket sock, const Network_Addr *addr)
{
return net->funcs->connect(net->obj, sock, addr);
}
int Test_Network::recvbuf(void *obj, Socket sock) { return net->funcs->recvbuf(net->obj, sock); }
int Test_Network::recv(void *obj, Socket sock, uint8_t *buf, size_t len)
{
return net->funcs->recv(net->obj, sock, buf, len);
}
int Test_Network::recvfrom(void *obj, Socket sock, uint8_t *buf, size_t len, Network_Addr *addr)
{
return net->funcs->recvfrom(net->obj, sock, buf, len, addr);
}
int Test_Network::send(void *obj, Socket sock, const uint8_t *buf, size_t len)
{
return net->funcs->send(net->obj, sock, buf, len);
}
int Test_Network::sendto(
void *obj, Socket sock, const uint8_t *buf, size_t len, const Network_Addr *addr)
{
return net->funcs->sendto(net->obj, sock, buf, len, addr);
}
Socket Test_Network::socket(void *obj, int domain, int type, int proto)
{
return net->funcs->socket(net->obj, domain, type, proto);
}
int Test_Network::socket_nonblock(void *obj, Socket sock, bool nonblock)
{
return net->funcs->socket_nonblock(net->obj, sock, nonblock);
}
int Test_Network::getsockopt(
void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen)
{
return net->funcs->getsockopt(net->obj, sock, level, optname, optval, optlen);
}
int Test_Network::setsockopt(
void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen)
{
return net->funcs->setsockopt(net->obj, sock, level, optname, optval, optlen);
}
int Test_Network::getaddrinfo(void *obj, const Memory *mem, const char *address, int family,
int protocol, Network_Addr **addrs)
{
return net->funcs->getaddrinfo(net->obj, mem, address, family, protocol, addrs);
}
int Test_Network::freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs)
{
return net->funcs->freeaddrinfo(net->obj, mem, addrs);
}
Network_Class::~Network_Class() = default;
IP_Port increasing_ip_port::operator()()
{
IP_Port ip_port;

View File

@@ -8,66 +8,6 @@
#include "network.h"
#include "test_util.hh"
struct Network_Class {
static Network_Funcs const vtable;
Network const self;
operator Network const *() const { return &self; }
Network_Class(Network_Class const &) = default;
Network_Class()
: self{&vtable, this}
{
}
virtual ~Network_Class();
virtual net_close_cb close = 0;
virtual net_accept_cb accept = 0;
virtual net_bind_cb bind = 0;
virtual net_listen_cb listen = 0;
virtual net_connect_cb connect = 0;
virtual net_recvbuf_cb recvbuf = 0;
virtual net_recv_cb recv = 0;
virtual net_recvfrom_cb recvfrom = 0;
virtual net_send_cb send = 0;
virtual net_sendto_cb sendto = 0;
virtual net_socket_cb socket = 0;
virtual net_socket_nonblock_cb socket_nonblock = 0;
virtual net_getsockopt_cb getsockopt = 0;
virtual net_setsockopt_cb setsockopt = 0;
virtual net_getaddrinfo_cb getaddrinfo = 0;
virtual net_freeaddrinfo_cb freeaddrinfo = 0;
};
/**
* Base test Network class that just forwards to os_network. Can be
* subclassed to override individual (or all) functions.
*/
class Test_Network : public Network_Class {
const Network *net = REQUIRE_NOT_NULL(os_network());
int close(void *obj, Socket sock) override;
Socket accept(void *obj, Socket sock) override;
int bind(void *obj, Socket sock, const Network_Addr *addr) override;
int listen(void *obj, Socket sock, int backlog) override;
int connect(void *obj, Socket sock, const Network_Addr *addr) override;
int recvbuf(void *obj, Socket sock) override;
int recv(void *obj, Socket sock, uint8_t *buf, size_t len) override;
int recvfrom(void *obj, Socket sock, uint8_t *buf, size_t len, Network_Addr *addr) override;
int send(void *obj, Socket sock, const uint8_t *buf, size_t len) override;
int sendto(
void *obj, Socket sock, const uint8_t *buf, size_t len, const Network_Addr *addr) override;
Socket socket(void *obj, int domain, int type, int proto) override;
int socket_nonblock(void *obj, Socket sock, bool nonblock) override;
int getsockopt(
void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen) override;
int setsockopt(
void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen) override;
int getaddrinfo(void *obj, const Memory *mem, const char *address, int family, int protocol,
Network_Addr **addrs) override;
int freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs) override;
};
template <>
struct Deleter<Networking_Core> : Function_Deleter<Networking_Core, kill_networking> { };

View File

@@ -724,18 +724,23 @@ Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_tim
onion->timestamp = mono_time_get(onion->mono_time);
const uint8_t *secret_key = dht_get_self_secret_key(dht);
onion->shared_keys_1 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_2 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_3 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
Shared_Key_Cache *const temp_shared_keys_1 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
Shared_Key_Cache *const temp_shared_keys_2 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
Shared_Key_Cache *const temp_shared_keys_3 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (onion->shared_keys_1 == nullptr ||
onion->shared_keys_2 == nullptr ||
onion->shared_keys_3 == nullptr) {
if (temp_shared_keys_1 == nullptr || temp_shared_keys_2 == nullptr || temp_shared_keys_3 == nullptr) {
shared_key_cache_free(temp_shared_keys_3);
shared_key_cache_free(temp_shared_keys_2);
shared_key_cache_free(temp_shared_keys_1);
// cppcheck-suppress mismatchAllocDealloc
kill_onion(onion);
return nullptr;
}
onion->shared_keys_1 = temp_shared_keys_1;
onion->shared_keys_2 = temp_shared_keys_2;
onion->shared_keys_3 = temp_shared_keys_3;
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion);
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion);
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion);

View File

@@ -55,20 +55,20 @@ typedef struct Onion_Announce_Entry {
} Onion_Announce_Entry;
struct Onion_Announce {
const Logger *log;
const Mono_Time *mono_time;
const Random *rng;
const Memory *mem;
DHT *dht;
Networking_Core *net;
const Logger *_Nonnull log;
const Mono_Time *_Nonnull mono_time;
const Random *_Nonnull rng;
const Memory *_Nonnull mem;
DHT *_Nonnull dht;
Networking_Core *_Nonnull net;
Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES];
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
Shared_Key_Cache *shared_keys_recv;
Shared_Key_Cache *_Nonnull shared_keys_recv;
uint16_t extra_data_max_size;
pack_extra_data_cb *extra_data_callback;
void *extra_data_object;
pack_extra_data_cb *_Nullable extra_data_callback;
void *_Nullable extra_data_object;
};
void onion_announce_extra_data_callback(Onion_Announce *onion_a, uint16_t extra_data_max_size,
@@ -693,6 +693,13 @@ Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const R
return nullptr;
}
Shared_Key_Cache *const shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht_get_self_secret_key(dht), KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (shared_keys_recv == nullptr) {
mem_delete(mem, onion_a);
return nullptr;
}
onion_a->shared_keys_recv = shared_keys_recv;
onion_a->log = log;
onion_a->rng = rng;
onion_a->mem = mem;
@@ -704,13 +711,6 @@ Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const R
onion_a->extra_data_object = nullptr;
new_hmac_key(rng, onion_a->hmac_key);
onion_a->shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht_get_self_secret_key(dht), KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (onion_a->shared_keys_recv == nullptr) {
// cppcheck-suppress mismatchAllocDealloc
kill_onion_announce(onion_a);
return nullptr;
}
networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a);
networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST_OLD, &handle_announce_request_old, onion_a);
networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a);

View File

@@ -20,6 +20,7 @@
#include "crypto_core.h"
#include "group_announce.h"
#include "group_onion_announce.h"
#include "list.h"
#include "logger.h"
#include "mem.h"
#include "mono_time.h"
@@ -94,12 +95,12 @@ struct Onion_Friend {
Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];
uint8_t last_pinged_index;
recv_tcp_relay_cb *tcp_relay_node_callback;
void *tcp_relay_node_callback_object;
recv_tcp_relay_cb *_Nullable tcp_relay_node_callback;
void *_Nullable tcp_relay_node_callback_object;
uint32_t tcp_relay_node_callback_number;
onion_dht_pk_cb *dht_pk_callback;
void *dht_pk_callback_object;
onion_dht_pk_cb *_Nullable dht_pk_callback;
void *_Nullable dht_pk_callback_object;
uint32_t dht_pk_callback_number;
uint8_t gc_data[GCA_MAX_DATA_LENGTH];
@@ -111,21 +112,24 @@ struct Onion_Friend {
static const Onion_Friend empty_onion_friend = {false};
typedef struct Onion_Data_Handler {
oniondata_handler_cb *function;
void *object;
oniondata_handler_cb *_Nullable function;
void *_Nullable object;
} Onion_Data_Handler;
struct Onion_Client {
const Mono_Time *mono_time;
const Logger *logger;
const Random *rng;
const Memory *mem;
const Mono_Time *_Nonnull mono_time;
const Logger *_Nonnull logger;
const Random *_Nonnull rng;
const Memory *_Nonnull mem;
DHT *dht;
Net_Crypto *c;
Networking_Core *net;
Onion_Friend *friends_list;
uint16_t num_friends;
DHT *_Nonnull dht;
Net_Crypto *_Nonnull c;
Networking_Core *_Nonnull net;
Onion_Friend *_Nullable friends_list;
uint32_t friends_list_capacity;
uint32_t num_friends;
BS_List friends_lookup;
Onion_Node clients_announce_list[MAX_ONION_CLIENTS_ANNOUNCE];
uint64_t last_announce;
@@ -149,7 +153,7 @@ struct Onion_Client {
Node_format path_nodes_bs[MAX_PATH_NODES];
uint16_t path_nodes_index_bs;
Ping_Array *announce_ping_array;
Ping_Array *_Nonnull announce_ping_array;
uint8_t last_pinged_index;
Onion_Data_Handler onion_data_handlers[256];
@@ -159,16 +163,16 @@ struct Onion_Client {
unsigned int onion_connected;
bool udp_connected;
onion_group_announce_cb *group_announce_response;
void *group_announce_response_user_data;
onion_group_announce_cb *_Nullable group_announce_response;
void *_Nullable group_announce_response_user_data;
};
uint16_t onion_get_friend_count(const Onion_Client *const onion_c)
uint32_t onion_get_friend_count(const Onion_Client *const onion_c)
{
return onion_c->num_friends;
}
Onion_Friend *onion_get_friend(const Onion_Client *const onion_c, uint16_t friend_num)
Onion_Friend *onion_get_friend(const Onion_Client *const onion_c, uint32_t friend_num)
{
return &onion_c->friends_list[friend_num];
}
@@ -954,9 +958,9 @@ static int handle_announce_response(void *_Nonnull object, const IP_Port *_Nonnu
return 1;
}
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
IP_Port ip_port;
uint32_t path_num;
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE] = {0};
IP_Port ip_port = {0};
uint32_t path_num = 0;
const uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num);
if (num > onion_c->num_friends) {
@@ -1001,6 +1005,11 @@ static int handle_announce_response(void *_Nonnull object, const IP_Port *_Nonnu
}
uint16_t len_nodes = 0;
if (plain_size <= 1 + ONION_PING_ID_SIZE) {
return 1;
}
const uint8_t nodes_count = plain[1 + ONION_PING_ID_SIZE];
if (nodes_count > 0) {
@@ -1056,9 +1065,9 @@ static int handle_announce_response_old(void *_Nonnull object, const IP_Port *_N
const uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
IP_Port ip_port;
uint32_t path_num;
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE] = {0};
IP_Port ip_port = {0};
uint32_t path_num = 0;
const uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num);
if (num > onion_c->num_friends) {
@@ -1378,7 +1387,7 @@ static int send_dht_dhtpk(const Onion_Client *_Nonnull onion_c, int friend_num,
onion_c->mem, onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data,
onion_c->friends_list[friend_num].dht_public_key, temp, temp_size, CRYPTO_PACKET_DHTPK);
assert(len <= UINT16_MAX);
const Packet packet = {packet_data, (uint16_t)len};
const Net_Packet packet = {packet_data, (uint16_t)len};
if (len == -1) {
return -1;
@@ -1426,7 +1435,7 @@ static int handle_dht_dhtpk(void *_Nonnull object, const IP_Port *_Nonnull sourc
* return the number of packets sent on success
* return -1 on failure.
*/
static int send_dhtpk_announce(Onion_Client *_Nonnull onion_c, uint16_t friend_num, uint8_t onion_dht_both)
static int send_dhtpk_announce(Onion_Client *_Nonnull onion_c, uint32_t friend_num, uint8_t onion_dht_both)
{
if (friend_num >= onion_c->num_friends) {
return -1;
@@ -1481,17 +1490,7 @@ static int send_dhtpk_announce(Onion_Client *_Nonnull onion_c, uint16_t friend_n
*/
int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key)
{
for (unsigned int i = 0; i < onion_c->num_friends; ++i) {
if (!onion_c->friends_list[i].is_valid) {
continue;
}
if (pk_equal(public_key, onion_c->friends_list[i].real_public_key)) {
return i;
}
}
return -1;
return bs_list_find(&onion_c->friends_lookup, public_key);
}
/** @brief Set the size of the friend list to num.
@@ -1504,16 +1503,28 @@ static int realloc_onion_friends(Onion_Client *_Nonnull onion_c, uint32_t num)
if (num == 0) {
mem_delete(onion_c->mem, onion_c->friends_list);
onion_c->friends_list = nullptr;
onion_c->friends_list_capacity = 0;
return 0;
}
Onion_Friend *newonion_friends = (Onion_Friend *)mem_vrealloc(onion_c->mem, onion_c->friends_list, num, sizeof(Onion_Friend));
if (num <= onion_c->friends_list_capacity) {
return 0;
}
// Geometric growth: Double the capacity or set to num if starting.
uint32_t new_capacity = onion_c->friends_list_capacity == 0 ? num : onion_c->friends_list_capacity * 2;
if (new_capacity < num) {
new_capacity = num;
}
Onion_Friend *newonion_friends = (Onion_Friend *)mem_vrealloc(onion_c->mem, onion_c->friends_list, new_capacity, sizeof(Onion_Friend));
if (newonion_friends == nullptr) {
return -1;
}
onion_c->friends_list = newonion_friends;
onion_c->friends_list_capacity = new_capacity;
return 0;
}
@@ -1530,9 +1541,9 @@ int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key)
return num;
}
unsigned int index = -1;
uint32_t index = (uint32_t) -1;
for (unsigned int i = 0; i < onion_c->num_friends; ++i) {
for (uint32_t i = 0; i < onion_c->num_friends; ++i) {
if (!onion_c->friends_list[i].is_valid) {
index = i;
break;
@@ -1553,6 +1564,12 @@ int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key)
memcpy(onion_c->friends_list[index].real_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
crypto_new_keypair(onion_c->rng, onion_c->friends_list[index].temp_public_key,
onion_c->friends_list[index].temp_secret_key);
if (!bs_list_add(&onion_c->friends_lookup, public_key, index)) {
LOGGER_ERROR(onion_c->logger, "Failed to add friend to lookup list (index: %u)", index);
return -1;
}
return index;
}
@@ -1575,8 +1592,12 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
#endif /* 0 */
if (!bs_list_remove(&onion_c->friends_lookup, onion_c->friends_list[friend_num].real_public_key, friend_num)) {
LOGGER_ERROR(onion_c->logger, "Failed to remove friend from lookup list (index: %d)", friend_num);
}
crypto_memzero(&onion_c->friends_list[friend_num], sizeof(Onion_Friend));
unsigned int i;
uint32_t i;
for (i = onion_c->num_friends; i != 0; --i) {
if (onion_c->friends_list[i - 1].is_valid) {
@@ -1584,10 +1605,7 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
}
}
if (onion_c->num_friends != i) {
onion_c->num_friends = i;
realloc_onion_friends(onion_c, onion_c->num_friends);
}
onion_c->num_friends = i;
return friend_num;
}
@@ -1752,7 +1770,7 @@ static void populate_path_nodes(Onion_Client *_Nonnull onion_c)
/* Max exponent when calculating the announce request interval */
#define MAX_RUN_COUNT_EXPONENT 12
static void do_friend(Onion_Client *_Nonnull onion_c, uint16_t friendnum)
static void do_friend(Onion_Client *_Nonnull onion_c, uint32_t friendnum)
{
if (friendnum >= onion_c->num_friends) {
return;
@@ -2088,7 +2106,7 @@ static bool onion_isconnected(Onion_Client *_Nonnull onion_c)
static void reset_friend_run_counts(Onion_Client *_Nonnull onion_c)
{
for (uint16_t i = 0; i < onion_c->num_friends; ++i) {
for (uint32_t i = 0; i < onion_c->num_friends; ++i) {
Onion_Friend *o_friend = &onion_c->friends_list[i];
if (o_friend->is_valid) {
@@ -2147,7 +2165,7 @@ void do_onion_client(Onion_Client *onion_c)
}
if (onion_connection_status(onion_c) != ONION_CONNECTION_STATUS_NONE) {
for (unsigned i = 0; i < onion_c->num_friends; ++i) {
for (uint32_t i = 0; i < onion_c->num_friends; ++i) {
do_friend(onion_c, i);
}
}
@@ -2172,12 +2190,13 @@ Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Ra
return nullptr;
}
onion_c->announce_ping_array = ping_array_new(mem, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT);
Ping_Array *const temp_ping_array = ping_array_new(mem, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT);
if (onion_c->announce_ping_array == nullptr) {
if (temp_ping_array == nullptr) {
mem_delete(mem, onion_c);
return nullptr;
}
onion_c->announce_ping_array = temp_ping_array;
onion_c->mono_time = mono_time;
onion_c->logger = logger;
@@ -2186,6 +2205,9 @@ Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Ra
onion_c->dht = dht;
onion_c->net = net;
onion_c->c = c;
onion_c->friends_list_capacity = 0;
bs_list_init(&onion_c->friends_lookup, mem, CRYPTO_PUBLIC_KEY_SIZE, 0, memcmp);
new_symmetric_key(rng, onion_c->secret_symmetric_key);
crypto_new_keypair(rng, onion_c->temp_public_key, onion_c->temp_secret_key);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c);
@@ -2208,6 +2230,7 @@ void kill_onion_client(Onion_Client *onion_c)
ping_array_kill(onion_c->announce_ping_array);
realloc_onion_friends(onion_c, 0);
bs_list_free(&onion_c->friends_lookup);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, nullptr, nullptr);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, nullptr, nullptr);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, nullptr, nullptr);
@@ -2217,3 +2240,18 @@ void kill_onion_client(Onion_Client *onion_c)
crypto_memzero(onion_c, sizeof(Onion_Client));
mem_delete(mem, onion_c);
}
uint64_t onion_testonly_get_last_packet_recv(const Onion_Client *onion_c)
{
return onion_c->last_packet_recv;
}
void onion_testonly_get_temp_public_key(const Onion_Client *onion_c, uint8_t *public_key)
{
memcpy(public_key, onion_c->temp_public_key, CRYPTO_PUBLIC_KEY_SIZE);
}
void onion_testonly_get_secret_symmetric_key(const Onion_Client *onion_c, uint8_t *secret_key)
{
memcpy(secret_key, onion_c->secret_symmetric_key, CRYPTO_SYMMETRIC_KEY_SIZE);
}

View File

@@ -63,6 +63,10 @@
#define ONION_DATA_FRIEND_REQ CRYPTO_PACKET_FRIEND_REQ
#define ONION_DATA_DHTPK CRYPTO_PACKET_DHTPK
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Onion_Client Onion_Client;
/** @brief Add a node to the path_nodes bootstrap array.
@@ -208,12 +212,21 @@ Onion_Connection_Status onion_connection_status(const Onion_Client *_Nonnull oni
typedef struct Onion_Friend Onion_Friend;
uint16_t onion_get_friend_count(const Onion_Client *_Nonnull onion_c);
Onion_Friend *_Nullable onion_get_friend(const Onion_Client *_Nonnull onion_c, uint16_t friend_num);
const uint8_t *_Nullable onion_friend_get_gc_public_key(const Onion_Friend *_Nonnull onion_friend);
const uint8_t *_Nullable onion_friend_get_gc_public_key_num(const Onion_Client *_Nonnull onion_c, uint32_t num);
uint32_t onion_get_friend_count(const Onion_Client *_Nonnull onion_c);
Onion_Friend *_Nonnull onion_get_friend(const Onion_Client *_Nonnull onion_c, uint32_t friend_num);
const uint8_t *_Nonnull onion_friend_get_gc_public_key(const Onion_Friend *_Nonnull onion_friend);
const uint8_t *_Nonnull onion_friend_get_gc_public_key_num(const Onion_Client *_Nonnull onion_c, uint32_t num);
void onion_friend_set_gc_public_key(Onion_Friend *_Nonnull onion_friend, const uint8_t *_Nonnull public_key);
void onion_friend_set_gc_data(Onion_Friend *_Nonnull onion_friend, const uint8_t *_Nullable gc_data, uint16_t gc_data_length);
bool onion_friend_is_groupchat(const Onion_Friend *_Nonnull onion_friend);
/** Unit test support functions. Do not use outside tests. */
uint64_t onion_testonly_get_last_packet_recv(const Onion_Client *_Nonnull onion_c);
void onion_testonly_get_temp_public_key(const Onion_Client *_Nonnull onion_c, uint8_t *_Nonnull public_key);
void onion_testonly_get_secret_symmetric_key(const Onion_Client *_Nonnull onion_c, uint8_t *_Nonnull secret_key);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_ONION_CLIENT_H */

View File

@@ -0,0 +1,390 @@
#include "onion_client.h"
#include <algorithm>
#include <cstring>
#include <map>
#include <memory>
#include <vector>
#include "../testing/support/doubles/fake_sockets.hh"
#include "../testing/support/public/fuzz_data.hh"
#include "../testing/support/public/simulated_environment.hh"
#include "DHT.h"
#include "net_crypto.h"
#include "net_profile.h"
#include "network.h"
namespace {
using tox::test::FakeUdpSocket;
using tox::test::Fuzz_Data;
using tox::test::SimulatedEnvironment;
template <typename T>
T consume_range(Fuzz_Data &input, T min, T max)
{
T val = input.consume_integral<T>();
if (max <= min)
return min;
return min + (val % (max - min + 1));
}
// Minimal DHT wrapper for fuzzing
class FuzzDHT {
public:
FuzzDHT(SimulatedEnvironment &env, uint16_t port)
: node_(env.create_node(port))
, logger_(logger_new(&node_->c_memory), [](Logger *l) { logger_kill(l); })
, mono_time_(mono_time_new(
&node_->c_memory,
[](void *ud) -> uint64_t {
return static_cast<tox::test::FakeClock *>(ud)->current_time_ms();
},
&env.fake_clock()),
[mem = &node_->c_memory](Mono_Time *t) { mono_time_free(mem, t); })
, networking_(nullptr, [](Networking_Core *n) { kill_networking(n); })
, dht_(nullptr, [](DHT *d) { kill_dht(d); })
{
IP ip;
ip_init(&ip, true);
unsigned int error = 0;
networking_.reset(new_networking_ex(
logger_.get(), &node_->c_memory, &node_->c_network, &ip, port, port + 1, &error));
// In fuzzing we might ignore assert, but setup should succeed
node_->endpoint = node_->node->get_primary_socket();
dht_.reset(new_dht(logger_.get(), &node_->c_memory, &node_->c_random, &node_->c_network,
mono_time_.get(), networking_.get(), true, true));
}
DHT *get_dht() { return dht_.get(); }
Networking_Core *networking() { return networking_.get(); }
Mono_Time *mono_time() { return mono_time_.get(); }
Logger *logger() { return logger_.get(); }
tox::test::ScopedToxSystem &node() { return *node_; }
FakeUdpSocket *endpoint() { return node_->endpoint; }
static const Net_Crypto_DHT_Funcs funcs;
private:
std::unique_ptr<tox::test::ScopedToxSystem> node_;
std::unique_ptr<Logger, void (*)(Logger *)> logger_;
std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time_;
std::unique_ptr<Networking_Core, void (*)(Networking_Core *)> networking_;
std::unique_ptr<DHT, void (*)(DHT *)> dht_;
};
const Net_Crypto_DHT_Funcs FuzzDHT::funcs = {
[](void *obj, const uint8_t *public_key) {
return dht_get_shared_key_sent(static_cast<DHT *>(obj), public_key);
},
[](const void *obj) { return dht_get_self_public_key(static_cast<const DHT *>(obj)); },
[](const void *obj) { return dht_get_self_secret_key(static_cast<const DHT *>(obj)); },
};
class OnionClientFuzzer {
public:
OnionClientFuzzer(SimulatedEnvironment &env)
: env_(env)
, dht_(env, 33445)
, net_profile_(netprof_new(dht_.logger(), &dht_.node().c_memory),
[mem = &dht_.node().c_memory](Net_Profile *p) { netprof_kill(mem, p); })
, net_crypto_(nullptr, [](Net_Crypto *c) { kill_net_crypto(c); })
, onion_client_(nullptr, [](Onion_Client *c) { kill_onion_client(c); })
{
TCP_Proxy_Info proxy_info = {{0}, TCP_PROXY_NONE};
net_crypto_.reset(new_net_crypto(dht_.logger(), &dht_.node().c_memory,
&dht_.node().c_random, &dht_.node().c_network, dht_.mono_time(), dht_.networking(),
dht_.get_dht(), &FuzzDHT::funcs, &proxy_info, net_profile_.get()));
onion_client_.reset(
new_onion_client(dht_.logger(), &dht_.node().c_memory, &dht_.node().c_random,
dht_.mono_time(), net_crypto_.get(), dht_.get_dht(), dht_.networking()));
// Register a handler for onion data to verify reception
oniondata_registerhandler(
onion_client_.get(), 0,
[](void *, const uint8_t *, const uint8_t *, uint16_t, void *) {
// Callback hit
return 0;
},
nullptr);
}
void Run(Fuzz_Data &input)
{
while (!input.empty()) {
Action(input);
// Always pump the loop
do_onion_client(onion_client_.get());
networking_poll(dht_.networking(), nullptr);
}
}
private:
void Action(Fuzz_Data &input)
{
uint8_t op = input.consume_integral<uint8_t>();
switch (op % 12) {
case 0:
AddFriend(input);
break;
case 1:
DelFriend(input);
break;
case 2:
SetOnline(input);
break;
case 3:
SetDHTKey(input);
break;
case 4:
AddBSNode(input);
break;
case 5:
ReceivePacket(input);
break;
case 6:
AdvanceTime(input);
break;
case 7:
SendData(input);
break;
case 8:
GetFriendIP(input);
break;
case 9:
BackupNodes(input);
break;
case 10:
CheckStatus();
break;
case 11:
SetFriendTCPRelay(input);
break;
}
}
void AddFriend(Fuzz_Data &input)
{
uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&dht_.node().c_random, pk, sk);
int friend_num = onion_addfriend(onion_client_.get(), pk);
if (friend_num != -1) {
friends_.push_back(friend_num);
friend_keys_[friend_num] = {std::vector<uint8_t>(pk, pk + CRYPTO_PUBLIC_KEY_SIZE),
std::vector<uint8_t>(sk, sk + CRYPTO_SECRET_KEY_SIZE)};
}
}
void DelFriend(Fuzz_Data &input)
{
if (friends_.empty())
return;
size_t idx = consume_range<size_t>(input, 0, friends_.size() - 1);
int friend_num = friends_[idx];
onion_delfriend(onion_client_.get(), friend_num);
friends_.erase(friends_.begin() + idx);
friend_keys_.erase(friend_num);
}
void SetOnline(Fuzz_Data &input)
{
if (friends_.empty())
return;
int friend_num = friends_[consume_range<size_t>(input, 0, friends_.size() - 1)];
bool online = input.consume_integral<bool>();
onion_set_friend_online(onion_client_.get(), friend_num, online);
}
void SetDHTKey(Fuzz_Data &input)
{
if (friends_.empty())
return;
int friend_num = friends_[consume_range<size_t>(input, 0, friends_.size() - 1)];
CONSUME_OR_RETURN(const uint8_t *pk, input, CRYPTO_PUBLIC_KEY_SIZE);
onion_set_friend_dht_pubkey(onion_client_.get(), friend_num, pk);
}
void AddBSNode(Fuzz_Data &input)
{
IP_Port ip_port;
ip_init(&ip_port.ip, 1);
ip_port.port = input.consume_integral<uint16_t>();
CONSUME_OR_RETURN(const uint8_t *pk, input, CRYPTO_PUBLIC_KEY_SIZE);
onion_add_bs_path_node(onion_client_.get(), &ip_port, pk);
}
void ReceivePacket(Fuzz_Data &input)
{
if (input.remaining_bytes() < 1)
return;
std::vector<uint8_t> packet;
uint8_t type = input.consume_integral<uint8_t>();
if (type < 50) {
size_t size = consume_range<size_t>(input, 10, 500);
if (input.remaining_bytes() >= size) {
const uint8_t *ptr = input.consume("ReceivePacket", size);
if (ptr)
packet.assign(ptr, ptr + size);
}
} else if (type >= 50 && type < 150) {
// Generate valid NET_PACKET_ANNOUNCE_RESPONSE
uint8_t secret_key[CRYPTO_SYMMETRIC_KEY_SIZE];
onion_testonly_get_secret_symmetric_key(onion_client_.get(), secret_key);
uint8_t nonce[CRYPTO_NONCE_SIZE];
random_bytes(&dht_.node().c_random, nonce, sizeof(nonce));
size_t data_len = consume_range<size_t>(input, 1, 100);
std::vector<uint8_t> plaintext = input.consume_bytes(data_len);
if (plaintext.empty())
plaintext = {1, 2, 3}; // fallback
std::vector<uint8_t> ciphertext(plaintext.size() + CRYPTO_MAC_SIZE);
int len = encrypt_data_symmetric(&dht_.node().c_memory, secret_key, nonce,
plaintext.data(), plaintext.size(), ciphertext.data());
if (len != -1) {
packet.push_back(NET_PACKET_ANNOUNCE_RESPONSE);
packet.insert(packet.end(), nonce, nonce + CRYPTO_NONCE_SIZE);
packet.insert(packet.end(), ciphertext.begin(), ciphertext.end());
}
} else if (type >= 150 && !friends_.empty()) {
// Valid onion data response injection
int friend_num = friends_[consume_range<size_t>(input, 0, friends_.size() - 1)];
const auto &keys = friend_keys_[friend_num];
uint8_t sender_temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t sender_temp_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(&dht_.node().c_random, sender_temp_pk, sender_temp_sk);
uint8_t nonce[CRYPTO_NONCE_SIZE];
random_bytes(&dht_.node().c_random, nonce, sizeof(nonce));
// Inner packet - Let fuzzer choose type
uint8_t inner_type = input.consume_integral<uint8_t>();
std::vector<uint8_t> inner_data = {inner_type};
size_t data_len = consume_range<size_t>(input, 1, 100);
std::vector<uint8_t> rand_data = input.consume_bytes(data_len);
inner_data.insert(inner_data.end(), rand_data.begin(), rand_data.end());
std::vector<uint8_t> inner_ciphertext(inner_data.size() + CRYPTO_MAC_SIZE);
int len = encrypt_data(&dht_.node().c_memory, dht_get_self_public_key(dht_.get_dht()),
keys.second.data(), nonce, inner_data.data(), inner_data.size(),
inner_ciphertext.data());
if (len == -1)
return;
// Outer packet content: Sender Real PK + Inner Ciphertext
std::vector<uint8_t> outer_plaintext(CRYPTO_PUBLIC_KEY_SIZE + inner_ciphertext.size());
memcpy(outer_plaintext.data(), keys.first.data(), CRYPTO_PUBLIC_KEY_SIZE);
memcpy(outer_plaintext.data() + CRYPTO_PUBLIC_KEY_SIZE, inner_ciphertext.data(),
inner_ciphertext.size());
uint8_t receiver_temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
onion_testonly_get_temp_public_key(onion_client_.get(), receiver_temp_pk);
std::vector<uint8_t> outer_ciphertext(outer_plaintext.size() + CRYPTO_MAC_SIZE);
len = encrypt_data(&dht_.node().c_memory, receiver_temp_pk, sender_temp_sk, nonce,
outer_plaintext.data(), outer_plaintext.size(), outer_ciphertext.data());
if (len == -1)
return;
// Final packet: Type + Nonce + Sender Temp PK + Outer Ciphertext
packet.push_back(NET_PACKET_ONION_DATA_RESPONSE);
packet.insert(packet.end(), nonce, nonce + CRYPTO_NONCE_SIZE);
packet.insert(packet.end(), sender_temp_pk, sender_temp_pk + CRYPTO_PUBLIC_KEY_SIZE);
packet.insert(packet.end(), outer_ciphertext.begin(), outer_ciphertext.end());
} else {
packet = input.consume_remaining_bytes();
}
if (packet.empty())
return;
IP_Port from;
ip_init(&from.ip, 1); // loopback
from.port = 12345; // arbitrary
dht_.endpoint()->push_packet(packet, from);
}
void AdvanceTime(Fuzz_Data &input)
{
uint32_t ms = input.consume_integral_in_range<uint32_t>(1, 10000);
env_.fake_clock().advance(ms);
}
void SendData(Fuzz_Data &input)
{
if (friends_.empty())
return;
int friend_num = friends_[consume_range<size_t>(input, 0, friends_.size() - 1)];
uint16_t length = consume_range<uint16_t>(input, 1, 1024);
if (input.remaining_bytes() >= length) {
const uint8_t *ptr = input.consume("SendData", length);
if (ptr)
send_onion_data(onion_client_.get(), friend_num, ptr, length);
}
}
void GetFriendIP(Fuzz_Data &input)
{
if (friends_.empty())
return;
int friend_num = friends_[consume_range<size_t>(input, 0, friends_.size() - 1)];
IP_Port ip_port;
onion_getfriendip(onion_client_.get(), friend_num, &ip_port);
}
void BackupNodes(Fuzz_Data &input)
{
Node_format nodes[10];
onion_backup_nodes(onion_client_.get(), nodes, 10);
}
void CheckStatus() { onion_connection_status(onion_client_.get()); }
void SetFriendTCPRelay(Fuzz_Data &input)
{
if (friends_.empty())
return;
int friend_num = friends_[input.consume_integral_in_range<size_t>(0, friends_.size() - 1)];
// Just setting a dummy callback
recv_tcp_relay_handler(
onion_client_.get(), friend_num,
[](void *, uint32_t, const IP_Port *, const uint8_t *) { return 0; }, this, 0);
}
SimulatedEnvironment &env_;
FuzzDHT dht_;
std::unique_ptr<Net_Profile, std::function<void(Net_Profile *)>> net_profile_;
std::unique_ptr<Net_Crypto, void (*)(Net_Crypto *)> net_crypto_;
std::unique_ptr<Onion_Client, void (*)(Onion_Client *)> onion_client_;
std::vector<int> friends_;
std::map<int, std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> friend_keys_;
};
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
if (size == 0)
return 0;
SimulatedEnvironment env;
OnionClientFuzzer fuzzer(env);
Fuzz_Data input(data, size);
fuzzer.Run(input);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More