9ed2fa80d fix(toxav): remove extra copy of video frame on encode de30cf3ad docs: Add new file kinds, that should be useful to all clients. d5b5e879d fix(DHT): Correct node skipping logic timed out nodes. 30e71fe97 refactor: Generate event dispatch functions and add tox_events_dispatch. 8fdbb0b50 style: Format parameter lists in event handlers. d00dee12b refactor: Add warning logs when losing chat invites. b144e8db1 feat: Add a way to look up a file number by ID. 849281ea0 feat: Add a way to fetch groups by chat ID. a2c177396 refactor: Harden event system and improve type safety. 8f5caa656 refactor: Add MessagePack string support to bin_pack. 34e8d5ad5 chore: Add GitHub CodeQL workflow and local Docker runner. f7b068010 refactor: Add nullability annotations to event headers. 788abe651 refactor(toxav): Use system allocator for mutexes. 2e4b423eb refactor: Use specific typedefs for public API arrays. 2baf34775 docs(toxav): update idle iteration interval see 679444751876fa3882a717772918ebdc8f083354 2f87ac67b feat: Add Event Loop abstraction (Ev). f8dfc38d8 test: Fix data race in ToxScenario virtual_clock. 38313921e test(TCP): Add regression test for TCP priority queue integrity. f94a50d9a refactor(toxav): Replace mutable_mutex with dynamically allocated mutex. ad054511e refactor: Internalize DHT structs and add debug helpers. 8b467cc96 fix: Prevent potential integer overflow in group chat handshake. 4962bdbb8 test: Improve TCP simulation and add tests 5f0227093 refactor: Allow nullable data in group chat handlers. e97b18ea9 chore: Improve Windows Docker support. b14943bbd refactor: Move Logger out of Messenger into Tox. dd3136250 cleanup: Apply nullability qualifiers to C++ codebase. 1849f70fc refactor: Extract low-level networking code to net and os_network. 8fec75421 refactor: Delete tox_random, align on rng and os_random. a03ae8051 refactor: Delete tox_memory, align on mem and os_memory. 4c88fed2c refactor: Use `std::` prefixes more consistently in C++ code. 72452f2ae test: Add some more tests for onion and shared key cache. d5a51b09a cleanup: Use tox_attributes.h in tox_private.h and install it. b6f5b9fc5 test: Add some benchmarks for various high level things. 8a8d02785 test(support): Introduce threaded Tox runner and simulation barrier d68d1d095 perf(toxav): optimize audio and video intermediate buffers by keeping them around REVERT: c9cdae001 fix(toxav): remove extra copy of video frame on encode git-subtree-dir: external/toxcore/c-toxcore git-subtree-split: 9ed2fa80d582c714d6bdde6a7648220a92cddff8
190 lines
6.7 KiB
C++
190 lines
6.7 KiB
C++
#include "friend_connection.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "../testing/support/public/simulated_environment.hh"
|
|
#include "DHT_test_util.hh"
|
|
#include "attributes.h"
|
|
#include "crypto_core.h"
|
|
#include "logger.h"
|
|
#include "mono_time.h"
|
|
#include "net_crypto.h"
|
|
#include "net_profile.h"
|
|
#include "network.h"
|
|
#include "onion_client.h"
|
|
#include "test_util.hh"
|
|
|
|
namespace {
|
|
|
|
using namespace tox::test;
|
|
|
|
// --- Helper Class ---
|
|
|
|
template <typename DHTWrapper>
|
|
class FriendConnTestNode {
|
|
public:
|
|
FriendConnTestNode(SimulatedEnvironment &env, std::uint16_t port)
|
|
: dht_wrapper_(env, port)
|
|
, net_profile_(netprof_new(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory),
|
|
[mem = &dht_wrapper_.node().c_memory](Net_Profile *p) { netprof_kill(mem, p); })
|
|
, net_crypto_(nullptr, [](Net_Crypto *c) { kill_net_crypto(c); })
|
|
, onion_client_(nullptr, [](Onion_Client *c) { kill_onion_client(c); })
|
|
, friend_connections_(nullptr, [](Friend_Connections *c) { kill_friend_connections(c); })
|
|
{
|
|
logger_callback_log(
|
|
dht_wrapper_.logger(),
|
|
[](void *_Nullable context, Logger_Level level, const char *_Nonnull file,
|
|
std::uint32_t line, const char *_Nonnull func, const char *_Nonnull message,
|
|
void *_Nullable userdata) {
|
|
fprintf(stderr, "[%d] %s:%u: %s: %s\n", level, file, line, func, message);
|
|
},
|
|
nullptr, nullptr);
|
|
|
|
// Setup NetCrypto
|
|
TCP_Proxy_Info proxy_info = {{0}, TCP_PROXY_NONE};
|
|
net_crypto_.reset(new_net_crypto(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
|
|
&dht_wrapper_.node().c_random, &dht_wrapper_.node().c_network, dht_wrapper_.mono_time(),
|
|
dht_wrapper_.networking(), dht_wrapper_.get_dht(), &DHTWrapper::funcs, &proxy_info,
|
|
net_profile_.get()));
|
|
|
|
new_keys(net_crypto_.get());
|
|
|
|
// Setup Onion Client
|
|
onion_client_.reset(new_onion_client(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
|
|
&dht_wrapper_.node().c_random, dht_wrapper_.mono_time(), net_crypto_.get(),
|
|
dht_wrapper_.get_dht(), dht_wrapper_.networking()));
|
|
|
|
// Setup Friend Connections
|
|
friend_connections_.reset(
|
|
new_friend_connections(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
|
|
dht_wrapper_.mono_time(), &dht_wrapper_.node().c_network, onion_client_.get(),
|
|
dht_wrapper_.get_dht(), net_crypto_.get(), dht_wrapper_.networking(), true));
|
|
}
|
|
|
|
Friend_Connections *_Nonnull get_friend_connections()
|
|
{
|
|
return REQUIRE_NOT_NULL(friend_connections_.get());
|
|
}
|
|
Onion_Client *_Nonnull get_onion_client() { return REQUIRE_NOT_NULL(onion_client_.get()); }
|
|
Net_Crypto *_Nonnull get_net_crypto() { return REQUIRE_NOT_NULL(net_crypto_.get()); }
|
|
DHT *_Nonnull get_dht() { return dht_wrapper_.get_dht(); }
|
|
const std::uint8_t *dht_public_key() const { return dht_wrapper_.dht_public_key(); }
|
|
const std::uint8_t *real_public_key() const
|
|
{
|
|
return nc_get_self_public_key(net_crypto_.get());
|
|
}
|
|
const Random *get_random() { return &dht_wrapper_.node().c_random; }
|
|
|
|
IP_Port get_ip_port() const { return dht_wrapper_.get_ip_port(); }
|
|
|
|
void poll()
|
|
{
|
|
dht_wrapper_.poll();
|
|
do_net_crypto(net_crypto_.get(), nullptr);
|
|
do_onion_client(onion_client_.get());
|
|
do_friend_connections(friend_connections_.get(), nullptr);
|
|
}
|
|
|
|
~FriendConnTestNode();
|
|
|
|
private:
|
|
DHTWrapper dht_wrapper_;
|
|
std::unique_ptr<Net_Profile, std::function<void(Net_Profile *)>> net_profile_;
|
|
std::unique_ptr<Net_Crypto, void (*)(Net_Crypto *)> net_crypto_;
|
|
std::unique_ptr<Onion_Client, void (*)(Onion_Client *)> onion_client_;
|
|
std::unique_ptr<Friend_Connections, void (*)(Friend_Connections *)> friend_connections_;
|
|
};
|
|
|
|
template <typename DHTWrapper>
|
|
FriendConnTestNode<DHTWrapper>::~FriendConnTestNode() = default;
|
|
|
|
using FriendConnNode = FriendConnTestNode<WrappedDHT>;
|
|
|
|
class FriendConnectionTest : public ::testing::Test {
|
|
protected:
|
|
SimulatedEnvironment env;
|
|
};
|
|
|
|
TEST_F(FriendConnectionTest, CreationAndDestruction)
|
|
{
|
|
FriendConnNode alice(env, 33445);
|
|
EXPECT_NE(alice.get_friend_connections(), nullptr);
|
|
}
|
|
|
|
TEST_F(FriendConnectionTest, AddKillConnection)
|
|
{
|
|
FriendConnNode alice(env, 33445);
|
|
std::uint8_t friend_pk[CRYPTO_PUBLIC_KEY_SIZE];
|
|
std::uint8_t friend_sk[CRYPTO_SECRET_KEY_SIZE];
|
|
crypto_new_keypair(alice.get_random(), friend_pk, friend_sk);
|
|
|
|
// Add Connection
|
|
int conn_id = new_friend_connection(alice.get_friend_connections(), friend_pk);
|
|
EXPECT_NE(conn_id, -1);
|
|
|
|
// Verify status (should be connecting or none initially, but ID is valid)
|
|
EXPECT_NE(
|
|
friend_con_connected(alice.get_friend_connections(), conn_id), FRIENDCONN_STATUS_NONE);
|
|
|
|
// Kill Connection
|
|
EXPECT_EQ(kill_friend_connection(alice.get_friend_connections(), conn_id), 0);
|
|
}
|
|
|
|
TEST_F(FriendConnectionTest, ConnectTwoNodes)
|
|
{
|
|
FriendConnNode alice(env, 33445);
|
|
FriendConnNode bob(env, 33446);
|
|
|
|
// Alice adds Bob as friend
|
|
int alice_conn_id
|
|
= new_friend_connection(alice.get_friend_connections(), bob.real_public_key());
|
|
ASSERT_NE(alice_conn_id, -1);
|
|
|
|
// Bob adds Alice as friend
|
|
int bob_conn_id = new_friend_connection(bob.get_friend_connections(), alice.real_public_key());
|
|
ASSERT_NE(bob_conn_id, -1);
|
|
|
|
// Helper to inject peer info into DHT and trigger connection
|
|
auto inject_peer = [](FriendConnNode &self, const FriendConnNode &peer, int conn_id) {
|
|
// 1. Tell DHT where the peer is (IP/Port + DHT Public Key)
|
|
IP_Port peer_ip = peer.get_ip_port();
|
|
addto_lists(self.get_dht(), &peer_ip, peer.dht_public_key());
|
|
|
|
// 2. Tell friend_connection the peer's DHT Public Key (normally found via Onion)
|
|
set_dht_temp_pk(self.get_friend_connections(), conn_id, peer.dht_public_key(), nullptr);
|
|
};
|
|
|
|
inject_peer(alice, bob, alice_conn_id);
|
|
inject_peer(bob, alice, bob_conn_id);
|
|
|
|
auto start = env.clock().current_time_ms();
|
|
bool connected = false;
|
|
|
|
while ((env.clock().current_time_ms() - start) < 5000) { // 5 seconds timeout
|
|
alice.poll();
|
|
bob.poll();
|
|
env.advance_time(10);
|
|
|
|
if (friend_con_connected(alice.get_friend_connections(), alice_conn_id)
|
|
== FRIENDCONN_STATUS_CONNECTED
|
|
&& friend_con_connected(bob.get_friend_connections(), bob_conn_id)
|
|
== FRIENDCONN_STATUS_CONNECTED) {
|
|
connected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXPECT_TRUE(connected) << "Alice and Bob failed to connect";
|
|
}
|
|
|
|
} // namespace
|