From 83e200df43eb790719c40103099c8d70e37c0477 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Sun, 24 Dec 2023 12:21:34 +0100 Subject: [PATCH] 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 --- .github/workflows/ci.yml | 10 - .github/workflows/post-submit.yml | 16 + CMakeLists.txt | 1 + auto_tests/group_general_test.c | 26 + auto_tests/onion_test.c | 8 +- auto_tests/tox_dispatch_test.c | 14 + other/bootstrap_daemon/docker/Dockerfile | 9 +- .../docker/tox-bootstrapd.sha256 | 2 +- testing/BUILD.bazel | 22 + third_party/BUILD.bazel | 6 + toxav/msi.c | 1 + toxcore/BUILD.bazel | 2 + toxcore/DHT.c | 20 +- toxcore/Messenger.c | 11 + toxcore/TCP_common.c | 6 +- toxcore/TCP_connection.h | 2 +- toxcore/announce.c | 2 +- toxcore/group_chats.c | 57 + toxcore/group_chats.h | 23 + toxcore/logger.c | 5 + toxcore/logger.h | 5 +- toxcore/mono_time.c | 5 +- toxcore/mono_time_test.cc | 21 + toxcore/network.c | 23 +- toxcore/network.h | 7 +- toxcore/onion.c | 60 +- toxcore/onion.h | 3 +- toxcore/onion_announce.c | 24 +- toxcore/onion_announce.h | 18 +- toxcore/onion_client.c | 109 +- toxcore/shared_key_cache.c | 20 +- toxcore/shared_key_cache.h | 8 +- toxcore/tox.c | 6 +- toxcore/tox.h | 142 ++ toxcore/tox_api.c | 1394 +++++++++++++++++ toxcore/tox_private.c | 55 + toxcore/tox_private.h | 45 + toxcore/tox_unpack.c | 95 +- toxcore/util.c | 4 + toxcore/util.h | 1 + 40 files changed, 2174 insertions(+), 114 deletions(-) create mode 100644 .github/workflows/post-submit.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2266f2cd..1fe12fb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: diff --git a/.github/workflows/post-submit.yml b/.github/workflows/post-submit.yml new file mode 100644 index 00000000..56895a6a --- /dev/null +++ b/.github/workflows/post-submit.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e0aa8fc..fd4f071b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/auto_tests/group_general_test.c b/auto_tests/group_general_test.c index 1a506ab4..328e76f3 100644 --- a/auto_tests/group_general_test.c +++ b/auto_tests/group_general_test.c @@ -9,6 +9,7 @@ #include #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); diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 6975c3ec..8a5a821c 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c @@ -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")); diff --git a/auto_tests/tox_dispatch_test.c b/auto_tests/tox_dispatch_test.c index 209e1378..98634369 100644 --- a/auto_tests/tox_dispatch_test.c +++ b/auto_tests/tox_dispatch_test.c @@ -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; } diff --git a/other/bootstrap_daemon/docker/Dockerfile b/other/bootstrap_daemon/docker/Dockerfile index e86290b1..babaf219 100644 --- a/other/bootstrap_daemon/docker/Dockerfile +++ b/other/bootstrap_daemon/docker/Dockerfile @@ -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 \ diff --git a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 index 684a7911..7b49f7c4 100644 --- a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 +++ b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 @@ -1 +1 @@ -5aac1df4d6c1de289e8e9f646d06099c84fd4d9b80d19f45e3254eec3ece2bff /usr/local/bin/tox-bootstrapd +21cf23b1a2e46712663dc4f8daa322991af51b9e82626a127cf1bc8dc583b598 /usr/local/bin/tox-bootstrapd diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel index 52a77862..3206e5f5 100644 --- a/testing/BUILD.bazel +++ b/testing/BUILD.bazel @@ -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", diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel index 7a004d8a..45344cb2 100644 --- a/third_party/BUILD.bazel +++ b/third_party/BUILD.bazel @@ -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__"], +) diff --git a/toxav/msi.c b/toxav/msi.c index 9b016ade..e243884a 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -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: { diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 46d1cb40..56693417 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -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", ], diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 397e18cf..9a418039 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -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; } diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index cd1e53d9..cf6f613d 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -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 diff --git a/toxcore/TCP_common.c b/toxcore/TCP_common.c index 5d001948..4d0d009f 100644 --- a/toxcore/TCP_common.c +++ b/toxcore/TCP_common.c @@ -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; } diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h index f01e7054..04b48525 100644 --- a/toxcore/TCP_connection.h +++ b/toxcore/TCP_connection.h @@ -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. diff --git a/toxcore/announce.c b/toxcore/announce.c index fbbb2350..402d1136 100644 --- a/toxcore/announce.c +++ b/toxcore/announce.c @@ -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; diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 311960de..f3731108 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c @@ -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); diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h index 066b717c..920e1a67 100644 --- a/toxcore/group_chats.h +++ b/toxcore/group_chats.h @@ -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 diff --git a/toxcore/logger.c b/toxcore/logger.c index d281a660..6c532623 100644 --- a/toxcore/logger.c +++ b/toxcore/logger.c @@ -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(); +} diff --git a/toxcore/logger.h b/toxcore/logger.h index ee5838ae..8388b166 100644 --- a/toxcore/logger.h +++ b/toxcore/logger.h @@ -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, ...) \ diff --git a/toxcore/mono_time.c b/toxcore/mono_time.c index 2ce817f6..7076cb07 100644 --- a/toxcore/mono_time.c +++ b/toxcore/mono_time.c @@ -32,6 +32,7 @@ #include #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); diff --git a/toxcore/mono_time_test.cc b/toxcore/mono_time_test.cc index 379b606c..cc667199 100644 --- a/toxcore/mono_time_test.cc +++ b/toxcore/mono_time_test.cc @@ -2,6 +2,9 @@ #include +#include +#include + 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(); diff --git a/toxcore/network.c b/toxcore/network.c index 3e0e6f49..d8cabc71 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -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; } diff --git a/toxcore/network.h b/toxcore/network.h index 2f518c1d..2a6a0833 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -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. * diff --git a/toxcore/onion.c b/toxcore/onion.c index d7ec8bfd..80bb4920 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c @@ -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 || diff --git a/toxcore/onion.h b/toxcore/onion.h index 7f71c249..732d926c 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h @@ -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. diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 551e7b1f..d4a37ad9 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -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; diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index 857f4706..90195351 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -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, diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index c15eb555..cdf0b85d 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -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; } diff --git a/toxcore/shared_key_cache.c b/toxcore/shared_key_cache.c index 4b87945c..0adc1e82 100644 --- a/toxcore/shared_key_cache.c +++ b/toxcore/shared_key_cache.c @@ -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]); } } diff --git a/toxcore/shared_key_cache.h b/toxcore/shared_key_cache.h index dc42b380..b7112720 100644 --- a/toxcore/shared_key_cache.h +++ b/toxcore/shared_key_cache.h @@ -8,6 +8,7 @@ #include // 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. diff --git a/toxcore/tox.c b/toxcore/tox.c index 768d5f9e..f802ce16 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -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); diff --git a/toxcore/tox.h b/toxcore/tox.h index b3c7de00..7bf26d44 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -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. diff --git a/toxcore/tox_api.c b/toxcore/tox_api.c index 61c248c3..9b3a888d 100644 --- a/toxcore/tox_api.c +++ b/toxcore/tox_api.c @@ -124,6 +124,10 @@ uint32_t tox_group_peer_public_key_size(void) { return TOX_GROUP_PEER_PUBLIC_KEY_SIZE; } +uint32_t tox_group_peer_ip_string_max_length(void) +{ + return TOX_GROUP_PEER_IP_STRING_MAX_LENGTH; +} uint32_t tox_dht_node_ip_string_size(void) { return TOX_DHT_NODE_IP_STRING_SIZE; @@ -209,3 +213,1393 @@ void tox_options_free(struct Tox_Options *options) { free(options); } + +const char *tox_user_status_to_string(Tox_User_Status value) +{ + switch (value) { + case TOX_USER_STATUS_NONE: + return "TOX_USER_STATUS_NONE"; + + case TOX_USER_STATUS_AWAY: + return "TOX_USER_STATUS_AWAY"; + + case TOX_USER_STATUS_BUSY: + return "TOX_USER_STATUS_BUSY"; + } + + return ""; +} +const char *tox_message_type_to_string(Tox_Message_Type value) +{ + switch (value) { + case TOX_MESSAGE_TYPE_NORMAL: + return "TOX_MESSAGE_TYPE_NORMAL"; + + case TOX_MESSAGE_TYPE_ACTION: + return "TOX_MESSAGE_TYPE_ACTION"; + } + + return ""; +} +const char *tox_proxy_type_to_string(Tox_Proxy_Type value) +{ + switch (value) { + case TOX_PROXY_TYPE_NONE: + return "TOX_PROXY_TYPE_NONE"; + + case TOX_PROXY_TYPE_HTTP: + return "TOX_PROXY_TYPE_HTTP"; + + case TOX_PROXY_TYPE_SOCKS5: + return "TOX_PROXY_TYPE_SOCKS5"; + } + + return ""; +} +const char *tox_savedata_type_to_string(Tox_Savedata_Type value) +{ + switch (value) { + case TOX_SAVEDATA_TYPE_NONE: + return "TOX_SAVEDATA_TYPE_NONE"; + + case TOX_SAVEDATA_TYPE_TOX_SAVE: + return "TOX_SAVEDATA_TYPE_TOX_SAVE"; + + case TOX_SAVEDATA_TYPE_SECRET_KEY: + return "TOX_SAVEDATA_TYPE_SECRET_KEY"; + } + + return ""; +} +const char *tox_log_level_to_string(Tox_Log_Level value) +{ + switch (value) { + case TOX_LOG_LEVEL_TRACE: + return "TOX_LOG_LEVEL_TRACE"; + + case TOX_LOG_LEVEL_DEBUG: + return "TOX_LOG_LEVEL_DEBUG"; + + case TOX_LOG_LEVEL_INFO: + return "TOX_LOG_LEVEL_INFO"; + + case TOX_LOG_LEVEL_WARNING: + return "TOX_LOG_LEVEL_WARNING"; + + case TOX_LOG_LEVEL_ERROR: + return "TOX_LOG_LEVEL_ERROR"; + } + + return ""; +} +const char *tox_err_options_new_to_string(Tox_Err_Options_New value) +{ + switch (value) { + case TOX_ERR_OPTIONS_NEW_OK: + return "TOX_ERR_OPTIONS_NEW_OK"; + + case TOX_ERR_OPTIONS_NEW_MALLOC: + return "TOX_ERR_OPTIONS_NEW_MALLOC"; + } + + return ""; +} +const char *tox_err_new_to_string(Tox_Err_New value) +{ + switch (value) { + case TOX_ERR_NEW_OK: + return "TOX_ERR_NEW_OK"; + + case TOX_ERR_NEW_NULL: + return "TOX_ERR_NEW_NULL"; + + case TOX_ERR_NEW_MALLOC: + return "TOX_ERR_NEW_MALLOC"; + + case TOX_ERR_NEW_PORT_ALLOC: + return "TOX_ERR_NEW_PORT_ALLOC"; + + case TOX_ERR_NEW_PROXY_BAD_TYPE: + return "TOX_ERR_NEW_PROXY_BAD_TYPE"; + + case TOX_ERR_NEW_PROXY_BAD_HOST: + return "TOX_ERR_NEW_PROXY_BAD_HOST"; + + case TOX_ERR_NEW_PROXY_BAD_PORT: + return "TOX_ERR_NEW_PROXY_BAD_PORT"; + + case TOX_ERR_NEW_PROXY_NOT_FOUND: + return "TOX_ERR_NEW_PROXY_NOT_FOUND"; + + case TOX_ERR_NEW_LOAD_ENCRYPTED: + return "TOX_ERR_NEW_LOAD_ENCRYPTED"; + + case TOX_ERR_NEW_LOAD_BAD_FORMAT: + return "TOX_ERR_NEW_LOAD_BAD_FORMAT"; + } + + return ""; +} +const char *tox_err_bootstrap_to_string(Tox_Err_Bootstrap value) +{ + switch (value) { + case TOX_ERR_BOOTSTRAP_OK: + return "TOX_ERR_BOOTSTRAP_OK"; + + case TOX_ERR_BOOTSTRAP_NULL: + return "TOX_ERR_BOOTSTRAP_NULL"; + + case TOX_ERR_BOOTSTRAP_BAD_HOST: + return "TOX_ERR_BOOTSTRAP_BAD_HOST"; + + case TOX_ERR_BOOTSTRAP_BAD_PORT: + return "TOX_ERR_BOOTSTRAP_BAD_PORT"; + } + + return ""; +} +const char *tox_connection_to_string(Tox_Connection value) +{ + switch (value) { + case TOX_CONNECTION_NONE: + return "TOX_CONNECTION_NONE"; + + case TOX_CONNECTION_TCP: + return "TOX_CONNECTION_TCP"; + + case TOX_CONNECTION_UDP: + return "TOX_CONNECTION_UDP"; + } + + return ""; +} +const char *tox_err_set_info_to_string(Tox_Err_Set_Info value) +{ + switch (value) { + case TOX_ERR_SET_INFO_OK: + return "TOX_ERR_SET_INFO_OK"; + + case TOX_ERR_SET_INFO_NULL: + return "TOX_ERR_SET_INFO_NULL"; + + case TOX_ERR_SET_INFO_TOO_LONG: + return "TOX_ERR_SET_INFO_TOO_LONG"; + } + + return ""; +} +const char *tox_err_friend_add_to_string(Tox_Err_Friend_Add value) +{ + switch (value) { + case TOX_ERR_FRIEND_ADD_OK: + return "TOX_ERR_FRIEND_ADD_OK"; + + case TOX_ERR_FRIEND_ADD_NULL: + return "TOX_ERR_FRIEND_ADD_NULL"; + + case TOX_ERR_FRIEND_ADD_TOO_LONG: + return "TOX_ERR_FRIEND_ADD_TOO_LONG"; + + case TOX_ERR_FRIEND_ADD_NO_MESSAGE: + return "TOX_ERR_FRIEND_ADD_NO_MESSAGE"; + + case TOX_ERR_FRIEND_ADD_OWN_KEY: + return "TOX_ERR_FRIEND_ADD_OWN_KEY"; + + case TOX_ERR_FRIEND_ADD_ALREADY_SENT: + return "TOX_ERR_FRIEND_ADD_ALREADY_SENT"; + + case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM: + return "TOX_ERR_FRIEND_ADD_BAD_CHECKSUM"; + + case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM: + return "TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM"; + + case TOX_ERR_FRIEND_ADD_MALLOC: + return "TOX_ERR_FRIEND_ADD_MALLOC"; + } + + return ""; +} +const char *tox_err_friend_delete_to_string(Tox_Err_Friend_Delete value) +{ + switch (value) { + case TOX_ERR_FRIEND_DELETE_OK: + return "TOX_ERR_FRIEND_DELETE_OK"; + + case TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_by_public_key_to_string(Tox_Err_Friend_By_Public_Key value) +{ + switch (value) { + case TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK: + return "TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK"; + + case TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL: + return "TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL"; + + case TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND: + return "TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_get_public_key_to_string(Tox_Err_Friend_Get_Public_Key value) +{ + switch (value) { + case TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK: + return "TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK"; + + case TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_get_last_online_to_string(Tox_Err_Friend_Get_Last_Online value) +{ + switch (value) { + case TOX_ERR_FRIEND_GET_LAST_ONLINE_OK: + return "TOX_ERR_FRIEND_GET_LAST_ONLINE_OK"; + + case TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_query_to_string(Tox_Err_Friend_Query value) +{ + switch (value) { + case TOX_ERR_FRIEND_QUERY_OK: + return "TOX_ERR_FRIEND_QUERY_OK"; + + case TOX_ERR_FRIEND_QUERY_NULL: + return "TOX_ERR_FRIEND_QUERY_NULL"; + + case TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_set_typing_to_string(Tox_Err_Set_Typing value) +{ + switch (value) { + case TOX_ERR_SET_TYPING_OK: + return "TOX_ERR_SET_TYPING_OK"; + + case TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND: + return "TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_send_message_to_string(Tox_Err_Friend_Send_Message value) +{ + switch (value) { + case TOX_ERR_FRIEND_SEND_MESSAGE_OK: + return "TOX_ERR_FRIEND_SEND_MESSAGE_OK"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_NULL: + return "TOX_ERR_FRIEND_SEND_MESSAGE_NULL"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ: + return "TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG: + return "TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG"; + + case TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY: + return "TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY"; + } + + return ""; +} +const char *tox_file_control_to_string(Tox_File_Control value) +{ + switch (value) { + case TOX_FILE_CONTROL_RESUME: + return "TOX_FILE_CONTROL_RESUME"; + + case TOX_FILE_CONTROL_PAUSE: + return "TOX_FILE_CONTROL_PAUSE"; + + case TOX_FILE_CONTROL_CANCEL: + return "TOX_FILE_CONTROL_CANCEL"; + } + + return ""; +} +const char *tox_err_file_control_to_string(Tox_Err_File_Control value) +{ + switch (value) { + case TOX_ERR_FILE_CONTROL_OK: + return "TOX_ERR_FILE_CONTROL_OK"; + + case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: + return "TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND"; + + case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FILE_CONTROL_NOT_FOUND: + return "TOX_ERR_FILE_CONTROL_NOT_FOUND"; + + case TOX_ERR_FILE_CONTROL_NOT_PAUSED: + return "TOX_ERR_FILE_CONTROL_NOT_PAUSED"; + + case TOX_ERR_FILE_CONTROL_DENIED: + return "TOX_ERR_FILE_CONTROL_DENIED"; + + case TOX_ERR_FILE_CONTROL_ALREADY_PAUSED: + return "TOX_ERR_FILE_CONTROL_ALREADY_PAUSED"; + + case TOX_ERR_FILE_CONTROL_SENDQ: + return "TOX_ERR_FILE_CONTROL_SENDQ"; + } + + return ""; +} +const char *tox_err_file_seek_to_string(Tox_Err_File_Seek value) +{ + switch (value) { + case TOX_ERR_FILE_SEEK_OK: + return "TOX_ERR_FILE_SEEK_OK"; + + case TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND: + return "TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND"; + + case TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FILE_SEEK_NOT_FOUND: + return "TOX_ERR_FILE_SEEK_NOT_FOUND"; + + case TOX_ERR_FILE_SEEK_DENIED: + return "TOX_ERR_FILE_SEEK_DENIED"; + + case TOX_ERR_FILE_SEEK_INVALID_POSITION: + return "TOX_ERR_FILE_SEEK_INVALID_POSITION"; + + case TOX_ERR_FILE_SEEK_SENDQ: + return "TOX_ERR_FILE_SEEK_SENDQ"; + } + + return ""; +} +const char *tox_err_file_get_to_string(Tox_Err_File_Get value) +{ + switch (value) { + case TOX_ERR_FILE_GET_OK: + return "TOX_ERR_FILE_GET_OK"; + + case TOX_ERR_FILE_GET_NULL: + return "TOX_ERR_FILE_GET_NULL"; + + case TOX_ERR_FILE_GET_FRIEND_NOT_FOUND: + return "TOX_ERR_FILE_GET_FRIEND_NOT_FOUND"; + + case TOX_ERR_FILE_GET_NOT_FOUND: + return "TOX_ERR_FILE_GET_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_file_send_to_string(Tox_Err_File_Send value) +{ + switch (value) { + case TOX_ERR_FILE_SEND_OK: + return "TOX_ERR_FILE_SEND_OK"; + + case TOX_ERR_FILE_SEND_NULL: + return "TOX_ERR_FILE_SEND_NULL"; + + case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: + return "TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND"; + + case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FILE_SEND_NAME_TOO_LONG: + return "TOX_ERR_FILE_SEND_NAME_TOO_LONG"; + + case TOX_ERR_FILE_SEND_TOO_MANY: + return "TOX_ERR_FILE_SEND_TOO_MANY"; + } + + return ""; +} +const char *tox_err_file_send_chunk_to_string(Tox_Err_File_Send_Chunk value) +{ + switch (value) { + case TOX_ERR_FILE_SEND_CHUNK_OK: + return "TOX_ERR_FILE_SEND_CHUNK_OK"; + + case TOX_ERR_FILE_SEND_CHUNK_NULL: + return "TOX_ERR_FILE_SEND_CHUNK_NULL"; + + case TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND: + return "TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND"; + + case TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND: + return "TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND"; + + case TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING: + return "TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING"; + + case TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH: + return "TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH"; + + case TOX_ERR_FILE_SEND_CHUNK_SENDQ: + return "TOX_ERR_FILE_SEND_CHUNK_SENDQ"; + + case TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION: + return "TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION"; + } + + return ""; +} +const char *tox_conference_type_to_string(Tox_Conference_Type value) +{ + switch (value) { + case TOX_CONFERENCE_TYPE_TEXT: + return "TOX_CONFERENCE_TYPE_TEXT"; + + case TOX_CONFERENCE_TYPE_AV: + return "TOX_CONFERENCE_TYPE_AV"; + } + + return ""; +} +const char *tox_err_conference_new_to_string(Tox_Err_Conference_New value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_NEW_OK: + return "TOX_ERR_CONFERENCE_NEW_OK"; + + case TOX_ERR_CONFERENCE_NEW_INIT: + return "TOX_ERR_CONFERENCE_NEW_INIT"; + } + + return ""; +} +const char *tox_err_conference_delete_to_string(Tox_Err_Conference_Delete value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_DELETE_OK: + return "TOX_ERR_CONFERENCE_DELETE_OK"; + + case TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_conference_peer_query_to_string(Tox_Err_Conference_Peer_Query value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_PEER_QUERY_OK: + return "TOX_ERR_CONFERENCE_PEER_QUERY_OK"; + + case TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND: + return "TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION: + return "TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION"; + } + + return ""; +} +const char *tox_err_conference_set_max_offline_to_string(Tox_Err_Conference_Set_Max_Offline value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK: + return "TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK"; + + case TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_conference_invite_to_string(Tox_Err_Conference_Invite value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_INVITE_OK: + return "TOX_ERR_CONFERENCE_INVITE_OK"; + + case TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_INVITE_FAIL_SEND: + return "TOX_ERR_CONFERENCE_INVITE_FAIL_SEND"; + + case TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION: + return "TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION"; + } + + return ""; +} +const char *tox_err_conference_join_to_string(Tox_Err_Conference_Join value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_JOIN_OK: + return "TOX_ERR_CONFERENCE_JOIN_OK"; + + case TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH: + return "TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH"; + + case TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE: + return "TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE"; + + case TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND: + return "TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_JOIN_DUPLICATE: + return "TOX_ERR_CONFERENCE_JOIN_DUPLICATE"; + + case TOX_ERR_CONFERENCE_JOIN_INIT_FAIL: + return "TOX_ERR_CONFERENCE_JOIN_INIT_FAIL"; + + case TOX_ERR_CONFERENCE_JOIN_FAIL_SEND: + return "TOX_ERR_CONFERENCE_JOIN_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_conference_send_message_to_string(Tox_Err_Conference_Send_Message value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_SEND_MESSAGE_OK: + return "TOX_ERR_CONFERENCE_SEND_MESSAGE_OK"; + + case TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG: + return "TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG"; + + case TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION: + return "TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION"; + + case TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND: + return "TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_conference_title_to_string(Tox_Err_Conference_Title value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_TITLE_OK: + return "TOX_ERR_CONFERENCE_TITLE_OK"; + + case TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND"; + + case TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH: + return "TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH"; + + case TOX_ERR_CONFERENCE_TITLE_FAIL_SEND: + return "TOX_ERR_CONFERENCE_TITLE_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_conference_get_type_to_string(Tox_Err_Conference_Get_Type value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_GET_TYPE_OK: + return "TOX_ERR_CONFERENCE_GET_TYPE_OK"; + + case TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND: + return "TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_conference_by_id_to_string(Tox_Err_Conference_By_Id value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_BY_ID_OK: + return "TOX_ERR_CONFERENCE_BY_ID_OK"; + + case TOX_ERR_CONFERENCE_BY_ID_NULL: + return "TOX_ERR_CONFERENCE_BY_ID_NULL"; + + case TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND: + return "TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_conference_by_uid_to_string(Tox_Err_Conference_By_Uid value) +{ + switch (value) { + case TOX_ERR_CONFERENCE_BY_UID_OK: + return "TOX_ERR_CONFERENCE_BY_UID_OK"; + + case TOX_ERR_CONFERENCE_BY_UID_NULL: + return "TOX_ERR_CONFERENCE_BY_UID_NULL"; + + case TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND: + return "TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_friend_custom_packet_to_string(Tox_Err_Friend_Custom_Packet value) +{ + switch (value) { + case TOX_ERR_FRIEND_CUSTOM_PACKET_OK: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_OK"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_NULL: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_NULL"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG"; + + case TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ: + return "TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ"; + } + + return ""; +} +const char *tox_err_get_port_to_string(Tox_Err_Get_Port value) +{ + switch (value) { + case TOX_ERR_GET_PORT_OK: + return "TOX_ERR_GET_PORT_OK"; + + case TOX_ERR_GET_PORT_NOT_BOUND: + return "TOX_ERR_GET_PORT_NOT_BOUND"; + } + + return ""; +} +const char *tox_group_privacy_state_to_string(Tox_Group_Privacy_State value) +{ + switch (value) { + case TOX_GROUP_PRIVACY_STATE_PUBLIC: + return "TOX_GROUP_PRIVACY_STATE_PUBLIC"; + + case TOX_GROUP_PRIVACY_STATE_PRIVATE: + return "TOX_GROUP_PRIVACY_STATE_PRIVATE"; + } + + return ""; +} +const char *tox_group_topic_lock_to_string(Tox_Group_Topic_Lock value) +{ + switch (value) { + case TOX_GROUP_TOPIC_LOCK_ENABLED: + return "TOX_GROUP_TOPIC_LOCK_ENABLED"; + + case TOX_GROUP_TOPIC_LOCK_DISABLED: + return "TOX_GROUP_TOPIC_LOCK_DISABLED"; + } + + return ""; +} +const char *tox_group_voice_state_to_string(Tox_Group_Voice_State value) +{ + switch (value) { + case TOX_GROUP_VOICE_STATE_ALL: + return "TOX_GROUP_VOICE_STATE_ALL"; + + case TOX_GROUP_VOICE_STATE_MODERATOR: + return "TOX_GROUP_VOICE_STATE_MODERATOR"; + + case TOX_GROUP_VOICE_STATE_FOUNDER: + return "TOX_GROUP_VOICE_STATE_FOUNDER"; + } + + return ""; +} +const char *tox_group_role_to_string(Tox_Group_Role value) +{ + switch (value) { + case TOX_GROUP_ROLE_FOUNDER: + return "TOX_GROUP_ROLE_FOUNDER"; + + case TOX_GROUP_ROLE_MODERATOR: + return "TOX_GROUP_ROLE_MODERATOR"; + + case TOX_GROUP_ROLE_USER: + return "TOX_GROUP_ROLE_USER"; + + case TOX_GROUP_ROLE_OBSERVER: + return "TOX_GROUP_ROLE_OBSERVER"; + } + + return ""; +} +const char *tox_err_group_new_to_string(Tox_Err_Group_New value) +{ + switch (value) { + case TOX_ERR_GROUP_NEW_OK: + return "TOX_ERR_GROUP_NEW_OK"; + + case TOX_ERR_GROUP_NEW_TOO_LONG: + return "TOX_ERR_GROUP_NEW_TOO_LONG"; + + case TOX_ERR_GROUP_NEW_EMPTY: + return "TOX_ERR_GROUP_NEW_EMPTY"; + + case TOX_ERR_GROUP_NEW_INIT: + return "TOX_ERR_GROUP_NEW_INIT"; + + case TOX_ERR_GROUP_NEW_STATE: + return "TOX_ERR_GROUP_NEW_STATE"; + + case TOX_ERR_GROUP_NEW_ANNOUNCE: + return "TOX_ERR_GROUP_NEW_ANNOUNCE"; + } + + return ""; +} +const char *tox_err_group_join_to_string(Tox_Err_Group_Join value) +{ + switch (value) { + case TOX_ERR_GROUP_JOIN_OK: + return "TOX_ERR_GROUP_JOIN_OK"; + + case TOX_ERR_GROUP_JOIN_INIT: + return "TOX_ERR_GROUP_JOIN_INIT"; + + case TOX_ERR_GROUP_JOIN_BAD_CHAT_ID: + return "TOX_ERR_GROUP_JOIN_BAD_CHAT_ID"; + + case TOX_ERR_GROUP_JOIN_EMPTY: + return "TOX_ERR_GROUP_JOIN_EMPTY"; + + case TOX_ERR_GROUP_JOIN_TOO_LONG: + return "TOX_ERR_GROUP_JOIN_TOO_LONG"; + + case TOX_ERR_GROUP_JOIN_PASSWORD: + return "TOX_ERR_GROUP_JOIN_PASSWORD"; + + case TOX_ERR_GROUP_JOIN_CORE: + return "TOX_ERR_GROUP_JOIN_CORE"; + } + + return ""; +} +const char *tox_err_group_is_connected_to_string(Tox_Err_Group_Is_Connected value) +{ + switch (value) { + case TOX_ERR_GROUP_IS_CONNECTED_OK: + return "TOX_ERR_GROUP_IS_CONNECTED_OK"; + + case TOX_ERR_GROUP_IS_CONNECTED_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_IS_CONNECTED_GROUP_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_group_disconnect_to_string(Tox_Err_Group_Disconnect value) +{ + switch (value) { + case TOX_ERR_GROUP_DISCONNECT_OK: + return "TOX_ERR_GROUP_DISCONNECT_OK"; + + case TOX_ERR_GROUP_DISCONNECT_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_DISCONNECT_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED: + return "TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_reconnect_to_string(Tox_Err_Group_Reconnect value) +{ + switch (value) { + case TOX_ERR_GROUP_RECONNECT_OK: + return "TOX_ERR_GROUP_RECONNECT_OK"; + + case TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_RECONNECT_CORE: + return "TOX_ERR_GROUP_RECONNECT_CORE"; + } + + return ""; +} +const char *tox_err_group_leave_to_string(Tox_Err_Group_Leave value) +{ + switch (value) { + case TOX_ERR_GROUP_LEAVE_OK: + return "TOX_ERR_GROUP_LEAVE_OK"; + + case TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_LEAVE_TOO_LONG: + return "TOX_ERR_GROUP_LEAVE_TOO_LONG"; + + case TOX_ERR_GROUP_LEAVE_FAIL_SEND: + return "TOX_ERR_GROUP_LEAVE_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_group_self_query_to_string(Tox_Err_Group_Self_Query value) +{ + switch (value) { + case TOX_ERR_GROUP_SELF_QUERY_OK: + return "TOX_ERR_GROUP_SELF_QUERY_OK"; + + case TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_group_self_name_set_to_string(Tox_Err_Group_Self_Name_Set value) +{ + switch (value) { + case TOX_ERR_GROUP_SELF_NAME_SET_OK: + return "TOX_ERR_GROUP_SELF_NAME_SET_OK"; + + case TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG: + return "TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG"; + + case TOX_ERR_GROUP_SELF_NAME_SET_INVALID: + return "TOX_ERR_GROUP_SELF_NAME_SET_INVALID"; + + case TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND: + return "TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_group_self_status_set_to_string(Tox_Err_Group_Self_Status_Set value) +{ + switch (value) { + case TOX_ERR_GROUP_SELF_STATUS_SET_OK: + return "TOX_ERR_GROUP_SELF_STATUS_SET_OK"; + + case TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND: + return "TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND"; + } + + return ""; +} +const char *tox_err_group_peer_query_to_string(Tox_Err_Group_Peer_Query value) +{ + switch (value) { + case TOX_ERR_GROUP_PEER_QUERY_OK: + return "TOX_ERR_GROUP_PEER_QUERY_OK"; + + case TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_group_state_queries_to_string(Tox_Err_Group_State_Queries value) +{ + switch (value) { + case TOX_ERR_GROUP_STATE_QUERIES_OK: + return "TOX_ERR_GROUP_STATE_QUERIES_OK"; + + case TOX_ERR_GROUP_STATE_QUERIES_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_STATE_QUERIES_GROUP_NOT_FOUND"; + } + + return ""; +} +const char *tox_err_group_topic_set_to_string(Tox_Err_Group_Topic_Set value) +{ + switch (value) { + case TOX_ERR_GROUP_TOPIC_SET_OK: + return "TOX_ERR_GROUP_TOPIC_SET_OK"; + + case TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: + return "TOX_ERR_GROUP_TOPIC_SET_TOO_LONG"; + + case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: + return "TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS"; + + case TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE: + return "TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE"; + + case TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND: + return "TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND"; + + case TOX_ERR_GROUP_TOPIC_SET_DISCONNECTED: + return "TOX_ERR_GROUP_TOPIC_SET_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_send_message_to_string(Tox_Err_Group_Send_Message value) +{ + switch (value) { + case TOX_ERR_GROUP_SEND_MESSAGE_OK: + return "TOX_ERR_GROUP_SEND_MESSAGE_OK"; + + case TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG: + return "TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG"; + + case TOX_ERR_GROUP_SEND_MESSAGE_EMPTY: + return "TOX_ERR_GROUP_SEND_MESSAGE_EMPTY"; + + case TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE: + return "TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE"; + + case TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS: + return "TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS"; + + case TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND: + return "TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND"; + + case TOX_ERR_GROUP_SEND_MESSAGE_DISCONNECTED: + return "TOX_ERR_GROUP_SEND_MESSAGE_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Private_Message value) +{ + switch (value) { + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED"; + + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE"; + } + + return ""; +} +const char *tox_err_group_send_custom_packet_to_string(Tox_Err_Group_Send_Custom_Packet value) +{ + switch (value) { + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_PERMISSIONS: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_PERMISSIONS"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PACKET_DISCONNECTED: + return "TOX_ERR_GROUP_SEND_CUSTOM_PACKET_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_send_custom_private_packet_to_string(Tox_Err_Group_Send_Custom_Private_Packet value) +{ + switch (value) { + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_TOO_LONG: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_TOO_LONG"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_EMPTY: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_EMPTY"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PEER_NOT_FOUND"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PERMISSIONS: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PERMISSIONS"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_FAIL_SEND: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_FAIL_SEND"; + + case TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_DISCONNECTED: + return "TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_invite_friend_to_string(Tox_Err_Group_Invite_Friend value) +{ + switch (value) { + case TOX_ERR_GROUP_INVITE_FRIEND_OK: + return "TOX_ERR_GROUP_INVITE_FRIEND_OK"; + + case TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND: + return "TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND"; + + case TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL: + return "TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL"; + + case TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND: + return "TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND"; + + case TOX_ERR_GROUP_INVITE_FRIEND_DISCONNECTED: + return "TOX_ERR_GROUP_INVITE_FRIEND_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_invite_accept_to_string(Tox_Err_Group_Invite_Accept value) +{ + switch (value) { + case TOX_ERR_GROUP_INVITE_ACCEPT_OK: + return "TOX_ERR_GROUP_INVITE_ACCEPT_OK"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE: + return "TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED: + return "TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG: + return "TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_EMPTY: + return "TOX_ERR_GROUP_INVITE_ACCEPT_EMPTY"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD: + return "TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_CORE: + return "TOX_ERR_GROUP_INVITE_ACCEPT_CORE"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND: + return "TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND"; + } + + return ""; +} +const char *tox_group_exit_type_to_string(Tox_Group_Exit_Type value) +{ + switch (value) { + case TOX_GROUP_EXIT_TYPE_QUIT: + return "TOX_GROUP_EXIT_TYPE_QUIT"; + + case TOX_GROUP_EXIT_TYPE_TIMEOUT: + return "TOX_GROUP_EXIT_TYPE_TIMEOUT"; + + case TOX_GROUP_EXIT_TYPE_DISCONNECTED: + return "TOX_GROUP_EXIT_TYPE_DISCONNECTED"; + + case TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED: + return "TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED"; + + case TOX_GROUP_EXIT_TYPE_KICK: + return "TOX_GROUP_EXIT_TYPE_KICK"; + + case TOX_GROUP_EXIT_TYPE_SYNC_ERROR: + return "TOX_GROUP_EXIT_TYPE_SYNC_ERROR"; + } + + return ""; +} +const char *tox_group_join_fail_to_string(Tox_Group_Join_Fail value) +{ + switch (value) { + case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: + return "TOX_GROUP_JOIN_FAIL_PEER_LIMIT"; + + case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: + return "TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD"; + + case TOX_GROUP_JOIN_FAIL_UNKNOWN: + return "TOX_GROUP_JOIN_FAIL_UNKNOWN"; + } + + return ""; +} +const char *tox_err_group_founder_set_password_to_string(Tox_Err_Group_Founder_Set_Password value) +{ + switch (value) { + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_FAIL_SEND: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_FAIL_SEND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_MALLOC: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_MALLOC"; + + case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_DISCONNECTED: + return "TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_founder_set_topic_lock_to_string(Tox_Err_Group_Founder_Set_Topic_Lock value) +{ + switch (value) { + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_OK: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_OK"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_INVALID: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_INVALID"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_PERMISSIONS: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_PERMISSIONS"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SET: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SET"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SEND: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SEND"; + + case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_DISCONNECTED: + return "TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_founder_set_voice_state_to_string(Tox_Err_Group_Founder_Set_Voice_State value) +{ + switch (value) { + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_OK: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_OK"; + + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_PERMISSIONS: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_PERMISSIONS"; + + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SET: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SET"; + + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SEND: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SEND"; + + case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_DISCONNECTED: + return "TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_founder_set_privacy_state_to_string(Tox_Err_Group_Founder_Set_Privacy_State value) +{ + switch (value) { + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK"; + + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS"; + + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SET: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SET"; + + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SEND: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SEND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_DISCONNECTED: + return "TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_founder_set_peer_limit_to_string(Tox_Err_Group_Founder_Set_Peer_Limit value) +{ + switch (value) { + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK"; + + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS"; + + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SET: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SET"; + + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SEND: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SEND"; + + case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_DISCONNECTED: + return "TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_DISCONNECTED"; + } + + return ""; +} +const char *tox_err_group_set_ignore_to_string(Tox_Err_Group_Set_Ignore value) +{ + switch (value) { + case TOX_ERR_GROUP_SET_IGNORE_OK: + return "TOX_ERR_GROUP_SET_IGNORE_OK"; + + case TOX_ERR_GROUP_SET_IGNORE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_SET_IGNORE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND"; + + case TOX_ERR_GROUP_SET_IGNORE_SELF: + return "TOX_ERR_GROUP_SET_IGNORE_SELF"; + } + + return ""; +} +const char *tox_err_group_mod_set_role_to_string(Tox_Err_Group_Mod_Set_Role value) +{ + switch (value) { + case TOX_ERR_GROUP_MOD_SET_ROLE_OK: + return "TOX_ERR_GROUP_MOD_SET_ROLE_OK"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_MOD_SET_ROLE_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: + return "TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: + return "TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_FAIL_ACTION: + return "TOX_ERR_GROUP_MOD_SET_ROLE_FAIL_ACTION"; + + case TOX_ERR_GROUP_MOD_SET_ROLE_SELF: + return "TOX_ERR_GROUP_MOD_SET_ROLE_SELF"; + } + + return ""; +} +const char *tox_err_group_mod_kick_peer_to_string(Tox_Err_Group_Mod_Kick_Peer value) +{ + switch (value) { + case TOX_ERR_GROUP_MOD_KICK_PEER_OK: + return "TOX_ERR_GROUP_MOD_KICK_PEER_OK"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_GROUP_NOT_FOUND: + return "TOX_ERR_GROUP_MOD_KICK_PEER_GROUP_NOT_FOUND"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_PEER_NOT_FOUND: + return "TOX_ERR_GROUP_MOD_KICK_PEER_PEER_NOT_FOUND"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_PERMISSIONS: + return "TOX_ERR_GROUP_MOD_KICK_PEER_PERMISSIONS"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_ACTION: + return "TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_ACTION"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_SEND: + return "TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_SEND"; + + case TOX_ERR_GROUP_MOD_KICK_PEER_SELF: + return "TOX_ERR_GROUP_MOD_KICK_PEER_SELF"; + } + + return ""; +} +const char *tox_group_mod_event_to_string(Tox_Group_Mod_Event value) +{ + switch (value) { + case TOX_GROUP_MOD_EVENT_KICK: + return "TOX_GROUP_MOD_EVENT_KICK"; + + case TOX_GROUP_MOD_EVENT_OBSERVER: + return "TOX_GROUP_MOD_EVENT_OBSERVER"; + + case TOX_GROUP_MOD_EVENT_USER: + return "TOX_GROUP_MOD_EVENT_USER"; + + case TOX_GROUP_MOD_EVENT_MODERATOR: + return "TOX_GROUP_MOD_EVENT_MODERATOR"; + } + + return ""; +} diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index b42619f7..cab991f2 100644 --- a/toxcore/tox_private.c +++ b/toxcore/tox_private.c @@ -11,6 +11,7 @@ #include #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 */ diff --git a/toxcore/tox_private.h b/toxcore/tox_private.h index 15032936..541641a5 100644 --- a/toxcore/tox_private.h +++ b/toxcore/tox_private.h @@ -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 diff --git a/toxcore/tox_unpack.c b/toxcore/tox_unpack.c index 76127c54..09f5de2a 100644 --- a/toxcore/tox_unpack.c +++ b/toxcore/tox_unpack.c @@ -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; } diff --git a/toxcore/util.c b/toxcore/util.c index 3b3779bd..507524df 100644 --- a/toxcore/util.c +++ b/toxcore/util.c @@ -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; diff --git a/toxcore/util.h b/toxcore/util.h index 44091b36..c16605c1 100644 --- a/toxcore/util.h +++ b/toxcore/util.h @@ -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);