From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../test/network/network_emulation_unittest.cc | 676 +++++++++++++++++++++ 1 file changed, 676 insertions(+) create mode 100644 third_party/libwebrtc/test/network/network_emulation_unittest.cc (limited to 'third_party/libwebrtc/test/network/network_emulation_unittest.cc') diff --git a/third_party/libwebrtc/test/network/network_emulation_unittest.cc b/third_party/libwebrtc/test/network/network_emulation_unittest.cc new file mode 100644 index 0000000000..2e67a5a00a --- /dev/null +++ b/third_party/libwebrtc/test/network/network_emulation_unittest.cc @@ -0,0 +1,676 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/network/network_emulation.h" + +#include +#include +#include + +#include "api/test/simulated_network.h" +#include "api/units/time_delta.h" +#include "call/simulated_network.h" +#include "rtc_base/event.h" +#include "rtc_base/gunit.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/task_queue_for_test.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/network/network_emulation_manager.h" + +namespace webrtc { +namespace test { +namespace { + +using ::testing::ElementsAreArray; + +constexpr TimeDelta kNetworkPacketWaitTimeout = TimeDelta::Millis(100); +constexpr TimeDelta kStatsWaitTimeout = TimeDelta::Seconds(1); +constexpr int kOverheadIpv4Udp = 20 + 8; + +class SocketReader : public sigslot::has_slots<> { + public: + explicit SocketReader(rtc::Socket* socket, rtc::Thread* network_thread) + : socket_(socket), network_thread_(network_thread) { + socket_->SignalReadEvent.connect(this, &SocketReader::OnReadEvent); + size_ = 128 * 1024; + buf_ = new char[size_]; + } + ~SocketReader() override { delete[] buf_; } + + void OnReadEvent(rtc::Socket* socket) { + RTC_DCHECK(socket_ == socket); + RTC_DCHECK(network_thread_->IsCurrent()); + int64_t timestamp; + len_ = socket_->Recv(buf_, size_, ×tamp); + + MutexLock lock(&lock_); + received_count_++; + } + + int ReceivedCount() { + MutexLock lock(&lock_); + return received_count_; + } + + private: + rtc::Socket* const socket_; + rtc::Thread* const network_thread_; + char* buf_; + size_t size_; + int len_; + + Mutex lock_; + int received_count_ RTC_GUARDED_BY(lock_) = 0; +}; + +class MockReceiver : public EmulatedNetworkReceiverInterface { + public: + MOCK_METHOD(void, OnPacketReceived, (EmulatedIpPacket packet), (override)); +}; + +class NetworkEmulationManagerThreeNodesRoutingTest : public ::testing::Test { + public: + NetworkEmulationManagerThreeNodesRoutingTest() { + e1_ = emulation_.CreateEndpoint(EmulatedEndpointConfig()); + e2_ = emulation_.CreateEndpoint(EmulatedEndpointConfig()); + e3_ = emulation_.CreateEndpoint(EmulatedEndpointConfig()); + } + + void SetupRouting( + std::function create_routing_func) { + create_routing_func(e1_, e2_, e3_, &emulation_); + } + + void SendPacketsAndValidateDelivery() { + EXPECT_CALL(r_e1_e2_, OnPacketReceived(::testing::_)).Times(1); + EXPECT_CALL(r_e2_e1_, OnPacketReceived(::testing::_)).Times(1); + EXPECT_CALL(r_e1_e3_, OnPacketReceived(::testing::_)).Times(1); + EXPECT_CALL(r_e3_e1_, OnPacketReceived(::testing::_)).Times(1); + + uint16_t common_send_port = 80; + uint16_t r_e1_e2_port = e2_->BindReceiver(0, &r_e1_e2_).value(); + uint16_t r_e2_e1_port = e1_->BindReceiver(0, &r_e2_e1_).value(); + uint16_t r_e1_e3_port = e3_->BindReceiver(0, &r_e1_e3_).value(); + uint16_t r_e3_e1_port = e1_->BindReceiver(0, &r_e3_e1_).value(); + + // Next code is using API of EmulatedEndpoint, that is visible only for + // internals of network emulation layer. Don't use this API in other tests. + // Send packet from e1 to e2. + e1_->SendPacket( + rtc::SocketAddress(e1_->GetPeerLocalAddress(), common_send_port), + rtc::SocketAddress(e2_->GetPeerLocalAddress(), r_e1_e2_port), + rtc::CopyOnWriteBuffer(10)); + + // Send packet from e2 to e1. + e2_->SendPacket( + rtc::SocketAddress(e2_->GetPeerLocalAddress(), common_send_port), + rtc::SocketAddress(e1_->GetPeerLocalAddress(), r_e2_e1_port), + rtc::CopyOnWriteBuffer(10)); + + // Send packet from e1 to e3. + e1_->SendPacket( + rtc::SocketAddress(e1_->GetPeerLocalAddress(), common_send_port), + rtc::SocketAddress(e3_->GetPeerLocalAddress(), r_e1_e3_port), + rtc::CopyOnWriteBuffer(10)); + + // Send packet from e3 to e1. + e3_->SendPacket( + rtc::SocketAddress(e3_->GetPeerLocalAddress(), common_send_port), + rtc::SocketAddress(e1_->GetPeerLocalAddress(), r_e3_e1_port), + rtc::CopyOnWriteBuffer(10)); + + // Sleep at the end to wait for async packets delivery. + emulation_.time_controller()->AdvanceTime(kNetworkPacketWaitTimeout); + } + + private: + // Receivers: r__ + // They must be destroyed after emulation, so they should be declared before. + MockReceiver r_e1_e2_; + MockReceiver r_e2_e1_; + MockReceiver r_e1_e3_; + MockReceiver r_e3_e1_; + + NetworkEmulationManagerImpl emulation_{ + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault}; + EmulatedEndpoint* e1_; + EmulatedEndpoint* e2_; + EmulatedEndpoint* e3_; +}; + +EmulatedNetworkNode* CreateEmulatedNodeWithDefaultBuiltInConfig( + NetworkEmulationManager* emulation) { + return emulation->CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); +} + +} // namespace + +using ::testing::_; + +TEST(NetworkEmulationManagerTest, GeneratedIpv4AddressDoesNotCollide) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault); + std::set ips; + EmulatedEndpointConfig config; + config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv4; + for (int i = 0; i < 1000; i++) { + EmulatedEndpoint* endpoint = network_manager.CreateEndpoint(config); + ASSERT_EQ(endpoint->GetPeerLocalAddress().family(), AF_INET); + bool result = ips.insert(endpoint->GetPeerLocalAddress()).second; + ASSERT_TRUE(result); + } +} + +TEST(NetworkEmulationManagerTest, GeneratedIpv6AddressDoesNotCollide) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault); + std::set ips; + EmulatedEndpointConfig config; + config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv6; + for (int i = 0; i < 1000; i++) { + EmulatedEndpoint* endpoint = network_manager.CreateEndpoint(config); + ASSERT_EQ(endpoint->GetPeerLocalAddress().family(), AF_INET6); + bool result = ips.insert(endpoint->GetPeerLocalAddress()).second; + ASSERT_TRUE(result); + } +} + +TEST(NetworkEmulationManagerTest, Run) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault); + + EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedNetworkNode* bob_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedEndpoint* alice_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + EmulatedEndpoint* bob_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint); + network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint); + + EmulatedNetworkManagerInterface* nt1 = + network_manager.CreateEmulatedNetworkManagerInterface({alice_endpoint}); + EmulatedNetworkManagerInterface* nt2 = + network_manager.CreateEmulatedNetworkManagerInterface({bob_endpoint}); + + rtc::Thread* t1 = nt1->network_thread(); + rtc::Thread* t2 = nt2->network_thread(); + + rtc::CopyOnWriteBuffer data("Hello"); + for (uint64_t j = 0; j < 2; j++) { + rtc::Socket* s1 = nullptr; + rtc::Socket* s2 = nullptr; + SendTask(t1, [&] { + s1 = t1->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); + }); + SendTask(t2, [&] { + s2 = t2->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); + }); + + SocketReader r1(s1, t1); + SocketReader r2(s2, t2); + + rtc::SocketAddress a1(alice_endpoint->GetPeerLocalAddress(), 0); + rtc::SocketAddress a2(bob_endpoint->GetPeerLocalAddress(), 0); + + SendTask(t1, [&] { + s1->Bind(a1); + a1 = s1->GetLocalAddress(); + }); + SendTask(t2, [&] { + s2->Bind(a2); + a2 = s2->GetLocalAddress(); + }); + + SendTask(t1, [&] { s1->Connect(a2); }); + SendTask(t2, [&] { s2->Connect(a1); }); + + for (uint64_t i = 0; i < 1000; i++) { + t1->PostTask([&]() { s1->Send(data.data(), data.size()); }); + t2->PostTask([&]() { s2->Send(data.data(), data.size()); }); + } + + network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); + + EXPECT_EQ(r1.ReceivedCount(), 1000); + EXPECT_EQ(r2.ReceivedCount(), 1000); + + SendTask(t1, [&] { delete s1; }); + SendTask(t2, [&] { delete s2; }); + } + + const int64_t single_packet_size = data.size() + kOverheadIpv4Udp; + std::atomic received_stats_count{0}; + nt1->GetStats([&](EmulatedNetworkStats st) { + EXPECT_EQ(st.PacketsSent(), 2000l); + EXPECT_EQ(st.BytesSent().bytes(), single_packet_size * 2000l); + EXPECT_THAT(st.local_addresses, + ElementsAreArray({alice_endpoint->GetPeerLocalAddress()})); + EXPECT_EQ(st.PacketsReceived(), 2000l); + EXPECT_EQ(st.BytesReceived().bytes(), single_packet_size * 2000l); + EXPECT_EQ(st.PacketsDiscardedNoReceiver(), 0l); + EXPECT_EQ(st.BytesDiscardedNoReceiver().bytes(), 0l); + + rtc::IPAddress bob_ip = bob_endpoint->GetPeerLocalAddress(); + std::map source_st = + st.incoming_stats_per_source; + ASSERT_EQ(source_st.size(), 1lu); + EXPECT_EQ(source_st.at(bob_ip).packets_received, 2000l); + EXPECT_EQ(source_st.at(bob_ip).bytes_received.bytes(), + single_packet_size * 2000l); + EXPECT_EQ(source_st.at(bob_ip).packets_discarded_no_receiver, 0l); + EXPECT_EQ(source_st.at(bob_ip).bytes_discarded_no_receiver.bytes(), 0l); + + std::map dest_st = + st.outgoing_stats_per_destination; + ASSERT_EQ(dest_st.size(), 1lu); + EXPECT_EQ(dest_st.at(bob_ip).packets_sent, 2000l); + EXPECT_EQ(dest_st.at(bob_ip).bytes_sent.bytes(), + single_packet_size * 2000l); + + // No debug stats are collected by default. + EXPECT_TRUE(st.SentPacketsSizeCounter().IsEmpty()); + EXPECT_TRUE(st.sent_packets_queue_wait_time_us.IsEmpty()); + EXPECT_TRUE(st.ReceivedPacketsSizeCounter().IsEmpty()); + EXPECT_TRUE(st.PacketsDiscardedNoReceiverSizeCounter().IsEmpty()); + EXPECT_TRUE(dest_st.at(bob_ip).sent_packets_size.IsEmpty()); + EXPECT_TRUE(source_st.at(bob_ip).received_packets_size.IsEmpty()); + EXPECT_TRUE( + source_st.at(bob_ip).packets_discarded_no_receiver_size.IsEmpty()); + + received_stats_count++; + }); + nt2->GetStats([&](EmulatedNetworkStats st) { + EXPECT_EQ(st.PacketsSent(), 2000l); + EXPECT_EQ(st.BytesSent().bytes(), single_packet_size * 2000l); + EXPECT_THAT(st.local_addresses, + ElementsAreArray({bob_endpoint->GetPeerLocalAddress()})); + EXPECT_EQ(st.PacketsReceived(), 2000l); + EXPECT_EQ(st.BytesReceived().bytes(), single_packet_size * 2000l); + EXPECT_EQ(st.PacketsDiscardedNoReceiver(), 0l); + EXPECT_EQ(st.BytesDiscardedNoReceiver().bytes(), 0l); + EXPECT_GT(st.FirstReceivedPacketSize(), DataSize::Zero()); + EXPECT_TRUE(st.FirstPacketReceivedTime().IsFinite()); + EXPECT_TRUE(st.LastPacketReceivedTime().IsFinite()); + + rtc::IPAddress alice_ip = alice_endpoint->GetPeerLocalAddress(); + std::map source_st = + st.incoming_stats_per_source; + ASSERT_EQ(source_st.size(), 1lu); + EXPECT_EQ(source_st.at(alice_ip).packets_received, 2000l); + EXPECT_EQ(source_st.at(alice_ip).bytes_received.bytes(), + single_packet_size * 2000l); + EXPECT_EQ(source_st.at(alice_ip).packets_discarded_no_receiver, 0l); + EXPECT_EQ(source_st.at(alice_ip).bytes_discarded_no_receiver.bytes(), 0l); + + std::map dest_st = + st.outgoing_stats_per_destination; + ASSERT_EQ(dest_st.size(), 1lu); + EXPECT_EQ(dest_st.at(alice_ip).packets_sent, 2000l); + EXPECT_EQ(dest_st.at(alice_ip).bytes_sent.bytes(), + single_packet_size * 2000l); + + // No debug stats are collected by default. + EXPECT_TRUE(st.SentPacketsSizeCounter().IsEmpty()); + EXPECT_TRUE(st.sent_packets_queue_wait_time_us.IsEmpty()); + EXPECT_TRUE(st.ReceivedPacketsSizeCounter().IsEmpty()); + EXPECT_TRUE(st.PacketsDiscardedNoReceiverSizeCounter().IsEmpty()); + EXPECT_TRUE(dest_st.at(alice_ip).sent_packets_size.IsEmpty()); + EXPECT_TRUE(source_st.at(alice_ip).received_packets_size.IsEmpty()); + EXPECT_TRUE( + source_st.at(alice_ip).packets_discarded_no_receiver_size.IsEmpty()); + + received_stats_count++; + }); + ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 2, + kStatsWaitTimeout.ms(), + *network_manager.time_controller()); +} + +TEST(NetworkEmulationManagerTest, DebugStatsCollectedInDebugMode) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDebug); + + EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedNetworkNode* bob_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedEndpoint* alice_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + EmulatedEndpoint* bob_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint); + network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint); + + EmulatedNetworkManagerInterface* nt1 = + network_manager.CreateEmulatedNetworkManagerInterface({alice_endpoint}); + EmulatedNetworkManagerInterface* nt2 = + network_manager.CreateEmulatedNetworkManagerInterface({bob_endpoint}); + + rtc::Thread* t1 = nt1->network_thread(); + rtc::Thread* t2 = nt2->network_thread(); + + rtc::CopyOnWriteBuffer data("Hello"); + for (uint64_t j = 0; j < 2; j++) { + rtc::Socket* s1 = nullptr; + rtc::Socket* s2 = nullptr; + SendTask(t1, [&] { + s1 = t1->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); + }); + SendTask(t2, [&] { + s2 = t2->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); + }); + + SocketReader r1(s1, t1); + SocketReader r2(s2, t2); + + rtc::SocketAddress a1(alice_endpoint->GetPeerLocalAddress(), 0); + rtc::SocketAddress a2(bob_endpoint->GetPeerLocalAddress(), 0); + + SendTask(t1, [&] { + s1->Bind(a1); + a1 = s1->GetLocalAddress(); + }); + SendTask(t2, [&] { + s2->Bind(a2); + a2 = s2->GetLocalAddress(); + }); + + SendTask(t1, [&] { s1->Connect(a2); }); + SendTask(t2, [&] { s2->Connect(a1); }); + + for (uint64_t i = 0; i < 1000; i++) { + t1->PostTask([&]() { s1->Send(data.data(), data.size()); }); + t2->PostTask([&]() { s2->Send(data.data(), data.size()); }); + } + + network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); + + EXPECT_EQ(r1.ReceivedCount(), 1000); + EXPECT_EQ(r2.ReceivedCount(), 1000); + + SendTask(t1, [&] { delete s1; }); + SendTask(t2, [&] { delete s2; }); + } + + const int64_t single_packet_size = data.size() + kOverheadIpv4Udp; + std::atomic received_stats_count{0}; + nt1->GetStats([&](EmulatedNetworkStats st) { + rtc::IPAddress bob_ip = bob_endpoint->GetPeerLocalAddress(); + std::map source_st = + st.incoming_stats_per_source; + ASSERT_EQ(source_st.size(), 1lu); + + std::map dest_st = + st.outgoing_stats_per_destination; + ASSERT_EQ(dest_st.size(), 1lu); + + // No debug stats are collected by default. + EXPECT_EQ(st.SentPacketsSizeCounter().NumSamples(), 2000l); + EXPECT_EQ(st.ReceivedPacketsSizeCounter().GetAverage(), single_packet_size); + EXPECT_EQ(st.sent_packets_queue_wait_time_us.NumSamples(), 2000l); + EXPECT_LT(st.sent_packets_queue_wait_time_us.GetMax(), 1); + EXPECT_TRUE(st.PacketsDiscardedNoReceiverSizeCounter().IsEmpty()); + EXPECT_EQ(dest_st.at(bob_ip).sent_packets_size.NumSamples(), 2000l); + EXPECT_EQ(dest_st.at(bob_ip).sent_packets_size.GetAverage(), + single_packet_size); + EXPECT_EQ(source_st.at(bob_ip).received_packets_size.NumSamples(), 2000l); + EXPECT_EQ(source_st.at(bob_ip).received_packets_size.GetAverage(), + single_packet_size); + EXPECT_TRUE( + source_st.at(bob_ip).packets_discarded_no_receiver_size.IsEmpty()); + + received_stats_count++; + }); + ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 1, + kStatsWaitTimeout.ms(), + *network_manager.time_controller()); +} + +TEST(NetworkEmulationManagerTest, ThroughputStats) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault); + + EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedNetworkNode* bob_node = network_manager.CreateEmulatedNode( + std::make_unique(BuiltInNetworkBehaviorConfig())); + EmulatedEndpoint* alice_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + EmulatedEndpoint* bob_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint); + network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint); + + EmulatedNetworkManagerInterface* nt1 = + network_manager.CreateEmulatedNetworkManagerInterface({alice_endpoint}); + EmulatedNetworkManagerInterface* nt2 = + network_manager.CreateEmulatedNetworkManagerInterface({bob_endpoint}); + + rtc::Thread* t1 = nt1->network_thread(); + rtc::Thread* t2 = nt2->network_thread(); + + constexpr int64_t kUdpPayloadSize = 100; + constexpr int64_t kSinglePacketSize = kUdpPayloadSize + kOverheadIpv4Udp; + rtc::CopyOnWriteBuffer data(kUdpPayloadSize); + + rtc::Socket* s1 = nullptr; + rtc::Socket* s2 = nullptr; + SendTask(t1, + [&] { s1 = t1->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); }); + SendTask(t2, + [&] { s2 = t2->socketserver()->CreateSocket(AF_INET, SOCK_DGRAM); }); + + SocketReader r1(s1, t1); + SocketReader r2(s2, t2); + + rtc::SocketAddress a1(alice_endpoint->GetPeerLocalAddress(), 0); + rtc::SocketAddress a2(bob_endpoint->GetPeerLocalAddress(), 0); + + SendTask(t1, [&] { + s1->Bind(a1); + a1 = s1->GetLocalAddress(); + }); + SendTask(t2, [&] { + s2->Bind(a2); + a2 = s2->GetLocalAddress(); + }); + + SendTask(t1, [&] { s1->Connect(a2); }); + SendTask(t2, [&] { s2->Connect(a1); }); + + // Send 11 packets, totalizing 1 second between the first and the last-> + const int kNumPacketsSent = 11; + const TimeDelta kDelay = TimeDelta::Millis(100); + for (int i = 0; i < kNumPacketsSent; i++) { + t1->PostTask([&]() { s1->Send(data.data(), data.size()); }); + t2->PostTask([&]() { s2->Send(data.data(), data.size()); }); + network_manager.time_controller()->AdvanceTime(kDelay); + } + + std::atomic received_stats_count{0}; + nt1->GetStats([&](EmulatedNetworkStats st) { + EXPECT_EQ(st.PacketsSent(), kNumPacketsSent); + EXPECT_EQ(st.BytesSent().bytes(), kSinglePacketSize * kNumPacketsSent); + + const double tolerance = 0.95; // Accept 5% tolerance for timing. + EXPECT_GE(st.LastPacketSentTime() - st.FirstPacketSentTime(), + (kNumPacketsSent - 1) * kDelay * tolerance); + EXPECT_GT(st.AverageSendRate().bps(), 0); + received_stats_count++; + }); + + ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 1, + kStatsWaitTimeout.ms(), + *network_manager.time_controller()); + + EXPECT_EQ(r1.ReceivedCount(), 11); + EXPECT_EQ(r2.ReceivedCount(), 11); + + SendTask(t1, [&] { delete s1; }); + SendTask(t2, [&] { delete s2; }); +} + +// Testing that packets are delivered via all routes using a routing scheme as +// follows: +// * e1 -> n1 -> e2 +// * e2 -> n2 -> e1 +// * e1 -> n3 -> e3 +// * e3 -> n4 -> e1 +TEST_F(NetworkEmulationManagerThreeNodesRoutingTest, + PacketsAreDeliveredInBothWaysWhenConnectedToTwoPeers) { + SetupRouting([](EmulatedEndpoint* e1, EmulatedEndpoint* e2, + EmulatedEndpoint* e3, NetworkEmulationManager* emulation) { + auto* node1 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + auto* node2 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + auto* node3 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + auto* node4 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + + emulation->CreateRoute(e1, {node1}, e2); + emulation->CreateRoute(e2, {node2}, e1); + + emulation->CreateRoute(e1, {node3}, e3); + emulation->CreateRoute(e3, {node4}, e1); + }); + SendPacketsAndValidateDelivery(); +} + +// Testing that packets are delivered via all routes using a routing scheme as +// follows: +// * e1 -> n1 -> e2 +// * e2 -> n2 -> e1 +// * e1 -> n1 -> e3 +// * e3 -> n4 -> e1 +TEST_F(NetworkEmulationManagerThreeNodesRoutingTest, + PacketsAreDeliveredInBothWaysWhenConnectedToTwoPeersOverSameSendLink) { + SetupRouting([](EmulatedEndpoint* e1, EmulatedEndpoint* e2, + EmulatedEndpoint* e3, NetworkEmulationManager* emulation) { + auto* node1 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + auto* node2 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + auto* node3 = CreateEmulatedNodeWithDefaultBuiltInConfig(emulation); + + emulation->CreateRoute(e1, {node1}, e2); + emulation->CreateRoute(e2, {node2}, e1); + + emulation->CreateRoute(e1, {node1}, e3); + emulation->CreateRoute(e3, {node3}, e1); + }); + SendPacketsAndValidateDelivery(); +} + +TEST(NetworkEmulationManagerTest, EndpointLoopback) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault); + auto endpoint = network_manager.CreateEndpoint(EmulatedEndpointConfig()); + + MockReceiver receiver; + EXPECT_CALL(receiver, OnPacketReceived(::testing::_)).Times(1); + ASSERT_EQ(endpoint->BindReceiver(80, &receiver), 80); + + endpoint->SendPacket(rtc::SocketAddress(endpoint->GetPeerLocalAddress(), 80), + rtc::SocketAddress(endpoint->GetPeerLocalAddress(), 80), + "Hello"); + network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); +} + +TEST(NetworkEmulationManagerTest, EndpointCanSendWithDifferentSourceIp) { + constexpr uint32_t kEndpointIp = 0xC0A80011; // 192.168.0.17 + constexpr uint32_t kSourceIp = 0xC0A80012; // 192.168.0.18 + NetworkEmulationManagerImpl network_manager( + TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault); + EmulatedEndpointConfig endpoint_config; + endpoint_config.ip = rtc::IPAddress(kEndpointIp); + endpoint_config.allow_send_packet_with_different_source_ip = true; + auto endpoint = network_manager.CreateEndpoint(endpoint_config); + + MockReceiver receiver; + EXPECT_CALL(receiver, OnPacketReceived(::testing::_)).Times(1); + ASSERT_EQ(endpoint->BindReceiver(80, &receiver), 80); + + endpoint->SendPacket(rtc::SocketAddress(kSourceIp, 80), + rtc::SocketAddress(endpoint->GetPeerLocalAddress(), 80), + "Hello"); + network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); +} + +TEST(NetworkEmulationManagerTest, + EndpointCanReceiveWithDifferentDestIpThroughDefaultRoute) { + constexpr uint32_t kDestEndpointIp = 0xC0A80011; // 192.168.0.17 + constexpr uint32_t kDestIp = 0xC0A80012; // 192.168.0.18 + NetworkEmulationManagerImpl network_manager( + TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault); + auto sender_endpoint = + network_manager.CreateEndpoint(EmulatedEndpointConfig()); + EmulatedEndpointConfig endpoint_config; + endpoint_config.ip = rtc::IPAddress(kDestEndpointIp); + endpoint_config.allow_receive_packets_with_different_dest_ip = true; + auto receiver_endpoint = network_manager.CreateEndpoint(endpoint_config); + + MockReceiver receiver; + EXPECT_CALL(receiver, OnPacketReceived(::testing::_)).Times(1); + ASSERT_EQ(receiver_endpoint->BindReceiver(80, &receiver), 80); + + network_manager.CreateDefaultRoute( + sender_endpoint, {network_manager.NodeBuilder().Build().node}, + receiver_endpoint); + + sender_endpoint->SendPacket( + rtc::SocketAddress(sender_endpoint->GetPeerLocalAddress(), 80), + rtc::SocketAddress(kDestIp, 80), "Hello"); + network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); +} + +TEST(NetworkEmulationManagerTURNTest, GetIceServerConfig) { + NetworkEmulationManagerImpl network_manager( + TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault); + auto turn = network_manager.CreateTURNServer(EmulatedTURNServerConfig()); + + EXPECT_GT(turn->GetIceServerConfig().username.size(), 0u); + EXPECT_GT(turn->GetIceServerConfig().password.size(), 0u); + EXPECT_NE(turn->GetIceServerConfig().url.find( + turn->GetClientEndpoint()->GetPeerLocalAddress().ToString()), + std::string::npos); +} + +TEST(NetworkEmulationManagerTURNTest, ClientTraffic) { + NetworkEmulationManagerImpl emulation( + TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault); + auto* ep = emulation.CreateEndpoint(EmulatedEndpointConfig()); + auto* turn = emulation.CreateTURNServer(EmulatedTURNServerConfig()); + auto* node = CreateEmulatedNodeWithDefaultBuiltInConfig(&emulation); + emulation.CreateRoute(ep, {node}, turn->GetClientEndpoint()); + emulation.CreateRoute(turn->GetClientEndpoint(), {node}, ep); + + MockReceiver recv; + int port = ep->BindReceiver(0, &recv).value(); + + // Construct a STUN BINDING. + cricket::StunMessage ping(cricket::STUN_BINDING_REQUEST); + rtc::ByteBufferWriter buf; + ping.Write(&buf); + rtc::CopyOnWriteBuffer packet(buf.Data(), buf.Length()); + + // We expect to get a ping reply. + EXPECT_CALL(recv, OnPacketReceived(::testing::_)).Times(1); + + ep->SendPacket(rtc::SocketAddress(ep->GetPeerLocalAddress(), port), + turn->GetClientEndpointAddress(), packet); + emulation.time_controller()->AdvanceTime(TimeDelta::Seconds(1)); +} + +} // namespace test +} // namespace webrtc -- cgit v1.2.3