perf: Slightly reduce bandwidth usage when there are few nodes.

This mainly saves spam in test logs, but may save some packets here and
there, if nodes are randomly selected twice for GET_NODES and onion
routing packets.
This commit is contained in:
iphydf 2023-12-01 15:20:18 +00:00
parent 90f7496819
commit 028b017d79
No known key found for this signature in database
GPG Key ID: 3855DBA2D74403C9
24 changed files with 246 additions and 83 deletions

View File

@ -435,6 +435,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

@ -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

@ -1 +1 @@
849ec5686eeaea448f4ef99650b016c883e6ea13d5fa2e7b2a344c9275a10431 /usr/local/bin/tox-bootstrapd
d9f100677e54c65fc1651da701a59c7a184ffe06381c6376102c668a8034a570 /usr/local/bin/tox-bootstrapd

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

@ -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

@ -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",

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

@ -2810,7 +2810,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 +2827,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

@ -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);