Merge commit '9ddeea3d06045c8ae38cd2d6eed0fc2891c6e146'

This commit is contained in:
2023-12-15 15:21:40 +01:00
78 changed files with 892 additions and 415 deletions

View File

@ -2,10 +2,11 @@ load("@rules_cc//cc:defs.bzl", "cc_test")
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
load("//tools:no_undefined.bzl", "cc_library")
package(features = ["layering_check"])
exports_files(
srcs = ["tox.h"],
srcs = [
"tox.h",
"tox_private.h",
],
visibility = ["//c-toxcore:__pkg__"],
)
@ -76,6 +77,22 @@ cc_test(
],
)
cc_library(
name = "logger",
srcs = ["logger.c"],
hdrs = ["logger.h"],
visibility = [
"//c-toxcore/auto_tests:__pkg__",
"//c-toxcore/other:__pkg__",
"//c-toxcore/other/bootstrap_daemon:__pkg__",
"//c-toxcore/toxav:__pkg__",
],
deps = [
":attributes",
":ccompat",
],
)
cc_library(
name = "bin_pack",
srcs = ["bin_pack.c"],
@ -84,6 +101,7 @@ cc_library(
deps = [
":attributes",
":ccompat",
":logger",
"//c-toxcore/third_party:cmp",
],
)
@ -158,22 +176,6 @@ cc_test(
],
)
cc_library(
name = "logger",
srcs = ["logger.c"],
hdrs = ["logger.h"],
visibility = [
"//c-toxcore/auto_tests:__pkg__",
"//c-toxcore/other:__pkg__",
"//c-toxcore/other/bootstrap_daemon:__pkg__",
"//c-toxcore/toxav:__pkg__",
],
deps = [
":attributes",
":ccompat",
],
)
cc_library(
name = "state",
srcs = ["state.c"],
@ -339,6 +341,7 @@ cc_library(
deps = [
":LAN_discovery",
":attributes",
":bin_pack",
":ccompat",
":crypto_core",
":logger",
@ -366,6 +369,7 @@ cc_test(
cc_fuzz_test(
name = "DHT_fuzz_test",
size = "small",
srcs = ["DHT_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"],
deps = [
@ -405,6 +409,7 @@ cc_library(
cc_fuzz_test(
name = "forwarding_fuzz_test",
size = "small",
srcs = ["forwarding_fuzz_test.cc"],
#corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
deps = [
@ -603,6 +608,7 @@ cc_library(
cc_fuzz_test(
name = "group_announce_fuzz_test",
size = "small",
srcs = ["group_announce_fuzz_test.cc"],
#corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
deps = [
@ -706,6 +712,7 @@ cc_test(
cc_fuzz_test(
name = "group_moderation_fuzz_test",
size = "small",
srcs = ["group_moderation_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
deps = [
@ -862,6 +869,7 @@ cc_test(
cc_fuzz_test(
name = "tox_events_fuzz_test",
size = "small",
srcs = ["tox_events_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:tox_events_fuzz_test"],
deps = [

View File

@ -9,10 +9,12 @@
#include "DHT.h"
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "LAN_discovery.h"
#include "bin_pack.h"
#include "ccompat.h"
#include "logger.h"
#include "mono_time.h"
@ -360,12 +362,32 @@ int packed_node_size(Family ip_family)
}
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port)
/** @brief Packs an IP structure.
*
* It's the caller's responsibility to make sure `is_ipv4` tells the truth. This
* function is an implementation detail of @ref bin_pack_ip_port.
*
* @param is_ipv4 whether this IP is an IP4 or IP6.
*
* @retval true on success.
*/
non_null()
static bool bin_pack_ip(Bin_Pack *bp, const IP *ip, bool is_ipv4)
{
if (data == nullptr) {
return -1;
if (is_ipv4) {
return bin_pack_bin_b(bp, ip->ip.v4.uint8, SIZE_IP4);
} else {
return bin_pack_bin_b(bp, ip->ip.v6.uint8, SIZE_IP6);
}
}
/** @brief Packs an IP_Port structure.
*
* @retval true on success.
*/
non_null()
static bool bin_pack_ip_port(Bin_Pack *bp, const Logger *logger, const IP_Port *ip_port)
{
bool is_ipv4;
uint8_t family;
@ -387,32 +409,34 @@ int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_
// TODO(iphydf): Find out why we're trying to pack invalid IPs, stop
// doing that, and turn this into an error.
LOGGER_TRACE(logger, "cannot pack invalid IP: %s", net_ip_ntoa(&ip_port->ip, &ip_str));
return false;
}
return bin_pack_u08_b(bp, family)
&& bin_pack_ip(bp, &ip_port->ip, is_ipv4)
&& bin_pack_u16_b(bp, net_ntohs(ip_port->port));
}
non_null()
static bool bin_pack_ip_port_handler(Bin_Pack *bp, const Logger *logger, const void *obj)
{
return bin_pack_ip_port(bp, logger, (const IP_Port *)obj);
}
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port)
{
const uint32_t size = bin_pack_obj_size(bin_pack_ip_port_handler, logger, ip_port);
if (size > length) {
return -1;
}
if (is_ipv4) {
const uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t);
if (size > length) {
return -1;
}
data[0] = family;
memcpy(data + 1, &ip_port->ip.ip.v4, SIZE_IP4);
memcpy(data + 1 + SIZE_IP4, &ip_port->port, sizeof(uint16_t));
return size;
} else {
const uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t);
if (size > length) {
return -1;
}
data[0] = family;
memcpy(data + 1, &ip_port->ip.ip.v6, SIZE_IP6);
memcpy(data + 1 + SIZE_IP6, &ip_port->port, sizeof(uint16_t));
return size;
if (!bin_pack_obj(bin_pack_ip_port_handler, logger, ip_port, data, length)) {
return -1;
}
assert(size < INT_MAX);
return (int)size;
}
int dht_create_packet(const Memory *mem, const Random *rng,
@ -511,33 +535,25 @@ int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool
}
}
/** @brief Pack a single node from a node array.
*
* @retval true on success.
*/
non_null()
static bool bin_pack_node_handler(Bin_Pack *bp, const Logger *logger, const void *arr, uint32_t index)
{
const Node_format *nodes = (const Node_format *)arr;
return bin_pack_ip_port(bp, logger, &nodes[index].ip_port)
&& bin_pack_bin_b(bp, nodes[index].public_key, CRYPTO_PUBLIC_KEY_SIZE);
}
int pack_nodes(const Logger *logger, uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number)
{
uint32_t packed_length = 0;
for (uint32_t i = 0; i < number && packed_length < length; ++i) {
const int ipp_size = pack_ip_port(logger, data + packed_length, length - packed_length, &nodes[i].ip_port);
if (ipp_size == -1) {
return -1;
}
packed_length += ipp_size;
if (packed_length + CRYPTO_PUBLIC_KEY_SIZE > length) {
return -1;
}
memcpy(data + packed_length, nodes[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
packed_length += CRYPTO_PUBLIC_KEY_SIZE;
#ifndef NDEBUG
const uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE;
assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6);
#endif
const uint32_t size = bin_pack_obj_array_size(bin_pack_node_handler, logger, nodes, number);
if (!bin_pack_obj_array(bin_pack_node_handler, logger, nodes, number, data, length)) {
return -1;
}
return packed_length;
return size;
}
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
@ -2829,8 +2845,9 @@ void dht_save(const DHT *dht, uint8_t *data)
}
}
state_write_section_header(old_data, DHT_STATE_COOKIE_TYPE, pack_nodes(dht->log, data, sizeof(Node_format) * num,
clients, num), DHT_STATE_TYPE_NODES);
state_write_section_header(
old_data, DHT_STATE_COOKIE_TYPE, pack_nodes(dht->log, data, sizeof(Node_format) * num, clients, num),
DHT_STATE_TYPE_NODES);
mem_delete(dht->mem, clients);
}

View File

@ -214,6 +214,16 @@ int packed_node_size(Family ip_family);
non_null()
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port);
/** @brief Unpack IP_Port structure from data of max size length into ip_port.
*
* len_processed is the offset of data currently unpacked.
*
* @return size of unpacked ip_port on success.
* @retval -1 on failure.
*/
non_null()
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled);
/** @brief Encrypt plain and write resulting DHT packet into packet with max size length.
*
* @return size of packet on success.
@ -226,16 +236,6 @@ int dht_create_packet(const Memory *mem, const Random *rng,
const uint8_t *plain, size_t plain_length,
uint8_t *packet, size_t length);
/** @brief Unpack IP_Port structure from data of max size length into ip_port.
*
* len_processed is the offset of data currently unpacked.
*
* @return size of unpacked ip_port on success.
* @retval -1 on failure.
*/
non_null()
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled);
/** @brief Pack number of nodes into data of maxlength length.
*
* @return length of packed nodes on success.

View File

@ -1,6 +1,8 @@
#include "DHT.h"
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "../testing/fuzzing/fuzz_support.h"
@ -36,6 +38,16 @@ void TestUnpackNodes(Fuzz_Data &input)
LOGGER_ASSERT(logger, packed_size == processed_data_len,
"packed size (%d) != unpacked size (%d)", packed_size, processed_data_len);
logger_kill(logger);
// Check that packed nodes can be unpacked again and result in the
// original unpacked nodes.
Node_format nodes2[node_count];
uint16_t processed_data_len2;
const int packed_count2 = unpack_nodes(
nodes2, node_count, &processed_data_len2, packed.data(), packed.size(), tcp_enabled);
assert(processed_data_len2 == processed_data_len);
assert(packed_count2 == packed_count);
assert(memcmp(nodes, nodes2, sizeof(Node_format) * packed_count) == 0);
}
}

View File

@ -1,7 +1,8 @@
lib_LTLIBRARIES += libtoxcore.la
libtoxcore_la_include_HEADERS = \
../toxcore/tox.h
../toxcore/tox.h \
../toxcore/tox_private.h
libtoxcore_la_includedir = $(includedir)/tox

View File

@ -757,6 +757,20 @@ int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length)
return 0;
}
static Userstatus userstatus_from_int(uint8_t status)
{
switch (status) {
case 0:
return USERSTATUS_NONE;
case 1:
return USERSTATUS_AWAY;
case 2:
return USERSTATUS_BUSY;
default:
return USERSTATUS_INVALID;
}
}
int m_set_userstatus(Messenger *m, uint8_t status)
{
if (status >= USERSTATUS_INVALID) {
@ -767,7 +781,7 @@ int m_set_userstatus(Messenger *m, uint8_t status)
return 0;
}
m->userstatus = (Userstatus)status;
m->userstatus = userstatus_from_int(status);
for (uint32_t i = 0; i < m->numfriends; ++i) {
m->friendlist[i].userstatus_sent = false;
@ -923,7 +937,7 @@ static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, co
non_null()
static void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)
{
m->friendlist[friendnumber].userstatus = (Userstatus)status;
m->friendlist[friendnumber].userstatus = userstatus_from_int(status);
}
non_null()
@ -2024,7 +2038,7 @@ non_null(1, 3) nullable(5)
static int m_handle_packet_offline(Messenger *m, const int i, const uint8_t *data, const uint16_t data_length, void *userdata)
{
if (data_length == 0) {
set_friend_status(m, i, FRIEND_CONFIRMED, userdata);
set_friend_status(m, i, FRIEND_CONFIRMED, userdata);
}
return 0;
@ -2081,9 +2095,9 @@ static int m_handle_packet_userstatus(Messenger *m, const int i, const uint8_t *
return 0;
}
const Userstatus status = (Userstatus)data[0];
const Userstatus status = userstatus_from_int(data[0]);
if (status >= USERSTATUS_INVALID) {
if (status == USERSTATUS_INVALID) {
return 0;
}
@ -2403,8 +2417,8 @@ static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t le
return m_handle_packet_file_data(m, i, data, data_length, userdata);
case PACKET_ID_MSI:
return m_handle_packet_msi(m, i, data, data_length, userdata);
case PACKET_ID_INVITE_GROUPCHAT:
return m_handle_packet_invite_groupchat(m, i, data, data_length, userdata);
case PACKET_ID_INVITE_GROUPCHAT:
return m_handle_packet_invite_groupchat(m, i, data, data_length, userdata);
}
return handle_custom_lossless_packet(object, i, temp, len, userdata);
@ -2627,7 +2641,7 @@ void do_messenger(Messenger *m, void *userdata)
if (m->tcp_server != nullptr) {
/* Add self tcp server. */
IP_Port local_ip_port;
local_ip_port.port = m->options.tcp_server_port;
local_ip_port.port = net_htons(m->options.tcp_server_port);
local_ip_port.ip.family = net_family_ipv4();
local_ip_port.ip.ip.v4 = get_ip4_loopback();
add_tcp_relay(m->net_crypto, &local_ip_port, tcp_server_public_key(m->tcp_server));
@ -3153,7 +3167,7 @@ static void pack_groupchats(const GC_Session *c, Bin_Pack *bp)
}
non_null()
static bool pack_groupchats_handler(Bin_Pack *bp, const void *obj)
static bool pack_groupchats_handler(Bin_Pack *bp, const Logger *log, const void *obj)
{
pack_groupchats((const GC_Session *)obj, bp);
return true; // TODO(iphydf): Return bool from pack functions.
@ -3163,7 +3177,7 @@ non_null()
static uint32_t saved_groups_size(const Messenger *m)
{
GC_Session *c = m->group_handler;
return bin_pack_obj_size(pack_groupchats_handler, c);
return bin_pack_obj_size(pack_groupchats_handler, m->log, c);
}
non_null()
@ -3185,7 +3199,7 @@ static uint8_t *groups_save(const Messenger *m, uint8_t *data)
data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_GROUPS);
if (!bin_pack_obj(pack_groupchats_handler, c, data, len)) {
if (!bin_pack_obj(pack_groupchats_handler, m->log, c, data, len)) {
LOGGER_FATAL(m->log, "failed to pack group chats into buffer of length %u", len);
return data;
}
@ -3622,7 +3636,9 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->onion = new_onion(m->log, m->mem, m->mono_time, m->rng, m->dht);
m->onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht);
m->onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto);
m->fr_c = new_friend_connections(m->log, m->mono_time, m->ns, m->onion_c, options->local_discovery_enabled);
if (m->onion_c != nullptr) {
m->fr_c = new_friend_connections(m->log, m->mono_time, m->ns, m->onion_c, options->local_discovery_enabled);
}
if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {

View File

@ -18,7 +18,7 @@
#define GNU_PRINTF(f, a)
#endif
#if defined(__GNUC__) && defined(_DEBUG) && !defined(__OPTIMIZE__)
#if defined(__GNUC__) && defined(_DEBUG)
#define non_null(...) __attribute__((__nonnull__(__VA_ARGS__)))
#else
#define non_null(...)

View File

@ -62,21 +62,47 @@ static void bin_pack_init(Bin_Pack *bp, uint8_t *buf, uint32_t buf_size)
cmp_init(&bp->ctx, bp, null_reader, null_skipper, buf_writer);
}
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size)
{
Bin_Pack bp;
bin_pack_init(&bp, buf, buf_size);
return callback(&bp, obj);
}
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj)
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const Logger *logger, const void *obj)
{
Bin_Pack bp;
bin_pack_init(&bp, nullptr, 0);
callback(&bp, obj);
if (!callback(&bp, logger, obj)) {
return UINT32_MAX;
}
return bp.bytes_pos;
}
bool bin_pack_obj(bin_pack_cb *callback, const Logger *logger, const void *obj, uint8_t *buf, uint32_t buf_size)
{
Bin_Pack bp;
bin_pack_init(&bp, buf, buf_size);
return callback(&bp, logger, obj);
}
uint32_t bin_pack_obj_array_size(bin_pack_array_cb *callback, const Logger *logger, const void *arr, uint32_t count)
{
Bin_Pack bp;
bin_pack_init(&bp, nullptr, 0);
for (uint32_t i = 0; i < count; ++i) {
if (!callback(&bp, logger, arr, i)) {
return UINT32_MAX;
}
}
return bp.bytes_pos;
}
bool bin_pack_obj_array(bin_pack_array_cb *callback, const Logger *logger, const void *arr, uint32_t count, uint8_t *buf, uint32_t buf_size)
{
Bin_Pack bp;
bin_pack_init(&bp, buf, buf_size);
for (uint32_t i = 0; i < count; ++i) {
if (!callback(&bp, logger, arr, i)) {
return false;
}
}
return true;
}
Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size)
{
Bin_Pack *bp = (Bin_Pack *)calloc(1, sizeof(Bin_Pack));

View File

@ -8,6 +8,7 @@
#include <stdint.h>
#include "attributes.h"
#include "logger.h"
#ifdef __cplusplus
extern "C" {
@ -23,18 +24,29 @@ typedef struct Bin_Pack Bin_Pack;
* This function would typically cast the `void *` to the actual object pointer type and then call
* more appropriately typed packing functions.
*/
typedef bool bin_pack_cb(Bin_Pack *bp, const void *obj);
typedef bool bin_pack_cb(Bin_Pack *bp, const Logger *logger, const void *obj);
/** @brief Function used to pack an array of objects.
*
* This function would typically cast the `void *` to the actual object pointer type and then call
* more appropriately typed packing functions.
*
* @param arr is the object array as void pointer.
* @param index is the index in the object array that is currently being packed.
*/
typedef bool bin_pack_array_cb(Bin_Pack *bp, const Logger *logger, const void *arr, uint32_t index);
/** @brief Determine the serialised size of an object.
*
* @param callback The function called on the created packer and packed object.
* @param logger Optional logger object to pass to the callback.
* @param obj The object to be packed, passed as `obj` to the callback.
*
* @return The packed size of the passed object according to the callback. UINT32_MAX in case of
* errors such as buffer overflow.
* @return The packed size of the passed object according to the callback.
* @retval UINT32_MAX in case of errors such as buffer overflow.
*/
non_null(1) nullable(2)
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj);
non_null(1) nullable(2, 3)
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const Logger *logger, const void *obj);
/** @brief Pack an object into a buffer of a given size.
*
@ -45,14 +57,57 @@ uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj);
* overflows `uint32_t`, this function returns `false`.
*
* @param callback The function called on the created packer and packed object.
* @param logger Optional logger object to pass to the callback.
* @param obj The object to be packed, passed as `obj` to the callback.
* @param buf A byte array large enough to hold the serialised representation of `obj`.
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
*
* @retval false if an error occurred (e.g. buffer overflow).
*/
non_null(1, 4) nullable(2, 3)
bool bin_pack_obj(bin_pack_cb *callback, const Logger *logger, const void *obj, uint8_t *buf, uint32_t buf_size);
/** @brief Determine the serialised size of an object array.
*
* Calls the callback `count` times with increasing `index` argument from 0 to
* `count`. This function is here just so we don't need to write the same
* trivial loop many times and so we don't need an extra struct just to contain
* an array with size so it can be passed to `bin_pack_obj_size`.
*
* @param callback The function called on the created packer and each object to
* be packed.
* @param logger Optional logger object to pass to the callback.
* @param arr The object array to be packed, passed as `arr` to the callback.
* @param count The number of elements in the object array.
*
* @return The packed size of the passed object array according to the callback.
* @retval UINT32_MAX in case of errors such as buffer overflow.
*/
non_null(1, 3) nullable(2)
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size);
uint32_t bin_pack_obj_array_size(bin_pack_array_cb *callback, const Logger *logger, const void *arr, uint32_t count);
/** @brief Pack an object array into a buffer of a given size.
*
* Calls the callback `count` times with increasing `index` argument from 0 to
* `count`. This function is here just so we don't need to write the same
* trivial loop many times and so we don't need an extra struct just to contain
* an array with size so it can be passed to `bin_pack_obj`.
*
* Similar to `bin_pack_obj` but for arrays. Does not write the array length, so
* if you need that, write it manually using `bin_pack_array`.
*
* @param callback The function called on the created packer and packed object
* array.
* @param logger Optional logger object to pass to the callback.
* @param arr The object array to be packed, passed as `arr` to the callback.
* @param count The number of elements in the object array.
* @param buf A byte array large enough to hold the serialised representation of `arr`.
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
*
* @retval false if an error occurred (e.g. buffer overflow).
*/
non_null(1, 3, 5) nullable(2)
bool bin_pack_obj_array(bin_pack_array_cb *callback, const Logger *logger, const void *arr, uint32_t count, uint8_t *buf, uint32_t buf_size);
/** @brief Allocate a new packer object.
*

View File

@ -12,11 +12,30 @@ namespace {
using HmacKey = std::array<uint8_t, CRYPTO_HMAC_KEY_SIZE>;
using Hmac = std::array<uint8_t, CRYPTO_HMAC_SIZE>;
using PublicKey = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
using ExtPublicKey = std::array<uint8_t, EXT_PUBLIC_KEY_SIZE>;
using ExtSecretKey = std::array<uint8_t, EXT_SECRET_KEY_SIZE>;
using Signature = std::array<uint8_t, CRYPTO_SIGNATURE_SIZE>;
using Nonce = std::array<uint8_t, CRYPTO_NONCE_SIZE>;
TEST(CryptoCore, EncryptLargeData)
{
const Random *rng = system_random();
ASSERT_NE(rng, nullptr);
Nonce nonce{};
PublicKey pk;
SecretKey sk;
crypto_new_keypair(rng, pk.data(), sk.data());
// 100 MiB of data (all zeroes, doesn't matter what's inside).
std::vector<uint8_t> plain(100 * 1024 * 1024);
std::vector<uint8_t> encrypted(plain.size() + CRYPTO_MAC_SIZE);
encrypt_data(pk.data(), sk.data(), nonce.data(), plain.data(), plain.size(), encrypted.data());
}
TEST(CryptoCore, IncrementNonce)
{
Nonce nonce{};
@ -60,7 +79,8 @@ TEST(CryptoCore, Signatures)
EXPECT_TRUE(create_extended_keypair(pk.data(), sk.data()));
std::vector<uint8_t> message;
std::vector<uint8_t> message{0};
message.clear();
// Try a few different sizes, including empty 0 length message.
for (uint8_t i = 0; i < 100; ++i) {
@ -82,7 +102,8 @@ TEST(CryptoCore, Hmac)
HmacKey sk;
new_hmac_key(rng, sk.data());
std::vector<uint8_t> message;
std::vector<uint8_t> message{0};
message.clear();
// Try a few different sizes, including empty 0 length message.
for (uint8_t i = 0; i < 100; ++i) {

View File

@ -50,8 +50,10 @@ TEST_F(Announces, CanBeCreatedAndDeleted)
GC_Public_Announce ann{};
ann.chat_public_key[0] = 0x88;
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann), nullptr);
#ifndef _DEBUG
ASSERT_EQ(gca_add_announce(mono_time_, gca_, nullptr), nullptr);
ASSERT_EQ(gca_add_announce(mono_time_, nullptr, &ann), nullptr);
#endif
}
TEST_F(Announces, AnnouncesCanTimeOut)
@ -103,7 +105,9 @@ TEST_F(Announces, AnnouncesGetAndCleanup)
cleanup_gca(gca_, ann2.chat_public_key);
ASSERT_EQ(gca_get_announces(gca_, &announces, 1, ann2.chat_public_key, empty_pk), 0);
#ifndef _DEBUG
ASSERT_EQ(gca_get_announces(gca_, nullptr, 1, ann2.chat_public_key, empty_pk), -1);
#endif
}
struct AnnouncesPack : ::testing::Test {
@ -162,19 +166,23 @@ TEST_F(AnnouncesPack, PublicAnnounceCanBePackedAndUnpacked)
TEST_F(AnnouncesPack, UnpackEmptyPublicAnnounce)
{
#ifndef _DEBUG
GC_Public_Announce ann{};
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
EXPECT_EQ(gca_unpack_public_announce(logger_, nullptr, 0, &ann), -1);
EXPECT_EQ(gca_unpack_public_announce(logger_, packed.data(), packed.size(), nullptr), -1);
#endif
}
TEST_F(AnnouncesPack, PackEmptyPublicAnnounce)
{
#ifndef _DEBUG
GC_Public_Announce ann{};
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
EXPECT_EQ(gca_pack_public_announce(logger_, packed.data(), packed.size(), nullptr), -1);
EXPECT_EQ(gca_pack_public_announce(logger_, nullptr, 0, &ann), -1);
#endif
}
TEST_F(AnnouncesPack, PublicAnnouncePackNull)
@ -198,7 +206,9 @@ TEST_F(AnnouncesPack, PublicAnnouncePackNull)
TEST_F(AnnouncesPack, AnnouncesValidationCheck)
{
#ifndef _DEBUG
EXPECT_EQ(gca_is_valid_announce(nullptr), false);
#endif
GC_Announce announce = {0};
EXPECT_EQ(gca_is_valid_announce(&announce), false);
@ -217,8 +227,10 @@ TEST_F(AnnouncesPack, UnpackIncompleteAnnouncesList)
GC_Announce announce;
EXPECT_EQ(gca_unpack_announces_list(logger_, data, sizeof(data), &announce, 1), -1);
#ifndef _DEBUG
EXPECT_EQ(gca_unpack_announces_list(logger_, data, sizeof(data), nullptr, 1), -1);
EXPECT_EQ(gca_unpack_announces_list(logger_, nullptr, 0, &announce, 1), -1);
#endif
}
TEST_F(AnnouncesPack, PackedAnnouncesListCanBeUnpacked)
@ -246,17 +258,21 @@ TEST_F(AnnouncesPack, PackingEmptyAnnounceFails)
std::vector<uint8_t> packed(gca_pack_announces_list_size(1));
EXPECT_EQ(
gca_pack_announces_list(logger_, packed.data(), packed.size(), &announce, 1, nullptr), -1);
#ifndef _DEBUG
EXPECT_EQ(
gca_pack_announces_list(logger_, packed.data(), packed.size(), nullptr, 1, nullptr), -1);
EXPECT_EQ(gca_pack_announces_list(logger_, nullptr, 0, &announce, 1, nullptr), -1);
#endif
}
TEST_F(AnnouncesPack, PackAnnounceNull)
{
#ifndef _DEBUG
std::vector<uint8_t> data(GCA_ANNOUNCE_MAX_SIZE);
GC_Announce announce;
ASSERT_EQ(gca_pack_announce(logger_, nullptr, 0, &announce), -1);
ASSERT_EQ(gca_pack_announce(logger_, data.data(), data.size(), nullptr), -1);
#endif
}
} // namespace

View File

@ -182,7 +182,7 @@ static void kill_group_friend_connection(const GC_Session *c, const GC_Chat *cha
uint16_t gc_get_wrapped_packet_size(uint16_t length, Net_Packet_Type packet_type)
{
assert(length <= MAX_GC_PACKET_CHUNK_SIZE);
assert(length <= (packet_type == NET_PACKET_GC_LOSSY ? MAX_GC_CUSTOM_LOSSY_PACKET_SIZE : MAX_GC_PACKET_CHUNK_SIZE));
const uint16_t min_header_size = packet_type == NET_PACKET_GC_LOSSY
? GC_MIN_LOSSY_PAYLOAD_SIZE
@ -226,10 +226,20 @@ GC_Connection *get_gc_connection(const GC_Chat *chat, int peer_number)
return &peer->gconn;
}
/** Returns the amount of empty padding a packet of designated length should have. */
static uint16_t group_packet_padding_length(uint16_t length)
/** Returns the max packet size, not wrapped */
static uint16_t group_packet_max_packet_size(Net_Packet_Type net_packet_type)
{
return (MAX_GC_PACKET_CHUNK_SIZE - length) % GC_MAX_PACKET_PADDING;
if (net_packet_type == NET_PACKET_GC_LOSSY) {
return MAX_GC_CUSTOM_LOSSY_PACKET_SIZE;
} else {
return MAX_GC_PACKET_CHUNK_SIZE;
}
}
/** Returns the amount of empty padding a packet of designated length should have. */
static uint16_t group_packet_padding_length(uint16_t length, uint16_t max_length)
{
return (max_length - length) % GC_MAX_PACKET_PADDING;
}
void gc_get_self_nick(const GC_Chat *chat, uint8_t *nick)
@ -1270,8 +1280,8 @@ static uint16_t unpack_gc_shared_state(GC_SharedState *shared_state, const uint8
memcpy(&voice_state, data + len_processed, sizeof(uint8_t));
len_processed += sizeof(uint8_t);
shared_state->voice_state = (Group_Voice_State)voice_state;
shared_state->privacy_state = (Group_Privacy_State)privacy_state;
shared_state->voice_state = group_voice_state_from_int(voice_state);
shared_state->privacy_state = group_privacy_state_from_int(privacy_state);
return len_processed;
}
@ -1483,9 +1493,10 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
int group_packet_wrap(
const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
uint8_t gp_packet_type, uint8_t net_packet_type)
uint8_t gp_packet_type, Net_Packet_Type net_packet_type)
{
const uint16_t padding_len = group_packet_padding_length(length);
const uint16_t max_packet_size = group_packet_max_packet_size(net_packet_type);
const uint16_t padding_len = group_packet_padding_length(length, max_packet_size);
const uint16_t min_packet_size = net_packet_type == NET_PACKET_GC_LOSSLESS
? length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + GC_MESSAGE_ID_BYTES + 1
: length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1;
@ -1495,8 +1506,8 @@ int group_packet_wrap(
return -1;
}
if (length > MAX_GC_PACKET_CHUNK_SIZE) {
LOGGER_ERROR(log, "Packet payload size (%u) exceeds maximum (%u)", length, MAX_GC_PACKET_CHUNK_SIZE);
if (length > max_packet_size) {
LOGGER_ERROR(log, "Packet payload size (%u) exceeds maximum (%u)", length, max_packet_size);
return -1;
}
@ -1563,7 +1574,7 @@ non_null()
static bool send_lossy_group_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *data,
uint16_t length, uint8_t packet_type)
{
assert(length <= MAX_GC_PACKET_CHUNK_SIZE);
assert(length <= MAX_GC_CUSTOM_LOSSY_PACKET_SIZE);
if (!gconn->handshaked || gconn->pending_delete) {
return false;
@ -3510,8 +3521,8 @@ 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);
if (peer_number_is_self(peer_number)) { // we cannot have a connection with ourselves
return 0;
if (peer_number_is_self(peer_number)) {
return chat->self_udp_status == SELF_UDP_STATUS_NONE ? 1 : 2;
}
const GC_Connection *gconn = get_gc_connection(chat, peer_number);
@ -7224,7 +7235,9 @@ static int get_new_group_index(GC_Session *c)
c->chats[new_index] = empty_gc_chat;
memset(&c->chats[new_index].saved_invites, -1, sizeof(c->chats[new_index].saved_invites));
for (size_t i = 0; i < sizeof(c->chats[new_index].saved_invites)/sizeof(*c->chats[new_index].saved_invites); ++i) {
c->chats[new_index].saved_invites[i] = -1;
}
++c->chats_index;
@ -7279,7 +7292,7 @@ static bool init_gc_tcp_connection(const GC_Session *c, GC_Chat *chat)
/** Initializes default shared state values. */
non_null()
static void init_gc_shared_state(GC_Chat *chat, const Group_Privacy_State privacy_state)
static void init_gc_shared_state(GC_Chat *chat, Group_Privacy_State privacy_state)
{
chat->shared_state.maxpeers = MAX_GC_PEERS_DEFAULT;
chat->shared_state.privacy_state = privacy_state;

View File

@ -142,7 +142,7 @@ non_null(1, 2, 3, 4, 5) nullable(7)
int group_packet_wrap(
const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
uint8_t gp_packet_type, uint8_t net_packet_type);
uint8_t gp_packet_type, Net_Packet_Type net_packet_type);
/** @brief Returns the size of a wrapped/encrypted packet with a plain size of `length`.
*
@ -162,7 +162,7 @@ uint16_t gc_get_wrapped_packet_size(uint16_t length, Net_Packet_Type packet_type
* Returns -4 if the sender does not have permission to speak.
* Returns -5 if the packet fails to send.
*/
non_null(1, 2, 3, 4) nullable(5)
non_null(1, 2) nullable(5)
int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length, uint8_t type,
uint32_t *message_id);
@ -391,10 +391,13 @@ 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 Gets the connection status for peer associated with `peer_id`.
*
* If `peer_id` designates ourself, the return value indicates whether we're capable
* of making UDP connections with other peers, or are limited to TCP connections.
*
* Returns 2 if we have a direct (UDP) connection with a peer.
* Returns 1 if we have an indirect (TCP) connection with a peer.
* Returns 0 if peer_id is invalid or corresponds to ourselves.
* Returns 0 if peer_id is invalid.
*
* Note: Return values must correspond to Tox_Connection enum in API.
*/

View File

@ -34,7 +34,7 @@
#define MAX_GC_MESSAGE_SIZE GROUP_MAX_MESSAGE_LENGTH
#define MAX_GC_MESSAGE_RAW_SIZE (MAX_GC_MESSAGE_SIZE + GC_MESSAGE_PSEUDO_ID_SIZE)
#define MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE 1373
#define MAX_GC_CUSTOM_LOSSY_PACKET_SIZE MAX_GC_PACKET_CHUNK_SIZE
#define MAX_GC_CUSTOM_LOSSY_PACKET_SIZE 1373
#define MAX_GC_PASSWORD_SIZE 32
#define MAX_GC_SAVED_INVITES 10
#define MAX_GC_PEERS_DEFAULT 100
@ -401,7 +401,8 @@ int unpack_gc_saved_peers(GC_Chat *chat, const uint8_t *data, uint16_t length);
/** @brief Packs all valid entries from saved peerlist into `data`.
*
* If `processed` is non-null it will be set to the length of the packed data.
* If `processed` is non-null it will be set to the length of the packed data
* on success, and will be untouched on error.
*
* Return the number of packed saved peers on success.
* Return -1 if buffer is too small.

View File

@ -453,6 +453,7 @@ int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer
gconn = get_gc_connection(chat, peer_number);
if (gconn == nullptr) {
free(payload);
return 0;
}

View File

@ -9,7 +9,6 @@
#include "group_pack.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -19,6 +18,32 @@
#include "ccompat.h"
#include "util.h"
Group_Privacy_State group_privacy_state_from_int(uint8_t value)
{
switch (value) {
case 0:
return GI_PUBLIC;
case 1:
return GI_PRIVATE;
default:
return GI_PUBLIC;
}
}
Group_Voice_State group_voice_state_from_int(uint8_t value)
{
switch (value) {
case 0:
return GV_ALL;
case 1:
return GV_MODS;
case 2:
return GV_FOUNDER;
default:
return GV_ALL;
}
}
non_null()
static bool load_unpack_state_values(GC_Chat *chat, Bin_Unpack *bu)
{
@ -44,8 +69,8 @@ static bool load_unpack_state_values(GC_Chat *chat, Bin_Unpack *bu)
}
chat->connection_state = manually_disconnected ? CS_DISCONNECTED : CS_CONNECTING;
chat->shared_state.privacy_state = (Group_Privacy_State)privacy_state;
chat->shared_state.voice_state = (Group_Voice_State)voice_state;
chat->shared_state.privacy_state = group_privacy_state_from_int(privacy_state);
chat->shared_state.voice_state = group_voice_state_from_int(voice_state);
// we always load saved groups as private in case the group became private while we were offline.
// this will have no detrimental effect if the group is public, as the correct privacy
@ -125,7 +150,7 @@ static bool load_unpack_mod_list(GC_Chat *chat, Bin_Unpack *bu)
if (chat->moderation.num_mods > MOD_MAX_NUM_MODERATORS) {
LOGGER_ERROR(chat->log, "moderation count %u exceeds maximum %u", chat->moderation.num_mods, MOD_MAX_NUM_MODERATORS);
return false;
chat->moderation.num_mods = MOD_MAX_NUM_MODERATORS;
}
uint8_t *packed_mod_list = (uint8_t *)malloc(chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE);
@ -193,7 +218,10 @@ static bool load_unpack_self_info(GC_Chat *chat, Bin_Unpack *bu)
return false;
}
assert(self_nick_len <= MAX_GC_NICK_SIZE);
if (self_nick_len > MAX_GC_NICK_SIZE) {
LOGGER_ERROR(chat->log, "self_nick too big (%u bytes), truncating to %d", self_nick_len, MAX_GC_NICK_SIZE);
self_nick_len = MAX_GC_NICK_SIZE;
}
if (!bin_unpack_bin_fixed(bu, self_nick, self_nick_len)) {
LOGGER_ERROR(chat->log, "Failed to unpack self nick bytes");
@ -206,7 +234,10 @@ static bool load_unpack_self_info(GC_Chat *chat, Bin_Unpack *bu)
return false;
}
assert(chat->numpeers > 0);
if (chat->numpeers == 0) {
LOGGER_ERROR(chat->log, "Failed to unpack self: numpeers should be > 0");
return false;
}
GC_Peer *self = &chat->group[0];
@ -369,9 +400,12 @@ static void save_pack_self_info(const GC_Chat *chat, Bin_Pack *bp)
{
bin_pack_array(bp, 4);
const GC_Peer *self = &chat->group[0];
GC_Peer *self = &chat->group[0];
assert(self->nick_length <= MAX_GC_NICK_SIZE);
if (self->nick_length > MAX_GC_NICK_SIZE) {
LOGGER_ERROR(chat->log, "self_nick is too big (%u). Truncating to %d", self->nick_length, MAX_GC_NICK_SIZE);
self->nick_length = MAX_GC_NICK_SIZE;
}
bin_pack_u16(bp, self->nick_length); // 1
bin_pack_u08(bp, (uint8_t)self->role); // 2

View File

@ -32,4 +32,7 @@ void gc_save_pack_group(const GC_Chat *chat, Bin_Pack *bp);
non_null()
bool gc_load_unpack_group(GC_Chat *chat, Bin_Unpack *bu);
Group_Privacy_State group_privacy_state_from_int(uint8_t value);
Group_Voice_State group_voice_state_from_int(uint8_t value);
#endif // GROUP_PACK_H

View File

@ -165,7 +165,7 @@ 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) - (current_time_monotonic(mono_time) / 1000ULL);
mono_time->base_time = (uint64_t)time(nullptr) * 1000ULL - current_time_monotonic(mono_time);
#endif
mono_time_update(mono_time);
@ -190,14 +190,13 @@ void mono_time_free(const Memory *mem, Mono_Time *mono_time)
void mono_time_update(Mono_Time *mono_time)
{
uint64_t cur_time = 0;
#ifdef OS_WIN32
/* we actually want to update the overflow state of mono_time here */
pthread_mutex_lock(&mono_time->last_clock_lock);
mono_time->last_clock_update = true;
#endif
cur_time = mono_time->current_time_callback(mono_time->user_data) / 1000ULL;
cur_time += mono_time->base_time;
const uint64_t cur_time =
mono_time->base_time + mono_time->current_time_callback(mono_time->user_data);
#ifdef OS_WIN32
pthread_mutex_unlock(&mono_time->last_clock_lock);
#endif
@ -211,21 +210,22 @@ void mono_time_update(Mono_Time *mono_time)
#endif
}
uint64_t mono_time_get(const Mono_Time *mono_time)
uint64_t mono_time_get_ms(const Mono_Time *mono_time)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
// Fuzzing is only single thread for now, no locking needed */
return mono_time->cur_time;
#else
#ifndef ESP_PLATFORM
pthread_rwlock_rdlock(mono_time->time_update_lock);
#endif
const uint64_t cur_time = mono_time->cur_time;
#ifndef ESP_PLATFORM
#if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
pthread_rwlock_unlock(mono_time->time_update_lock);
#endif
return cur_time;
#endif
}
uint64_t mono_time_get(const Mono_Time *mono_time)
{
return mono_time_get_ms(mono_time) / 1000ULL;
}
bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout)
@ -245,9 +245,10 @@ void mono_time_set_current_time_callback(Mono_Time *mono_time,
}
}
/**
* Return current monotonic time in milliseconds (ms). The starting point is
* unspecified.
/** @brief Return current monotonic time in milliseconds (ms).
*
* The starting point is unspecified and in particular is likely not comparable
* to the return value of `mono_time_get_ms()`.
*/
uint64_t current_time_monotonic(Mono_Time *mono_time)
{

View File

@ -61,8 +61,16 @@ void mono_time_free(const Memory *mem, Mono_Time *mono_time);
non_null()
void mono_time_update(Mono_Time *mono_time);
/**
* Return unix time since epoch in seconds.
/** @brief Return current monotonic time in milliseconds (ms).
*
* The starting point is UNIX epoch as measured by `time()` in `mono_time_new()`.
*/
non_null()
uint64_t mono_time_get_ms(const Mono_Time *mono_time);
/** @brief Return a monotonically increasing time in seconds.
*
* The starting point is UNIX epoch as measured by `time()` in `mono_time_new()`.
*/
non_null()
uint64_t mono_time_get(const Mono_Time *mono_time);
@ -73,9 +81,10 @@ uint64_t mono_time_get(const Mono_Time *mono_time);
non_null()
bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout);
/**
* Return current monotonic time in milliseconds (ms). The starting point is
* unspecified.
/** @brief Return current monotonic time in milliseconds (ms).
*
* The starting point is unspecified and in particular is likely not comparable
* to the return value of `mono_time_get_ms()`.
*/
non_null()
uint64_t current_time_monotonic(Mono_Time *mono_time);

View File

@ -1184,11 +1184,11 @@ Networking_Core *new_networking_ex(
int n = 1024 * 1024 * 2;
if (net_setsockopt(ns, temp->sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) != 0) {
LOGGER_ERROR(log, "failed to set socket option %d", SO_RCVBUF);
LOGGER_WARNING(log, "failed to set socket option %d", SO_RCVBUF);
}
if (net_setsockopt(ns, temp->sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) != 0) {
LOGGER_ERROR(log, "failed to set socket option %d", SO_SNDBUF);
LOGGER_WARNING(log, "failed to set socket option %d", SO_SNDBUF);
}
/* Enable broadcast on socket */

View File

@ -3307,7 +3307,7 @@ uint32_t tox_group_max_message_length(void);
/**
* Maximum length of a group custom lossy packet.
*/
#define TOX_GROUP_MAX_CUSTOM_LOSSY_PACKET_LENGTH 500
#define TOX_GROUP_MAX_CUSTOM_LOSSY_PACKET_LENGTH 1373
uint32_t tox_group_max_custom_lossy_packet_length(void);
@ -3967,7 +3967,8 @@ Tox_Group_Role tox_group_peer_get_role(const Tox *tox, uint32_t group_number, ui
/**
* Return the type of connection we have established with a peer.
*
* This function will return an error if called on ourselves.
* If `peer_id` designates ourself, the return value indicates whether we're capable
* of making UDP connections with other peers, or are limited to TCP connections.
*
* @param group_number The group number of the group we wish to query.
* @param peer_id The ID of the peer whose connection status we wish to query.

View File

@ -326,20 +326,20 @@ bool tox_events_unpack(Tox_Events *events, Bin_Unpack *bu)
return true;
}
non_null(1) nullable(2)
static bool tox_events_bin_pack_handler(Bin_Pack *bp, const void *obj)
non_null(1) nullable(2, 3)
static bool tox_events_bin_pack_handler(Bin_Pack *bp, const Logger *logger, const void *obj)
{
return tox_events_pack((const Tox_Events *)obj, bp);
}
uint32_t tox_events_bytes_size(const Tox_Events *events)
{
return bin_pack_obj_size(tox_events_bin_pack_handler, events);
return bin_pack_obj_size(tox_events_bin_pack_handler, nullptr, events);
}
void tox_events_get_bytes(const Tox_Events *events, uint8_t *bytes)
{
bin_pack_obj(tox_events_bin_pack_handler, events, bytes, UINT32_MAX);
bin_pack_obj(tox_events_bin_pack_handler, nullptr, events, bytes, UINT32_MAX);
}
Tox_Events *tox_events_load(const Tox_System *sys, const uint8_t *bytes, uint32_t bytes_size)

View File

@ -9,6 +9,17 @@
#include "bin_unpack.h"
#include "ccompat.h"
static Tox_Conference_Type tox_conference_type_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_CONFERENCE_TYPE_TEXT;
case 1:
return TOX_CONFERENCE_TYPE_AV;
default:
return TOX_CONFERENCE_TYPE_TEXT;
}
}
bool tox_unpack_conference_type(Bin_Unpack *bu, Tox_Conference_Type *val)
{
uint32_t u32;
@ -17,10 +28,23 @@ bool tox_unpack_conference_type(Bin_Unpack *bu, Tox_Conference_Type *val)
return false;
}
*val = (Tox_Conference_Type)u32;
*val = tox_conference_type_from_int(u32);
return true;
}
static Tox_Connection tox_connection_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_CONNECTION_NONE;
case 1:
return TOX_CONNECTION_TCP;
case 2:
return TOX_CONNECTION_UDP;
default:
return TOX_CONNECTION_NONE;
}
}
bool tox_unpack_connection(Bin_Unpack *bu, Tox_Connection *val)
{
uint32_t u32;
@ -29,10 +53,23 @@ bool tox_unpack_connection(Bin_Unpack *bu, Tox_Connection *val)
return false;
}
*val = (Tox_Connection)u32;
*val = tox_connection_from_int(u32);
return true;
}
static Tox_File_Control tox_file_control_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_FILE_CONTROL_RESUME;
case 1:
return TOX_FILE_CONTROL_PAUSE;
case 2:
return TOX_FILE_CONTROL_CANCEL;
default:
return TOX_FILE_CONTROL_RESUME;
}
}
bool tox_unpack_file_control(Bin_Unpack *bu, Tox_File_Control *val)
{
uint32_t u32;
@ -41,10 +78,21 @@ bool tox_unpack_file_control(Bin_Unpack *bu, Tox_File_Control *val)
return false;
}
*val = (Tox_File_Control)u32;
*val = tox_file_control_from_int(u32);
return true;
}
static Tox_Message_Type tox_message_type_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_MESSAGE_TYPE_NORMAL;
case 1:
return TOX_MESSAGE_TYPE_ACTION;
default:
return TOX_MESSAGE_TYPE_NORMAL;
}
}
bool tox_unpack_message_type(Bin_Unpack *bu, Tox_Message_Type *val)
{
uint32_t u32;
@ -53,10 +101,23 @@ bool tox_unpack_message_type(Bin_Unpack *bu, Tox_Message_Type *val)
return false;
}
*val = (Tox_Message_Type)u32;
*val = tox_message_type_from_int(u32);
return true;
}
static Tox_User_Status tox_user_status_from_int(uint32_t value)
{
switch (value) {
case 0:
return TOX_USER_STATUS_NONE;
case 1:
return TOX_USER_STATUS_AWAY;
case 2:
return TOX_USER_STATUS_BUSY;
default:
return TOX_USER_STATUS_NONE;
}
}
bool tox_unpack_user_status(Bin_Unpack *bu, Tox_User_Status *val)
{
uint32_t u32;
@ -65,7 +126,7 @@ bool tox_unpack_user_status(Bin_Unpack *bu, Tox_User_Status *val)
return false;
}
*val = (Tox_User_Status)u32;
*val = tox_user_status_from_int(u32);
return true;
}