From 706fad1ce88c2104009a3835ee343ff9d8ec8b79 Mon Sep 17 00:00:00 2001 From: iphydf Date: Mon, 25 Jun 2018 12:37:46 +0000 Subject: [PATCH] Add a test to try and overflow the send queue in net_crypto. --- CMakeLists.txt | 3 + auto_tests/BUILD.bazel | 1 + auto_tests/friend_connection_test.c | 33 ++++++++++ auto_tests/overflow_recvq_test.c | 68 ++++++++++++++++++++ auto_tests/overflow_sendq_test.c | 53 ++++++++++++++++ auto_tests/run_auto_test.h | 96 +++++++++++++++++++++++++++++ toxcore/Messenger.c | 6 ++ 7 files changed, 260 insertions(+) create mode 100644 auto_tests/friend_connection_test.c create mode 100644 auto_tests/overflow_recvq_test.c create mode 100644 auto_tests/overflow_sendq_test.c create mode 100644 auto_tests/run_auto_test.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cd05ad70..cc55a235 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -492,6 +492,7 @@ auto_test(crypto MSVC_DONT_BUILD) auto_test(dht MSVC_DONT_BUILD) auto_test(encryptsave) auto_test(file_transfer) +auto_test(friend_connection) auto_test(friend_request) auto_test(invalid_proxy) auto_test(invalid_tcp_proxy) @@ -501,6 +502,8 @@ auto_test(lossy_packet) auto_test(messenger MSVC_DONT_BUILD) auto_test(network) auto_test(onion) +auto_test(overflow_recvq) +auto_test(overflow_sendq) auto_test(save_friend) auto_test(save_load) auto_test(send_message) diff --git a/auto_tests/BUILD.bazel b/auto_tests/BUILD.bazel index 7b0cab7d..4f1f1892 100644 --- a/auto_tests/BUILD.bazel +++ b/auto_tests/BUILD.bazel @@ -4,6 +4,7 @@ cc_library( hdrs = [ "check_compat.h", "helpers.h", + "run_auto_test.h", ], ) diff --git a/auto_tests/friend_connection_test.c b/auto_tests/friend_connection_test.c new file mode 100644 index 00000000..7af1b575 --- /dev/null +++ b/auto_tests/friend_connection_test.c @@ -0,0 +1,33 @@ +/* Tests that we can make a friend connection. + * + * This is the simplest test that brings up two toxes that can talk to each + * other. It's useful as a copy/pasteable starting point for testing other + * features. + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#include "check_compat.h" + +#include "../toxcore/tox.h" + +typedef struct State { + uint32_t index; +} State; + +#include "run_auto_test.h" + +static void friend_connection_test(Tox **toxes, State *state) +{ + // Nothing to do here. When copying this test, add test-specific code here. +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + run_auto_test(2, friend_connection_test); + return 0; +} diff --git a/auto_tests/overflow_recvq_test.c b/auto_tests/overflow_recvq_test.c new file mode 100644 index 00000000..3227c5f4 --- /dev/null +++ b/auto_tests/overflow_recvq_test.c @@ -0,0 +1,68 @@ +/* Try to overflow the net_crypto packet buffer. + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#include "check_compat.h" + +#include "../toxcore/tox.h" + +typedef struct State { + uint32_t index; + uint32_t recv_count; +} State; + +#include "run_auto_test.h" + +#define NUM_MSGS 40000 + +static void handle_friend_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, + const uint8_t *message, size_t length, void *user_data) +{ + State *state = (State *)user_data; + state->recv_count++; +} + +static void net_crypto_overflow_test(Tox **toxes, State *state) +{ + tox_callback_friend_message(toxes[0], handle_friend_message); + + printf("sending many messages to tox0\n"); + + for (uint32_t tox_index = 1; tox_index < 3; tox_index++) { + for (uint32_t i = 0; i < NUM_MSGS; i++) { + uint8_t message[128] = {0}; + snprintf((char *)message, sizeof(message), "%u-%u", tox_index, i); + + TOX_ERR_FRIEND_SEND_MESSAGE err; + tox_friend_send_message(toxes[tox_index], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err); + + if (err == TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ) { + printf("tox%u sent %u messages to friend 0\n", tox_index, i); + break; + } + + ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK, + "tox%u failed to send message number %u: %d", tox_index, i, err); + } + } + + // TODO(iphydf): Wait until all messages have arrived. Currently, not all + // messages arrive, so this test would always fail. + for (uint32_t i = 0; i < 200; i++) { + iterate_all(3, toxes, state); + c_sleep(ITERATION_INTERVAL); + } + + printf("tox%u received %u messages\n", state[0].index, state[0].recv_count); +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + run_auto_test(3, net_crypto_overflow_test); + return 0; +} diff --git a/auto_tests/overflow_sendq_test.c b/auto_tests/overflow_sendq_test.c new file mode 100644 index 00000000..94f5c12a --- /dev/null +++ b/auto_tests/overflow_sendq_test.c @@ -0,0 +1,53 @@ +/* Try to overflow the net_crypto packet buffer. + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#include "check_compat.h" + +#include "../toxcore/tox.h" + +typedef struct State { + uint32_t index; +} State; + +#include "run_auto_test.h" + +#define NUM_MSGS 40000 + +static void net_crypto_overflow_test(Tox **toxes, State *state) +{ + const uint8_t message[] = {0}; + bool errored = false; + + for (uint32_t i = 0; i < NUM_MSGS; i++) { + TOX_ERR_FRIEND_SEND_MESSAGE err; + tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err); + + if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK) { + errored = true; + } + + if (errored) { + // As soon as we get the first error, we expect the same error (SENDQ) + // every time we try to send. + ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ, + "expected SENDQ error on message %u, but got %d", i, err); + } else { + ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK, + "failed to send message number %u: %d", i, err); + } + } + + ck_assert_msg(errored, "expected SENDQ error at some point (increase NUM_MSGS?)"); +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + run_auto_test(2, net_crypto_overflow_test); + return 0; +} diff --git a/auto_tests/run_auto_test.h b/auto_tests/run_auto_test.h new file mode 100644 index 00000000..6ae8ad6a --- /dev/null +++ b/auto_tests/run_auto_test.h @@ -0,0 +1,96 @@ +#include "helpers.h" + +static bool all_connected(uint32_t tox_count, Tox **toxes) +{ + for (uint32_t i = 0; i < tox_count; i++) { + if (tox_self_get_connection_status(toxes[i]) == TOX_CONNECTION_NONE) { + return false; + } + } + + return true; +} + +static bool all_friends_connected(uint32_t tox_count, Tox **toxes) +{ + for (uint32_t i = 0; i < tox_count; i++) { + const size_t friend_count = tox_self_get_friend_list_size(toxes[i]); + + for (size_t j = 0; j < friend_count; j++) { + if (tox_friend_get_connection_status(toxes[i], j, nullptr) == TOX_CONNECTION_NONE) { + return false; + } + } + } + + return true; +} + +static bool iterate_all(uint32_t tox_count, Tox **toxes, State *state) +{ + for (uint32_t i = 0; i < tox_count; i++) { + tox_iterate(toxes[i], &state[i]); + } + + return true; +} + +static void run_auto_test(uint32_t tox_count, void test(Tox **toxes, State *state)) +{ + printf("initialising %u toxes\n", tox_count); + Tox **toxes = (Tox **)calloc(tox_count, sizeof(Tox *)); + State *state = (State *)calloc(tox_count, sizeof(State)); + + for (uint32_t i = 0; i < tox_count; i++) { + state[i].index = i; + toxes[i] = tox_new_log(nullptr, nullptr, &state[i].index); + ck_assert_msg(toxes[i], "failed to create %u tox instances", i + 1); + } + + printf("toxes all add each other as friends\n"); + + for (uint32_t i = 0; i < tox_count; i++) { + for (uint32_t j = 0; j < tox_count; j++) { + if (i != j) { + uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; + tox_self_get_public_key(toxes[j], public_key); + tox_friend_add_norequest(toxes[i], public_key, nullptr); + } + } + } + + + printf("bootstrapping all toxes off toxes[0]\n"); + uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; + tox_self_get_dht_id(toxes[0], dht_key); + const uint16_t dht_port = tox_self_get_udp_port(toxes[0], nullptr); + + for (uint32_t i = 1; i < tox_count; i++) { + tox_bootstrap(toxes[i], "localhost", dht_port, dht_key, nullptr); + } + + while (!all_connected(tox_count, toxes)) { + iterate_all(tox_count, toxes, state); + + c_sleep(ITERATION_INTERVAL); + } + + printf("toxes are online\n"); + + while (!all_friends_connected(tox_count, toxes)) { + iterate_all(tox_count, toxes, state); + + c_sleep(ITERATION_INTERVAL); + } + + printf("tox clients connected\n"); + + test(toxes, state); + + for (uint32_t i = 0; i < tox_count; i++) { + tox_kill(toxes[i]); + } + + free(state); + free(toxes); +} diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index e3ceeb86..7b931bdb 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -493,18 +493,22 @@ int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, con uint32_t *message_id) { if (type > MESSAGE_ACTION) { + LOGGER_ERROR(m->log, "Message type %d is invalid", type); return -5; } if (friend_not_valid(m, friendnumber)) { + LOGGER_ERROR(m->log, "Friend number %d is invalid", friendnumber); return -1; } if (length >= MAX_CRYPTO_DATA_SIZE) { + LOGGER_ERROR(m->log, "Message length %d is too large", friendnumber); return -2; } if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + LOGGER_ERROR(m->log, "Friend %d is not online", friendnumber); return -3; } @@ -519,6 +523,8 @@ int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, con m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0); if (packet_num == -1) { + LOGGER_ERROR(m->log, "Failed to write crypto packet for message of length %d to friend %d", + length, friendnumber); return -4; }