Compare commits

..

2 Commits

Author SHA1 Message Date
260d3b7818
Merge commit '83e200df43eb790719c40103099c8d70e37c0477' 2023-12-24 12:21:34 +01:00
83e200df43 Squashed 'external/toxcore/c-toxcore/' changes from adbd5b32d8..e29e185c03
e29e185c03 feat: add ngc events
2b0dc0f46b add ngc related unpack functions
b2315c50e0 Add groupchat API function that returns an IP address string for a peer
5f863a5492 feat: Add `to_string` functions for all public enums.
0c998a7598 add real timeout test
68c827609a chore: Move s390x build to post-merge.
028b017d79 perf: Slightly reduce bandwidth usage when there are few nodes.
90f7496819 feat: Enable ubsan on bootstrap nodes.
89b6450d66 test: Add check-c run to bazel build.
REVERT: adbd5b32d8 feat: add ngc events

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: e29e185c03fea7337036e5ef4d1d9080a6cee721
2023-12-24 12:21:34 +01:00
40 changed files with 2174 additions and 114 deletions

View File

@ -90,16 +90,6 @@ jobs:
with:
file: other/docker/compcert/Dockerfile
build-alpine-s390x:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker Build
uses: docker/build-push-action@v2
with:
file: other/docker/alpine-s390x/Dockerfile
cimplefmt:
runs-on: ubuntu-latest
steps:

View File

@ -0,0 +1,16 @@
name: post-submit
on:
push:
branches: [master]
jobs:
build-alpine-s390x:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker Build
uses: docker/build-push-action@v2
with:
file: other/docker/alpine-s390x/Dockerfile

View File

@ -453,6 +453,7 @@ unit_test(toxcore bin_pack)
unit_test(toxcore crypto_core)
unit_test(toxcore group_announce)
unit_test(toxcore group_moderation)
unit_test(toxcore list)
unit_test(toxcore mem)
unit_test(toxcore mono_time)
unit_test(toxcore ping_array)

View File

@ -9,6 +9,7 @@
#include <string.h>
#include "auto_test_support.h"
#include "../toxcore/tox_private.h"
typedef struct State {
size_t peer_joined_count;
@ -42,6 +43,22 @@ typedef struct State {
#define PEER_LIMIT 20
static void print_ip(Tox *tox, uint32_t groupnumber, uint32_t peer_id)
{
Tox_Err_Group_Peer_Query err;
size_t length = tox_group_peer_get_ip_address_size(tox, groupnumber, peer_id, &err);
ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address size: error %d", err);
uint8_t ip_str[TOX_GROUP_PEER_IP_STRING_MAX_LENGTH];
tox_group_peer_get_ip_address(tox, groupnumber, peer_id, ip_str, &err);
ip_str[length] = '\0';
ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address: error %d", err);
fprintf(stderr, "%s\n", ip_str);
}
static bool all_group_peers_connected(AutoTox *autotoxes, uint32_t tox_count, uint32_t groupnumber, size_t name_length)
{
for (size_t i = 0; i < tox_count; ++i) {
@ -119,6 +136,9 @@ static void group_peer_join_handler(Tox *tox, uint32_t groupnumber, uint32_t pee
}
}
fprintf(stderr, "%s joined with IP: ", peer_name);
print_ip(tox, groupnumber, peer_id);
state->peer_id = peer_id;
++state->peer_joined_count;
}
@ -178,6 +198,11 @@ static void group_peer_self_join_handler(Tox *tox, uint32_t groupnumber, void *u
ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERIES_OK, "%d", query_err);
ck_assert(memcmp(topic, TOPIC, TOPIC_LEN) == 0);
uint32_t peer_id = tox_group_self_get_peer_id(tox, groupnumber, nullptr);
fprintf(stderr, "self joined with IP: ");
print_ip(tox, groupnumber, peer_id);
++state->self_joined_count;
}
@ -341,6 +366,7 @@ static void group_announce_test(AutoTox *autotoxes)
ck_assert(memcmp(tox0_pk_query, tox0_self_pk, TOX_GROUP_PEER_PUBLIC_KEY_SIZE) == 0);
fprintf(stderr, "Peer 0 disconnecting...\n");
// tox 0 disconnects then reconnects
Tox_Err_Group_Disconnect d_err;
tox_group_disconnect(tox0, groupnumber, &d_err);

View File

@ -53,7 +53,7 @@ static int handle_test_1(void *object, const IP_Port *source, const uint8_t *pac
res_packet[0] = NET_PACKET_ANNOUNCE_RESPONSE;
memcpy(res_packet + 1, res_message, sizeof(res_message));
if (send_onion_response(onion->net, source, res_packet, sizeof(res_packet),
if (send_onion_response(onion->log, onion->net, source, res_packet, sizeof(res_packet),
packet + sizeof(res_packet)) == -1) {
return 1;
}
@ -293,7 +293,7 @@ static void test_basic(void)
uint64_t s;
memcpy(&s, sb_data, sizeof(uint64_t));
memcpy(test_3_pub_key, nodes[3].public_key, CRYPTO_PUBLIC_KEY_SIZE);
int ret = send_announce_request(onion1->net, rng, &path, &nodes[3],
int ret = send_announce_request(log1, onion1->net, rng, &path, &nodes[3],
dht_get_self_public_key(onion1->dht),
dht_get_self_secret_key(onion1->dht),
zeroes,
@ -315,7 +315,7 @@ static void test_basic(void)
memcpy(onion_announce_entry_public_key(onion2_a, 1), dht_get_self_public_key(onion2->dht), CRYPTO_PUBLIC_KEY_SIZE);
onion_announce_entry_set_time(onion2_a, 1, mono_time_get(mono_time2));
networking_registerhandler(onion1->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_test_4, onion1);
send_announce_request(onion1->net, rng, &path, &nodes[3],
send_announce_request(log1, onion1->net, rng, &path, &nodes[3],
dht_get_self_public_key(onion1->dht),
dht_get_self_secret_key(onion1->dht),
test_3_ping_id,
@ -340,7 +340,7 @@ static void test_basic(void)
ck_assert_msg((onion3 != nullptr), "Onion failed initializing.");
random_nonce(rng, nonce);
ret = send_data_request(onion3->net, rng, &path, &nodes[3].ip_port,
ret = send_data_request(log3, onion3->net, rng, &path, &nodes[3].ip_port,
dht_get_self_public_key(onion1->dht),
dht_get_self_public_key(onion1->dht),
nonce, (const uint8_t *)"Install gentoo", sizeof("Install gentoo"));

View File

@ -10,6 +10,7 @@
#include "../toxcore/tox.h"
#include "../toxcore/tox_dispatch.h"
#include "../toxcore/tox_events.h"
#include "../toxcore/tox_unpack.h"
#include "auto_test_support.h"
#include "check_compat.h"
@ -160,9 +161,22 @@ static void test_tox_events(void)
}
}
static void fake_test_unpack(void)
{
// TODO(Green-Sky): add proper unpack tests and/or implement ngc events
(void)tox_unpack_group_privacy_state;
(void)tox_unpack_group_privacy_state;
(void)tox_unpack_group_voice_state;
(void)tox_unpack_group_topic_lock;
(void)tox_unpack_group_join_fail;
(void)tox_unpack_group_mod_event;
(void)tox_unpack_group_exit_type;
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
test_tox_events();
fake_test_unpack();
return 0;
}

View File

@ -1,15 +1,16 @@
###########################################################
# Builder image: we compile the code here (static build)
FROM alpine:3.18.5 AS build
FROM alpine:3.19.0 AS build
RUN ["apk", "--no-cache", "add",\
"build-base",\
"clang",\
"cmake",\
"linux-headers",\
"libconfig-dev",\
"libconfig-static",\
"libsodium-dev",\
"libsodium-static",\
"musl-dev",\
"ninja",\
"python3"\
]
@ -34,9 +35,9 @@ COPY CMakeLists.txt so.version ./
COPY other/bootstrap_daemon/CMakeLists.txt other/bootstrap_daemon/CMakeLists.txt
COPY testing/CMakeLists.txt testing/CMakeLists.txt
RUN cmake -B_build -H. \
RUN CC=clang cmake -B_build -H. \
-GNinja \
-DCMAKE_C_FLAGS="-DTCP_SERVER_USE_EPOLL -fstack-protector-all -fisolate-erroneous-paths-attribute" \
-DCMAKE_C_FLAGS="-DTCP_SERVER_USE_EPOLL -fsanitize=alignment,return,returns-nonnull-attribute,vla-bound,unreachable,float-cast-overflow,null -fsanitize-trap=all -fstack-protector-all" \
-DCMAKE_UNITY_BUILD=ON \
-DCMAKE_BUILD_TYPE=Release \
-DFULLY_STATIC=ON \

View File

@ -1 +1 @@
5aac1df4d6c1de289e8e9f646d06099c84fd4d9b80d19f45e3254eec3ece2bff /usr/local/bin/tox-bootstrapd
21cf23b1a2e46712663dc4f8daa322991af51b9e82626a127cf1bc8dc583b598 /usr/local/bin/tox-bootstrapd

View File

@ -22,6 +22,28 @@ sh_test(
tags = ["haskell"],
)
sh_test(
name = "c_test",
size = "small",
srcs = ["//hs-tokstyle/tools:check-c"],
args = [
"--cc=$(CC)",
"-Iexternal/libsodium/include",
"-Iexternal/libvpx",
"-Iexternal/opus/include",
"-Ihs-tokstyle/include",
] + ["$(locations %s)" % f for f in CIMPLE_FILES],
data = CIMPLE_FILES + [
"//c-toxcore/third_party:headers",
"//hs-tokstyle:headers",
"@libsodium//:headers",
"@libvpx//:headers",
"@opus//:headers",
],
tags = ["haskell"],
toolchains = ["@rules_cc//cc:current_cc_toolchain"],
)
sh_test(
name = "cimplefmt_test",
size = "small",

View File

@ -7,3 +7,9 @@ cc_library(
copts = ["-DCMP_NO_FLOAT"],
visibility = ["//c-toxcore:__subpackages__"],
)
filegroup(
name = "headers",
srcs = ["cmp/cmp.h"],
visibility = ["//c-toxcore:__subpackages__"],
)

View File

@ -821,6 +821,7 @@ static void handle_pop(MSICall *call, const MSIMessage *msg)
switch (call->state) {
case MSI_CALL_INACTIVE: {
LOGGER_FATAL(call->session->messenger->log, "Handling what should be impossible case");
break;
}
case MSI_CALL_ACTIVE: {

View File

@ -201,6 +201,7 @@ cc_library(
":attributes",
":ccompat",
":mem",
":util",
"@pthread",
],
)
@ -230,6 +231,7 @@ cc_library(
deps = [
":ccompat",
":crypto_core",
":logger",
":mem",
":mono_time",
],

View File

@ -1828,7 +1828,9 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
++not_kill;
if (mono_time_is_timeout(dht->mono_time, assoc->last_pinged, PING_INTERVAL)) {
dht_getnodes(dht, &assoc->ip_port, client->public_key, public_key);
const IP_Port *target = &assoc->ip_port;
const uint8_t *target_key = client->public_key;
dht_getnodes(dht, target, target_key, public_key);
assoc->last_pinged = temp_time;
}
@ -1861,7 +1863,9 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
rand_node += random_range_u32(dht->rng, num_nodes - (rand_node + 1));
}
dht_getnodes(dht, &assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key);
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);
*lastgetnode = temp_time;
++*bootstrap_times;
@ -1890,8 +1894,7 @@ static void do_dht_friends(DHT *dht)
dht_friend->num_to_bootstrap = 0;
do_ping_and_sendnode_requests(dht, &dht_friend->lastgetnode, dht_friend->public_key, dht_friend->client_list,
MAX_FRIEND_CLIENTS,
&dht_friend->bootstrap_times, true);
MAX_FRIEND_CLIENTS, &dht_friend->bootstrap_times, true);
}
}
@ -2634,6 +2637,7 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
DHT *const dht = (DHT *)mem_alloc(mem, sizeof(DHT));
if (dht == nullptr) {
LOGGER_ERROR(log, "failed to allocate DHT struct (%ld bytes)", (unsigned long)sizeof(DHT));
return nullptr;
}
@ -2651,6 +2655,7 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
dht->ping = ping_new(mem, mono_time, rng, dht);
if (dht->ping == nullptr) {
LOGGER_ERROR(log, "failed to initialise ping");
kill_dht(dht);
return nullptr;
}
@ -2667,10 +2672,11 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
crypto_new_keypair(rng, dht->self_public_key, dht->self_secret_key);
dht->shared_keys_recv = shared_key_cache_new(mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
dht->shared_keys_sent = shared_key_cache_new(mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
dht->shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
dht->shared_keys_sent = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (dht->shared_keys_recv == nullptr || dht->shared_keys_sent == nullptr) {
LOGGER_ERROR(log, "failed to initialise shared key cache");
kill_dht(dht);
return nullptr;
}
@ -2679,6 +2685,7 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
dht->dht_ping_array = ping_array_new(mem, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
if (dht->dht_ping_array == nullptr) {
LOGGER_ERROR(log, "failed to initialise ping array");
kill_dht(dht);
return nullptr;
}
@ -2691,6 +2698,7 @@ DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Netw
uint32_t token; // We don't intend to delete these ever, but need to pass the token
if (dht_addfriend(dht, random_public_key_bytes, nullptr, nullptr, 0, &token) != 0) {
LOGGER_ERROR(log, "failed to add initial random seed DHT friends");
kill_dht(dht);
return nullptr;
}

View File

@ -3583,6 +3583,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
mem_delete(mem, m);
if (error != nullptr && net_err == 1) {
LOGGER_WARNING(m->log, "network initialisation failed (no ports available)");
*error = MESSENGER_ERROR_PORT;
}
@ -3602,6 +3603,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->dht, &options->proxy_info);
if (m->net_crypto == nullptr) {
LOGGER_WARNING(m->log, "net_crypto initialisation failed");
kill_dht(m->dht);
kill_networking(m->net);
friendreq_kill(m->fr);
@ -3614,6 +3617,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->group_announce = new_gca_list();
if (m->group_announce == nullptr) {
LOGGER_WARNING(m->log, "DHT group chats initialisation failed");
kill_net_crypto(m->net_crypto);
kill_dht(m->dht);
kill_networking(m->net);
@ -3642,6 +3647,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {
LOGGER_WARNING(m->log, "onion initialisation failed");
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
kill_onion_client(m->onion_c);
@ -3666,6 +3673,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->group_handler = new_dht_groupchats(m);
if (m->group_handler == nullptr) {
LOGGER_WARNING(m->log, "conferences initialisation failed");
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
kill_onion_client(m->onion_c);
@ -3690,6 +3699,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->onion, m->forwarding);
if (m->tcp_server == nullptr) {
LOGGER_WARNING(m->log, "TCP server initialisation failed");
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
#ifndef VANILLA_NACL

View File

@ -201,7 +201,11 @@ int read_tcp_packet(
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
if (count < length) {
LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
if (count != 0) {
// Only log when there are some bytes available, as empty buffer
// is a very common case and this spams our logs.
LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
}
return -1;
}

View File

@ -120,7 +120,7 @@ bool tcp_get_random_conn_ip_port(const TCP_Connections *tcp_c, IP_Port *ip_port)
* return -1 on failure.
*/
non_null()
int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data,
int tcp_send_onion_request(TCP_Connections *tcp_c, uint32_t tcp_connections_number, const uint8_t *data,
uint16_t length);
/** @brief Set if we want TCP_connection to allocate some connection for onion use.

View File

@ -660,7 +660,7 @@ Announcements *new_announcements(const Logger *log, const Memory *mem, const Ran
announce->public_key = dht_get_self_public_key(announce->dht);
announce->secret_key = dht_get_self_secret_key(announce->dht);
new_hmac_key(announce->rng, announce->hmac_key);
announce->shared_keys = shared_key_cache_new(mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
announce->shared_keys = shared_key_cache_new(log, mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (announce->shared_keys == nullptr) {
free(announce);
return nullptr;

View File

@ -3517,6 +3517,63 @@ int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uin
return 0;
}
/** @brief Puts a string of the IP associated with `ip_port` in `ip_str` if the
* connection is direct, otherwise puts a placeholder in the buffer indicating that
* the IP cannot be displayed.
*/
non_null()
static void get_gc_ip_ntoa(const IP_Port *ip_port, Ip_Ntoa *ip_str)
{
net_ip_ntoa(&ip_port->ip, ip_str);
if (!ip_str->ip_is_valid) {
ip_str->buf[0] = '-';
ip_str->buf[1] = '\0';
ip_str->length = 1;
}
}
int gc_get_peer_ip_address_size(const GC_Chat *chat, uint32_t peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
const GC_Connection *gconn = get_gc_connection(chat, peer_number);
if (gconn == nullptr) {
return -1;
}
const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
Ip_Ntoa ip_str;
get_gc_ip_ntoa(ip_port, &ip_str);
return ip_str.length;
}
int gc_get_peer_ip_address(const GC_Chat *chat, uint32_t peer_id, uint8_t *ip_addr)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
const GC_Connection *gconn = get_gc_connection(chat, peer_number);
if (gconn == nullptr) {
return -1;
}
if (ip_addr == nullptr) {
return -2;
}
const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
Ip_Ntoa ip_str;
get_gc_ip_ntoa(ip_port, &ip_str);
assert(ip_str.length <= IP_NTOA_LEN);
memcpy(ip_addr, ip_str.buf, ip_str.length);
return 0;
}
unsigned int gc_get_peer_connection_status(const GC_Chat *chat, uint32_t peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);

View File

@ -390,6 +390,29 @@ int gc_get_peer_nick_size(const GC_Chat *chat, uint32_t peer_id);
non_null(1) nullable(3)
int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uint8_t *public_key);
/** @brief Returns the length of the IP address for the peer designated by `peer_id`.
* Returns -1 if peer_id is invalid.
*/
non_null()
int gc_get_peer_ip_address_size(const GC_Chat *chat, uint32_t peer_id);
/** @brief Copies peer_id's IP address to `ip_addr`.
*
* If the peer is forcing TCP connections this will be a placeholder value indicating
* that their real IP address is unknown to us.
*
* If `peer_id` designates ourself, it will write either our own IP address or a
* placeholder value, depending on whether or not we're forcing TCP connections.
*
* `ip_addr` should have room for at least IP_NTOA_LEN bytes.
*
* Returns 0 on success.
* Returns -1 if peer_id is invalid or doesn't correspond to a valid peer connection.
* Returns -2 if `ip_addr` is null.
*/
non_null(1) nullable(3)
int gc_get_peer_ip_address(const GC_Chat *chat, uint32_t peer_id, uint8_t *ip_addr);
/** @brief Gets the connection status for peer associated with `peer_id`.
*
* If `peer_id` designates ourself, the return value indicates whether we're capable

View File

@ -117,3 +117,8 @@ void logger_write(const Logger *log, Logger_Level level, const char *file, int l
log->callback(log->context, level, file, line, func, msg, log->userdata);
}
void logger_abort(void)
{
abort();
}

View File

@ -67,6 +67,9 @@ void logger_write(
const Logger *log, Logger_Level level, const char *file, int line, const char *func,
const char *format, ...);
/* @brief Terminate the program with a signal. */
void logger_abort(void);
#define LOGGER_WRITE(log, level, ...) \
do { \
@ -85,7 +88,7 @@ void logger_write(
#define LOGGER_FATAL(log, ...) \
do { \
LOGGER_ERROR(log, __VA_ARGS__); \
abort(); \
logger_abort(); \
} while (0)
#define LOGGER_ASSERT(log, cond, ...) \

View File

@ -32,6 +32,7 @@
#include <time.h>
#include "ccompat.h"
#include "util.h"
/** don't call into system billions of times for no reason */
struct Mono_Time {
@ -165,7 +166,9 @@ Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_t
// Maximum reproducibility. Never return time = 0.
mono_time->base_time = 1;
#else
mono_time->base_time = (uint64_t)time(nullptr) * 1000ULL - current_time_monotonic(mono_time);
// Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
// without battery-powered RTC or ones where NTP didn't initialise it yet).
mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * 1000ULL - current_time_monotonic(mono_time);
#endif
mono_time_update(mono_time);

View File

@ -2,6 +2,9 @@
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
namespace {
TEST(MonoTime, UnixTimeIncreasesOverTime)
@ -41,6 +44,24 @@ TEST(MonoTime, IsTimeout)
mono_time_free(mem, mono_time);
}
TEST(MonoTime, IsTimeoutReal)
{
const Memory *mem = system_memory();
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr);
uint64_t const start = mono_time_get(mono_time);
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 5));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mono_time_update(mono_time);
// should still not have timed out (5sec) after sleeping ~100ms
EXPECT_FALSE(mono_time_is_timeout(mono_time, start, 5));
mono_time_free(mem, mono_time);
}
TEST(MonoTime, CustomTime)
{
const Memory *mem = system_memory();

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016-2018 The TokTok team.
* Copyright © 2016-2023 The TokTok team.
* Copyright © 2013 Tox project.
*/
@ -778,7 +778,7 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
Ip_Ntoa ip_str;
const int error = net_error();
char *strerror = net_new_strerror(error);
LOGGER_TRACE(log, "[%02x = %-20s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
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,
@ -786,14 +786,14 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
net_kill_strerror(strerror);
} else if ((res > 0) && ((size_t)res <= buflen)) {
Ip_Ntoa ip_str;
LOGGER_TRACE(log, "[%02x = %-20s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
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(res, 999), (size_t)res < buflen ? '<' : '=',
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK",
data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
} else { /* empty or overwrite */
Ip_Ntoa ip_str;
LOGGER_TRACE(log, "[%02x = %-20s] %s %lu%c%u %s:%u (%u: %s) | %08x%08x...%02x",
LOGGER_TRACE(log, "[%02x = %-21s] %s %lu%c%u %s:%u (%u: %s) | %08x%08x...%02x",
buffer[0], net_packet_type_name((Net_Packet_Type)buffer[0]), message,
res, res == 0 ? '!' : '>', buflen,
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK",
@ -1514,30 +1514,29 @@ void ipport_copy(IP_Port *target, const IP_Port *source)
*target = *source;
}
/** @brief Converts IP into a string.
*
* Writes error message into the buffer on error.
*
* @param ip_str contains a buffer of the required size.
*
* @return Pointer to the buffer inside `ip_str` containing the IP string.
*/
const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str)
{
assert(ip_str != nullptr);
ip_str->ip_is_valid = false;
if (ip == nullptr) {
snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid: NULL)");
ip_str->length = (uint16_t)strlen(ip_str->buf);
return ip_str->buf;
}
if (!ip_parse_addr(ip, ip_str->buf, sizeof(ip_str->buf))) {
snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid, family %u)", ip->family.value);
ip_str->length = (uint16_t)strlen(ip_str->buf);
return ip_str->buf;
}
/* brute force protection against lacking termination */
ip_str->buf[sizeof(ip_str->buf) - 1] = '\0';
ip_str->length = (uint16_t)strlen(ip_str->buf);
ip_str->ip_is_valid = true;
return ip_str->buf;
}

View File

@ -343,11 +343,14 @@ bool ipv6_ipv4_in_v6(const IP6 *a);
/** this would be TOX_INET6_ADDRSTRLEN, but it might be too short for the error message */
#define IP_NTOA_LEN 96 // TODO(irungentoo): magic number. Why not INET6_ADDRSTRLEN ?
/** Contains a null terminated string of an IP address. */
typedef struct Ip_Ntoa {
char buf[IP_NTOA_LEN];
char buf[IP_NTOA_LEN]; // a string formatted IP address or an error message.
uint16_t length; // the length of the string (not including the null byte).
bool ip_is_valid; // if this is false `buf` will contain an error message.
} Ip_Ntoa;
/** @brief Converts IP into a string.
/** @brief Converts IP into a null terminated string.
*
* Writes error message into the buffer on error.
*

View File

@ -283,22 +283,27 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac
* return -1 on failure.
* return 0 on success.
*/
int send_onion_response(const Networking_Core *net, const IP_Port *dest, const uint8_t *data, uint16_t length,
int send_onion_response(const Logger *log, const Networking_Core *net,
const IP_Port *dest, const uint8_t *data, uint16_t length,
const uint8_t *ret)
{
if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) {
return -1;
}
VLA(uint8_t, packet, 1 + RETURN_3 + length);
const uint16_t packet_size = 1 + RETURN_3 + length;
VLA(uint8_t, packet, packet_size);
packet[0] = NET_PACKET_ONION_RECV_3;
memcpy(packet + 1, ret, RETURN_3);
memcpy(packet + 1 + RETURN_3, data, length);
if ((uint32_t)sendpacket(net, dest, packet, SIZEOF_VLA(packet)) != SIZEOF_VLA(packet)) {
if ((uint16_t)sendpacket(net, dest, packet, packet_size) != packet_size) {
return -1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(log, "forwarded onion RECV_3 to %s:%d (%02x in %02x, %d bytes)",
net_ip_ntoa(&dest->ip, &ip_str), net_ntohs(dest->port), data[0], packet[0], packet_size);
return 0;
}
@ -309,28 +314,42 @@ static int handle_send_initial(void *object, const IP_Port *source, const uint8_
Onion *onion = (Onion *)object;
if (length > ONION_MAX_PACKET_SIZE) {
LOGGER_TRACE(onion->log, "invalid initial onion packet length: %u (max: %u)",
length, ONION_MAX_PACKET_SIZE);
return 1;
}
if (length <= 1 + SEND_1) {
LOGGER_TRACE(onion->log, "initial onion packet cannot contain SEND_1 packet: %u <= %u",
length, 1 + SEND_1);
return 1;
}
change_symmetric_key(onion);
const int nonce_start = 1;
const int public_key_start = nonce_start + CRYPTO_NONCE_SIZE;
const int ciphertext_start = public_key_start + CRYPTO_PUBLIC_KEY_SIZE;
const int ciphertext_length = length - ciphertext_start;
const int plaintext_length = ciphertext_length - CRYPTO_MAC_SIZE;
uint8_t plain[ONION_MAX_PACKET_SIZE];
const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE;
const uint8_t *public_key = &packet[public_key_start];
const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_1, public_key);
if (shared_key == nullptr) {
/* Error looking up/deriving the shared key */
LOGGER_TRACE(onion->log, "shared onion key lookup failed for pk %02x%02x...",
public_key[0], public_key[1]);
return 1;
}
const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain);
const int len = decrypt_data_symmetric(
shared_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_length, plain);
if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE)) {
if (len != plaintext_length) {
LOGGER_TRACE(onion->log, "decrypt failed: %d != %d", len, plaintext_length);
return 1;
}
@ -339,7 +358,9 @@ static int handle_send_initial(void *object, const IP_Port *source, const uint8_
int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, const IP_Port *source, const uint8_t *nonce)
{
if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + CRYPTO_NONCE_SIZE + ONION_RETURN_1)) {
const uint16_t max_len = ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + CRYPTO_NONCE_SIZE + ONION_RETURN_1);
if (len > max_len) {
LOGGER_TRACE(onion->log, "invalid SEND_1 length: %d > %d", len, max_len);
return 1;
}
@ -376,6 +397,9 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, const I
return 1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 1 (%02x in %02x, %d bytes)",
net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), plain[0], data[0], data_len);
return 0;
}
@ -439,6 +463,9 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac
return 1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 2 (%02x in %02x, %d bytes)",
net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len);
return 0;
}
@ -509,6 +536,9 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac
return 1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion->log, "forwarded onion packet to %s:%d, level 3 (%02x in %02x, %d bytes)",
net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len);
return 0;
}
@ -546,6 +576,7 @@ static int handle_recv_3(void *object, const IP_Port *source, const uint8_t *pac
IP_Port send_to;
if (ipport_unpack(&send_to, plain, len, false) == -1) {
LOGGER_DEBUG(onion->log, "failed to unpack IP/Port");
return 1;
}
@ -559,6 +590,9 @@ static int handle_recv_3(void *object, const IP_Port *source, const uint8_t *pac
return 1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion->log, "forwarded onion RECV_2 to %s:%d (%02x in %02x, %d bytes)",
net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len);
return 0;
}
@ -608,6 +642,9 @@ static int handle_recv_2(void *object, const IP_Port *source, const uint8_t *pac
return 1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion->log, "forwarded onion RECV_1 to %s:%d (%02x in %02x, %d bytes)",
net_ip_ntoa(&send_to.ip, &ip_str), net_ntohs(send_to.port), packet[0], data[0], data_len);
return 0;
}
@ -644,6 +681,7 @@ static int handle_recv_1(void *object, const IP_Port *source, const uint8_t *pac
IP_Port send_to;
if (ipport_unpack(&send_to, plain, len, true) == -1) {
LOGGER_DEBUG(onion->log, "failed to unpack IP/Port");
return 1;
}
@ -690,9 +728,9 @@ Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_tim
onion->timestamp = mono_time_get(onion->mono_time);
const uint8_t *secret_key = dht_get_self_secret_key(dht);
onion->shared_keys_1 = shared_key_cache_new(mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_2 = shared_key_cache_new(mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_3 = shared_key_cache_new(mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_1 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_2 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion->shared_keys_3 = shared_key_cache_new(log, mono_time, mem, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (onion->shared_keys_1 == nullptr ||
onion->shared_keys_2 == nullptr ||

View File

@ -127,7 +127,8 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac
* return 0 on success.
*/
non_null()
int send_onion_response(const Networking_Core *net, const IP_Port *dest, const uint8_t *data, uint16_t length,
int send_onion_response(const Logger *log, const Networking_Core *net,
const IP_Port *dest, const uint8_t *data, uint16_t length,
const uint8_t *ret);
/** @brief Function to handle/send received decrypted versions of the packet created by create_onion_packet.

View File

@ -186,11 +186,12 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_
* return -1 on failure.
* return 0 on success.
*/
int send_announce_request(const Networking_Core *net, const Random *rng,
const Onion_Path *path, const Node_format *dest,
const uint8_t *public_key, const uint8_t *secret_key,
const uint8_t *ping_id, const uint8_t *client_id,
const uint8_t *data_public_key, uint64_t sendback_data)
int send_announce_request(
const Logger *log, const Networking_Core *net, const Random *rng,
const Onion_Path *path, const Node_format *dest,
const uint8_t *public_key, const uint8_t *secret_key,
const uint8_t *ping_id, const uint8_t *client_id,
const uint8_t *data_public_key, uint64_t sendback_data)
{
uint8_t request[ONION_ANNOUNCE_REQUEST_MIN_SIZE];
int len = create_announce_request(rng, request, sizeof(request), dest->public_key, public_key, secret_key, ping_id,
@ -230,9 +231,10 @@ int send_announce_request(const Networking_Core *net, const Random *rng,
* return -1 on failure.
* return 0 on success.
*/
int send_data_request(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
const uint8_t *data, uint16_t length)
int send_data_request(
const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
const uint8_t *data, uint16_t length)
{
uint8_t request[ONION_MAX_DATA_SIZE];
int len = create_data_request(rng, request, sizeof(request), public_key, encrypt_public_key, nonce, data, length);
@ -549,7 +551,7 @@ static int handle_announce_request_common(
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, CRYPTO_NONCE_SIZE);
if (send_onion_response(onion_a->net, source, data,
if (send_onion_response(onion_a->log, onion_a->net, source, data,
1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + len,
packet + (length - ONION_RETURN_3)) == -1) {
mem_delete(onion_a->mem, response);
@ -634,7 +636,7 @@ static int handle_data_request(void *object, const IP_Port *source, const uint8_
data[0] = NET_PACKET_ONION_DATA_RESPONSE;
memcpy(data + 1, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_PUBLIC_KEY_SIZE + ONION_RETURN_3));
if (send_onion_response(onion_a->net, &onion_a->entries[index].ret_ip_port, data, SIZEOF_VLA(data),
if (send_onion_response(onion_a->log, onion_a->net, &onion_a->entries[index].ret_ip_port, data, SIZEOF_VLA(data),
onion_a->entries[index].ret) == -1) {
return 1;
}
@ -665,7 +667,7 @@ Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const R
onion_a->extra_data_object = nullptr;
new_hmac_key(rng, onion_a->hmac_key);
onion_a->shared_keys_recv = shared_key_cache_new(mono_time, mem, dht_get_self_secret_key(dht), KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
onion_a->shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht_get_self_secret_key(dht), KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
if (onion_a->shared_keys_recv == nullptr) {
kill_onion_announce(onion_a);
return nullptr;

View File

@ -94,11 +94,12 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_
* return 0 on success.
*/
non_null()
int send_announce_request(const Networking_Core *net, const Random *rng,
const Onion_Path *path, const Node_format *dest,
const uint8_t *public_key, const uint8_t *secret_key,
const uint8_t *ping_id, const uint8_t *client_id,
const uint8_t *data_public_key, uint64_t sendback_data);
int send_announce_request(
const Logger *log, const Networking_Core *net, const Random *rng,
const Onion_Path *path, const Node_format *dest,
const uint8_t *public_key, const uint8_t *secret_key,
const uint8_t *ping_id, const uint8_t *client_id,
const uint8_t *data_public_key, uint64_t sendback_data);
/** @brief Create and send an onion data request packet.
*
@ -117,9 +118,10 @@ int send_announce_request(const Networking_Core *net, const Random *rng,
* return 0 on success.
*/
non_null()
int send_data_request(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
const uint8_t *data, uint16_t length);
int send_data_request(
const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
const uint8_t *data, uint16_t length);
typedef int pack_extra_data_cb(void *object, const Logger *logger, const Mono_Time *mono_time,

View File

@ -582,6 +582,7 @@ static int new_sendback(Onion_Client *onion_c, uint32_t num, const uint8_t *publ
*sendback = ping_array_add(onion_c->announce_ping_array, onion_c->mono_time, onion_c->rng, data, sizeof(data));
if (*sendback == 0) {
LOGGER_TRACE(onion_c->logger, "generating sendback in announce ping array failed");
return -1;
}
@ -624,6 +625,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
const uint8_t *dest_pubkey, const uint8_t *ping_id, uint32_t pathnum)
{
if (num > onion_c->num_friends) {
LOGGER_TRACE(onion_c->logger, "not sending announce to out of bounds friend %u (num friends: %u)", num, onion_c->num_friends);
return -1;
}
@ -632,10 +634,12 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
if (num == 0) {
if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1) {
LOGGER_TRACE(onion_c->logger, "cannot find path to self");
return -1;
}
} else {
if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1) {
LOGGER_TRACE(onion_c->logger, "cannot find path to friend");
return -1;
}
}
@ -682,9 +686,13 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
}
if (len == -1) {
LOGGER_TRACE(onion_c->logger, "failed to create announce request");
return -1;
}
Ip_Ntoa ip_str;
LOGGER_TRACE(onion_c->logger, "sending onion packet to %s:%d (%02x, %d bytes)",
net_ip_ntoa(&dest->ip, &ip_str), net_ntohs(dest->port), request[0], len);
return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len);
}
@ -934,6 +942,8 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
Onion_Client *onion_c = (Onion_Client *)object;
if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) {
LOGGER_TRACE(onion_c->logger, "invalid announce response length: %u (min: %u, max: %u)",
length, (unsigned int)ONION_ANNOUNCE_RESPONSE_MIN_SIZE, (unsigned int)ONION_ANNOUNCE_RESPONSE_MAX_SIZE);
return 1;
}
@ -949,30 +959,37 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
uint8_t plain[1 + ONION_PING_ID_SIZE + ONION_ANNOUNCE_RESPONSE_MAX_SIZE - ONION_ANNOUNCE_RESPONSE_MIN_SIZE];
const int plain_size = 1 + ONION_PING_ID_SIZE + length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;
int len;
const uint16_t nonce_start = 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH;
const uint16_t ciphertext_start = nonce_start + CRYPTO_NONCE_SIZE;
const uint16_t ciphertext_size = length - ciphertext_start;
if (num == 0) {
len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c),
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
&packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain);
} else {
if (!onion_c->friends_list[num - 1].is_valid) {
LOGGER_TRACE(onion_c->logger, "friend number %lu is invalid", (unsigned long)(num - 1));
return 1;
}
len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
&packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain);
}
if (len < 0) {
// This happens a lot, so don't log it.
return 1;
}
if ((uint32_t)len != plain_size) {
LOGGER_WARNING(onion_c->logger, "decrypted size (%lu) is not the expected plain text size (%lu)", (unsigned long)len, (unsigned long)plain_size);
return 1;
}
const uint32_t path_used = set_path_timeouts(onion_c, num, path_num);
if (client_add_to_list(onion_c, num, public_key, &ip_port, plain[0], plain + 1, path_used) == -1) {
LOGGER_WARNING(onion_c->logger, "failed to add client to list");
return 1;
}
@ -989,10 +1006,12 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
plain_size - 2 - ONION_PING_ID_SIZE, false);
if (num_nodes < 0) {
LOGGER_WARNING(onion_c->logger, "no nodes to unpack in onion response");
return 1;
}
if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) {
LOGGER_WARNING(onion_c->logger, "pinging %d nodes failed", num_nodes);
return 1;
}
}
@ -1011,6 +1030,8 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
// TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline?
onion_c->last_packet_recv = mono_time_get(onion_c->mono_time);
LOGGER_TRACE(onion_c->logger, "onion has received a packet at %llu",
(unsigned long long)onion_c->last_packet_recv);
return 0;
}
@ -1023,6 +1044,8 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con
Onion_Client *onion_c = (Onion_Client *)object;
if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) {
LOGGER_TRACE(onion_c->logger, "invalid announce response length: %u (min: %u, max: %u)",
length, (unsigned int)ONION_ANNOUNCE_RESPONSE_MIN_SIZE, (unsigned int)ONION_ANNOUNCE_RESPONSE_MAX_SIZE);
return 1;
}
@ -1039,30 +1062,37 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con
VLA(uint8_t, plain, 1 + ONION_PING_ID_SIZE + len_nodes);
int len;
const uint16_t nonce_start = 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH;
const uint16_t ciphertext_start = nonce_start + CRYPTO_NONCE_SIZE;
const uint16_t ciphertext_size = length - ciphertext_start;
if (num == 0) {
len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c),
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
&packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain);
} else {
if (!onion_c->friends_list[num - 1].is_valid) {
LOGGER_TRACE(onion_c->logger, "friend number %lu is invalid", (unsigned long)(num - 1));
return 1;
}
len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
&packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain);
}
if (len < 0) {
// This happens a lot, so don't log it.
return 1;
}
if ((uint32_t)len != SIZEOF_VLA(plain)) {
LOGGER_WARNING(onion_c->logger, "decrypted size (%lu) is not the expected plain text size (%lu)", (unsigned long)len, (unsigned long)SIZEOF_VLA(plain));
return 1;
}
const uint32_t path_used = set_path_timeouts(onion_c, num, path_num);
if (client_add_to_list(onion_c, num, public_key, &ip_port, plain[0], plain + 1, path_used) == -1) {
LOGGER_WARNING(onion_c->logger, "failed to add client to list");
return 1;
}
@ -1071,16 +1101,21 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con
const int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, nullptr, plain + 1 + ONION_PING_ID_SIZE, len_nodes, false);
if (num_nodes <= 0) {
LOGGER_WARNING(onion_c->logger, "no nodes to unpack in onion response");
return 1;
}
if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) {
LOGGER_WARNING(onion_c->logger, "pinging %d nodes failed", num_nodes);
return 1;
}
}
// TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline?
onion_c->last_packet_recv = mono_time_get(onion_c->mono_time);
LOGGER_TRACE(onion_c->logger, "onion has received a packet at %llu",
(unsigned long long)onion_c->last_packet_recv);
return 0;
}
@ -1378,6 +1413,7 @@ static int handle_dht_dhtpk(void *object, const IP_Port *source, const uint8_t *
return handle_dhtpk_announce(onion_c, packet, plain, len, userdata);
}
/** @brief Send the packets to tell our friends what our DHT public key is.
*
* if onion_dht_both is 0, use only the onion to send the packet.
@ -1857,6 +1893,18 @@ void onion_group_announce_register(Onion_Client *onion_c, onion_group_announce_c
#define TIME_TO_STABLE (ONION_NODE_PING_INTERVAL * 6)
#define ANNOUNCE_INTERVAL_STABLE (ONION_NODE_PING_INTERVAL * 8)
non_null()
static bool key_list_contains(const uint8_t *const *keys, uint16_t keys_size, const uint8_t *public_key)
{
for (uint16_t i = 0; i < keys_size; ++i) {
if (memeq(keys[i], CRYPTO_PUBLIC_KEY_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE)) {
return true;
}
}
return false;
}
non_null()
static void do_announce(Onion_Client *onion_c)
{
@ -1945,9 +1993,27 @@ static void do_announce(Onion_Client *onion_c)
return;
}
for (unsigned int i = 0; i < (MAX_ONION_CLIENTS_ANNOUNCE / 2); ++i) {
// Don't send announces to the same node twice. If we don't have many nodes,
// the random selection below may have overlaps. This ensures that we deduplicate
// nodes before sending packets to save some bandwidth.
const uint8_t *targets[MAX_ONION_CLIENTS_ANNOUNCE / 2];
unsigned int targets_count = 0;
for (unsigned int i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE / 2; ++i) {
const uint32_t num = random_range_u32(onion_c->rng, num_nodes);
client_send_announce_request(onion_c, 0, &path_nodes[num].ip_port, path_nodes[num].public_key, nullptr, -1);
const Node_format *target = &path_nodes[num];
if (!key_list_contains(targets, targets_count, target->public_key)) {
client_send_announce_request(onion_c, 0, &target->ip_port, target->public_key, nullptr, -1);
targets[targets_count] = target->public_key;
++targets_count;
assert(targets_count <= MAX_ONION_CLIENTS_ANNOUNCE / 2);
} else {
Ip_Ntoa ip_str;
LOGGER_TRACE(onion_c->logger, "not sending repeated announce request to %s:%d",
net_ip_ntoa(&target->ip_port.ip, &ip_str), net_ntohs(target->ip_port.port));
}
}
}
}
@ -1959,22 +2025,25 @@ static void do_announce(Onion_Client *onion_c)
non_null()
static bool onion_isconnected(Onion_Client *onion_c)
{
unsigned int num = 0;
unsigned int live = 0;
unsigned int announced = 0;
if (mono_time_is_timeout(onion_c->mono_time, onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT)) {
LOGGER_TRACE(onion_c->logger, "onion is NOT connected: last packet received at %llu (timeout=%u)",
(unsigned long long)onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT);
onion_c->last_populated = 0;
return false;
}
if (onion_c->path_nodes_index == 0) {
LOGGER_TRACE(onion_c->logger, "onion is NOT connected: no path nodes available");
onion_c->last_populated = 0;
return false;
}
for (unsigned int i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) {
if (!onion_node_timed_out(&onion_c->clients_announce_list[i], onion_c->mono_time)) {
++num;
++live;
if (onion_c->clients_announce_list[i].is_stored != 0) {
++announced;
@ -1990,14 +2059,18 @@ static bool onion_isconnected(Onion_Client *onion_c)
/* Consider ourselves online if we are announced to half or more nodes
* we are connected to */
if (num != 0 && announced != 0) {
if ((num / 2) <= announced && (pnodes / 2) <= num) {
if (live != 0 && announced != 0) {
if ((live / 2) <= announced && (pnodes / 2) <= live) {
LOGGER_TRACE(onion_c->logger, "onion is connected: %u live nodes, %u announced, %d path nodes",
live, announced, pnodes);
return true;
}
}
onion_c->last_populated = 0;
LOGGER_TRACE(onion_c->logger, "onion is NOT connected: %u live nodes, %u announced, %d path nodes",
live, announced, pnodes);
return false;
}

View File

@ -24,12 +24,13 @@ struct Shared_Key_Cache {
uint64_t timeout; /** After this time (in seconds), a key is erased on the next housekeeping cycle */
const Mono_Time *mono_time;
const Memory *mem;
const Logger *log;
uint8_t keys_per_slot;
};
non_null()
static bool shared_key_is_empty(const Shared_Key *k) {
assert(k != nullptr);
static bool shared_key_is_empty(const Logger *log, const Shared_Key *k) {
LOGGER_ASSERT(log, k != nullptr, "shared key must not be NULL");
/*
* Since time can never be 0, we use that to determine if a key slot is empty.
* Additionally this allows us to use crypto_memzero and leave the slot in a valid state.
@ -38,12 +39,12 @@ static bool shared_key_is_empty(const Shared_Key *k) {
}
non_null()
static void shared_key_set_empty(Shared_Key *k) {
static void shared_key_set_empty(const Logger *log, Shared_Key *k) {
crypto_memzero(k, sizeof (Shared_Key));
assert(shared_key_is_empty(k));
LOGGER_ASSERT(log, shared_key_is_empty(log, k), "shared key must be empty after clearing it");
}
Shared_Key_Cache *shared_key_cache_new(const Mono_Time *mono_time, const Memory *mem, const uint8_t *self_secret_key, uint64_t timeout, uint8_t keys_per_slot)
Shared_Key_Cache *shared_key_cache_new(const Logger *log, const Mono_Time *mono_time, const Memory *mem, const uint8_t *self_secret_key, uint64_t timeout, uint8_t keys_per_slot)
{
if (mono_time == nullptr || self_secret_key == nullptr || timeout == 0 || keys_per_slot == 0) {
return nullptr;
@ -52,7 +53,7 @@ Shared_Key_Cache *shared_key_cache_new(const Mono_Time *mono_time, const Memory
// Time must not be zero, since we use that as special value for empty slots
if (mono_time_get(mono_time) == 0) {
// Fail loudly in debug environments
assert(false);
LOGGER_FATAL(log, "time must not be zero (mono_time not initialised?)");
return nullptr;
}
@ -64,6 +65,7 @@ Shared_Key_Cache *shared_key_cache_new(const Mono_Time *mono_time, const Memory
res->self_secret_key = self_secret_key;
res->mono_time = mono_time;
res->mem = mem;
res->log = log;
res->keys_per_slot = keys_per_slot;
// We take one byte from the public key for each bucket and store keys_per_slot elements there
const size_t cache_size = 256 * keys_per_slot;
@ -106,7 +108,7 @@ const uint8_t *shared_key_cache_lookup(Shared_Key_Cache *cache, const uint8_t pu
// Perform lookup
for(size_t i = 0; i < cache->keys_per_slot; ++i) {
if (shared_key_is_empty(&bucket_start[i])) {
if (shared_key_is_empty(cache->log, &bucket_start[i])) {
continue;
}
@ -119,13 +121,13 @@ const uint8_t *shared_key_cache_lookup(Shared_Key_Cache *cache, const uint8_t pu
// Perform housekeeping for this bucket
for (size_t i = 0; i < cache->keys_per_slot; ++i) {
if (shared_key_is_empty(&bucket_start[i])) {
if (shared_key_is_empty(cache->log, &bucket_start[i])) {
continue;
}
const bool timed_out = (bucket_start[i].time_last_requested + cache->timeout) < cur_time;
if (timed_out) {
shared_key_set_empty(&bucket_start[i]);
shared_key_set_empty(cache->log, &bucket_start[i]);
}
}

View File

@ -8,6 +8,7 @@
#include <stdint.h> // uint*_t
#include "crypto_core.h"
#include "logger.h"
#include "mem.h"
#include "mono_time.h"
@ -27,9 +28,10 @@ typedef struct Shared_Key_Cache Shared_Key_Cache;
* @return nullptr on error.
*/
non_null()
Shared_Key_Cache *shared_key_cache_new(const Mono_Time *mono_time, const Memory *mem,
const uint8_t *self_secret_key,
uint64_t timeout, uint8_t keys_per_slot);
Shared_Key_Cache *shared_key_cache_new(
const Logger *log, const Mono_Time *mono_time, const Memory *mem,
const uint8_t *self_secret_key,
uint64_t timeout, uint8_t keys_per_slot);
/**
* @brief Deletes the cache and frees all resources.

View File

@ -43,6 +43,8 @@ static_assert(FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
"FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
static_assert(TOX_DHT_NODE_IP_STRING_SIZE == IP_NTOA_LEN,
"TOX_DHT_NODE_IP_STRING_SIZE is assumed to be equal to IP_NTOA_LEN");
static_assert(TOX_GROUP_PEER_IP_STRING_MAX_LENGTH == IP_NTOA_LEN,
"TOX_GROUP_PEER_IP_STRING_MAX_LENGTH is assumed to be equal to IP_NTOA_LEN");
static_assert(TOX_DHT_NODE_PUBLIC_KEY_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
"TOX_DHT_NODE_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE");
static_assert(TOX_FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
@ -2810,7 +2812,7 @@ uint16_t tox_self_get_udp_port(const Tox *tox, Tox_Err_Get_Port *error)
{
assert(tox != nullptr);
tox_lock(tox);
const uint16_t port = net_htons(net_port(tox->m->net));
const uint16_t port = tox->m == nullptr || tox->m->net == nullptr ? 0 : net_htons(net_port(tox->m->net));
tox_unlock(tox);
if (port == 0) {
@ -2827,7 +2829,7 @@ uint16_t tox_self_get_tcp_port(const Tox *tox, Tox_Err_Get_Port *error)
assert(tox != nullptr);
tox_lock(tox);
if (tox->m->tcp_server != nullptr) {
if (tox->m != nullptr && tox->m->tcp_server != nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
const uint16_t ret = tox->m->options.tcp_server_port;
tox_unlock(tox);

View File

@ -373,6 +373,8 @@ typedef enum Tox_User_Status {
} Tox_User_Status;
const char *tox_user_status_to_string(Tox_User_Status value);
/**
* @brief Represents message types for tox_friend_send_message and conference
@ -393,6 +395,8 @@ typedef enum Tox_Message_Type {
} Tox_Message_Type;
const char *tox_message_type_to_string(Tox_Message_Type value);
/** @} */
@ -422,6 +426,8 @@ typedef enum Tox_Proxy_Type {
} Tox_Proxy_Type;
const char *tox_proxy_type_to_string(Tox_Proxy_Type value);
/**
* @brief Type of savedata to create the Tox instance from.
@ -445,6 +451,8 @@ typedef enum Tox_Savedata_Type {
} Tox_Savedata_Type;
const char *tox_savedata_type_to_string(Tox_Savedata_Type value);
/**
* @brief Severity level of log messages.
@ -478,6 +486,8 @@ typedef enum Tox_Log_Level {
} Tox_Log_Level;
const char *tox_log_level_to_string(Tox_Log_Level value);
/**
* @brief This event is triggered when the toxcore library logs an events_alloc message.
@ -791,6 +801,8 @@ typedef enum Tox_Err_Options_New {
} 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
@ -883,6 +895,8 @@ typedef enum Tox_Err_New {
} Tox_Err_New;
const char *tox_err_new_to_string(Tox_Err_New value);
/**
* @brief Creates and initialises a new Tox instance with the options passed.
@ -962,6 +976,8 @@ typedef enum Tox_Err_Bootstrap {
} 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,
@ -1029,6 +1045,8 @@ typedef enum Tox_Connection {
} Tox_Connection;
const char *tox_connection_to_string(Tox_Connection value);
/**
* @brief Return whether we are connected to the DHT.
*
@ -1155,6 +1173,8 @@ typedef enum Tox_Err_Set_Info {
} Tox_Err_Set_Info;
const char *tox_err_set_info_to_string(Tox_Err_Set_Info value);
/**
* @brief Set the nickname for the Tox client.
@ -1297,6 +1317,8 @@ typedef enum Tox_Err_Friend_Add {
} Tox_Err_Friend_Add;
const char *tox_err_friend_add_to_string(Tox_Err_Friend_Add value);
/**
* @brief Add a friend to the friend list and send a friend request.
@ -1358,6 +1380,8 @@ typedef enum Tox_Err_Friend_Delete {
} Tox_Err_Friend_Delete;
const char *tox_err_friend_delete_to_string(Tox_Err_Friend_Delete value);
/**
* @brief Remove a friend from the friend list.
@ -1398,6 +1422,8 @@ typedef enum Tox_Err_Friend_By_Public_Key {
} Tox_Err_Friend_By_Public_Key;
const char *tox_err_friend_by_public_key_to_string(Tox_Err_Friend_By_Public_Key value);
/**
* @brief Return the friend number associated with that Public Key.
@ -1445,6 +1471,8 @@ typedef enum Tox_Err_Friend_Get_Public_Key {
} Tox_Err_Friend_Get_Public_Key;
const char *tox_err_friend_get_public_key_to_string(Tox_Err_Friend_Get_Public_Key value);
/**
* @brief Copies the Public Key associated with a given friend number to a byte array.
@ -1472,6 +1500,8 @@ typedef enum Tox_Err_Friend_Get_Last_Online {
} Tox_Err_Friend_Get_Last_Online;
const char *tox_err_friend_get_last_online_to_string(Tox_Err_Friend_Get_Last_Online value);
/**
* @brief Return a unix-time timestamp of the last time the friend associated with a given
@ -1514,6 +1544,8 @@ typedef enum Tox_Err_Friend_Query {
} Tox_Err_Friend_Query;
const char *tox_err_friend_query_to_string(Tox_Err_Friend_Query value);
/**
* @brief Return the length of the friend's name.
@ -1726,6 +1758,8 @@ typedef enum Tox_Err_Set_Typing {
} Tox_Err_Set_Typing;
const char *tox_err_set_typing_to_string(Tox_Err_Set_Typing value);
/**
* @brief Set the client's typing status for a friend.
@ -1778,6 +1812,8 @@ typedef enum Tox_Err_Friend_Send_Message {
} Tox_Err_Friend_Send_Message;
const char *tox_err_friend_send_message_to_string(Tox_Err_Friend_Send_Message value);
/**
* @brief Send a text chat message to an online friend.
@ -1960,6 +1996,8 @@ typedef enum Tox_File_Control {
} Tox_File_Control;
const char *tox_file_control_to_string(Tox_File_Control value);
typedef enum Tox_Err_File_Control {
@ -2006,6 +2044,8 @@ typedef enum Tox_Err_File_Control {
} Tox_Err_File_Control;
const char *tox_err_file_control_to_string(Tox_Err_File_Control value);
/**
* @brief Sends a file control command to a friend for a given file transfer.
@ -2082,6 +2122,8 @@ typedef enum Tox_Err_File_Seek {
} Tox_Err_File_Seek;
const char *tox_err_file_seek_to_string(Tox_Err_File_Seek value);
/**
* @brief Sends a file seek control command to a friend for a given file transfer.
@ -2120,6 +2162,8 @@ typedef enum Tox_Err_File_Get {
} Tox_Err_File_Get;
const char *tox_err_file_get_to_string(Tox_Err_File_Get value);
/**
* @brief Copy the file id associated to the file transfer to a byte array.
@ -2177,6 +2221,8 @@ typedef enum Tox_Err_File_Send {
} Tox_Err_File_Send;
const char *tox_err_file_send_to_string(Tox_Err_File_Send value);
/**
* @brief Send a file transmission request.
@ -2291,6 +2337,8 @@ typedef enum Tox_Err_File_Send_Chunk {
} Tox_Err_File_Send_Chunk;
const char *tox_err_file_send_chunk_to_string(Tox_Err_File_Send_Chunk value);
/**
* @brief Send a chunk of file data to a friend.
@ -2438,6 +2486,8 @@ typedef enum Tox_Conference_Type {
} Tox_Conference_Type;
const char *tox_conference_type_to_string(Tox_Conference_Type value);
/**
* The invitation will remain valid until the inviting friend goes offline
@ -2571,6 +2621,8 @@ typedef enum Tox_Err_Conference_New {
} Tox_Err_Conference_New;
const char *tox_err_conference_new_to_string(Tox_Err_Conference_New value);
/**
* @brief Creates a new conference.
@ -2597,6 +2649,8 @@ typedef enum Tox_Err_Conference_Delete {
} Tox_Err_Conference_Delete;
const char *tox_err_conference_delete_to_string(Tox_Err_Conference_Delete value);
/**
* @brief This function deletes a conference.
@ -2634,6 +2688,8 @@ typedef enum Tox_Err_Conference_Peer_Query {
} Tox_Err_Conference_Peer_Query;
const char *tox_err_conference_peer_query_to_string(Tox_Err_Conference_Peer_Query value);
/**
* @brief Return the number of online peers in the conference.
@ -2742,6 +2798,8 @@ typedef enum Tox_Err_Conference_Set_Max_Offline {
} Tox_Err_Conference_Set_Max_Offline;
const char *tox_err_conference_set_max_offline_to_string(Tox_Err_Conference_Set_Max_Offline value);
/**
* @brief Set maximum number of offline peers to store, overriding the default.
@ -2773,6 +2831,8 @@ typedef enum Tox_Err_Conference_Invite {
} Tox_Err_Conference_Invite;
const char *tox_err_conference_invite_to_string(Tox_Err_Conference_Invite value);
/**
* @brief Invites a friend to a conference.
@ -2824,6 +2884,8 @@ typedef enum Tox_Err_Conference_Join {
} Tox_Err_Conference_Join;
const char *tox_err_conference_join_to_string(Tox_Err_Conference_Join value);
/**
* @brief Joins a conference that the client has been invited to.
@ -2874,6 +2936,8 @@ typedef enum Tox_Err_Conference_Send_Message {
} Tox_Err_Conference_Send_Message;
const char *tox_err_conference_send_message_to_string(Tox_Err_Conference_Send_Message value);
/**
* @brief Send a text chat message to the conference.
@ -2921,6 +2985,8 @@ typedef enum Tox_Err_Conference_Title {
} Tox_Err_Conference_Title;
const char *tox_err_conference_title_to_string(Tox_Err_Conference_Title value);
/**
* @brief Return the length of the conference title.
@ -3000,6 +3066,8 @@ typedef enum Tox_Err_Conference_Get_Type {
} Tox_Err_Conference_Get_Type;
const char *tox_err_conference_get_type_to_string(Tox_Err_Conference_Get_Type value);
/**
* @brief Get the type (text or A/V) for the conference.
@ -3037,6 +3105,8 @@ typedef enum Tox_Err_Conference_By_Id {
} Tox_Err_Conference_By_Id;
const char *tox_err_conference_by_id_to_string(Tox_Err_Conference_By_Id value);
/**
* @brief Return the conference number associated with the specified id.
@ -3078,6 +3148,8 @@ typedef enum Tox_Err_Conference_By_Uid {
} Tox_Err_Conference_By_Uid;
const char *tox_err_conference_by_uid_to_string(Tox_Err_Conference_By_Uid value);
/**
* @brief Return the conference number associated with the specified uid.
@ -3141,6 +3213,8 @@ typedef enum Tox_Err_Friend_Custom_Packet {
} Tox_Err_Friend_Custom_Packet;
const char *tox_err_friend_custom_packet_to_string(Tox_Err_Friend_Custom_Packet value);
/**
* @brief Send a custom lossy packet to a friend.
@ -3237,6 +3311,8 @@ typedef enum Tox_Err_Get_Port {
} Tox_Err_Get_Port;
const char *tox_err_get_port_to_string(Tox_Err_Get_Port value);
/**
* @brief Writes the temporary DHT public key of this instance to a byte array.
@ -3382,6 +3458,8 @@ typedef enum Tox_Group_Privacy_State {
} Tox_Group_Privacy_State;
const char *tox_group_privacy_state_to_string(Tox_Group_Privacy_State value);
/**
* Represents the state of the group topic lock.
@ -3400,6 +3478,8 @@ typedef enum Tox_Group_Topic_Lock {
} Tox_Group_Topic_Lock;
const char *tox_group_topic_lock_to_string(Tox_Group_Topic_Lock value);
/**
* Represents the group voice state, which determines which Group Roles have permission to speak
* in the group chat. The voice state does not have any effect private messages or topic setting.
@ -3421,6 +3501,8 @@ typedef enum Tox_Group_Voice_State {
TOX_GROUP_VOICE_STATE_FOUNDER,
} Tox_Group_Voice_State;
const char *tox_group_voice_state_to_string(Tox_Group_Voice_State value);
/**
* Represents group roles.
*
@ -3453,6 +3535,8 @@ typedef enum Tox_Group_Role {
} Tox_Group_Role;
const char *tox_group_role_to_string(Tox_Group_Role value);
/*******************************************************************************
@ -3498,6 +3582,8 @@ typedef enum Tox_Err_Group_New {
} Tox_Err_Group_New;
const char *tox_err_group_new_to_string(Tox_Err_Group_New value);
/**
* Creates a new group chat.
@ -3564,6 +3650,8 @@ typedef enum Tox_Err_Group_Join {
} Tox_Err_Group_Join;
const char *tox_err_group_join_to_string(Tox_Err_Group_Join value);
/**
* Joins a group chat with specified Chat ID.
@ -3599,6 +3687,8 @@ typedef enum Tox_Err_Group_Is_Connected {
} Tox_Err_Group_Is_Connected;
const char *tox_err_group_is_connected_to_string(Tox_Err_Group_Is_Connected value);
/**
* Returns true if the group chat is currently connected or attempting to connect to other peers
@ -3626,6 +3716,8 @@ typedef enum Tox_Err_Group_Disconnect {
TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED,
} Tox_Err_Group_Disconnect;
const char *tox_err_group_disconnect_to_string(Tox_Err_Group_Disconnect value);
/**
* Disconnects from a group chat while retaining the group state and credentials.
@ -3655,6 +3747,8 @@ typedef enum Tox_Err_Group_Reconnect {
} Tox_Err_Group_Reconnect;
const char *tox_err_group_reconnect_to_string(Tox_Err_Group_Reconnect value);
/**
* Reconnects to a group.
@ -3691,6 +3785,8 @@ typedef enum Tox_Err_Group_Leave {
TOX_ERR_GROUP_LEAVE_FAIL_SEND,
} Tox_Err_Group_Leave;
const char *tox_err_group_leave_to_string(Tox_Err_Group_Leave value);
/**
* Leaves a group.
@ -3735,6 +3831,8 @@ typedef enum Tox_Err_Group_Self_Query {
} Tox_Err_Group_Self_Query;
const char *tox_err_group_self_query_to_string(Tox_Err_Group_Self_Query value);
/**
* Error codes for self name setting.
@ -3768,6 +3866,8 @@ typedef enum Tox_Err_Group_Self_Name_Set {
} Tox_Err_Group_Self_Name_Set;
const char *tox_err_group_self_name_set_to_string(Tox_Err_Group_Self_Name_Set value);
/**
* Set the client's nickname for the group instance designated by the given group number.
@ -3831,6 +3931,8 @@ typedef enum Tox_Err_Group_Self_Status_Set {
} Tox_Err_Group_Self_Status_Set;
const char *tox_err_group_self_status_set_to_string(Tox_Err_Group_Self_Status_Set value);
/**
* Set the client's status for the group instance. Status must be a Tox_User_Status.
@ -3906,6 +4008,8 @@ typedef enum Tox_Err_Group_Peer_Query {
} Tox_Err_Group_Peer_Query;
const char *tox_err_group_peer_query_to_string(Tox_Err_Group_Peer_Query value);
/**
* Return the length of the peer's name. If the group number or ID is invalid, the
@ -4054,6 +4158,8 @@ typedef enum Tox_Err_Group_State_Queries {
} Tox_Err_Group_State_Queries;
const char *tox_err_group_state_queries_to_string(Tox_Err_Group_State_Queries value);
/**
* Error codes for group topic setting.
@ -4097,6 +4203,8 @@ typedef enum Tox_Err_Group_Topic_Set {
} Tox_Err_Group_Topic_Set;
const char *tox_err_group_topic_set_to_string(Tox_Err_Group_Topic_Set value);
/**
* Set the group topic and broadcast it to the rest of the group.
@ -4384,6 +4492,8 @@ typedef enum Tox_Err_Group_Send_Message {
} Tox_Err_Group_Send_Message;
const char *tox_err_group_send_message_to_string(Tox_Err_Group_Send_Message value);
/**
* Send a text chat message to the group.
@ -4458,6 +4568,8 @@ typedef enum Tox_Err_Group_Send_Private_Message {
} Tox_Err_Group_Send_Private_Message;
const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Private_Message value);
/**
* Send a text chat message to the specified peer in the specified group.
@ -4516,6 +4628,8 @@ typedef enum Tox_Err_Group_Send_Custom_Packet {
} Tox_Err_Group_Send_Custom_Packet;
const char *tox_err_group_send_custom_packet_to_string(Tox_Err_Group_Send_Custom_Packet value);
/**
* Send a custom packet to the group.
@ -4592,6 +4706,8 @@ typedef enum Tox_Err_Group_Send_Custom_Private_Packet {
} Tox_Err_Group_Send_Custom_Private_Packet;
const char *tox_err_group_send_custom_private_packet_to_string(Tox_Err_Group_Send_Custom_Private_Packet value);
/**
* Send a custom private packet to a designated peer in the group.
*
@ -4743,6 +4859,8 @@ typedef enum Tox_Err_Group_Invite_Friend {
} Tox_Err_Group_Invite_Friend;
const char *tox_err_group_invite_friend_to_string(Tox_Err_Group_Invite_Friend value);
/**
* Invite a friend to a group.
@ -4801,6 +4919,8 @@ typedef enum Tox_Err_Group_Invite_Accept {
} Tox_Err_Group_Invite_Accept;
const char *tox_err_group_invite_accept_to_string(Tox_Err_Group_Invite_Accept value);
/**
* Accept an invite to a group chat that the client previously received from a friend. The invite
@ -4891,6 +5011,8 @@ typedef enum Tox_Group_Exit_Type {
} Tox_Group_Exit_Type;
const char *tox_group_exit_type_to_string(Tox_Group_Exit_Type value);
/**
* @param group_number The group number of the group in which a peer has left.
@ -4951,6 +5073,8 @@ typedef enum Tox_Group_Join_Fail {
} Tox_Group_Join_Fail;
const char *tox_group_join_fail_to_string(Tox_Group_Join_Fail value);
/**
* @param group_number The group number of the group for which the join has failed.
@ -5014,6 +5138,8 @@ typedef enum Tox_Err_Group_Founder_Set_Password {
} Tox_Err_Group_Founder_Set_Password;
const char *tox_err_group_founder_set_password_to_string(Tox_Err_Group_Founder_Set_Password value);
/**
* Set or unset the group password.
@ -5070,6 +5196,8 @@ typedef enum Tox_Err_Group_Founder_Set_Topic_Lock {
} Tox_Err_Group_Founder_Set_Topic_Lock;
const char *tox_err_group_founder_set_topic_lock_to_string(Tox_Err_Group_Founder_Set_Topic_Lock value);
/**
* Set the group topic lock state.
@ -5123,6 +5251,8 @@ typedef enum Tox_Err_Group_Founder_Set_Voice_State {
} Tox_Err_Group_Founder_Set_Voice_State;
const char *tox_err_group_founder_set_voice_state_to_string(Tox_Err_Group_Founder_Set_Voice_State value);
/**
* Set the group voice state.
*
@ -5175,6 +5305,8 @@ typedef enum Tox_Err_Group_Founder_Set_Privacy_State {
} Tox_Err_Group_Founder_Set_Privacy_State;
const char *tox_err_group_founder_set_privacy_state_to_string(Tox_Err_Group_Founder_Set_Privacy_State value);
/**
* Set the group privacy state.
*
@ -5227,6 +5359,8 @@ typedef enum Tox_Err_Group_Founder_Set_Peer_Limit {
} Tox_Err_Group_Founder_Set_Peer_Limit;
const char *tox_err_group_founder_set_peer_limit_to_string(Tox_Err_Group_Founder_Set_Peer_Limit value);
/**
* Set the group peer limit.
@ -5275,6 +5409,8 @@ typedef enum Tox_Err_Group_Set_Ignore {
} Tox_Err_Group_Set_Ignore;
const char *tox_err_group_set_ignore_to_string(Tox_Err_Group_Set_Ignore value);
/**
* Ignore or unignore a peer.
@ -5329,6 +5465,8 @@ typedef enum Tox_Err_Group_Mod_Set_Role {
} Tox_Err_Group_Mod_Set_Role;
const char *tox_err_group_mod_set_role_to_string(Tox_Err_Group_Mod_Set_Role value);
/**
* Set a peer's role.
@ -5385,6 +5523,8 @@ typedef enum Tox_Err_Group_Mod_Kick_Peer {
} Tox_Err_Group_Mod_Kick_Peer;
const char *tox_err_group_mod_kick_peer_to_string(Tox_Err_Group_Mod_Kick_Peer value);
/**
* Kick a peer.
@ -5428,6 +5568,8 @@ typedef enum Tox_Group_Mod_Event {
} Tox_Group_Mod_Event;
const char *tox_group_mod_event_to_string(Tox_Group_Mod_Event value);
/**
* @param group_number The group number of the group the event is intended for.

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include <assert.h>
#include "ccompat.h"
#include "group_chats.h"
#include "mem.h"
#include "network.h"
#include "tox_struct.h"
@ -166,3 +167,57 @@ uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox){
return num_cap;
}
#ifndef VANILLA_NACL
size_t tox_group_peer_get_ip_address_size(const Tox *tox, uint32_t group_number, uint32_t peer_id,
Tox_Err_Group_Peer_Query *error)
{
assert(tox != nullptr);
tox_lock(tox);
const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
if (chat == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
tox_unlock(tox);
return -1;
}
const int ret = gc_get_peer_ip_address_size(chat, peer_id);
tox_unlock(tox);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
return -1;
} else {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
return ret;
}
}
bool tox_group_peer_get_ip_address(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t *ip_addr,
Tox_Err_Group_Peer_Query *error)
{
assert(tox != nullptr);
tox_lock(tox);
const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
if (chat == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
tox_unlock(tox);
return false;
}
const int ret = gc_get_peer_ip_address(chat, peer_id, ip_addr);
tox_unlock(tox);
if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
return false;
}
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
return true;
}
#endif /* VANILLA_NACL */

View File

@ -156,6 +156,51 @@ uint16_t tox_dht_get_num_closelist(const Tox *tox);
*/
uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox);
/*******************************************************************************
*
* :: DHT groupchat queries.
*
******************************************************************************/
/**
* Maximum size of a peer IP address string.
*/
#define TOX_GROUP_PEER_IP_STRING_MAX_LENGTH 96
uint32_t tox_group_peer_ip_string_max_length(void);
/**
* Return the length of the peer's IP address in string form. If the group number or ID
* is invalid, the return value is unspecified.
*
* @param group_number The group number of the group we wish to query.
* @param peer_id The ID of the peer whose IP address length we want to retrieve.
*/
size_t tox_group_peer_get_ip_address_size(const Tox *tox, uint32_t group_number, uint32_t peer_id,
Tox_Err_Group_Peer_Query *error);
/**
* Write the IP address associated with the designated peer_id for the designated group number
* to ip_addr.
*
* If the peer is forcing TCP connections a placeholder value will be written instead,
* indicating that their real IP address is unknown to us.
*
* If `peer_id` designates ourself, it will write either our own IP address or a placeholder value,
* depending on whether or not we're forcing TCP connections.
*
* Call tox_group_peer_get_ip_address_size to determine the allocation size for the `ip_addr` parameter.
*
* @param group_number The group number of the group we wish to query.
* @param peer_id The ID of the peer whose public key we wish to retrieve.
* @param ip_addr A valid memory region large enough to store the IP address string.
* If this parameter is NULL, this function call has no effect.
*
* @return true on success.
*/
bool tox_group_peer_get_ip_address(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t *ip_addr,
Tox_Err_Group_Peer_Query *error);
#ifdef __cplusplus
}
#endif

View File

@ -130,6 +130,17 @@ bool tox_unpack_user_status(Bin_Unpack *bu, Tox_User_Status *val)
return true;
}
static Tox_Group_Privacy_State tox_group_privacy_state_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_PRIVACY_STATE_PUBLIC;
case 1:
return TOX_GROUP_PRIVACY_STATE_PRIVATE;
default:
return TOX_GROUP_PRIVACY_STATE_PRIVATE;
}
}
bool tox_unpack_group_privacy_state(Bin_Unpack *bu, Tox_Group_Privacy_State *val)
{
uint32_t u32;
@ -138,10 +149,22 @@ bool tox_unpack_group_privacy_state(Bin_Unpack *bu, Tox_Group_Privacy_State *val
return false;
}
*val = (Tox_Group_Privacy_State)u32;
*val = tox_group_privacy_state_from_int(u32);
return true;
}
static Tox_Group_Voice_State tox_group_voice_state_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_VOICE_STATE_ALL;
case 1:
return TOX_GROUP_VOICE_STATE_MODERATOR;
case 2:
return TOX_GROUP_VOICE_STATE_FOUNDER;
default:
return TOX_GROUP_VOICE_STATE_FOUNDER;
}
}
bool tox_unpack_group_voice_state(Bin_Unpack *bu, Tox_Group_Voice_State *val)
{
uint32_t u32;
@ -150,10 +173,21 @@ bool tox_unpack_group_voice_state(Bin_Unpack *bu, Tox_Group_Voice_State *val)
return false;
}
*val = (Tox_Group_Voice_State)u32;
*val = tox_group_voice_state_from_int(u32);
return true;
}
static Tox_Group_Topic_Lock tox_group_topic_lock_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_TOPIC_LOCK_ENABLED;
case 1:
return TOX_GROUP_TOPIC_LOCK_DISABLED;
default:
return TOX_GROUP_TOPIC_LOCK_ENABLED;
}
}
bool tox_unpack_group_topic_lock(Bin_Unpack *bu, Tox_Group_Topic_Lock *val)
{
uint32_t u32;
@ -162,10 +196,23 @@ bool tox_unpack_group_topic_lock(Bin_Unpack *bu, Tox_Group_Topic_Lock *val)
return false;
}
*val = (Tox_Group_Topic_Lock)u32;
*val = tox_group_topic_lock_from_int(u32);
return true;
}
static Tox_Group_Join_Fail tox_group_join_fail_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_JOIN_FAIL_PEER_LIMIT;
case 1:
return TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD;
case 2:
return TOX_GROUP_JOIN_FAIL_UNKNOWN;
default:
return TOX_GROUP_JOIN_FAIL_UNKNOWN;
}
}
bool tox_unpack_group_join_fail(Bin_Unpack *bu, Tox_Group_Join_Fail *val)
{
uint32_t u32;
@ -174,10 +221,25 @@ bool tox_unpack_group_join_fail(Bin_Unpack *bu, Tox_Group_Join_Fail *val)
return false;
}
*val = (Tox_Group_Join_Fail)u32;
*val = tox_group_join_fail_from_int(u32);
return true;
}
static Tox_Group_Mod_Event tox_group_mod_event_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_MOD_EVENT_KICK;
case 1:
return TOX_GROUP_MOD_EVENT_OBSERVER;
case 2:
return TOX_GROUP_MOD_EVENT_USER;
case 3:
return TOX_GROUP_MOD_EVENT_MODERATOR;
default:
return TOX_GROUP_MOD_EVENT_MODERATOR;
}
}
bool tox_unpack_group_mod_event(Bin_Unpack *bu, Tox_Group_Mod_Event *val)
{
uint32_t u32;
@ -186,10 +248,29 @@ bool tox_unpack_group_mod_event(Bin_Unpack *bu, Tox_Group_Mod_Event *val)
return false;
}
*val = (Tox_Group_Mod_Event)u32;
*val = tox_group_mod_event_from_int(u32);
return true;
}
static Tox_Group_Exit_Type tox_group_exit_type_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_GROUP_EXIT_TYPE_QUIT;
case 1:
return TOX_GROUP_EXIT_TYPE_TIMEOUT;
case 2:
return TOX_GROUP_EXIT_TYPE_DISCONNECTED;
case 3:
return TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED;
case 4:
return TOX_GROUP_EXIT_TYPE_KICK;
case 5:
return TOX_GROUP_EXIT_TYPE_SYNC_ERROR;
default:
return TOX_GROUP_EXIT_TYPE_QUIT;
}
}
bool tox_unpack_group_exit_type(Bin_Unpack *bu, Tox_Group_Exit_Type *val)
{
uint32_t u32;
@ -198,6 +279,6 @@ bool tox_unpack_group_exit_type(Bin_Unpack *bu, Tox_Group_Exit_Type *val)
return false;
}
*val = (Tox_Group_Exit_Type)u32;
*val = tox_group_exit_type_from_int(u32);
return true;
}

View File

@ -107,6 +107,10 @@ int64_t min_s64(int64_t a, int64_t b)
return a < b ? a : b;
}
uint8_t max_u08(uint8_t a, uint8_t b)
{
return a > b ? a : b;
}
uint16_t max_u16(uint16_t a, uint16_t b)
{
return a > b ? a : b;

View File

@ -53,6 +53,7 @@ int16_t min_s16(int16_t a, int16_t b);
int32_t min_s32(int32_t a, int32_t b);
int64_t min_s64(int64_t a, int64_t b);
uint8_t max_u08(uint8_t a, uint8_t b);
uint16_t max_u16(uint16_t a, uint16_t b);
uint32_t max_u32(uint32_t a, uint32_t b);
uint64_t max_u64(uint64_t a, uint64_t b);