Squashed 'external/toxcore/c-toxcore/' changes from d9b8fa6098d..81b1e4f6348

81b1e4f6348 chore: Release v0.2.21-rc.1
9303e2e49a1 chore: Update the pkgsrc versions in the update-versions tool
71ec4b3b1e9 chore: Update the version-sync script to work in a post-tox.api.h world
66da842f753 chore: Add version update script compatible with ci-tools.
199878f7660 chore: Use new bazel script for circle ci.
8278e9cda46 chore: Add release issue template and workflow.
a9bb3a1c4d1 chore: Fix alpine-s390x build.
6e0a641272e chore: Add a source tarball deploy workflow.
4adebe4d8b1 chore: Don't upload ios/macos variants in deploy workflows.
18f1d858ccb chore: Move one of the 3 freebsd builds to post-submit.
432ab60c002 feat: Add a Makefile for the single file deploy build.
a86c0011fd5 chore: Add deploy job for single C file library.
2e7495e8f2a docs: Update changelog format to use the new clog-compatible way.
a682da99e84 chore: Export wasmExports from the wasm binary.
12f34cdff27 chore: Add wasm to the nightly binary deploys.
1451029613f chore: Add strict-abi support for macOS/iOS.
c53c30e09d9 chore: Add time option to manual fuzz trigger.
2ccecdc2a1a chore: Add remaining fuzz tests to cflite.
4626c2e230e test: Add a Net_Crypto fuzz test.
b4a0e617c48 refactor: Use IP string length from ip_ntoa instead of strlen.
b85b91f22f6 cleanup: rename getnodes/sendnodes to nodes request/response This change alignes the naming to be closer to the spec and make it less ambiguous. This change also changes the naming of some private/experimental marked APIs. - tox_callback_dht_nodes_response() - tox_dht_nodes_request() - Tox_Event_Dht_Get_Nodes_Response
f1991aaa029 perf: Use stack allocation for strerror rendering.
3984211ccbf cleanup: remove kicked peers from saved peers list
26a991ed2be fix: ip to string function not accepting tcp families
712861f2e6d cleanup: Make websockify output qtox-compatible logging.
01932ea2f73 chore: Add opus and vpx to the toxcore wasm build.
d29c42ef631 refactor: don't fully discard received DHT nodes. This is mostly forward thinking, where we might introduce other ip families, in addition to ipv4, ipv6, tcp_ipv4 etc.
21e2325934f chore: Fix xcframework tarball creation.
b10c8b766ba chore: Fix xcframework checksum creation.
93787a9322e chore: Add ios/macos framework build.
9f723f891d3 fix: run do_gca also in bootstrap nodes
496cc703556 chore: Support arm64 iphone simulator.
aa0e2a8e928 chore: Add support for more iOS architectures.
13ad8e81cbf chore: Add binary deploy workflows.
c8344726378 refactor: Move tox_log_level out into its own file.
8799bea76c3 cleanup: Mark events/dispatch headers as experimental.
d4164edb548 refactor: Remove tox_types.h; use `struct` tags instead.
d408c982090 refactor: Move `Tox_Options` to `tox_options.h`.
5ab42d41209 chore: Move most cirrus jobs to circleci.
463eeae1144 cleanup: Avoid clashing with global define `DEBUG`.
92cc1e91747 refactor: Make Tox_Options own the passed proxy host and savedata.
f276b397226 test: Add some more asserts for I/O and alloc to succeed.
edb4dfc4869 fix: Don't crash on malloc failures in bin_unpack.
be457d5d0b2 cleanup: Use tox memory for bin_unpack and net_strerror.

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 81b1e4f6348124784088591c4fe9ab41e273031d
This commit is contained in:
Green Sky
2025-03-12 19:16:50 +01:00
parent 3b6bb15e86
commit 3105cc20ef
130 changed files with 3604 additions and 1776 deletions

View File

@ -6,6 +6,8 @@ exports_files(
"tox.h",
"tox_dispatch.h",
"tox_events.h",
"tox_log_level.h",
"tox_options.h",
"tox_private.h",
],
visibility = ["//c-toxcore:__subpackages__"],
@ -192,6 +194,7 @@ cc_library(
deps = [
":attributes",
":ccompat",
":mem",
"//c-toxcore/third_party:cmp",
],
)
@ -204,6 +207,7 @@ cc_test(
":bin_pack",
":bin_unpack",
":logger",
":mem",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
@ -766,6 +770,23 @@ cc_library(
],
)
cc_fuzz_test(
name = "net_crypto_fuzz_test",
size = "small",
testonly = True,
srcs = ["net_crypto_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:net_crypto_fuzz_test"],
deps = [
":DHT",
":TCP_client",
":mem_test_util",
":net_crypto",
":network",
"//c-toxcore/testing/fuzzing:fuzz_support",
"//c-toxcore/testing/fuzzing:fuzz_tox",
],
)
cc_library(
name = "onion_announce",
srcs = ["onion_announce.c"],
@ -1070,6 +1091,25 @@ cc_library(
],
)
cc_library(
name = "tox_options",
srcs = ["tox_options.c"],
hdrs = ["tox_options.h"],
copts = ["-UTOX_HIDE_DEPRECATED"],
visibility = ["//c-toxcore:__subpackages__"],
deps = [
":ccompat",
":tox_log_level",
],
)
cc_library(
name = "tox_log_level",
srcs = ["tox_log_level.c"],
hdrs = ["tox_log_level.h"],
visibility = ["//c-toxcore:__subpackages__"],
)
cc_library(
name = "tox",
srcs = [
@ -1102,6 +1142,8 @@ cc_library(
":network",
":onion_client",
":state",
":tox_log_level",
":tox_options",
":util",
"//c-toxcore/toxencryptsave:defines",
"@pthread",
@ -1115,6 +1157,8 @@ cc_test(
deps = [
":crypto_core",
":tox",
":tox_log_level",
":tox_options",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],

View File

@ -30,8 +30,8 @@
/** The timeout after which a node is discarded completely. */
#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL)
/** Ping interval in seconds for each random sending of a get nodes request. */
#define GET_NODE_INTERVAL 20
/** Ping interval in seconds for each random sending of a nodes request. */
#define NODES_REQUEST_INTERVAL 20
#define MAX_PUNCHING_PORTS 48
@ -46,7 +46,7 @@
#define NAT_PING_REQUEST 0
#define NAT_PING_RESPONSE 1
/** Number of get node requests to send to quickly find close nodes. */
/** Number of node requests to send to quickly find close nodes. */
#define MAX_BOOTSTRAP_TIMES 5
// TODO(sudden6): find out why we need multiple callbacks and if we really need 32
@ -66,9 +66,9 @@ struct DHT_Friend {
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
Client_data client_list[MAX_FRIEND_CLIENTS];
/* Time at which the last get_nodes request was sent. */
uint64_t lastgetnode;
/* number of times get_node packets were sent. */
/* Time at which the last nodes request was sent. */
uint64_t last_nodes_request;
/* number of times nodes request packets were sent. */
uint32_t bootstrap_times;
/* Symmetric NAT hole punching stuff. */
@ -104,7 +104,7 @@ struct DHT {
bool lan_discovery_enabled;
Client_data close_clientlist[LCLIENT_LIST];
uint64_t close_lastgetnodes;
uint64_t close_last_nodes_request;
uint32_t close_bootstrap_times;
/* DHT keypair */
@ -130,7 +130,7 @@ struct DHT {
Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];
unsigned int num_to_bootstrap;
dht_get_nodes_response_cb *get_nodes_response;
dht_nodes_response_cb *nodes_response_callback;
};
const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend)
@ -431,7 +431,7 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed
const int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled);
if (ipp_size == -1) {
return -1;
break;
}
len_processed += ipp_size;
@ -450,6 +450,10 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed
#endif /* NDEBUG */
}
if (num == 0 && max_num_nodes > 0 && length > 0) {
return -1;
}
if (processed_data_len != nullptr) {
*processed_data_len = len_processed;
}
@ -708,7 +712,7 @@ static void get_close_nodes_inner(
}
/**
* Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request:
* Find MAX_SENT_NODES nodes closest to the public_key for the nodes request:
* put them in the nodes_list and return how many were found.
*
* want_announce: return only nodes which implement the dht announcements protocol.
@ -1131,7 +1135,7 @@ static bool is_pk_in_close_list(const DHT *dht, const uint8_t *public_key, const
ip_port);
}
/** @brief Check if the node obtained with a get_nodes with public_key should be pinged.
/** @brief Check if the node obtained from a nodes response with public_key should be pinged.
*
* NOTE: for best results call it after addto_lists.
*
@ -1139,7 +1143,7 @@ static bool is_pk_in_close_list(const DHT *dht, const uint8_t *public_key, const
* return true if it should.
*/
non_null()
static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
static bool ping_node_from_nodes_response_ok(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
{
bool ret = false;
@ -1310,7 +1314,7 @@ static void returnedip_ports(DHT *dht, const IP_Port *ip_port, const uint8_t *pu
}
}
bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id)
bool dht_send_nodes_request(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id)
{
/* Check if packet is going to be sent to ourself. */
if (pk_equal(public_key, dht->self_public_key)) {
@ -1345,21 +1349,21 @@ bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, c
const uint8_t *shared_key = dht_get_shared_key_sent(dht, public_key);
const int len = dht_create_packet(dht->mem, dht->rng,
dht->self_public_key, shared_key, NET_PACKET_GET_NODES,
dht->self_public_key, shared_key, NET_PACKET_NODES_REQUEST,
plain, sizeof(plain), data, sizeof(data));
if (len != sizeof(data)) {
LOGGER_ERROR(dht->log, "getnodes packet encryption failed");
LOGGER_ERROR(dht->log, "nodes request packet encryption failed");
return false;
}
return sendpacket(dht->net, ip_port, data, len) > 0;
}
/** Send a send nodes response: message for IPv6 nodes */
/** Send a nodes response */
non_null()
static int sendnodes_ipv6(const DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id,
const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key)
static int send_nodes_response(const DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id,
const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key)
{
/* Check if packet is going to be sent to ourself. */
if (pk_equal(public_key, dht->self_public_key)) {
@ -1396,7 +1400,7 @@ static int sendnodes_ipv6(const DHT *dht, const IP_Port *ip_port, const uint8_t
VLA(uint8_t, data, data_size);
const int len = dht_create_packet(dht->mem, dht->rng,
dht->self_public_key, shared_encryption_key, NET_PACKET_SEND_NODES_IPV6,
dht->self_public_key, shared_encryption_key, NET_PACKET_NODES_RESPONSE,
plain, 1 + nodes_length + length, data, data_size);
if (len < 0 || (uint32_t)len != data_size) {
@ -1409,7 +1413,7 @@ static int sendnodes_ipv6(const DHT *dht, const IP_Port *ip_port, const uint8_t
#define CRYPTO_NODE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t))
non_null()
static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata)
static int handle_nodes_request(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata)
{
DHT *const dht = (DHT *)object;
@ -1436,16 +1440,16 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p
return 1;
}
sendnodes_ipv6(dht, source, packet + 1, plain, plain + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint64_t), shared_key);
send_nodes_response(dht, source, packet + 1, plain, plain + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint64_t), shared_key);
ping_add(dht->ping, packet + 1, source);
return 0;
}
/** Return true if we sent a getnode packet to the peer associated with the supplied info. */
/** Return true if we sent a nodes request packet to the peer associated with the supplied info. */
non_null()
static bool sent_getnode_to_node(DHT *dht, const uint8_t *public_key, const IP_Port *node_ip_port, uint64_t ping_id)
static bool sent_nodes_request_to_node(DHT *dht, const uint8_t *public_key, const IP_Port *node_ip_port, uint64_t ping_id)
{
uint8_t data[sizeof(Node_format) * 2];
@ -1463,8 +1467,8 @@ static bool sent_getnode_to_node(DHT *dht, const uint8_t *public_key, const IP_P
}
non_null()
static bool handle_sendnodes_core(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out)
static bool handle_nodes_response_core(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out)
{
DHT *const dht = (DHT *)object;
const uint32_t cid_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1 + sizeof(uint64_t) + CRYPTO_MAC_SIZE;
@ -1505,7 +1509,7 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin
uint64_t ping_id;
memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id));
if (!sent_getnode_to_node(dht, packet + 1, source, ping_id)) {
if (!sent_nodes_request_to_node(dht, packet + 1, source, ping_id)) {
return false;
}
@ -1533,14 +1537,14 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin
}
non_null()
static int handle_sendnodes_ipv6(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
static int handle_nodes_response(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
void *userdata)
{
DHT *const dht = (DHT *)object;
Node_format plain_nodes[MAX_SENT_NODES];
uint32_t num_nodes;
if (!handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) {
if (!handle_nodes_response_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) {
return 1;
}
@ -1550,11 +1554,11 @@ static int handle_sendnodes_ipv6(void *object, const IP_Port *source, const uint
for (uint32_t i = 0; i < num_nodes; ++i) {
if (ipport_isset(&plain_nodes[i].ip_port)) {
ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, &plain_nodes[i].ip_port);
ping_node_from_nodes_response_ok(dht, plain_nodes[i].public_key, &plain_nodes[i].ip_port);
returnedip_ports(dht, &plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1);
if (dht->get_nodes_response != nullptr) {
dht->get_nodes_response(dht, &plain_nodes[i], userdata);
if (dht->nodes_response_callback != nullptr) {
dht->nodes_response_callback(dht, &plain_nodes[i], userdata);
}
}
}
@ -1767,7 +1771,7 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
if (mono_time_is_timeout(dht->mono_time, assoc->last_pinged, PING_INTERVAL)) {
const IP_Port *target = &assoc->ip_port;
const uint8_t *target_key = client->public_key;
dht_getnodes(dht, target, target_key, public_key);
dht_send_nodes_request(dht, target, target_key, public_key);
assoc->last_pinged = temp_time;
}
@ -1792,7 +1796,7 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
sort_client_list(dht->mem, list, dht->cur_time, list_count, public_key);
}
if (num_nodes > 0 && (mono_time_is_timeout(dht->mono_time, *lastgetnode, GET_NODE_INTERVAL)
if (num_nodes > 0 && (mono_time_is_timeout(dht->mono_time, *lastgetnode, NODES_REQUEST_INTERVAL)
|| *bootstrap_times < MAX_BOOTSTRAP_TIMES)) {
uint32_t rand_node = random_range_u32(dht->rng, num_nodes);
@ -1802,7 +1806,7 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
const IP_Port *target = &assoc_list[rand_node]->ip_port;
const uint8_t *target_key = client_list[rand_node]->public_key;
dht_getnodes(dht, target, target_key, public_key);
dht_send_nodes_request(dht, target, target_key, public_key);
*lastgetnode = temp_time;
++*bootstrap_times;
@ -1815,7 +1819,7 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
/** @brief Ping each client in the "friends" list every PING_INTERVAL seconds.
*
* Send a get nodes request every GET_NODE_INTERVAL seconds to a random good
* Send a nodes request every NODES_REQUEST_INTERVAL seconds to a random good
* node for each "friend" in our "friends" list.
*/
non_null()
@ -1825,31 +1829,31 @@ static void do_dht_friends(DHT *dht)
DHT_Friend *const dht_friend = &dht->friends_list[i];
for (size_t j = 0; j < dht_friend->num_to_bootstrap; ++j) {
dht_getnodes(dht, &dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key);
dht_send_nodes_request(dht, &dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key);
}
dht_friend->num_to_bootstrap = 0;
do_ping_and_sendnode_requests(dht, &dht_friend->lastgetnode, dht_friend->public_key, dht_friend->client_list,
do_ping_and_sendnode_requests(dht, &dht_friend->last_nodes_request, dht_friend->public_key, dht_friend->client_list,
MAX_FRIEND_CLIENTS, &dht_friend->bootstrap_times, true);
}
}
/** @brief Ping each client in the close nodes list every PING_INTERVAL seconds.
*
* Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list.
* Send a nodes request every NODES_REQUEST_INTERVAL seconds to a random good node in the list.
*/
non_null()
static void do_close(DHT *dht)
{
for (size_t i = 0; i < dht->num_to_bootstrap; ++i) {
dht_getnodes(dht, &dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key);
dht_send_nodes_request(dht, &dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key);
}
dht->num_to_bootstrap = 0;
const uint8_t not_killed = do_ping_and_sendnode_requests(
dht, &dht->close_lastgetnodes, dht->self_public_key, dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times,
dht, &dht->close_last_nodes_request, dht->self_public_key, dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times,
false);
if (not_killed != 0) {
@ -1883,7 +1887,7 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key)
return true;
}
return dht_getnodes(dht, ip_port, public_key, dht->self_public_key);
return dht_send_nodes_request(dht, ip_port, public_key, dht->self_public_key);
}
bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled,
@ -2530,9 +2534,9 @@ static int cryptopacket_handle(void *object, const IP_Port *source, const uint8_
return 1;
}
void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function)
void dht_callback_nodes_response(DHT *dht, dht_nodes_response_cb *function)
{
dht->get_nodes_response = function;
dht->nodes_response_callback = function;
}
non_null(1, 2, 3) nullable(5)
@ -2593,8 +2597,8 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
return nullptr;
}
networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht);
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);
networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, &handle_lan_discovery, dht);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_nat_ping, dht);
@ -2672,8 +2676,8 @@ void kill_dht(DHT *dht)
return;
}
networking_registerhandler(dht->net, NET_PACKET_GET_NODES, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_NODES_REQUEST, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_NODES_RESPONSE, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_CRYPTO, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, nullptr, nullptr);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, nullptr, nullptr);

View File

@ -36,7 +36,7 @@ extern "C" {
#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8
/** The max number of nodes to send with send nodes. */
/** The max number of nodes to send with nodes response. */
#define MAX_SENT_NODES 4
/** Ping timeout in seconds */
@ -259,21 +259,21 @@ non_null()
const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key);
/**
* Sends a getnodes request to `ip_port` with the public key `public_key` for nodes
* Sends a nodes request to `ip_port` with the public key `public_key` for nodes
* that are close to `client_id`.
*
* @retval true on success.
*/
non_null()
bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id);
bool dht_send_nodes_request(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id);
typedef void dht_ip_cb(void *object, int32_t number, const IP_Port *ip_port);
typedef void dht_get_nodes_response_cb(const DHT *dht, const Node_format *node, void *user_data);
typedef void dht_nodes_response_cb(const DHT *dht, const Node_format *node, void *user_data);
/** Sets the callback to be triggered on a getnodes response. */
/** Sets the callback to be triggered on a nodes response. */
non_null(1) nullable(2)
void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function);
void dht_callback_nodes_response(DHT *dht, dht_nodes_response_cb *function);
/** @brief Add a new friend to the friends list.
* @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
@ -390,7 +390,7 @@ void do_dht(DHT *dht);
* Use these two functions to bootstrap the client.
*/
/**
* @brief Sends a "get nodes" request to the given node with ip, port and public_key
* @brief Sends a "nodes request" to the given node with ip, port and public_key
* to setup connections
*/
non_null()
@ -398,7 +398,7 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key);
/** @brief Resolves address into an IP address.
*
* If successful, sends a "get nodes" request to the given node with ip, port
* If successful, sends a "nodes request" to the given node with ip, port
* and public_key to setup connections
*
* @param address can be a hostname or an IP address (IPv4 or IPv6).

View File

@ -1,26 +1,20 @@
lib_LTLIBRARIES += libtoxcore.la
libtoxcore_la_include_HEADERS = \
../toxcore/tox.h
../toxcore/tox.h \
../toxcore/tox_options.h
libtoxcore_la_includedir = $(includedir)/tox
libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
../third_party/cmp/cmp.h \
../toxcore/attributes.h \
../toxcore/bin_pack.c \
../toxcore/bin_pack.h \
../toxcore/bin_unpack.c \
../toxcore/bin_unpack.h \
../toxcore/ccompat.c \
../toxcore/ccompat.h \
../toxcore/events/conference_connected.c \
../toxcore/events/conference_invite.c \
../toxcore/events/conference_message.c \
../toxcore/events/conference_peer_list_changed.c \
../toxcore/events/conference_peer_name.c \
../toxcore/events/conference_title.c \
../toxcore/events/dht_get_nodes_response.c \
../toxcore/events/dht_nodes_response.c \
../toxcore/events/events_alloc.c \
../toxcore/events/events_alloc.h \
../toxcore/events/file_chunk_request.c \
@ -56,97 +50,108 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
../toxcore/events/group_topic.c \
../toxcore/events/group_topic_lock.c \
../toxcore/events/group_voice_state.c \
../toxcore/DHT.h \
../toxcore/DHT.c \
../toxcore/mem.h \
../toxcore/mem.c \
../toxcore/mono_time.h \
../toxcore/mono_time.c \
../toxcore/network.h \
../toxcore/network.c \
../toxcore/crypto_core.h \
../toxcore/crypto_core.c \
../toxcore/crypto_core_pack.h \
../toxcore/announce.c \
../toxcore/announce.h \
../toxcore/attributes.h \
../toxcore/bin_pack.c \
../toxcore/bin_pack.h \
../toxcore/bin_unpack.c \
../toxcore/bin_unpack.h \
../toxcore/ccompat.c \
../toxcore/ccompat.h \
../toxcore/crypto_core_pack.c \
../toxcore/timed_auth.h \
../toxcore/timed_auth.c \
../toxcore/ping_array.h \
../toxcore/ping_array.c \
../toxcore/net_crypto.h \
../toxcore/net_crypto.c \
../toxcore/net_profile.c \
../toxcore/net_profile.h \
../toxcore/friend_requests.h \
../toxcore/friend_requests.c \
../toxcore/LAN_discovery.h \
../toxcore/LAN_discovery.c \
../toxcore/friend_connection.h \
../toxcore/crypto_core_pack.h \
../toxcore/crypto_core.c \
../toxcore/crypto_core.h \
../toxcore/DHT.c \
../toxcore/DHT.h \
../toxcore/forwarding.c \
../toxcore/forwarding.h \
../toxcore/friend_connection.c \
../toxcore/Messenger.h \
../toxcore/Messenger.c \
../toxcore/ping.h \
../toxcore/ping.c \
../toxcore/shared_key_cache.h \
../toxcore/shared_key_cache.c \
../toxcore/sort.h \
../toxcore/sort.c \
../toxcore/state.h \
../toxcore/state.c \
../toxcore/tox.h \
../toxcore/tox.c \
../toxcore/tox_dispatch.h \
../toxcore/tox_dispatch.c \
../toxcore/tox_event.h \
../toxcore/tox_event.c \
../toxcore/tox_events.h \
../toxcore/tox_events.c \
../toxcore/tox_pack.h \
../toxcore/tox_pack.c \
../toxcore/tox_unpack.h \
../toxcore/tox_unpack.c \
../toxcore/tox_private.c \
../toxcore/tox_private.h \
../toxcore/tox_struct.h \
../toxcore/tox_api.c \
../toxcore/util.h \
../toxcore/util.c \
../toxcore/group.h \
../toxcore/group.c \
../toxcore/group_announce.h \
../toxcore/friend_connection.h \
../toxcore/friend_requests.c \
../toxcore/friend_requests.h \
../toxcore/group_announce.c \
../toxcore/group_onion_announce.c \
../toxcore/group_onion_announce.h \
../toxcore/group_chats.h \
../toxcore/group_announce.h \
../toxcore/group_chats.c \
../toxcore/group_chats.h \
../toxcore/group_common.h \
../toxcore/group_connection.c \
../toxcore/group_connection.h \
../toxcore/group_pack.c \
../toxcore/group_pack.h \
../toxcore/group_moderation.c \
../toxcore/group_moderation.h \
../toxcore/onion.h \
../toxcore/onion.c \
../toxcore/logger.h \
../toxcore/logger.c \
../toxcore/onion_announce.h \
../toxcore/onion_announce.c \
../toxcore/onion_client.h \
../toxcore/onion_client.c \
../toxcore/announce.h \
../toxcore/announce.c \
../toxcore/forwarding.h \
../toxcore/forwarding.c \
../toxcore/TCP_client.h \
../toxcore/TCP_client.c \
../toxcore/TCP_common.h \
../toxcore/TCP_common.c \
../toxcore/TCP_server.h \
../toxcore/TCP_server.c \
../toxcore/TCP_connection.h \
../toxcore/TCP_connection.c \
../toxcore/group_onion_announce.c \
../toxcore/group_onion_announce.h \
../toxcore/group_pack.c \
../toxcore/group_pack.h \
../toxcore/group.c \
../toxcore/group.h \
../toxcore/LAN_discovery.c \
../toxcore/LAN_discovery.h \
../toxcore/list.c \
../toxcore/list.h
../toxcore/list.h \
../toxcore/logger.c \
../toxcore/logger.h \
../toxcore/mem.c \
../toxcore/mem.h \
../toxcore/Messenger.c \
../toxcore/Messenger.h \
../toxcore/mono_time.c \
../toxcore/mono_time.h \
../toxcore/net_crypto.c \
../toxcore/net_crypto.h \
../toxcore/net_profile.c \
../toxcore/net_profile.h \
../toxcore/network.c \
../toxcore/network.h \
../toxcore/onion_announce.c \
../toxcore/onion_announce.h \
../toxcore/onion_client.c \
../toxcore/onion_client.h \
../toxcore/onion.c \
../toxcore/onion.h \
../toxcore/ping_array.c \
../toxcore/ping_array.h \
../toxcore/ping.c \
../toxcore/ping.h \
../toxcore/shared_key_cache.c \
../toxcore/shared_key_cache.h \
../toxcore/sort.c \
../toxcore/sort.h \
../toxcore/state.c \
../toxcore/state.h \
../toxcore/TCP_client.c \
../toxcore/TCP_client.h \
../toxcore/TCP_common.c \
../toxcore/TCP_common.h \
../toxcore/TCP_connection.c \
../toxcore/TCP_connection.h \
../toxcore/TCP_server.c \
../toxcore/TCP_server.h \
../toxcore/timed_auth.c \
../toxcore/timed_auth.h \
../toxcore/tox_api.c \
../toxcore/tox_dispatch.c \
../toxcore/tox_dispatch.h \
../toxcore/tox_event.c \
../toxcore/tox_event.h \
../toxcore/tox_events.c \
../toxcore/tox_events.h \
../toxcore/tox_log_level.c \
../toxcore/tox_log_level.h \
../toxcore/tox_options.c \
../toxcore/tox_options.h \
../toxcore/tox_pack.c \
../toxcore/tox_pack.h \
../toxcore/tox_private.c \
../toxcore/tox_private.h \
../toxcore/tox_struct.h \
../toxcore/tox_unpack.c \
../toxcore/tox_unpack.h \
../toxcore/tox.c \
../toxcore/tox.h \
../toxcore/util.c \
../toxcore/util.h
libtoxcore_la_CFLAGS = -I$(top_srcdir) \
-I$(top_srcdir)/toxcore \

View File

@ -3171,7 +3171,7 @@ static bool handle_groups_load(void *obj, Bin_Unpack *bu)
non_null()
static State_Load_Status groups_load(Messenger *m, const uint8_t *data, uint32_t length)
{
if (!bin_unpack_obj(handle_groups_load, m, data, length)) {
if (!bin_unpack_obj(m->mem, handle_groups_load, m, data, length)) {
LOGGER_ERROR(m->log, "msgpack failed to unpack groupchats array");
return STATE_LOAD_STATUS_ERROR;
}

View File

@ -236,7 +236,7 @@ int read_tcp_packet(
* return -1 on failure.
*/
non_null()
static uint16_t read_tcp_length(const Logger *logger, const Memory *mem, const Network *ns, Socket sock, const IP_Port *ip_port)
static uint16_t read_tcp_length(const Logger *logger, const Network *ns, Socket sock, const IP_Port *ip_port)
{
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
@ -275,7 +275,7 @@ int read_packet_tcp_secure_connection(
uint16_t max_len, const IP_Port *ip_port)
{
if (*next_packet_length == 0) {
const uint16_t len = read_tcp_length(logger, mem, ns, sock, ip_port);
const uint16_t len = read_tcp_length(logger, ns, sock, ip_port);
if (len == (uint16_t) -1) {
return -1;

View File

@ -920,7 +920,7 @@ static int accept_connection(TCP_Server *tcp_server, Socket sock)
}
non_null()
static Socket new_listening_tcp_socket(const Logger *logger, const Network *ns, Family family, uint16_t port)
static Socket new_listening_tcp_socket(const Logger *logger, const Memory *mem, const Network *ns, Family family, uint16_t port)
{
const Socket sock = net_socket(ns, family, TOX_SOCK_STREAM, TOX_PROTO_TCP);
@ -942,10 +942,9 @@ static Socket new_listening_tcp_socket(const Logger *logger, const Network *ns,
ok = ok && bind_to_port(ns, sock, family, port) && (net_listen(ns, sock, TCP_MAX_BACKLOG) == 0);
if (!ok) {
char *const error = net_new_strerror(net_error());
Net_Strerror error_str;
LOGGER_WARNING(logger, "could not bind to TCP port %d (family = %d): %s",
port, family.value, error != nullptr ? error : "(null)");
net_kill_strerror(error);
port, family.value, net_strerror(net_error(), &error_str));
kill_sock(ns, sock);
return net_invalid_socket();
}
@ -1015,7 +1014,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random
const Family family = ipv6_enabled ? net_family_ipv6() : net_family_ipv4();
for (uint32_t i = 0; i < num_sockets; ++i) {
const Socket sock = new_listening_tcp_socket(logger, ns, family, ports[i]);
const Socket sock = new_listening_tcp_socket(logger, mem, ns, family, ports[i]);
if (!sock_valid(sock)) {
continue;

View File

@ -3,11 +3,10 @@
#include <gtest/gtest.h>
#include <array>
#include <memory>
#include <vector>
#include "bin_unpack.h"
#include "logger.h"
#include "mem.h"
namespace {
@ -24,6 +23,7 @@ TEST(BinPack, TooSmallBufferIsNotExceeded)
TEST(BinPack, PackedUint64CanBeUnpacked)
{
const Memory *mem = os_memory();
const uint64_t orig = 1234567812345678LL;
std::array<uint8_t, 8> buf;
EXPECT_TRUE(bin_pack_obj(
@ -34,6 +34,7 @@ TEST(BinPack, PackedUint64CanBeUnpacked)
uint64_t unpacked = 0;
EXPECT_TRUE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) {
return bin_unpack_u64_b(bu, static_cast<uint64_t *>(obj));
},
@ -43,6 +44,7 @@ TEST(BinPack, PackedUint64CanBeUnpacked)
TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
{
const Memory *mem = os_memory();
const uint8_t orig = 123;
std::array<uint8_t, 2> buf;
EXPECT_TRUE(bin_pack_obj(
@ -53,6 +55,7 @@ TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
uint32_t unpacked = 0;
EXPECT_TRUE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) { return bin_unpack_u32(bu, static_cast<uint32_t *>(obj)); },
&unpacked, buf.data(), buf.size()));
EXPECT_EQ(unpacked, 123);
@ -60,6 +63,7 @@ TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
{
const Memory *mem = os_memory();
const uint32_t orig = 123;
std::array<uint8_t, 2> buf;
EXPECT_TRUE(bin_pack_obj(
@ -70,6 +74,7 @@ TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
uint8_t unpacked = 0;
EXPECT_TRUE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) { return bin_unpack_u08(bu, static_cast<uint8_t *>(obj)); },
&unpacked, buf.data(), buf.size()));
@ -78,6 +83,7 @@ TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8)
{
const Memory *mem = os_memory();
const uint32_t orig = 1234567;
std::array<uint8_t, 5> buf;
EXPECT_TRUE(bin_pack_obj(
@ -88,12 +94,14 @@ TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8)
uint8_t unpacked = 0;
EXPECT_FALSE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) { return bin_unpack_u08(bu, static_cast<uint8_t *>(obj)); },
&unpacked, buf.data(), buf.size()));
}
TEST(BinPack, BinCanHoldPackedInts)
{
const Memory *mem = os_memory();
struct Stuff {
uint64_t u64;
uint16_t u16;
@ -113,6 +121,7 @@ TEST(BinPack, BinCanHoldPackedInts)
Stuff unpacked;
EXPECT_TRUE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) {
Stuff *stuff = static_cast<Stuff *>(obj);
uint32_t size;
@ -128,6 +137,7 @@ TEST(BinPack, BinCanHoldPackedInts)
TEST(BinPack, BinCanHoldArbitraryData)
{
const Memory *mem = os_memory();
std::array<uint8_t, 7> buf;
EXPECT_TRUE(bin_pack_obj(
[](const void *obj, const Logger *logger, Bin_Pack *bp) {
@ -138,6 +148,7 @@ TEST(BinPack, BinCanHoldArbitraryData)
std::array<uint8_t, 5> str;
EXPECT_TRUE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) {
uint8_t *data = static_cast<uint8_t *>(obj);
return bin_unpack_bin_fixed(bu, data, 5);
@ -148,10 +159,12 @@ TEST(BinPack, BinCanHoldArbitraryData)
TEST(BinPack, OversizedArrayFailsUnpack)
{
const Memory *mem = os_memory();
std::array<uint8_t, 1> buf = {0x91};
uint32_t size;
EXPECT_FALSE(bin_unpack_obj(
mem,
[](void *obj, Bin_Unpack *bu) {
uint32_t *size_ptr = static_cast<uint32_t *>(obj);
return bin_unpack_array(bu, size_ptr);

View File

@ -5,14 +5,16 @@
#include "bin_unpack.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../third_party/cmp/cmp.h"
#include "attributes.h"
#include "ccompat.h"
#include "mem.h"
struct Bin_Unpack {
const Memory *mem;
const uint8_t *bytes;
uint32_t bytes_size;
cmp_ctx_t ctx;
@ -54,17 +56,18 @@ static size_t null_writer(cmp_ctx_t *ctx, const void *data, size_t count)
}
non_null()
static void bin_unpack_init(Bin_Unpack *bu, const uint8_t *buf, uint32_t buf_size)
static void bin_unpack_init(Bin_Unpack *bu, const Memory *mem, const uint8_t *buf, uint32_t buf_size)
{
bu->mem = mem;
bu->bytes = buf;
bu->bytes_size = buf_size;
cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer);
}
bool bin_unpack_obj(bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size)
bool bin_unpack_obj(const Memory *mem, bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size)
{
Bin_Unpack bu;
bin_unpack_init(&bu, buf, buf_size);
bin_unpack_init(&bu, mem, buf, buf_size);
return callback(obj, &bu);
}
@ -120,10 +123,14 @@ bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_pt
// There aren't as many bytes as this bin claims to want to allocate.
return false;
}
uint8_t *const data = (uint8_t *)malloc(bin_size);
uint8_t *const data = (uint8_t *)mem_balloc(bu->mem, bin_size);
if (data == nullptr) {
return false;
}
if (!bin_unpack_bin_b(bu, data, bin_size)) {
free(data);
mem_delete(bu->mem, data);
return false;
}

View File

@ -9,6 +9,7 @@
#include <stdint.h>
#include "attributes.h"
#include "mem.h"
#ifdef __cplusplus
extern "C" {
@ -46,7 +47,7 @@ typedef bool bin_unpack_cb(void *obj, Bin_Unpack *bu);
* @retval false if an error occurred (e.g. buffer overrun).
*/
non_null()
bool bin_unpack_obj(bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size);
bool bin_unpack_obj(const Memory *mem, bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size);
/** @brief Start unpacking a MessagePack array.
*

View File

@ -1,227 +0,0 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2022-2025 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <string.h>
#include "../attributes.h"
#include "../bin_pack.h"
#include "../bin_unpack.h"
#include "../ccompat.h"
#include "../mem.h"
#include "../tox.h"
#include "../tox_event.h"
#include "../tox_events.h"
#include "../tox_private.h"
/*****************************************************
*
* :: struct and accessors
*
*****************************************************/
struct Tox_Event_Dht_Get_Nodes_Response {
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
uint8_t *ip;
uint32_t ip_length;
uint16_t port;
};
non_null()
static bool tox_event_dht_get_nodes_response_set_public_key(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE])
{
memcpy(dht_get_nodes_response->public_key, public_key, TOX_PUBLIC_KEY_SIZE);
return true;
}
const uint8_t *tox_event_dht_get_nodes_response_get_public_key(const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response)
{
return dht_get_nodes_response->public_key;
}
non_null()
static bool tox_event_dht_get_nodes_response_set_ip(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response,
const char *ip, uint32_t ip_length, const Memory *mem)
{
if (dht_get_nodes_response->ip != nullptr) {
mem_delete(mem, dht_get_nodes_response->ip);
dht_get_nodes_response->ip = nullptr;
dht_get_nodes_response->ip_length = 0;
}
uint8_t *ip_tmp = (uint8_t *)mem_balloc(mem, ip_length);
if (ip_tmp == nullptr) {
return false;
}
memcpy(ip_tmp, ip, ip_length);
dht_get_nodes_response->ip = ip_tmp;
dht_get_nodes_response->ip_length = ip_length;
return true;
}
uint32_t tox_event_dht_get_nodes_response_get_ip_length(const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response)
{
return dht_get_nodes_response->ip_length;
}
const uint8_t *tox_event_dht_get_nodes_response_get_ip(const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response)
{
return dht_get_nodes_response->ip;
}
non_null()
static bool tox_event_dht_get_nodes_response_set_port(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response, uint16_t port)
{
dht_get_nodes_response->port = port;
return true;
}
uint16_t tox_event_dht_get_nodes_response_get_port(const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response)
{
return dht_get_nodes_response->port;
}
non_null()
static void tox_event_dht_get_nodes_response_construct(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response)
{
*dht_get_nodes_response = (Tox_Event_Dht_Get_Nodes_Response) {
{
0
}
};
}
non_null()
static void tox_event_dht_get_nodes_response_destruct(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response, const Memory *mem)
{
mem_delete(mem, dht_get_nodes_response->ip);
}
bool tox_event_dht_get_nodes_response_pack(
const Tox_Event_Dht_Get_Nodes_Response *event, Bin_Pack *bp)
{
return bin_pack_array(bp, 3)
&& bin_pack_bin(bp, event->public_key, TOX_PUBLIC_KEY_SIZE)
&& bin_pack_bin(bp, event->ip, event->ip_length)
&& bin_pack_u16(bp, event->port);
}
non_null()
static bool tox_event_dht_get_nodes_response_unpack_into(
Tox_Event_Dht_Get_Nodes_Response *event, Bin_Unpack *bu)
{
if (!bin_unpack_array_fixed(bu, 3, nullptr)) {
return false;
}
return bin_unpack_bin_fixed(bu, event->public_key, TOX_PUBLIC_KEY_SIZE)
&& bin_unpack_bin(bu, &event->ip, &event->ip_length)
&& bin_unpack_u16(bu, &event->port);
}
const Tox_Event_Dht_Get_Nodes_Response *tox_event_get_dht_get_nodes_response(
const Tox_Event *event)
{
return event->type == TOX_EVENT_DHT_GET_NODES_RESPONSE ? event->data.dht_get_nodes_response : nullptr;
}
Tox_Event_Dht_Get_Nodes_Response *tox_event_dht_get_nodes_response_new(const Memory *mem)
{
Tox_Event_Dht_Get_Nodes_Response *const dht_get_nodes_response =
(Tox_Event_Dht_Get_Nodes_Response *)mem_alloc(mem, sizeof(Tox_Event_Dht_Get_Nodes_Response));
if (dht_get_nodes_response == nullptr) {
return nullptr;
}
tox_event_dht_get_nodes_response_construct(dht_get_nodes_response);
return dht_get_nodes_response;
}
void tox_event_dht_get_nodes_response_free(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response, const Memory *mem)
{
if (dht_get_nodes_response != nullptr) {
tox_event_dht_get_nodes_response_destruct(dht_get_nodes_response, mem);
}
mem_delete(mem, dht_get_nodes_response);
}
non_null()
static Tox_Event_Dht_Get_Nodes_Response *tox_events_add_dht_get_nodes_response(Tox_Events *events, const Memory *mem)
{
Tox_Event_Dht_Get_Nodes_Response *const dht_get_nodes_response = tox_event_dht_get_nodes_response_new(mem);
if (dht_get_nodes_response == nullptr) {
return nullptr;
}
Tox_Event event;
event.type = TOX_EVENT_DHT_GET_NODES_RESPONSE;
event.data.dht_get_nodes_response = dht_get_nodes_response;
if (!tox_events_add(events, &event)) {
tox_event_dht_get_nodes_response_free(dht_get_nodes_response, mem);
return nullptr;
}
return dht_get_nodes_response;
}
bool tox_event_dht_get_nodes_response_unpack(
Tox_Event_Dht_Get_Nodes_Response **event, Bin_Unpack *bu, const Memory *mem)
{
*event = tox_event_dht_get_nodes_response_new(mem);
if (*event == nullptr) {
return false;
}
return tox_event_dht_get_nodes_response_unpack_into(*event, bu);
}
non_null()
static Tox_Event_Dht_Get_Nodes_Response *tox_event_dht_get_nodes_response_alloc(void *user_data)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response = tox_events_add_dht_get_nodes_response(state->events, state->mem);
if (dht_get_nodes_response == nullptr) {
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
return nullptr;
}
return dht_get_nodes_response;
}
/*****************************************************
*
* :: event handler
*
*****************************************************/
void tox_events_handle_dht_get_nodes_response(
Tox *tox, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
const char *ip, uint16_t port, void *user_data)
{
Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response = tox_event_dht_get_nodes_response_alloc(user_data);
if (dht_get_nodes_response == nullptr) {
return;
}
const size_t ip_length = strlen(ip);
if (ip_length >= UINT32_MAX) {
return;
}
const Tox_System *sys = tox_get_system(tox);
tox_event_dht_get_nodes_response_set_public_key(dht_get_nodes_response, public_key);
tox_event_dht_get_nodes_response_set_ip(dht_get_nodes_response, ip, ip_length + 1, sys->mem);
tox_event_dht_get_nodes_response_set_port(dht_get_nodes_response, port);
}

View File

@ -0,0 +1,222 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2022-2025 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>
#include <string.h>
#include "../attributes.h"
#include "../bin_pack.h"
#include "../bin_unpack.h"
#include "../ccompat.h"
#include "../mem.h"
#include "../tox.h"
#include "../tox_event.h"
#include "../tox_events.h"
#include "../tox_private.h"
/*****************************************************
*
* :: struct and accessors
*
*****************************************************/
struct Tox_Event_Dht_Nodes_Response {
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
uint8_t *ip;
uint32_t ip_length;
uint16_t port;
};
non_null()
static bool tox_event_dht_nodes_response_set_public_key(Tox_Event_Dht_Nodes_Response *dht_nodes_response, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE])
{
memcpy(dht_nodes_response->public_key, public_key, TOX_PUBLIC_KEY_SIZE);
return true;
}
const uint8_t *tox_event_dht_nodes_response_get_public_key(const Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
return dht_nodes_response->public_key;
}
non_null()
static bool tox_event_dht_nodes_response_set_ip(Tox_Event_Dht_Nodes_Response *dht_nodes_response,
const char *ip, uint32_t ip_length, const Memory *mem)
{
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_tmp == nullptr) {
return false;
}
memcpy(ip_tmp, ip, ip_length + 1);
dht_nodes_response->ip = ip_tmp;
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)
{
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)
{
return dht_nodes_response->ip;
}
non_null()
static bool tox_event_dht_nodes_response_set_port(Tox_Event_Dht_Nodes_Response *dht_nodes_response, uint16_t port)
{
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)
{
return dht_nodes_response->port;
}
non_null()
static void tox_event_dht_nodes_response_construct(Tox_Event_Dht_Nodes_Response *dht_nodes_response)
{
*dht_nodes_response = (Tox_Event_Dht_Nodes_Response) {
{
0
}
};
}
non_null()
static void tox_event_dht_nodes_response_destruct(Tox_Event_Dht_Nodes_Response *dht_nodes_response, const Memory *mem)
{
mem_delete(mem, dht_nodes_response->ip);
}
bool tox_event_dht_nodes_response_pack(
const Tox_Event_Dht_Nodes_Response *event, Bin_Pack *bp)
{
return bin_pack_array(bp, 3)
&& bin_pack_bin(bp, event->public_key, TOX_PUBLIC_KEY_SIZE)
&& bin_pack_bin(bp, event->ip, event->ip_length)
&& bin_pack_u16(bp, event->port);
}
non_null()
static bool tox_event_dht_nodes_response_unpack_into(
Tox_Event_Dht_Nodes_Response *event, Bin_Unpack *bu)
{
if (!bin_unpack_array_fixed(bu, 3, nullptr)) {
return false;
}
return bin_unpack_bin_fixed(bu, event->public_key, TOX_PUBLIC_KEY_SIZE)
&& bin_unpack_bin(bu, &event->ip, &event->ip_length)
&& bin_unpack_u16(bu, &event->port);
}
const Tox_Event_Dht_Nodes_Response *tox_event_get_dht_nodes_response(
const Tox_Event *event)
{
return event->type == TOX_EVENT_DHT_GET_NODES_RESPONSE ? event->data.dht_nodes_response : nullptr;
}
Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_new(const Memory *mem)
{
Tox_Event_Dht_Nodes_Response *const dht_nodes_response =
(Tox_Event_Dht_Nodes_Response *)mem_alloc(mem, sizeof(Tox_Event_Dht_Nodes_Response));
if (dht_nodes_response == nullptr) {
return nullptr;
}
tox_event_dht_nodes_response_construct(dht_nodes_response);
return dht_nodes_response;
}
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);
}
mem_delete(mem, dht_nodes_response);
}
non_null()
static Tox_Event_Dht_Nodes_Response *tox_events_add_dht_nodes_response(Tox_Events *events, const Memory *mem)
{
Tox_Event_Dht_Nodes_Response *const dht_nodes_response = tox_event_dht_nodes_response_new(mem);
if (dht_nodes_response == nullptr) {
return nullptr;
}
Tox_Event event;
event.type = TOX_EVENT_DHT_GET_NODES_RESPONSE;
event.data.dht_nodes_response = dht_nodes_response;
if (!tox_events_add(events, &event)) {
tox_event_dht_nodes_response_free(dht_nodes_response, mem);
return nullptr;
}
return dht_nodes_response;
}
bool tox_event_dht_nodes_response_unpack(
Tox_Event_Dht_Nodes_Response **event, Bin_Unpack *bu, const Memory *mem)
{
*event = tox_event_dht_nodes_response_new(mem);
if (*event == nullptr) {
return false;
}
return tox_event_dht_nodes_response_unpack_into(*event, bu);
}
non_null()
static Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_alloc(void *user_data)
{
Tox_Events_State *state = tox_events_alloc(user_data);
assert(state != nullptr);
if (state->events == nullptr) {
return nullptr;
}
Tox_Event_Dht_Nodes_Response *dht_nodes_response = tox_events_add_dht_nodes_response(state->events, state->mem);
if (dht_nodes_response == nullptr) {
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
return nullptr;
}
return dht_nodes_response;
}
/*****************************************************
*
* :: event handler
*
*****************************************************/
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_Event_Dht_Nodes_Response *dht_nodes_response = tox_event_dht_nodes_response_alloc(user_data);
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_port(dht_nodes_response, port);
}

View File

@ -35,7 +35,7 @@ tox_conference_message_cb tox_events_handle_conference_message;
tox_conference_peer_list_changed_cb tox_events_handle_conference_peer_list_changed;
tox_conference_peer_name_cb tox_events_handle_conference_peer_name;
tox_conference_title_cb tox_events_handle_conference_title;
tox_dht_get_nodes_response_cb tox_events_handle_dht_get_nodes_response;
tox_dht_nodes_response_cb tox_events_handle_dht_nodes_response;
tox_file_chunk_request_cb tox_events_handle_file_chunk_request;
tox_file_recv_cb tox_events_handle_file_recv;
tox_file_recv_chunk_cb tox_events_handle_file_recv_chunk;

View File

@ -13,11 +13,11 @@ namespace {
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);
IP_Port ipp;
IP_Port ipp{};
unpack_ip_port(&ipp, ipp_packed, SIZE_IP6, true);
CONSUME_OR_RETURN_VAL(const uint8_t *forwarder_packed, input, SIZE_IP_PORT, std::nullopt);
IP_Port forwarder;
IP_Port forwarder{};
unpack_ip_port(&forwarder, forwarder_packed, SIZE_IP6, true);
// 2 bytes: size of the request
@ -37,22 +37,22 @@ void TestSendForwardRequest(Fuzz_Data &input)
const uint16_t chain_keys_size = chain_length * CRYPTO_PUBLIC_KEY_SIZE;
CONSUME_OR_RETURN(const uint8_t *chain_keys, input, chain_keys_size);
auto prep = prepare(input);
const auto prep = prepare(input);
if (!prep.has_value()) {
return;
}
auto [ipp, forwarder, data, data_size] = prep.value();
const auto [ipp, forwarder, data, data_size] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
const Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
if (logger == nullptr) {
return;
}
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(), sys.mem.get(), sys.ns.get(),
&ipp.ip, ipp.port, ipp.port + 100, nullptr),
kill_networking);
if (net == nullptr) {
return;
@ -66,22 +66,22 @@ void TestForwardReply(Fuzz_Data &input)
CONSUME1_OR_RETURN(const uint16_t, sendback_length, input);
CONSUME_OR_RETURN(const uint8_t *sendback, input, sendback_length);
auto prep = prepare(input);
const auto prep = prepare(input);
if (!prep.has_value()) {
return;
}
auto [ipp, forwarder, data, data_size] = prep.value();
const auto [ipp, forwarder, data, data_size] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
const Ptr<Logger> logger(logger_new(sys.mem.get()), logger_kill);
if (logger == nullptr) {
return;
}
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(), sys.mem.get(), sys.ns.get(),
&ipp.ip, ipp.port, ipp.port + 100, nullptr),
kill_networking);
if (net == nullptr) {
return;

View File

@ -168,8 +168,6 @@ non_null() static void group_delete(GC_Session *c, GC_Chat *chat);
non_null() static void group_cleanup(const GC_Session *c, GC_Chat *chat);
non_null() static bool group_exists(const GC_Session *c, const uint8_t *chat_id);
non_null() static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat);
non_null(1, 2) nullable(4)
static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, void *userdata);
non_null() static void create_gc_session_keypair(const Logger *log, const Random *rng, uint8_t *public_key,
uint8_t *secret_key);
non_null() static size_t load_gc_peers(GC_Chat *chat, const GC_SavedPeerInfo *addrs, uint16_t num_addrs);
@ -837,6 +835,21 @@ static int saved_peer_index(const GC_Chat *chat, const uint8_t *public_key)
return -1;
}
/** @brief Removes entry containing `public_key` from the saved peers list. */
non_null()
static void saved_peers_remove_entry(GC_Chat *chat, const uint8_t *public_key)
{
const int idx = saved_peer_index(chat, public_key);
if (idx < 0) {
return;
}
chat->saved_peers[idx] = (GC_SavedPeerInfo) {
0
};
}
/** @brief Returns the index of the first vacant entry in saved peers list.
*
* If `public_key` is non-null and already exists in the list, its index will be returned.
@ -6701,6 +6714,7 @@ void gc_callback_rejected(const Messenger *m, gc_rejected_cb *function)
*
* Return true on success.
*/
non_null(1, 2) nullable(4)
static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, void *userdata)
{
GC_Peer *peer = get_gc_peer(chat, peer_number);
@ -6709,17 +6723,23 @@ static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number
return false;
}
GC_Connection *gconn = &peer->gconn;
// We need to save some peer info for the callback before deleting it
const bool peer_confirmed = peer->gconn.confirmed;
const bool peer_confirmed = gconn->confirmed;
const GC_Peer_Id peer_id = peer->peer_id;
uint8_t nick[MAX_GC_NICK_SIZE];
const uint16_t nick_length = peer->nick_length;
const GC_Exit_Info exit_info = peer->gconn.exit_info;
const GC_Exit_Info exit_info = gconn->exit_info;
assert(nick_length <= MAX_GC_NICK_SIZE);
memcpy(nick, peer->nick, nick_length);
gcc_peer_cleanup(chat->mem, &peer->gconn);
if (exit_info.exit_type == GC_EXIT_TYPE_KICKED) {
saved_peers_remove_entry(chat, gconn->addr.public_key.enc);
}
gcc_peer_cleanup(chat->mem, gconn);
--chat->numpeers;

View File

@ -20,6 +20,10 @@
#include "net_profile.h"
#include "network.h"
#ifdef __cplusplus
extern "C" {
#endif
/*** Crypto payloads. */
/*** Ranges. */
@ -422,4 +426,8 @@ void kill_net_crypto(Net_Crypto *c);
non_null()
const Net_Profile *nc_get_tcp_client_net_profile(const Net_Crypto *c);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_NET_CRYPTO_H */

View File

@ -0,0 +1,93 @@
#include "net_crypto.h"
#include <cassert>
#include <cstring>
#include <functional>
#include <memory>
#include <optional>
#include "../testing/fuzzing/fuzz_support.hh"
#include "../testing/fuzzing/fuzz_tox.hh"
#include "DHT.h"
#include "TCP_client.h"
#include "network.h"
namespace {
std::optional<std::tuple<IP_Port, uint8_t>> prepare(Fuzz_Data &input)
{
IP_Port ipp;
ip_init(&ipp.ip, true);
ipp.port = 33445;
CONSUME_OR_RETURN_VAL(const uint8_t *iterations_packed, input, 1, std::nullopt);
uint8_t iterations = *iterations_packed;
return {{ipp, iterations}};
}
void TestNetCrypto(Fuzz_Data &input)
{
const auto prep = prepare(input);
if (!prep.has_value()) {
return;
}
const auto [ipp, iterations] = prep.value();
// rest of the fuzz data is input for malloc and network
Fuzz_System sys(input);
const Ptr<Logger> logger(logger_new(sys.mem.get()), 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),
kill_networking);
if (net == nullptr) {
return;
}
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); });
if (mono_time == nullptr) {
return;
}
const Ptr<DHT> dht(new_dht(logger.get(), sys.mem.get(), sys.rng.get(), sys.ns.get(),
mono_time.get(), net.get(), false, false),
kill_dht);
if (dht == nullptr) {
return;
}
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(), dht.get(), &proxy_info),
kill_net_crypto);
if (net_crypto == nullptr) {
return;
}
for (uint8_t i = 0; i < iterations; ++i) {
networking_poll(net.get(), nullptr);
do_dht(dht.get());
do_net_crypto(net_crypto.get(), nullptr);
// "Sleep"
sys.clock += System::BOOTSTRAP_ITERATION_INTERVAL;
}
}
} // namespace
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);
return 0;
}

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2024 The TokTok team.
* Copyright © 2023-2025 The TokTok team.
*/
/**

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2024 The TokTok team.
* Copyright © 2023-2025 The TokTok team.
*/
/**

View File

@ -264,9 +264,11 @@ static int make_family(Family tox_family)
{
switch (tox_family.value) {
case TOX_AF_INET:
case TCP_INET:
return AF_INET;
case TOX_AF_INET6:
case TCP_INET6:
return AF_INET6;
case TOX_AF_UNSPEC:
@ -590,7 +592,11 @@ static int sys_getsockopt(void *obj, Socket sock, int level, int optname, void *
non_null()
static int sys_setsockopt(void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen)
{
#ifdef EMSCRIPTEN
return 0;
#else
return setsockopt(net_socket_to_native(sock), level, optname, (const char *)optval, optlen);
#endif /* EMSCRIPTEN */
}
// sets and fills an array of addrs for address
@ -770,11 +776,11 @@ static const char *net_packet_type_name(Net_Packet_Type type)
case NET_PACKET_PING_RESPONSE:
return "PING_RESPONSE";
case NET_PACKET_GET_NODES:
return "GET_NODES";
case NET_PACKET_NODES_REQUEST:
return "NODES_REQUEST";
case NET_PACKET_SEND_NODES_IPV6:
return "SEND_NODES_IPV6";
case NET_PACKET_NODES_RESPONSE:
return "NODES_RESPONSE";
case NET_PACKET_COOKIE_REQUEST:
return "COOKIE_REQUEST";
@ -883,13 +889,12 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
if (res < 0) { /* Windows doesn't necessarily know `%zu` */
Ip_Ntoa ip_str;
const int error = net_error();
char *strerror = net_new_strerror(error);
Net_Strerror error_str;
LOGGER_TRACE(log, "[%02x = %-21s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
buffer[0], net_packet_type_name((Net_Packet_Type)buffer[0]), message,
min_u16(buflen, 999), 'E',
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error,
strerror, data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
net_kill_strerror(strerror);
net_strerror(error, &error_str), data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
} else if ((res > 0) && ((size_t)res <= buflen)) {
Ip_Ntoa ip_str;
LOGGER_TRACE(log, "[%02x = %-21s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
@ -1048,7 +1053,7 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe
if (net_family_is_unspec(net->family)) { /* Socket not initialized */
// TODO(iphydf): Make this an error. Currently, the onion client calls
// this via DHT getnodes.
// this via DHT nodes requests.
LOGGER_WARNING(net->log, "attempted to send message of length %u on uninitialised socket", packet.length);
return -1;
}
@ -1131,7 +1136,7 @@ int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t
* Packet length is put into length.
*/
non_null()
static int receivepacket(const Network *ns, const Memory *mem, const Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
static int receivepacket(const Network *ns, const Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
{
memset(ip_port, 0, sizeof(IP_Port));
Network_Addr addr = {{0}};
@ -1144,9 +1149,8 @@ static int receivepacket(const Network *ns, const Memory *mem, const Logger *log
const int error = net_error();
if (!should_ignore_recv_error(error)) {
char *strerror = net_new_strerror(error);
LOGGER_ERROR(log, "unexpected error reading from socket: %u, %s", error, strerror);
net_kill_strerror(strerror);
Net_Strerror error_str;
LOGGER_ERROR(log, "unexpected error reading from socket: %u, %s", error, net_strerror(error, &error_str));
}
return -1; /* Nothing received. */
@ -1210,7 +1214,7 @@ void networking_poll(const Networking_Core *net, void *userdata)
uint8_t data[MAX_UDP_PACKET_SIZE] = {0};
uint32_t length;
while (receivepacket(net->ns, net->mem, net->log, net->sock, &ip_port, data, &length) != -1) {
while (receivepacket(net->ns, net->log, net->sock, &ip_port, data, &length) != -1) {
if (length < 1) {
continue;
}
@ -1298,9 +1302,8 @@ Networking_Core *new_networking_ex(
/* Check for socket error. */
if (!sock_valid(temp->sock)) {
const int neterror = net_error();
char *strerror = net_new_strerror(neterror);
LOGGER_ERROR(log, "failed to get a socket?! %d, %s", neterror, strerror);
net_kill_strerror(strerror);
Net_Strerror error_str;
LOGGER_ERROR(log, "failed to get a socket?! %d, %s", neterror, net_strerror(neterror, &error_str));
netprof_kill(mem, temp->udp_net_profile);
mem_delete(mem, temp);
@ -1402,15 +1405,13 @@ Networking_Core *new_networking_ex(
const int res = net_setsockopt(ns, temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
const int neterror = net_error();
char *strerror = net_new_strerror(neterror);
Net_Strerror error_str;
if (res < 0) {
LOGGER_INFO(log, "Failed to activate local multicast membership in FF02::1. (%d, %s)", neterror, strerror);
LOGGER_INFO(log, "Failed to activate local multicast membership in FF02::1. (%d, %s)", neterror, net_strerror(neterror, &error_str));
} else {
LOGGER_TRACE(log, "Local multicast group joined successfully. (%d, %s)", neterror, strerror);
LOGGER_TRACE(log, "Local multicast group joined successfully. (%d, %s)", neterror, net_strerror(neterror, &error_str));
}
net_kill_strerror(strerror);
#endif /* ESP_PLATFORM */
}
@ -1468,10 +1469,9 @@ Networking_Core *new_networking_ex(
Ip_Ntoa ip_str;
const int neterror = net_error();
char *strerror = net_new_strerror(neterror);
Net_Strerror error_str;
LOGGER_ERROR(log, "failed to bind socket: %d, %s IP: %s port_from: %u port_to: %u",
neterror, strerror, net_ip_ntoa(ip, &ip_str), port_from, port_to);
net_kill_strerror(strerror);
neterror, net_strerror(neterror, &error_str), net_ip_ntoa(ip, &ip_str), port_from, port_to);
kill_networking(temp);
if (error != nullptr) {
@ -1878,14 +1878,14 @@ bool ip_parse_addr(const IP *ip, char *address, size_t length)
return false;
}
if (net_family_is_ipv4(ip->family)) {
if (net_family_is_ipv4(ip->family) || net_family_is_tcp_ipv4(ip->family)) {
struct in_addr addr;
assert(make_family(ip->family) == AF_INET);
fill_addr4(&ip->ip.v4, &addr);
return inet_ntop4(&addr, address, length) != nullptr;
}
if (net_family_is_ipv6(ip->family)) {
if (net_family_is_ipv6(ip->family) || net_family_is_tcp_ipv6(ip->family)) {
struct in6_addr addr;
assert(make_family(ip->family) == AF_INET6);
fill_addr6(&ip->ip.v6, &addr);
@ -2097,10 +2097,9 @@ bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket
// Non-blocking socket: "Operation in progress" means it's connecting.
if (!should_ignore_connect_error(error)) {
char *net_strerror = net_new_strerror(error);
Net_Strerror error_str;
LOGGER_WARNING(log, "failed to connect to %s:%d: %d (%s)",
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error, net_strerror);
net_kill_strerror(net_strerror);
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error, net_strerror(error, &error_str));
*err = NET_ERR_CONNECT_FAILED;
return false;
}
@ -2367,19 +2366,11 @@ int net_error(void)
}
#ifdef OS_WIN32
char *net_new_strerror(int error)
char *net_strerror(int error, Net_Strerror *buf)
{
char *str = nullptr;
// Windows API is weird. The 5th function arg is of char* type, but we
// have to pass char** so that it could assign new memory block to our
// pointer, so we have to cast our char** to char* for the compilation
// not to fail (otherwise it would fail to find a variant of this function
// accepting char** as the 5th arg) and Windows inside casts it back
// to char** to do the assignment. So no, this cast you see here, although
// it looks weird, is not a mistake.
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
error, 0, (char *)&str, 0, nullptr);
return str;
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
error, 0, buf->data, NET_STRERROR_SIZE, nullptr);
return buf->data;
}
#else
#if defined(_GNU_SOURCE) && defined(__GLIBC__)
@ -2407,36 +2398,19 @@ static const char *net_strerror_r(int error, char *tmp, size_t tmp_size)
return tmp;
}
#endif /* GNU */
char *net_new_strerror(int error)
char *net_strerror(int error, Net_Strerror *buf)
{
char tmp[256];
errno = 0;
const char *retstr = net_strerror_r(error, tmp, sizeof(tmp));
const char *retstr = net_strerror_r(error, buf->data, NET_STRERROR_SIZE);
const size_t retstr_len = strlen(retstr);
assert(retstr_len < NET_STRERROR_SIZE);
buf->size = (uint16_t)retstr_len;
char *str = (char *)malloc(retstr_len + 1);
if (str == nullptr) {
return nullptr;
}
memcpy(str, retstr, retstr_len + 1);
return str;
return buf->data;
}
#endif /* OS_WIN32 */
void net_kill_strerror(char *strerror)
{
#ifdef OS_WIN32
LocalFree((char *)strerror);
#else
free(strerror);
#endif /* OS_WIN32 */
}
const Net_Profile *net_get_net_profile(const Networking_Core *net)
{
if (net == nullptr) {

View File

@ -113,8 +113,8 @@ Family net_family_tox_tcp_ipv6(void);
typedef enum Net_Packet_Type {
NET_PACKET_PING_REQUEST = 0x00, /* Ping request packet ID. */
NET_PACKET_PING_RESPONSE = 0x01, /* Ping response packet ID. */
NET_PACKET_GET_NODES = 0x02, /* Get nodes request packet ID. */
NET_PACKET_SEND_NODES_IPV6 = 0x04, /* Send nodes response packet ID for other addresses. */
NET_PACKET_NODES_REQUEST = 0x02, /* Nodes request packet ID. */
NET_PACKET_NODES_RESPONSE = 0x04, /* Nodes response packet ID. */
NET_PACKET_COOKIE_REQUEST = 0x18, /* Cookie request packet */
NET_PACKET_COOKIE_RESPONSE = 0x19, /* Cookie response packet */
NET_PACKET_CRYPTO_HS = 0x1a, /* Crypto handshake packet */
@ -236,12 +236,27 @@ Socket net_invalid_socket(void);
/**
* Calls send(sockfd, buf, len, MSG_NOSIGNAL).
*
* @param ns System network object.
* @param log Logger object.
* @param sock Socket to send data with.
* @param buf Data to send.
* @param len Length of data.
* @param ip_port IP and port to send data to.
* @param net_profile Network profile to record the packet.
*/
non_null(1, 2, 4, 6) nullable(7)
int net_send(const Network *ns, const Logger *log, Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port,
Net_Profile *net_profile);
/**
* Calls recv(sockfd, buf, len, MSG_NOSIGNAL).
*
* @param ns System network object.
* @param log Logger object.
* @param sock Socket to receive data with.
* @param buf Buffer to store received data.
* @param len Length of buffer.
* @param ip_port IP and port of the sender.
*/
non_null()
int net_recv(const Network *ns, const Logger *log, Socket sock, uint8_t *buf, size_t len, const IP_Port *ip_port);
@ -582,26 +597,32 @@ bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port);
* Note that different platforms may return different codes for the same error,
* so you likely shouldn't be checking the value returned by this function
* unless you know what you are doing, you likely just want to use it in
* combination with `net_new_strerror()` to print the error.
* combination with `net_strerror()` to print the error.
*
* return platform-dependent network error code, if any.
*/
int net_error(void);
#define NET_STRERROR_SIZE 256
/** @brief Contains a null terminated formatted error message.
*
* This struct should not contain more than at most the 2 fields.
*/
typedef struct Net_Strerror {
char data[NET_STRERROR_SIZE];
uint16_t size;
} Net_Strerror;
/** @brief Get a text explanation for the error code from `net_error()`.
*
* return NULL on failure.
* return pointer to a NULL-terminated string describing the error code on
* success. The returned string must be freed using `net_kill_strerror()`.
* @param error The error code to get a string for.
* @param buf The struct to store the error message in (usually on stack).
*
* @return pointer to a NULL-terminated string describing the error code.
*/
char *net_new_strerror(int error);
/** @brief Frees the string returned by `net_new_strerror()`.
* It's valid to pass NULL as the argument, the function does nothing in this
* case.
*/
nullable(1)
void net_kill_strerror(char *strerror);
non_null()
char *net_strerror(int error, Net_Strerror *buf);
/** @brief Initialize networking.
* Bind to ip and port.

View File

@ -470,6 +470,7 @@ static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_pa
onion_paths->paths[pathnum].path_num = path_num;
} else {
assert(0 <= n && n < NUMBER_ONION_PATHS);
pathnum = n;
}
}
@ -1264,7 +1265,7 @@ static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, con
const Family family = nodes[i].ip_port.ip.family;
if (net_family_is_ipv4(family) || net_family_is_ipv6(family)) {
dht_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key);
dht_send_nodes_request(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key);
} else if (net_family_is_tcp_ipv4(family) || net_family_is_tcp_ipv6(family)) {
if (onion_c->friends_list[friend_num].tcp_relay_node_callback != nullptr) {
void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object;

View File

@ -32,6 +32,8 @@
#include "network.h"
#include "onion_client.h"
#include "state.h"
#include "tox_log_level.h"
#include "tox_options.h"
#include "tox_private.h"
#include "tox_struct.h" // IWYU pragma: keep
#include "util.h"
@ -360,20 +362,22 @@ static void tox_conference_peer_list_changed_handler(Messenger *m, uint32_t conf
}
}
static dht_get_nodes_response_cb tox_dht_get_nodes_response_handler;
static dht_nodes_response_cb tox_dht_nodes_response_handler;
non_null(1, 2) nullable(3)
static void tox_dht_get_nodes_response_handler(const DHT *dht, const Node_format *node, void *user_data)
static void tox_dht_nodes_response_handler(const DHT *dht, const Node_format *node, void *user_data)
{
struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
if (tox_data->tox->dht_get_nodes_response_callback == nullptr) {
if (tox_data->tox->dht_nodes_response_callback == nullptr) {
return;
}
Ip_Ntoa ip_str;
net_ip_ntoa(&node->ip_port.ip, &ip_str);
tox_unlock(tox_data->tox);
tox_data->tox->dht_get_nodes_response_callback(
tox_data->tox, node->public_key, net_ip_ntoa(&node->ip_port.ip, &ip_str), net_ntohs(node->ip_port.port),
tox_data->tox->dht_nodes_response_callback(
tox_data->tox, node->public_key, ip_str.buf, ip_str.length, net_ntohs(node->ip_port.port),
tox_data->user_data);
tox_lock(tox_data->tox);
}
@ -986,7 +990,7 @@ static Tox *tox_new_system(const struct Tox_Options *options, Tox_Err_New *error
callback_file_reqchunk(tox->m, tox_file_chunk_request_handler);
callback_file_sendrequest(tox->m, tox_file_recv_handler);
callback_file_data(tox->m, tox_file_recv_chunk_handler);
dht_callback_get_nodes_response(tox->m->dht, tox_dht_get_nodes_response_handler);
dht_callback_nodes_response(tox->m->dht, tox_dht_nodes_response_handler);
g_callback_group_invite(tox->m->conferences_object, tox_conference_invite_handler);
g_callback_group_connected(tox->m->conferences_object, tox_conference_connected_handler);
g_callback_group_message(tox->m->conferences_object, tox_conference_message_handler);

View File

@ -102,14 +102,14 @@
#include <stddef.h>
#include <stdint.h>
#include "tox_options.h" // IWYU pragma: export
#ifdef __cplusplus
extern "C" {
#endif
/** @{ @namespace tox */
#ifndef TOX_DEFINED
#define TOX_DEFINED
/**
* @brief The Tox instance type.
*
@ -120,7 +120,6 @@ extern "C" {
* limiting factor is the number of usable ports on a device.
*/
typedef struct Tox Tox;
#endif /* TOX_DEFINED */
/** @{
* @name API version
@ -155,7 +154,7 @@ uint32_t tox_version_minor(void);
* Incremented when bugfixes are applied without changing any functionality or
* API or ABI.
*/
#define TOX_VERSION_PATCH 20
#define TOX_VERSION_PATCH 21
uint32_t tox_version_patch(void);
@ -393,439 +392,6 @@ const char *tox_message_type_to_string(Tox_Message_Type value);
/** @} */
/** @{
* @name Startup options
*/
/**
* @brief Type of proxy used to connect to TCP relays.
*/
typedef enum Tox_Proxy_Type {
/**
* Don't use a proxy.
*/
TOX_PROXY_TYPE_NONE,
/**
* HTTP proxy using CONNECT.
*/
TOX_PROXY_TYPE_HTTP,
/**
* SOCKS proxy for simple socket pipes.
*/
TOX_PROXY_TYPE_SOCKS5,
} Tox_Proxy_Type;
const char *tox_proxy_type_to_string(Tox_Proxy_Type value);
/**
* @brief Type of savedata to create the Tox instance from.
*/
typedef enum Tox_Savedata_Type {
/**
* No savedata.
*/
TOX_SAVEDATA_TYPE_NONE,
/**
* Savedata is one that was obtained from tox_get_savedata.
*/
TOX_SAVEDATA_TYPE_TOX_SAVE,
/**
* Savedata is a secret key of length TOX_SECRET_KEY_SIZE.
*/
TOX_SAVEDATA_TYPE_SECRET_KEY,
} Tox_Savedata_Type;
const char *tox_savedata_type_to_string(Tox_Savedata_Type value);
/**
* @brief Severity level of log messages.
*/
typedef enum Tox_Log_Level {
/**
* Very detailed traces including all network activity.
*/
TOX_LOG_LEVEL_TRACE,
/**
* Debug messages such as which port we bind to.
*/
TOX_LOG_LEVEL_DEBUG,
/**
* Informational log messages such as video call status changes.
*/
TOX_LOG_LEVEL_INFO,
/**
* Warnings about internal inconsistency or logic errors.
*/
TOX_LOG_LEVEL_WARNING,
/**
* Severe unexpected errors caused by external or internal inconsistency.
*/
TOX_LOG_LEVEL_ERROR,
} Tox_Log_Level;
const char *tox_log_level_to_string(Tox_Log_Level value);
/**
* @brief This event is triggered when Tox logs an internal message.
*
* This is mostly useful for debugging. This callback can be called from any
* function, not just tox_iterate. This means the user data lifetime must at
* least extend between registering and unregistering it or tox_kill.
*
* Other toxcore modules such as toxav may concurrently call this callback at
* any time. Thus, user code must make sure it is equipped to handle concurrent
* execution, e.g. by employing appropriate mutex locking.
*
* When using the experimental_thread_safety option, no Tox API functions can
* be called from within the log callback.
*
* @param level The severity of the log message.
* @param file The source file from which the message originated.
* @param line The source line from which the message originated.
* @param func The function from which the message originated.
* @param message The log message.
* @param user_data The user data pointer passed to tox_new in options.
*/
typedef void tox_log_cb(Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data);
/**
* @brief This struct contains all the startup options for Tox.
*
* You must tox_options_new to allocate an object of this type.
*
* WARNING: Although this struct happens to be visible in the API, it is
* effectively private. Do not allocate this yourself or access members
* directly, as it *will* break binary compatibility frequently.
*
* @deprecated The memory layout of this struct (size, alignment, and field
* order) is not part of the ABI. To remain compatible, prefer to use
* tox_options_new to allocate the object and accessor functions to set the
* members. The struct will become opaque (i.e. the definition will become
* private) in v0.3.0.
*/
typedef struct Tox_Options Tox_Options;
#ifndef TOX_HIDE_DEPRECATED
struct Tox_Options {
/**
* The type of socket to create.
*
* If this is set to false, an IPv4 socket is created, which subsequently
* only allows IPv4 communication.
* If it is set to true, an IPv6 socket is created, allowing both IPv4 and
* IPv6 communication.
*/
bool ipv6_enabled;
/**
* Enable the use of UDP communication when available.
*
* Setting this to false will force Tox to use TCP only. Communications will
* need to be relayed through a TCP relay node, potentially slowing them
* down.
*
* If a proxy is enabled, UDP will be disabled if either the Tox library or
* the proxy don't support proxying UDP messages.
*/
bool udp_enabled;
/**
* Enable local network peer discovery.
*
* Disabling this will cause Tox to not look for peers on the local network.
*/
bool local_discovery_enabled;
/**
* Enable storing DHT announcements and forwarding corresponding requests.
*
* Disabling this will cause Tox to ignore the relevant packets.
*/
bool dht_announcements_enabled;
/**
* Pass communications through a proxy.
*/
Tox_Proxy_Type proxy_type;
/**
* The IP address or DNS name of the proxy to be used.
*
* If used, this must be non-NULL and be a valid DNS name. The name must not
* exceed TOX_MAX_HOSTNAME_LENGTH characters, and be in a NUL-terminated C
* string format (TOX_MAX_HOSTNAME_LENGTH includes the NUL byte).
*
* This member is ignored (it can be NULL) if proxy_type is
* TOX_PROXY_TYPE_NONE.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object.
*/
const char *proxy_host;
/**
* The port to use to connect to the proxy server.
*
* Ports must be in the range (1, 65535). The value is ignored if
* proxy_type is TOX_PROXY_TYPE_NONE.
*/
uint16_t proxy_port;
/**
* The start port of the inclusive port range to attempt to use.
*
* If both start_port and end_port are 0, the default port range will be
* used: `[33445, 33545]`.
*
* If either start_port or end_port is 0 while the other is non-zero, the
* non-zero port will be the only port in the range.
*
* Having start_port > end_port will yield the same behavior as if
* start_port and end_port were swapped.
*/
uint16_t start_port;
/**
* The end port of the inclusive port range to attempt to use.
*/
uint16_t end_port;
/**
* The port to use for the TCP server (relay). If 0, the TCP server is
* disabled.
*
* Enabling it is not required for Tox to function properly.
*
* When enabled, your Tox instance can act as a TCP relay for other Tox
* instance. This leads to increased traffic, thus when writing a client
* it is recommended to enable TCP server only if the user has an option
* to disable it.
*/
uint16_t tcp_port;
/**
* Enables or disables UDP hole-punching. (Default: enabled).
*/
bool hole_punching_enabled;
/**
* The type of savedata to load from.
*/
Tox_Savedata_Type savedata_type;
/**
* The savedata.
*
* The data pointed at by this member is owned by the user, so must outlive
* the options object.
*/
const uint8_t *savedata_data;
/**
* The length of the savedata.
*/
size_t savedata_length;
/**
* Logging callback for the new Tox instance.
*/
tox_log_cb *log_callback;
/**
* User data pointer passed to the logging callback.
*/
void *log_user_data;
/**
* These options are experimental, so avoid writing code that depends on
* them. Options marked "experimental" may change their behaviour or go away
* entirely in the future, or may be renamed to something non-experimental
* if they become part of the supported API.
*/
/**
* Make public API functions thread-safe using a per-instance lock.
*
* Default: false.
*/
bool experimental_thread_safety;
/**
* Enable saving DHT-based group chats to Tox save data (via
* `tox_get_savedata`). This format will change in the future, so don't rely
* on it.
*
* As an alternative, clients can save the group chat ID in client-owned
* savedata. Then, when the client starts, it can use `tox_group_join`
* with the saved chat ID to recreate the group chat.
*
* Default: false.
*/
bool experimental_groups_persistence;
/**
* @brief Disable DNS hostname resolution.
*
* Hostnames or IP addresses are passed to the bootstrap/add_tcp_relay
* function and proxy host options. If disabled (this flag is true), only
* IP addresses are allowed.
*
* If this is set to true, the library will not attempt to resolve
* hostnames. This is useful for clients that want to resolve hostnames
* themselves and pass the resolved IP addresses to the library (e.g. in
* case it wants to use Tor).
* Passing hostnames will result in a TOX_ERR_BOOTSTRAP_BAD_HOST error if
* this is set to true.
*
* Default: false. May become true in the future (0.3.0).
*/
bool experimental_disable_dns;
};
#endif /* TOX_HIDE_DEPRECATED */
bool tox_options_get_ipv6_enabled(const Tox_Options *options);
void tox_options_set_ipv6_enabled(Tox_Options *options, bool ipv6_enabled);
bool tox_options_get_udp_enabled(const Tox_Options *options);
void tox_options_set_udp_enabled(Tox_Options *options, bool udp_enabled);
bool tox_options_get_local_discovery_enabled(const Tox_Options *options);
void tox_options_set_local_discovery_enabled(Tox_Options *options, bool local_discovery_enabled);
bool tox_options_get_dht_announcements_enabled(const Tox_Options *options);
void tox_options_set_dht_announcements_enabled(Tox_Options *options, bool dht_announcements_enabled);
Tox_Proxy_Type tox_options_get_proxy_type(const Tox_Options *options);
void tox_options_set_proxy_type(Tox_Options *options, Tox_Proxy_Type proxy_type);
const char *tox_options_get_proxy_host(const Tox_Options *options);
void tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host);
uint16_t tox_options_get_proxy_port(const Tox_Options *options);
void tox_options_set_proxy_port(Tox_Options *options, uint16_t proxy_port);
uint16_t tox_options_get_start_port(const Tox_Options *options);
void tox_options_set_start_port(Tox_Options *options, uint16_t start_port);
uint16_t tox_options_get_end_port(const Tox_Options *options);
void tox_options_set_end_port(Tox_Options *options, uint16_t end_port);
uint16_t tox_options_get_tcp_port(const Tox_Options *options);
void tox_options_set_tcp_port(Tox_Options *options, uint16_t tcp_port);
bool tox_options_get_hole_punching_enabled(const Tox_Options *options);
void tox_options_set_hole_punching_enabled(Tox_Options *options, bool hole_punching_enabled);
Tox_Savedata_Type tox_options_get_savedata_type(const Tox_Options *options);
void tox_options_set_savedata_type(Tox_Options *options, Tox_Savedata_Type savedata_type);
const uint8_t *tox_options_get_savedata_data(const Tox_Options *options);
void tox_options_set_savedata_data(Tox_Options *options, const uint8_t savedata_data[], size_t length);
size_t tox_options_get_savedata_length(const Tox_Options *options);
void tox_options_set_savedata_length(Tox_Options *options, size_t savedata_length);
tox_log_cb *tox_options_get_log_callback(const Tox_Options *options);
void tox_options_set_log_callback(Tox_Options *options, tox_log_cb *log_callback);
void *tox_options_get_log_user_data(const Tox_Options *options);
void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data);
bool tox_options_get_experimental_thread_safety(const Tox_Options *options);
void tox_options_set_experimental_thread_safety(Tox_Options *options, bool experimental_thread_safety);
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options);
void tox_options_set_experimental_groups_persistence(Tox_Options *options, bool experimental_groups_persistence);
bool tox_options_get_experimental_disable_dns(const Tox_Options *options);
void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns);
/**
* @brief Initialises a Tox_Options object with the default options.
*
* The result of this function is independent of the original options. All
* values will be overwritten, no values will be read (so it is permissible
* to pass an uninitialised object).
*
* If options is NULL, this function has no effect.
*
* @param options An options object to be filled with default options.
*/
void tox_options_default(Tox_Options *options);
typedef enum Tox_Err_Options_New {
/**
* The function returned successfully.
*/
TOX_ERR_OPTIONS_NEW_OK,
/**
* The function failed to allocate enough memory for the options struct.
*/
TOX_ERR_OPTIONS_NEW_MALLOC,
} Tox_Err_Options_New;
const char *tox_err_options_new_to_string(Tox_Err_Options_New value);
/**
* @brief Allocates a new Tox_Options object and initialises it with the default
* options.
*
* This function can be used to preserve long term ABI compatibility by
* giving the responsibility of allocation and deallocation to the Tox library.
*
* Objects returned from this function must be freed using the tox_options_free
* function.
*
* @return A new Tox_Options object with default options or NULL on failure.
*/
Tox_Options *tox_options_new(Tox_Err_Options_New *error);
/**
* @brief Releases all resources associated with an options objects.
*
* Passing a pointer that was not returned by tox_options_new results in
* undefined behaviour.
*/
void tox_options_free(Tox_Options *options);
/** @} */
/** @{
* @name Creation and destruction
*/
@ -974,7 +540,7 @@ typedef enum Tox_Err_Bootstrap {
const char *tox_err_bootstrap_to_string(Tox_Err_Bootstrap value);
/**
* @brief Sends a "get nodes" request to the given bootstrap node with IP, port,
* @brief Sends a "nodes request" to the given bootstrap node with IP, port,
* and public key to setup connections.
*
* This function will attempt to connect to the node using UDP. You must use
@ -5795,7 +5361,6 @@ typedef Tox_User_Status TOX_USER_STATUS;
typedef Tox_Message_Type TOX_MESSAGE_TYPE;
typedef Tox_Proxy_Type TOX_PROXY_TYPE;
typedef Tox_Savedata_Type TOX_SAVEDATA_TYPE;
typedef Tox_Log_Level TOX_LOG_LEVEL;
typedef Tox_Connection TOX_CONNECTION;
typedef Tox_File_Control TOX_FILE_CONTROL;
typedef Tox_Conference_Type TOX_CONFERENCE_TYPE;

View File

@ -1,20 +1,11 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2025 The TokTok team.
*/
#include "tox.h"
#include "tox.h" // IWYU pragma: associated
#include <stdlib.h>
#include "ccompat.h"
#include "tox_options.h"
#include "tox_private.h"
#define SET_ERROR_PARAMETER(param, x) \
do { \
if (param != nullptr) { \
*param = x; \
} \
} while (0)
uint32_t tox_version_major(void)
{
return TOX_VERSION_MAJOR;
@ -136,200 +127,6 @@ uint32_t tox_dht_node_public_key_size(void)
return TOX_DHT_NODE_PUBLIC_KEY_SIZE;
}
bool tox_options_get_ipv6_enabled(const Tox_Options *options)
{
return options->ipv6_enabled;
}
void tox_options_set_ipv6_enabled(Tox_Options *options, bool ipv6_enabled)
{
options->ipv6_enabled = ipv6_enabled;
}
bool tox_options_get_udp_enabled(const Tox_Options *options)
{
return options->udp_enabled;
}
void tox_options_set_udp_enabled(Tox_Options *options, bool udp_enabled)
{
options->udp_enabled = udp_enabled;
}
Tox_Proxy_Type tox_options_get_proxy_type(const Tox_Options *options)
{
return options->proxy_type;
}
void tox_options_set_proxy_type(Tox_Options *options, Tox_Proxy_Type proxy_type)
{
options->proxy_type = proxy_type;
}
const char *tox_options_get_proxy_host(const Tox_Options *options)
{
return options->proxy_host;
}
void tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host)
{
options->proxy_host = proxy_host;
}
uint16_t tox_options_get_proxy_port(const Tox_Options *options)
{
return options->proxy_port;
}
void tox_options_set_proxy_port(Tox_Options *options, uint16_t proxy_port)
{
options->proxy_port = proxy_port;
}
uint16_t tox_options_get_start_port(const Tox_Options *options)
{
return options->start_port;
}
void tox_options_set_start_port(Tox_Options *options, uint16_t start_port)
{
options->start_port = start_port;
}
uint16_t tox_options_get_end_port(const Tox_Options *options)
{
return options->end_port;
}
void tox_options_set_end_port(Tox_Options *options, uint16_t end_port)
{
options->end_port = end_port;
}
uint16_t tox_options_get_tcp_port(const Tox_Options *options)
{
return options->tcp_port;
}
void tox_options_set_tcp_port(Tox_Options *options, uint16_t tcp_port)
{
options->tcp_port = tcp_port;
}
bool tox_options_get_hole_punching_enabled(const Tox_Options *options)
{
return options->hole_punching_enabled;
}
void tox_options_set_hole_punching_enabled(Tox_Options *options, bool hole_punching_enabled)
{
options->hole_punching_enabled = hole_punching_enabled;
}
Tox_Savedata_Type tox_options_get_savedata_type(const Tox_Options *options)
{
return options->savedata_type;
}
void tox_options_set_savedata_type(Tox_Options *options, Tox_Savedata_Type savedata_type)
{
options->savedata_type = savedata_type;
}
size_t tox_options_get_savedata_length(const Tox_Options *options)
{
return options->savedata_length;
}
void tox_options_set_savedata_length(Tox_Options *options, size_t savedata_length)
{
options->savedata_length = savedata_length;
}
tox_log_cb *tox_options_get_log_callback(const Tox_Options *options)
{
return options->log_callback;
}
void tox_options_set_log_callback(Tox_Options *options, tox_log_cb *log_callback)
{
options->log_callback = log_callback;
}
void *tox_options_get_log_user_data(const Tox_Options *options)
{
return options->log_user_data;
}
void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data)
{
options->log_user_data = log_user_data;
}
bool tox_options_get_local_discovery_enabled(const Tox_Options *options)
{
return options->local_discovery_enabled;
}
void tox_options_set_local_discovery_enabled(Tox_Options *options, bool local_discovery_enabled)
{
options->local_discovery_enabled = local_discovery_enabled;
}
bool tox_options_get_dht_announcements_enabled(const Tox_Options *options)
{
return options->dht_announcements_enabled;
}
void tox_options_set_dht_announcements_enabled(Tox_Options *options, bool dht_announcements_enabled)
{
options->dht_announcements_enabled = dht_announcements_enabled;
}
bool tox_options_get_experimental_thread_safety(const Tox_Options *options)
{
return options->experimental_thread_safety;
}
void tox_options_set_experimental_thread_safety(
Tox_Options *options, bool experimental_thread_safety)
{
options->experimental_thread_safety = experimental_thread_safety;
}
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options)
{
return options->experimental_groups_persistence;
}
void tox_options_set_experimental_groups_persistence(
Tox_Options *options, bool experimental_groups_persistence)
{
options->experimental_groups_persistence = experimental_groups_persistence;
}
bool tox_options_get_experimental_disable_dns(const Tox_Options *options)
{
return options->experimental_disable_dns;
}
void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns)
{
options->experimental_disable_dns = experimental_disable_dns;
}
const uint8_t *tox_options_get_savedata_data(const Tox_Options *options)
{
return options->savedata_data;
}
void tox_options_set_savedata_data(Tox_Options *options, const uint8_t *savedata_data, size_t length)
{
options->savedata_data = savedata_data;
options->savedata_length = length;
}
void tox_options_default(Tox_Options *options)
{
if (options != nullptr) {
const Tox_Options default_options = {false};
*options = default_options;
tox_options_set_ipv6_enabled(options, true);
tox_options_set_udp_enabled(options, true);
tox_options_set_proxy_type(options, TOX_PROXY_TYPE_NONE);
tox_options_set_hole_punching_enabled(options, true);
tox_options_set_local_discovery_enabled(options, true);
tox_options_set_dht_announcements_enabled(options, true);
tox_options_set_experimental_thread_safety(options, false);
tox_options_set_experimental_groups_persistence(options, false);
tox_options_set_experimental_disable_dns(options, false);
}
}
Tox_Options *tox_options_new(Tox_Err_Options_New *error)
{
Tox_Options *options = (Tox_Options *)calloc(1, sizeof(Tox_Options));
if (options != nullptr) {
tox_options_default(options);
SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK);
return options;
}
SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC);
return nullptr;
}
void tox_options_free(Tox_Options *options)
{
free(options);
}
const char *tox_user_status_to_string(Tox_User_Status value)
{
switch (value) {
@ -387,27 +184,6 @@ const char *tox_savedata_type_to_string(Tox_Savedata_Type value)
return "<invalid Tox_Savedata_Type>";
}
const char *tox_log_level_to_string(Tox_Log_Level value)
{
switch (value) {
case TOX_LOG_LEVEL_TRACE:
return "TOX_LOG_LEVEL_TRACE";
case TOX_LOG_LEVEL_DEBUG:
return "TOX_LOG_LEVEL_DEBUG";
case TOX_LOG_LEVEL_INFO:
return "TOX_LOG_LEVEL_INFO";
case TOX_LOG_LEVEL_WARNING:
return "TOX_LOG_LEVEL_WARNING";
case TOX_LOG_LEVEL_ERROR:
return "TOX_LOG_LEVEL_ERROR";
}
return "<invalid Tox_Log_Level>";
}
const char *tox_err_options_new_to_string(Tox_Err_Options_New value)
{
switch (value) {

View File

@ -53,7 +53,7 @@ struct Tox_Dispatch {
tox_events_group_self_join_cb *group_self_join_callback;
tox_events_group_join_fail_cb *group_join_fail_callback;
tox_events_group_moderation_cb *group_moderation_callback;
tox_events_dht_get_nodes_response_cb *dht_get_nodes_response_callback;
tox_events_dht_nodes_response_cb *dht_nodes_response_callback;
};
Tox_Dispatch *tox_dispatch_new(Tox_Err_Dispatch_New *error)
@ -279,10 +279,10 @@ void tox_events_callback_group_moderation(
{
dispatch->group_moderation_callback = callback;
}
void tox_events_callback_dht_get_nodes_response(
Tox_Dispatch *dispatch, tox_events_dht_get_nodes_response_cb *callback)
void tox_events_callback_dht_nodes_response(
Tox_Dispatch *dispatch, tox_events_dht_nodes_response_cb *callback)
{
dispatch->dht_get_nodes_response_callback = callback;
dispatch->dht_nodes_response_callback = callback;
}
non_null(1, 2) nullable(3)
@ -602,8 +602,8 @@ static void tox_dispatch_invoke_event(const Tox_Dispatch *dispatch, const Tox_Ev
}
case TOX_EVENT_DHT_GET_NODES_RESPONSE: {
if (dispatch->dht_get_nodes_response_callback != nullptr) {
dispatch->dht_get_nodes_response_callback(event->data.dht_get_nodes_response, user_data);
if (dispatch->dht_nodes_response_callback != nullptr) {
dispatch->dht_nodes_response_callback(event->data.dht_nodes_response, user_data);
}
break;

View File

@ -136,8 +136,8 @@ typedef void tox_events_group_join_fail_cb(
const Tox_Event_Group_Join_Fail *event, void *user_data);
typedef void tox_events_group_moderation_cb(
const Tox_Event_Group_Moderation *event, void *user_data);
typedef void tox_events_dht_get_nodes_response_cb(
const Tox_Event_Dht_Get_Nodes_Response *event, void *user_data);
typedef void tox_events_dht_nodes_response_cb(
const Tox_Event_Dht_Nodes_Response *event, void *user_data);
void tox_events_callback_conference_connected(
Tox_Dispatch *dispatch, tox_events_conference_connected_cb *callback);
@ -217,8 +217,8 @@ void tox_events_callback_group_join_fail(
Tox_Dispatch *dispatch, tox_events_group_join_fail_cb *callback);
void tox_events_callback_group_moderation(
Tox_Dispatch *dispatch, tox_events_group_moderation_cb *callback);
void tox_events_callback_dht_get_nodes_response(
Tox_Dispatch *dispatch, tox_events_dht_get_nodes_response_cb *callback);
void tox_events_callback_dht_nodes_response(
Tox_Dispatch *dispatch, tox_events_dht_nodes_response_cb *callback);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -351,7 +351,7 @@ bool tox_event_construct(Tox_Event *event, Tox_Event_Type type, const Memory *me
}
case TOX_EVENT_DHT_GET_NODES_RESPONSE: {
event->data.dht_get_nodes_response = tox_event_dht_get_nodes_response_new(mem);
event->data.dht_nodes_response = tox_event_dht_nodes_response_new(mem);
break;
}
@ -566,7 +566,7 @@ void tox_event_destruct(Tox_Event *event, const Memory *mem)
}
case TOX_EVENT_DHT_GET_NODES_RESPONSE: {
tox_event_dht_get_nodes_response_free(event->data.dht_get_nodes_response, mem);
tox_event_dht_nodes_response_free(event->data.dht_nodes_response, mem);
break;
}
@ -706,7 +706,7 @@ static bool tox_event_data_pack(Tox_Event_Type type, const Tox_Event_Data *data,
return tox_event_group_moderation_pack(data->group_moderation, bp);
case TOX_EVENT_DHT_GET_NODES_RESPONSE:
return tox_event_dht_get_nodes_response_pack(data->dht_get_nodes_response, bp);
return tox_event_dht_nodes_response_pack(data->dht_nodes_response, bp);
case TOX_EVENT_INVALID:
return false;
@ -1070,7 +1070,7 @@ static bool tox_event_data_unpack(Tox_Event_Type type, Tox_Event_Data *data, Bin
return tox_event_group_moderation_unpack(&data->group_moderation, bu, mem);
case TOX_EVENT_DHT_GET_NODES_RESPONSE:
return tox_event_dht_get_nodes_response_unpack(&data->dht_get_nodes_response, bu, mem);
return tox_event_dht_nodes_response_unpack(&data->dht_nodes_response, bu, mem);
case TOX_EVENT_INVALID:
return false;

View File

@ -61,7 +61,7 @@ typedef union Tox_Event_Data {
Tox_Event_Group_Self_Join *group_self_join;
Tox_Event_Group_Join_Fail *group_join_fail;
Tox_Event_Group_Moderation *group_moderation;
Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response;
Tox_Event_Dht_Nodes_Response *dht_nodes_response;
} Tox_Event_Data;
struct Tox_Event {
@ -113,7 +113,7 @@ non_null() Tox_Event_Group_Peer_Exit *tox_event_group_peer_exit_new(const Memory
non_null() Tox_Event_Group_Self_Join *tox_event_group_self_join_new(const Memory *mem);
non_null() Tox_Event_Group_Join_Fail *tox_event_group_join_fail_new(const Memory *mem);
non_null() Tox_Event_Group_Moderation *tox_event_group_moderation_new(const Memory *mem);
non_null() Tox_Event_Dht_Get_Nodes_Response *tox_event_dht_get_nodes_response_new(const Memory *mem);
non_null() Tox_Event_Dht_Nodes_Response *tox_event_dht_nodes_response_new(const Memory *mem);
/**
* Destructor.
@ -159,7 +159,7 @@ non_null(2) nullable(1) void tox_event_group_peer_exit_free(Tox_Event_Group_Peer
non_null(2) nullable(1) void tox_event_group_self_join_free(Tox_Event_Group_Self_Join *group_self_join, const Memory *mem);
non_null(2) nullable(1) void tox_event_group_join_fail_free(Tox_Event_Group_Join_Fail *group_join_fail, const Memory *mem);
non_null(2) nullable(1) void tox_event_group_moderation_free(Tox_Event_Group_Moderation *group_moderation, const Memory *mem);
non_null(2) nullable(1) void tox_event_dht_get_nodes_response_free(Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response, const Memory *mem);
non_null(2) nullable(1) void tox_event_dht_nodes_response_free(Tox_Event_Dht_Nodes_Response *dht_nodes_response, const Memory *mem);
/**
* Pack into msgpack.
@ -205,7 +205,7 @@ non_null() bool tox_event_group_peer_exit_pack(const Tox_Event_Group_Peer_Exit *
non_null() bool tox_event_group_self_join_pack(const Tox_Event_Group_Self_Join *event, Bin_Pack *bp);
non_null() bool tox_event_group_join_fail_pack(const Tox_Event_Group_Join_Fail *event, Bin_Pack *bp);
non_null() bool tox_event_group_moderation_pack(const Tox_Event_Group_Moderation *event, Bin_Pack *bp);
non_null() bool tox_event_dht_get_nodes_response_pack(const Tox_Event_Dht_Get_Nodes_Response *event, Bin_Pack *bp);
non_null() bool tox_event_dht_nodes_response_pack(const Tox_Event_Dht_Nodes_Response *event, Bin_Pack *bp);
/**
* Unpack from msgpack.
@ -251,7 +251,7 @@ non_null() bool tox_event_group_peer_exit_unpack(Tox_Event_Group_Peer_Exit **eve
non_null() bool tox_event_group_self_join_unpack(Tox_Event_Group_Self_Join **event, Bin_Unpack *bu, const Memory *mem);
non_null() bool tox_event_group_join_fail_unpack(Tox_Event_Group_Join_Fail **event, Bin_Unpack *bu, const Memory *mem);
non_null() bool tox_event_group_moderation_unpack(Tox_Event_Group_Moderation **event, Bin_Unpack *bu, const Memory *mem);
non_null() bool tox_event_dht_get_nodes_response_unpack(Tox_Event_Dht_Get_Nodes_Response **event, Bin_Unpack *bu, const Memory *mem);
non_null() bool tox_event_dht_nodes_response_unpack(Tox_Event_Dht_Nodes_Response **event, Bin_Unpack *bu, const Memory *mem);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -17,7 +17,7 @@
#include "tox.h"
#include "tox_event.h"
#include "tox_private.h"
#include "tox_struct.h"
#include "tox_struct.h" // IWYU pragma: keep
/*****************************************************
*
@ -66,7 +66,7 @@ void tox_events_init(Tox *tox)
tox_callback_group_self_join(tox, tox_events_handle_group_self_join);
tox_callback_group_join_fail(tox, tox_events_handle_group_join_fail);
tox_callback_group_moderation(tox, tox_events_handle_group_moderation);
tox_callback_dht_get_nodes_response(tox, tox_events_handle_dht_get_nodes_response);
tox_callback_dht_nodes_response(tox, tox_events_handle_dht_nodes_response);
}
uint32_t tox_events_get_size(const Tox_Events *events)
@ -173,7 +173,7 @@ Tox_Events *tox_events_load(const Tox_System *sys, const uint8_t *bytes, uint32_
};
events->mem = sys->mem;
if (!bin_unpack_obj(tox_events_unpack_handler, events, bytes, bytes_size)) {
if (!bin_unpack_obj(sys->mem, tox_events_unpack_handler, events, bytes, bytes_size)) {
tox_events_free(events);
return nullptr;
}

View File

@ -352,15 +352,15 @@ uint32_t tox_event_group_moderation_get_target_peer_id(
Tox_Group_Mod_Event tox_event_group_moderation_get_mod_type(
const Tox_Event_Group_Moderation *group_moderation);
typedef struct Tox_Event_Dht_Get_Nodes_Response Tox_Event_Dht_Get_Nodes_Response;
const uint8_t *tox_event_dht_get_nodes_response_get_public_key(
const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response);
const uint8_t *tox_event_dht_get_nodes_response_get_ip(
const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response);
uint32_t tox_event_dht_get_nodes_response_get_ip_length(
const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response);
uint16_t tox_event_dht_get_nodes_response_get_port(
const Tox_Event_Dht_Get_Nodes_Response *dht_get_nodes_response);
typedef struct Tox_Event_Dht_Nodes_Response Tox_Event_Dht_Nodes_Response;
const uint8_t *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_ip(
const Tox_Event_Dht_Nodes_Response *dht_nodes_response);
uint32_t tox_event_dht_nodes_response_get_ip_length(
const Tox_Event_Dht_Nodes_Response *dht_nodes_response);
uint16_t tox_event_dht_nodes_response_get_port(
const Tox_Event_Dht_Nodes_Response *dht_nodes_response);
typedef enum Tox_Event_Type {
TOX_EVENT_SELF_CONNECTION_STATUS = 0,
@ -507,7 +507,7 @@ const Tox_Event_Group_Join_Fail *tox_event_get_group_join_fail(
const Tox_Event *event);
const Tox_Event_Group_Moderation *tox_event_get_group_moderation(
const Tox_Event *event);
const Tox_Event_Dht_Get_Nodes_Response *tox_event_get_dht_get_nodes_response(
const Tox_Event_Dht_Nodes_Response *tox_event_get_dht_nodes_response(
const Tox_Event *event);
/**

27
toxcore/tox_log_level.c Normal file
View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2025 The TokTok team.
* Copyright © 2013 Tox project.
*/
#include "tox_log_level.h"
const char *tox_log_level_to_string(Tox_Log_Level value)
{
switch (value) {
case TOX_LOG_LEVEL_TRACE:
return "TOX_LOG_LEVEL_TRACE";
case TOX_LOG_LEVEL_DEBUG:
return "TOX_LOG_LEVEL_DEBUG";
case TOX_LOG_LEVEL_INFO:
return "TOX_LOG_LEVEL_INFO";
case TOX_LOG_LEVEL_WARNING:
return "TOX_LOG_LEVEL_WARNING";
case TOX_LOG_LEVEL_ERROR:
return "TOX_LOG_LEVEL_ERROR";
}
return "<invalid Tox_Log_Level>";
}

58
toxcore/tox_log_level.h Normal file
View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2022-2025 The TokTok team.
*/
#ifndef C_TOXCORE_TOXCORE_TOX_LOG_LEVEL_H
#define C_TOXCORE_TOXCORE_TOX_LOG_LEVEL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Severity level of log messages.
*/
typedef enum Tox_Log_Level {
/**
* Very detailed traces including all network activity.
*/
TOX_LOG_LEVEL_TRACE,
/**
* Debug messages such as which port we bind to.
*/
TOX_LOG_LEVEL_DEBUG,
/**
* Informational log messages such as video call status changes.
*/
TOX_LOG_LEVEL_INFO,
/**
* Warnings about internal inconsistency or logic errors.
*/
TOX_LOG_LEVEL_WARNING,
/**
* Severe unexpected errors caused by external or internal inconsistency.
*/
TOX_LOG_LEVEL_ERROR,
} Tox_Log_Level;
const char *tox_log_level_to_string(Tox_Log_Level value);
//!TOKSTYLE-
#ifndef DOXYGEN_IGNORE
#ifndef TOX_HIDE_DEPRECATED
typedef Tox_Log_Level TOX_LOG_LEVEL;
#endif /* TOX_HIDE_DEPRECATED */
#endif
//!TOKSTYLE+
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_TOX_LOG_LEVEL_H */

285
toxcore/tox_options.c Normal file
View File

@ -0,0 +1,285 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2025 The TokTok team.
* Copyright © 2013 Tox project.
*/
#include "tox_options.h"
#include <stdlib.h> // free, malloc, calloc
#include <string.h> // memcpy, strlen
#include "ccompat.h" // nullptr
#define SET_ERROR_PARAMETER(param, x) \
do { \
if (param != nullptr) { \
*param = x; \
} \
} while (0)
bool tox_options_get_ipv6_enabled(const Tox_Options *options)
{
return options->ipv6_enabled;
}
void tox_options_set_ipv6_enabled(Tox_Options *options, bool ipv6_enabled)
{
options->ipv6_enabled = ipv6_enabled;
}
bool tox_options_get_udp_enabled(const Tox_Options *options)
{
return options->udp_enabled;
}
void tox_options_set_udp_enabled(Tox_Options *options, bool udp_enabled)
{
options->udp_enabled = udp_enabled;
}
Tox_Proxy_Type tox_options_get_proxy_type(const Tox_Options *options)
{
return options->proxy_type;
}
void tox_options_set_proxy_type(Tox_Options *options, Tox_Proxy_Type proxy_type)
{
options->proxy_type = proxy_type;
}
const char *tox_options_get_proxy_host(const Tox_Options *options)
{
return options->proxy_host;
}
bool tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host)
{
if (!options->experimental_owned_data) {
options->proxy_host = proxy_host;
return true;
}
if (options->owned_proxy_host != nullptr) {
free(options->owned_proxy_host);
options->owned_proxy_host = nullptr;
}
if (proxy_host == nullptr) {
options->proxy_host = nullptr;
return true;
}
const size_t proxy_host_length = strlen(proxy_host) + 1;
char *owned_ptr = (char *)malloc(proxy_host_length);
if (owned_ptr == nullptr) {
options->proxy_host = proxy_host;
options->owned_proxy_host = nullptr;
return false;
}
memcpy(owned_ptr, proxy_host, proxy_host_length);
options->proxy_host = owned_ptr;
options->owned_proxy_host = owned_ptr;
return true;
}
uint16_t tox_options_get_proxy_port(const Tox_Options *options)
{
return options->proxy_port;
}
void tox_options_set_proxy_port(Tox_Options *options, uint16_t proxy_port)
{
options->proxy_port = proxy_port;
}
uint16_t tox_options_get_start_port(const Tox_Options *options)
{
return options->start_port;
}
void tox_options_set_start_port(Tox_Options *options, uint16_t start_port)
{
options->start_port = start_port;
}
uint16_t tox_options_get_end_port(const Tox_Options *options)
{
return options->end_port;
}
void tox_options_set_end_port(Tox_Options *options, uint16_t end_port)
{
options->end_port = end_port;
}
uint16_t tox_options_get_tcp_port(const Tox_Options *options)
{
return options->tcp_port;
}
void tox_options_set_tcp_port(Tox_Options *options, uint16_t tcp_port)
{
options->tcp_port = tcp_port;
}
bool tox_options_get_hole_punching_enabled(const Tox_Options *options)
{
return options->hole_punching_enabled;
}
void tox_options_set_hole_punching_enabled(Tox_Options *options, bool hole_punching_enabled)
{
options->hole_punching_enabled = hole_punching_enabled;
}
Tox_Savedata_Type tox_options_get_savedata_type(const Tox_Options *options)
{
return options->savedata_type;
}
void tox_options_set_savedata_type(Tox_Options *options, Tox_Savedata_Type savedata_type)
{
options->savedata_type = savedata_type;
}
size_t tox_options_get_savedata_length(const Tox_Options *options)
{
return options->savedata_length;
}
void tox_options_set_savedata_length(Tox_Options *options, size_t savedata_length)
{
options->savedata_length = savedata_length;
}
tox_log_cb *tox_options_get_log_callback(const Tox_Options *options)
{
return options->log_callback;
}
void tox_options_set_log_callback(Tox_Options *options, tox_log_cb *log_callback)
{
options->log_callback = log_callback;
}
void *tox_options_get_log_user_data(const Tox_Options *options)
{
return options->log_user_data;
}
void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data)
{
options->log_user_data = log_user_data;
}
bool tox_options_get_local_discovery_enabled(const Tox_Options *options)
{
return options->local_discovery_enabled;
}
void tox_options_set_local_discovery_enabled(Tox_Options *options, bool local_discovery_enabled)
{
options->local_discovery_enabled = local_discovery_enabled;
}
bool tox_options_get_dht_announcements_enabled(const Tox_Options *options)
{
return options->dht_announcements_enabled;
}
void tox_options_set_dht_announcements_enabled(Tox_Options *options, bool dht_announcements_enabled)
{
options->dht_announcements_enabled = dht_announcements_enabled;
}
bool tox_options_get_experimental_thread_safety(const Tox_Options *options)
{
return options->experimental_thread_safety;
}
void tox_options_set_experimental_thread_safety(
Tox_Options *options, bool experimental_thread_safety)
{
options->experimental_thread_safety = experimental_thread_safety;
}
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options)
{
return options->experimental_groups_persistence;
}
void tox_options_set_experimental_groups_persistence(
Tox_Options *options, bool experimental_groups_persistence)
{
options->experimental_groups_persistence = experimental_groups_persistence;
}
bool tox_options_get_experimental_disable_dns(const Tox_Options *options)
{
return options->experimental_disable_dns;
}
void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns)
{
options->experimental_disable_dns = experimental_disable_dns;
}
bool tox_options_get_experimental_owned_data(const Tox_Options *options)
{
return options->experimental_owned_data;
}
void tox_options_set_experimental_owned_data(
Tox_Options *options, bool experimental_owned_data)
{
options->experimental_owned_data = experimental_owned_data;
}
const uint8_t *tox_options_get_savedata_data(const Tox_Options *options)
{
return options->savedata_data;
}
bool tox_options_set_savedata_data(Tox_Options *options, const uint8_t *savedata_data, size_t length)
{
if (!options->experimental_owned_data) {
options->savedata_data = savedata_data;
options->savedata_length = length;
return true;
}
if (options->owned_savedata_data != nullptr) {
free(options->owned_savedata_data);
options->owned_savedata_data = nullptr;
}
if (savedata_data == nullptr) {
options->savedata_data = nullptr;
options->savedata_length = 0;
return true;
}
uint8_t *owned_ptr = (uint8_t *)malloc(length);
if (owned_ptr == nullptr) {
options->savedata_data = savedata_data;
options->savedata_length = length;
options->owned_savedata_data = nullptr;
return false;
}
memcpy(owned_ptr, savedata_data, length);
options->savedata_data = owned_ptr;
options->savedata_length = length;
options->owned_savedata_data = owned_ptr;
return true;
}
void tox_options_default(Tox_Options *options)
{
if (options != nullptr) {
// Free any owned data.
tox_options_set_proxy_host(options, nullptr);
tox_options_set_savedata_data(options, nullptr, 0);
// Set the rest to default values.
const Tox_Options default_options = {false};
*options = default_options;
tox_options_set_ipv6_enabled(options, true);
tox_options_set_udp_enabled(options, true);
tox_options_set_proxy_type(options, TOX_PROXY_TYPE_NONE);
tox_options_set_hole_punching_enabled(options, true);
tox_options_set_local_discovery_enabled(options, true);
tox_options_set_dht_announcements_enabled(options, true);
tox_options_set_experimental_thread_safety(options, false);
tox_options_set_experimental_groups_persistence(options, false);
tox_options_set_experimental_disable_dns(options, false);
tox_options_set_experimental_owned_data(options, false);
}
}
Tox_Options *tox_options_new(Tox_Err_Options_New *error)
{
Tox_Options *options = (Tox_Options *)calloc(1, sizeof(Tox_Options));
if (options != nullptr) {
tox_options_default(options);
SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK);
return options;
}
SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC);
return nullptr;
}
void tox_options_free(Tox_Options *options)
{
if (options != nullptr) {
// Free any owned data.
tox_options_set_proxy_host(options, nullptr);
tox_options_set_savedata_data(options, nullptr, 0);
free(options);
}
}

455
toxcore/tox_options.h Normal file
View File

@ -0,0 +1,455 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2025 The TokTok team.
* Copyright © 2013 Tox project.
*/
#ifndef C_TOXCORE_TOXCORE_TOX_OPTIONS_H
#define C_TOXCORE_TOXCORE_TOX_OPTIONS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "tox_log_level.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Tox;
/** @{
* @name Startup options
*/
/**
* @brief Type of proxy used to connect to TCP relays.
*/
typedef enum Tox_Proxy_Type {
/**
* Don't use a proxy.
*/
TOX_PROXY_TYPE_NONE,
/**
* HTTP proxy using CONNECT.
*/
TOX_PROXY_TYPE_HTTP,
/**
* SOCKS proxy for simple socket pipes.
*/
TOX_PROXY_TYPE_SOCKS5,
} Tox_Proxy_Type;
const char *tox_proxy_type_to_string(Tox_Proxy_Type value);
/**
* @brief Type of savedata to create the Tox instance from.
*/
typedef enum Tox_Savedata_Type {
/**
* No savedata.
*/
TOX_SAVEDATA_TYPE_NONE,
/**
* Savedata is one that was obtained from tox_get_savedata.
*/
TOX_SAVEDATA_TYPE_TOX_SAVE,
/**
* Savedata is a secret key of length TOX_SECRET_KEY_SIZE.
*/
TOX_SAVEDATA_TYPE_SECRET_KEY,
} Tox_Savedata_Type;
const char *tox_savedata_type_to_string(Tox_Savedata_Type value);
/**
* @brief This event is triggered when Tox logs an internal message.
*
* This is mostly useful for debugging. This callback can be called from any
* function, not just tox_iterate. This means the user data lifetime must at
* least extend between registering and unregistering it or tox_kill.
*
* Other toxcore modules such as toxav may concurrently call this callback at
* any time. Thus, user code must make sure it is equipped to handle concurrent
* execution, e.g. by employing appropriate mutex locking.
*
* When using the experimental_thread_safety option, no Tox API functions can
* be called from within the log callback.
*
* @param level The severity of the log message.
* @param file The source file from which the message originated.
* @param line The source line from which the message originated.
* @param func The function from which the message originated.
* @param message The log message.
* @param user_data The user data pointer passed to tox_new in options.
*/
typedef void tox_log_cb(struct Tox *tox, Tox_Log_Level level, const char *file,
uint32_t line, const char *func, const char *message,
void *user_data);
/**
* @brief This struct contains all the startup options for Tox.
*
* You must tox_options_new to allocate an object of this type.
*
* WARNING: Although this struct happens to be visible in the API, it is
* effectively private. Do not allocate this yourself or access members
* directly, as it *will* break binary compatibility frequently.
*
* @deprecated The memory layout of this struct (size, alignment, and field
* order) is not part of the ABI. To remain compatible, prefer to use
* tox_options_new to allocate the object and accessor functions to set the
* members. The struct will become opaque (i.e. the definition will become
* private) in v0.3.0.
*/
typedef struct Tox_Options Tox_Options;
#ifndef TOX_HIDE_DEPRECATED
struct Tox_Options {
/**
* The type of socket to create.
*
* If this is set to false, an IPv4 socket is created, which subsequently
* only allows IPv4 communication.
* If it is set to true, an IPv6 socket is created, allowing both IPv4 and
* IPv6 communication.
*/
bool ipv6_enabled;
/**
* Enable the use of UDP communication when available.
*
* Setting this to false will force Tox to use TCP only. Communications will
* need to be relayed through a TCP relay node, potentially slowing them
* down.
*
* If a proxy is enabled, UDP will be disabled if either the Tox library or
* the proxy don't support proxying UDP messages.
*/
bool udp_enabled;
/**
* Enable local network peer discovery.
*
* Disabling this will cause Tox to not look for peers on the local network.
*/
bool local_discovery_enabled;
/**
* Enable storing DHT announcements and forwarding corresponding requests.
*
* Disabling this will cause Tox to ignore the relevant packets.
*/
bool dht_announcements_enabled;
/**
* Pass communications through a proxy.
*/
Tox_Proxy_Type proxy_type;
/**
* The IP address or DNS name of the proxy to be used.
*
* If used, this must be non-NULL and be a valid DNS name. The name must not
* exceed TOX_MAX_HOSTNAME_LENGTH characters, and be in a NUL-terminated C
* string format (TOX_MAX_HOSTNAME_LENGTH includes the NUL byte).
*
* This member is ignored (it can be NULL) if proxy_type is
* TOX_PROXY_TYPE_NONE.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object (unless experimental_owned_data is set).
*/
const char *proxy_host;
/**
* The port to use to connect to the proxy server.
*
* Ports must be in the range (1, 65535). The value is ignored if
* proxy_type is TOX_PROXY_TYPE_NONE.
*/
uint16_t proxy_port;
/**
* The start port of the inclusive port range to attempt to use.
*
* If both start_port and end_port are 0, the default port range will be
* used: `[33445, 33545]`.
*
* If either start_port or end_port is 0 while the other is non-zero, the
* non-zero port will be the only port in the range.
*
* Having start_port > end_port will yield the same behavior as if
* start_port and end_port were swapped.
*/
uint16_t start_port;
/**
* The end port of the inclusive port range to attempt to use.
*/
uint16_t end_port;
/**
* The port to use for the TCP server (relay). If 0, the TCP server is
* disabled.
*
* Enabling it is not required for Tox to function properly.
*
* When enabled, your Tox instance can act as a TCP relay for other Tox
* instance. This leads to increased traffic, thus when writing a client
* it is recommended to enable TCP server only if the user has an option
* to disable it.
*/
uint16_t tcp_port;
/**
* Enables or disables UDP hole-punching. (Default: enabled).
*/
bool hole_punching_enabled;
/**
* The type of savedata to load from.
*/
Tox_Savedata_Type savedata_type;
/**
* The savedata (either a Tox save or a secret key) to load from.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object (unless experimental_owned_data is set).
*/
const uint8_t *savedata_data;
/**
* The length of the savedata.
*/
size_t savedata_length;
/**
* Logging callback for the new Tox instance.
*/
tox_log_cb *log_callback;
/**
* User data pointer passed to the logging callback.
*/
void *log_user_data;
/**
* These options are experimental, so avoid writing code that depends on
* them. Options marked "experimental" may change their behaviour or go away
* entirely in the future, or may be renamed to something non-experimental
* if they become part of the supported API.
*/
/**
* Make public API functions thread-safe using a per-instance lock.
*
* Default: false.
*/
bool experimental_thread_safety;
/**
* Enable saving DHT-based group chats to Tox save data (via
* `tox_get_savedata`). This format will change in the future, so don't rely
* on it.
*
* As an alternative, clients can save the group chat ID in client-owned
* savedata. Then, when the client starts, it can use `tox_group_join`
* with the saved chat ID to recreate the group chat.
*
* Default: false.
*/
bool experimental_groups_persistence;
/**
* @brief Disable DNS hostname resolution.
*
* Hostnames or IP addresses are passed to the bootstrap/add_tcp_relay
* function and proxy host options. If disabled (this flag is true), only
* IP addresses are allowed.
*
* If this is set to true, the library will not attempt to resolve
* hostnames. This is useful for clients that want to resolve hostnames
* themselves and pass the resolved IP addresses to the library (e.g. in
* case it wants to use Tor).
* Passing hostnames will result in a TOX_ERR_BOOTSTRAP_BAD_HOST error if
* this is set to true.
*
* Default: false. May become true in the future (0.3.0).
*/
bool experimental_disable_dns;
/**
* @brief Whether the savedata data is owned by the Tox_Options object.
*
* If true, the setters for savedata and proxy_host try to copy the string.
* If that fails, the value is not copied and the member is set to the
* user-provided pointer. In that case, the user must not free the string
* until the Tox_Options object is freed. Client code can check whether
* allocation succeeded by checking the returned bool. If
* experimental_owned_data is false, it will always return true. If set to
* true, the return value will be false on allocation failure.
*
* If set to true, this must be set before any other member that allocates
* memory is set.
*/
bool experimental_owned_data;
/**
* @brief Owned pointer to the savedata data.
* @private
*/
uint8_t *owned_savedata_data;
/**
* @brief Owned pointer to the proxy host.
* @private
*/
char *owned_proxy_host;
};
#endif /* TOX_HIDE_DEPRECATED */
bool tox_options_get_ipv6_enabled(const Tox_Options *options);
void tox_options_set_ipv6_enabled(Tox_Options *options, bool ipv6_enabled);
bool tox_options_get_udp_enabled(const Tox_Options *options);
void tox_options_set_udp_enabled(Tox_Options *options, bool udp_enabled);
bool tox_options_get_local_discovery_enabled(const Tox_Options *options);
void tox_options_set_local_discovery_enabled(Tox_Options *options, bool local_discovery_enabled);
bool tox_options_get_dht_announcements_enabled(const Tox_Options *options);
void tox_options_set_dht_announcements_enabled(
Tox_Options *options, bool dht_announcements_enabled);
Tox_Proxy_Type tox_options_get_proxy_type(const Tox_Options *options);
void tox_options_set_proxy_type(Tox_Options *options, Tox_Proxy_Type proxy_type);
const char *tox_options_get_proxy_host(const Tox_Options *options);
bool tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host);
uint16_t tox_options_get_proxy_port(const Tox_Options *options);
void tox_options_set_proxy_port(Tox_Options *options, uint16_t proxy_port);
uint16_t tox_options_get_start_port(const Tox_Options *options);
void tox_options_set_start_port(Tox_Options *options, uint16_t start_port);
uint16_t tox_options_get_end_port(const Tox_Options *options);
void tox_options_set_end_port(Tox_Options *options, uint16_t end_port);
uint16_t tox_options_get_tcp_port(const Tox_Options *options);
void tox_options_set_tcp_port(Tox_Options *options, uint16_t tcp_port);
bool tox_options_get_hole_punching_enabled(const Tox_Options *options);
void tox_options_set_hole_punching_enabled(Tox_Options *options, bool hole_punching_enabled);
Tox_Savedata_Type tox_options_get_savedata_type(const Tox_Options *options);
void tox_options_set_savedata_type(Tox_Options *options, Tox_Savedata_Type savedata_type);
const uint8_t *tox_options_get_savedata_data(const Tox_Options *options);
bool tox_options_set_savedata_data(
Tox_Options *options, const uint8_t savedata_data[], size_t length);
size_t tox_options_get_savedata_length(const Tox_Options *options);
void tox_options_set_savedata_length(Tox_Options *options, size_t savedata_length);
tox_log_cb *tox_options_get_log_callback(const Tox_Options *options);
void tox_options_set_log_callback(Tox_Options *options, tox_log_cb *log_callback);
void *tox_options_get_log_user_data(const Tox_Options *options);
void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data);
bool tox_options_get_experimental_owned_data(const Tox_Options *options);
void tox_options_set_experimental_owned_data(Tox_Options *options, bool experimental_owned_data);
bool tox_options_get_experimental_thread_safety(const Tox_Options *options);
void tox_options_set_experimental_thread_safety(
Tox_Options *options, bool experimental_thread_safety);
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options);
void tox_options_set_experimental_groups_persistence(
Tox_Options *options, bool experimental_groups_persistence);
bool tox_options_get_experimental_disable_dns(const Tox_Options *options);
void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns);
/**
* @brief Initialises a Tox_Options object with the default options.
*
* The result of this function is independent of the original options. All
* values will be overwritten, no values will be read (so it is permissible
* to pass an uninitialised object).
*
* If options is NULL, this function has no effect.
*
* @param options An options object to be filled with default options.
*/
void tox_options_default(Tox_Options *options);
typedef enum Tox_Err_Options_New {
/**
* The function returned successfully.
*/
TOX_ERR_OPTIONS_NEW_OK,
/**
* The function failed to allocate enough memory for the options struct.
*/
TOX_ERR_OPTIONS_NEW_MALLOC,
} Tox_Err_Options_New;
const char *tox_err_options_new_to_string(Tox_Err_Options_New value);
/**
* @brief Allocates a new Tox_Options object and initialises it with the default
* options.
*
* This function can be used to preserve long term ABI compatibility by
* giving the responsibility of allocation and deallocation to the Tox library.
*
* Objects returned from this function must be freed using the tox_options_free
* function.
*
* @return A new Tox_Options object with default options or NULL on failure.
*/
Tox_Options *tox_options_new(Tox_Err_Options_New *error);
/**
* @brief Releases all resources associated with an options objects.
*
* Passing a pointer that was not returned by tox_options_new results in
* undefined behaviour.
*/
void tox_options_free(Tox_Options *options);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* C_TOXCORE_TOXCORE_TOX_OPTIONS_H */

View File

@ -11,8 +11,8 @@
#include <assert.h>
#include "DHT.h"
#include "Messenger.h"
#include "TCP_server.h"
#include "attributes.h"
#include "ccompat.h"
#include "crypto_core.h"
#include "group_chats.h"
@ -23,7 +23,7 @@
#include "net_profile.h"
#include "network.h"
#include "tox.h"
#include "tox_struct.h"
#include "tox_struct.h" // IWYU pragma: keep
#define SET_ERROR_PARAMETER(param, x) \
do { \
@ -94,33 +94,33 @@ void *tox_get_av_object(const Tox *tox)
return object;
}
void tox_callback_dht_get_nodes_response(Tox *tox, tox_dht_get_nodes_response_cb *callback)
void tox_callback_dht_nodes_response(Tox *tox, tox_dht_nodes_response_cb *callback)
{
assert(tox != nullptr);
tox->dht_get_nodes_response_callback = callback;
tox->dht_nodes_response_callback = callback;
}
bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port,
const uint8_t *target_public_key, Tox_Err_Dht_Get_Nodes *error)
bool tox_dht_send_nodes_request(const Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port,
const uint8_t *target_public_key, Tox_Err_Dht_Send_Nodes_Request *error)
{
assert(tox != nullptr);
tox_lock(tox);
if (tox->m->options.udp_disabled) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_UDP_DISABLED);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_UDP_DISABLED);
tox_unlock(tox);
return false;
}
if (public_key == nullptr || ip == nullptr || target_public_key == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_NULL);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_NULL);
tox_unlock(tox);
return false;
}
if (port == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_BAD_PORT);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_BAD_PORT);
tox_unlock(tox);
return false;
}
@ -130,7 +130,7 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip
const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, ip, &root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled);
if (count < 1) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_BAD_IP);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_BAD_IP);
net_freeipport(tox->sys.mem, root);
tox_unlock(tox);
return false;
@ -141,7 +141,7 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip
for (int32_t i = 0; i < count; ++i) {
root[i].port = net_htons(port);
if (dht_getnodes(tox->m->dht, &root[i], public_key, target_public_key)) {
if (dht_send_nodes_request(tox->m->dht, &root[i], public_key, target_public_key)) {
success = true;
}
}
@ -151,11 +151,11 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip
net_freeipport(tox->sys.mem, root);
if (!success) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_FAIL);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_FAIL);
return false;
}
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_OK);
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_SEND_NODES_REQUEST_OK);
return true;
}

View File

@ -11,6 +11,7 @@
#include <stdint.h>
#include "tox.h"
#include "tox_options.h"
#ifdef __cplusplus
extern "C" {
@ -92,52 +93,53 @@ uint32_t tox_dht_node_public_key_size(void);
* @param ip The node's IP address, represented as a NUL-terminated C string.
* @param port The node's port.
*/
typedef void tox_dht_get_nodes_response_cb(Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port,
void *user_data);
typedef void tox_dht_nodes_response_cb(
Tox *tox, const uint8_t *public_key, const char *ip, uint32_t ip_length,
uint16_t port, void *user_data);
/**
* Set the callback for the `dht_get_nodes_response` event. Pass NULL to unset.
* Set the callback for the `dht_nodes_response` event. Pass NULL to unset.
*
* This event is triggered when a getnodes response is received from a DHT peer.
* This event is triggered when a nodes response is received from a DHT peer.
*/
void tox_callback_dht_get_nodes_response(Tox *tox, tox_dht_get_nodes_response_cb *callback);
void tox_callback_dht_nodes_response(Tox *tox, tox_dht_nodes_response_cb *callback);
typedef enum Tox_Err_Dht_Get_Nodes {
typedef enum Tox_Err_Dht_Send_Nodes_Request {
/**
* The function returned successfully.
*/
TOX_ERR_DHT_GET_NODES_OK,
TOX_ERR_DHT_SEND_NODES_REQUEST_OK,
/**
* UDP is disabled in Tox options; the DHT can only be queried when UDP is
* enabled.
*/
TOX_ERR_DHT_GET_NODES_UDP_DISABLED,
TOX_ERR_DHT_SEND_NODES_REQUEST_UDP_DISABLED,
/**
* One of the arguments to the function was NULL when it was not expected.
*/
TOX_ERR_DHT_GET_NODES_NULL,
TOX_ERR_DHT_SEND_NODES_REQUEST_NULL,
/**
* The supplied port is invalid.
*/
TOX_ERR_DHT_GET_NODES_BAD_PORT,
TOX_ERR_DHT_SEND_NODES_REQUEST_BAD_PORT,
/**
* The supplied IP address is invalid.
*/
TOX_ERR_DHT_GET_NODES_BAD_IP,
TOX_ERR_DHT_SEND_NODES_REQUEST_BAD_IP,
/**
* The getnodes request failed. This usually means the packet failed to
* The nodes request failed. This usually means the packet failed to
* send.
*/
TOX_ERR_DHT_GET_NODES_FAIL,
} Tox_Err_Dht_Get_Nodes;
TOX_ERR_DHT_SEND_NODES_REQUEST_FAIL,
} Tox_Err_Dht_Send_Nodes_Request;
/**
* This function sends a getnodes request to a DHT node for its peers that
* This function sends a nodes request to a DHT node for its peers that
* are "close" to the passed target public key according to the distance metric
* used by the DHT implementation.
*
@ -151,8 +153,8 @@ typedef enum Tox_Err_Dht_Get_Nodes {
*
* @return true on success.
*/
bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port,
const uint8_t *target_public_key, Tox_Err_Dht_Get_Nodes *error);
bool tox_dht_send_nodes_request(const Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port,
const uint8_t *target_public_key, Tox_Err_Dht_Send_Nodes_Request *error);
/**
* This function returns the number of DHT nodes in the closelist.
@ -201,7 +203,7 @@ typedef enum Tox_Netprof_Packet_Id {
TOX_NETPROF_PACKET_ID_ONE = 0x01,
/**
* Get nodes request packet (UDP).
* Nodes request packet (UDP).
* Connection notification (TCP).
*/
TOX_NETPROF_PACKET_ID_TWO = 0x02,
@ -212,7 +214,7 @@ typedef enum Tox_Netprof_Packet_Id {
TOX_NETPROF_PACKET_ID_TCP_DISCONNECT = 0x03,
/**
* Send nodes response packet (UDP).
* Nodes response packet (UDP).
* Ping packet (TCP).
*/
TOX_NETPROF_PACKET_ID_FOUR = 0x04,

View File

@ -8,10 +8,9 @@
#include <pthread.h>
#include "Messenger.h"
#include "mem.h"
#include "mono_time.h"
#include "tox.h"
#include "tox_options.h" // tox_log_cb
#include "tox_private.h"
#ifdef __cplusplus
@ -19,7 +18,7 @@ extern "C" {
#endif
struct Tox {
Messenger *m;
struct Messenger *m;
Mono_Time *mono_time;
Tox_System sys;
pthread_mutex_t *mutex;
@ -44,7 +43,7 @@ struct Tox {
tox_conference_title_cb *conference_title_callback;
tox_conference_peer_name_cb *conference_peer_name_callback;
tox_conference_peer_list_changed_cb *conference_peer_list_changed_callback;
tox_dht_get_nodes_response_cb *dht_get_nodes_response_callback;
tox_dht_nodes_response_cb *dht_nodes_response_callback;
tox_friend_lossy_packet_cb *friend_lossy_packet_callback_per_pktid[UINT8_MAX + 1];
tox_friend_lossless_packet_cb *friend_lossless_packet_callback_per_pktid[UINT8_MAX + 1];
tox_group_peer_name_cb *group_peer_name_callback;

View File

@ -6,6 +6,8 @@
#include <vector>
#include "crypto_core.h"
#include "tox_log_level.h"
#include "tox_options.h"
#include "tox_private.h"
namespace {