toxcore/TCP_server_test.cc
Rama master · réplica de lectura del repositorio original.
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
#include "TCP_client.h"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net.h"
#include "network.h"
#include "os_memory.h"
#include "os_network.h"
#include "os_random.h"
#include "tox.h"
namespace {
constexpr uint16_t kRelayPort = 33455;
void sleep_ms(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); }
// A relay must not read from a slot evicted earlier in the same epoll batch.
TEST(TCPServer, SurvivesSameKeyReconnectWithPendingData)
{
Tox_Options *opts = tox_options_new(nullptr);
ASSERT_NE(opts, nullptr);
tox_options_set_udp_enabled(opts, false);
tox_options_set_local_discovery_enabled(opts, false);
tox_options_set_tcp_port(opts, kRelayPort);
Tox_Err_New err;
Tox *tox = tox_new(opts, &err);
tox_options_free(opts);
ASSERT_EQ(err, TOX_ERR_NEW_OK);
ASSERT_NE(tox, nullptr);
auto pump_relay = [&] { tox_iterate(tox, nullptr); };
// Let the node settle, including its relay to itself (slot 0).
for (int i = 0; i < 10; ++i) {
pump_relay();
sleep_ms(10);
}
uint8_t relay_pk[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(tox, relay_pk);
const Random *rng = os_random();
const Network *ns = os_network();
const Memory *mem = os_memory();
ASSERT_NE(rng, nullptr);
ASSERT_NE(ns, nullptr);
ASSERT_NE(mem, nullptr);
Logger *logger = logger_new(mem);
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
IP_Port relay;
relay.ip.family = net_family_ipv4();
relay.ip.ip.v4 = get_ip4_loopback();
relay.port = net_htons(kRelayPort);
auto confirm = [&](const uint8_t *pk, const uint8_t *sk) -> TCP_Client_Connection * {
TCP_Client_Connection *c = new_tcp_connection(
logger, mem, mono_time, rng, ns, &relay, relay_pk, pk, sk, nullptr, nullptr);
sleep_ms(50);
for (int i = 0; i < 30 && tcp_con_status(c) != TCP_CLIENT_CONFIRMED; ++i) {
mono_time_update(mono_time);
do_tcp_connection(logger, mono_time, c, nullptr);
sleep_ms(10);
pump_relay();
sleep_ms(10);
}
return c;
};
// Shared by A and B.
uint8_t key_pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t key_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(rng, key_pk, key_sk);
uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t sk[CRYPTO_SECRET_KEY_SIZE];
// Slots are allocated from the top: put two above A, then free the top one so
// B doesn't reuse A's slot.
crypto_new_keypair(rng, pk, sk);
TCP_Client_Connection *high = confirm(pk, sk);
ASSERT_EQ(tcp_con_status(high), TCP_CLIENT_CONFIRMED);
crypto_new_keypair(rng, pk, sk);
TCP_Client_Connection *mid = confirm(pk, sk);
ASSERT_EQ(tcp_con_status(mid), TCP_CLIENT_CONFIRMED);
TCP_Client_Connection *a = confirm(key_pk, key_sk);
ASSERT_EQ(tcp_con_status(a), TCP_CLIENT_CONFIRMED);
kill_tcp_connection(high);
for (int i = 0; i < 3; ++i) {
pump_relay();
sleep_ms(10);
}
// Confirm B without letting the relay handle its confirming packet yet.
TCP_Client_Connection *b = new_tcp_connection(
logger, mem, mono_time, rng, ns, &relay, relay_pk, key_pk, key_sk, nullptr, nullptr);
ASSERT_NE(b, nullptr);
sleep_ms(50);
mono_time_update(mono_time);
do_tcp_connection(logger, mono_time, b, nullptr);
sleep_ms(20);
pump_relay();
sleep_ms(20);
mono_time_update(mono_time);
do_tcp_connection(logger, mono_time, b, nullptr);
sleep_ms(20);
ASSERT_EQ(tcp_con_status(b), TCP_CLIENT_CONFIRMED);
// Queue a packet on A behind B's, in the same batch.
ASSERT_EQ(send_routing_request(logger, a, relay_pk), 1);
mono_time_update(mono_time);
do_tcp_connection(logger, mono_time, a, nullptr);
sleep_ms(20);
// Confirming B evicts A's slot before A's packet is handled.
pump_relay();
sleep_ms(20);
pump_relay();
kill_tcp_connection(a);
kill_tcp_connection(b);
kill_tcp_connection(mid);
logger_kill(logger);
mono_time_free(mem, mono_time);
tox_kill(tox);
}
} // namespace