Add TURN server to Emulated Network infrastructure

This can be used to test ICE behavior.

Bug: chromium:1024965
Change-Id: Ie4ba9cd5c3cf3c2f71bab3637f925263dbc6296e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/193701
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32625}
This commit is contained in:
Jonas Oreland 2020-11-17 21:30:33 +01:00 committed by Commit Bot
parent 26ce03e469
commit 97050115f0
9 changed files with 512 additions and 2 deletions

View File

@ -13,6 +13,7 @@
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "api/array_view.h"
@ -66,6 +67,37 @@ struct EmulatedEndpointConfig {
StatsGatheringMode stats_gathering_mode = StatsGatheringMode::kDefault;
};
struct EmulatedTURNServerConfig {
EmulatedEndpointConfig client_config;
EmulatedEndpointConfig peer_config;
};
// EmulatedTURNServer is an abstraction for a TURN server.
class EmulatedTURNServerInterface {
public:
struct IceServerConfig {
std::string username;
std::string password;
std::string url;
};
virtual ~EmulatedTURNServerInterface() {}
// Get an IceServer configuration suitable to add to a PeerConnection.
virtual IceServerConfig GetIceServerConfig() const = 0;
// Get non-null client endpoint, an endpoint that accepts TURN allocations.
// This shall typically be connected to one or more webrtc endpoint.
virtual EmulatedEndpoint* GetClientEndpoint() const = 0;
// Returns socket address, which client should use to connect to TURN server
// and do TURN allocation.
virtual rtc::SocketAddress GetClientEndpointAddress() const = 0;
// Get non-null peer endpoint, that is "connected to the internet".
// This shall typically be connected to another TURN server.
virtual EmulatedEndpoint* GetPeerEndpoint() const = 0;
};
// Provide interface to obtain all required objects to inject network emulation
// layer into PeerConnection. Also contains information about network interfaces
@ -210,6 +242,13 @@ class NetworkEmulationManager {
rtc::ArrayView<EmulatedEndpoint*> endpoints,
std::function<void(std::unique_ptr<EmulatedNetworkStats>)>
stats_callback) = 0;
// Create a EmulatedTURNServer.
// The TURN server has 2 endpoints that need to be connected with routes,
// - GetClientEndpoint() - the endpoint that accepts TURN allocations.
// - GetPeerEndpoint() - the endpoint that is "connected to the internet".
virtual EmulatedTURNServerInterface* CreateTURNServer(
EmulatedTURNServerConfig config) = 0;
};
} // namespace webrtc

View File

@ -76,5 +76,8 @@ specific_include_rules = {
],
"benchmark_main\.cc": [
"+benchmark",
],
"emulated_turn_server\.h": [
"+p2p/base/turn_server.h",
]
}

View File

@ -25,6 +25,8 @@ rtc_library("emulated_network") {
"cross_traffic.h",
"emulated_network_manager.cc",
"emulated_network_manager.h",
"emulated_turn_server.cc",
"emulated_turn_server.h",
"fake_network_socket_server.cc",
"fake_network_socket_server.h",
"network_emulation.cc",
@ -37,14 +39,17 @@ rtc_library("emulated_network") {
deps = [
"../../api:array_view",
"../../api:network_emulation_manager_api",
"../../api:packet_socket_factory",
"../../api:simulated_network_api",
"../../api:time_controller",
"../../api/numerics",
"../../api/transport:stun_types",
"../../api/units:data_rate",
"../../api/units:data_size",
"../../api/units:time_delta",
"../../api/units:timestamp",
"../../call:simulated_network",
"../../p2p:p2p_server_utils",
"../../rtc_base",
"../../rtc_base:rtc_base_tests_utils",
"../../rtc_base:rtc_task_queue",

View File

@ -0,0 +1,188 @@
/*
* Copyright (c) 2020 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/emulated_turn_server.h"
#include <string>
#include <utility>
#include "api/packet_socket_factory.h"
namespace {
static const char kTestRealm[] = "example.org";
static const char kTestSoftware[] = "TestTurnServer";
// A wrapper class for copying data between an AsyncPacketSocket and a
// EmulatedEndpoint. This is used by the cricket::TurnServer when
// sending data back into the emulated network.
class AsyncPacketSocketWrapper : public rtc::AsyncPacketSocket {
public:
AsyncPacketSocketWrapper(webrtc::test::EmulatedTURNServer* turn_server,
webrtc::EmulatedEndpoint* endpoint,
uint16_t port)
: turn_server_(turn_server),
endpoint_(endpoint),
local_address_(
rtc::SocketAddress(endpoint_->GetPeerLocalAddress(), port)) {}
~AsyncPacketSocketWrapper() { turn_server_->Unbind(local_address_); }
rtc::SocketAddress GetLocalAddress() const override { return local_address_; }
rtc::SocketAddress GetRemoteAddress() const override {
return rtc::SocketAddress();
}
int Send(const void* pv,
size_t cb,
const rtc::PacketOptions& options) override {
RTC_CHECK(false) << "TCP not implemented";
return -1;
}
int SendTo(const void* pv,
size_t cb,
const rtc::SocketAddress& addr,
const rtc::PacketOptions& options) override {
// Copy from rtc::AsyncPacketSocket to EmulatedEndpoint.
rtc::CopyOnWriteBuffer buf(reinterpret_cast<const char*>(pv), cb);
endpoint_->SendPacket(local_address_, addr, buf);
return cb;
}
int Close() override { return 0; }
rtc::AsyncPacketSocket::State GetState() const override {
return rtc::AsyncPacketSocket::STATE_BOUND;
}
int GetOption(rtc::Socket::Option opt, int* value) override { return 0; }
int SetOption(rtc::Socket::Option opt, int value) override { return 0; }
int GetError() const override { return 0; }
void SetError(int error) override {}
private:
webrtc::test::EmulatedTURNServer* const turn_server_;
webrtc::EmulatedEndpoint* const endpoint_;
const rtc::SocketAddress local_address_;
};
// A wrapper class for cricket::TurnServer to allocate sockets.
class PacketSocketFactoryWrapper : public rtc::PacketSocketFactory {
public:
explicit PacketSocketFactoryWrapper(
webrtc::test::EmulatedTURNServer* turn_server)
: turn_server_(turn_server) {}
~PacketSocketFactoryWrapper() override {}
// This method is called from TurnServer when making a TURN ALLOCATION.
// It will create a socket on the |peer_| endpoint.
rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& address,
uint16_t min_port,
uint16_t max_port) override {
return turn_server_->CreatePeerSocket();
}
rtc::AsyncPacketSocket* CreateServerTcpSocket(
const rtc::SocketAddress& local_address,
uint16_t min_port,
uint16_t max_port,
int opts) override {
return nullptr;
}
rtc::AsyncPacketSocket* CreateClientTcpSocket(
const rtc::SocketAddress& local_address,
const rtc::SocketAddress& remote_address,
const rtc::ProxyInfo& proxy_info,
const std::string& user_agent,
const rtc::PacketSocketTcpOptions& tcp_options) override {
return nullptr;
}
rtc::AsyncResolverInterface* CreateAsyncResolver() override {
return nullptr;
}
private:
webrtc::test::EmulatedTURNServer* turn_server_;
};
} // namespace
namespace webrtc {
namespace test {
EmulatedTURNServer::EmulatedTURNServer(std::unique_ptr<rtc::Thread> thread,
EmulatedEndpoint* client,
EmulatedEndpoint* peer)
: thread_(std::move(thread)), client_(client), peer_(peer) {
ice_config_.username = "keso";
ice_config_.password = "keso";
thread_->Invoke<void>(RTC_FROM_HERE, [=]() {
RTC_DCHECK_RUN_ON(thread_.get());
turn_server_ = std::make_unique<cricket::TurnServer>(thread_.get());
turn_server_->set_realm(kTestRealm);
turn_server_->set_realm(kTestSoftware);
turn_server_->set_auth_hook(this);
auto client_socket = Wrap(client_);
turn_server_->AddInternalSocket(client_socket, cricket::PROTO_UDP);
turn_server_->SetExternalSocketFactory(new PacketSocketFactoryWrapper(this),
rtc::SocketAddress());
client_address_ = client_socket->GetLocalAddress();
char buf[256];
rtc::SimpleStringBuilder str(buf);
str.AppendFormat("turn:%s?transport=udp",
client_address_.ToString().c_str());
ice_config_.url = str.str();
});
}
void EmulatedTURNServer::Stop() {
thread_->Invoke<void>(RTC_FROM_HERE, [=]() {
RTC_DCHECK_RUN_ON(thread_.get());
sockets_.clear();
});
}
EmulatedTURNServer::~EmulatedTURNServer() {
thread_->Invoke<void>(RTC_FROM_HERE, [=]() {
RTC_DCHECK_RUN_ON(thread_.get());
turn_server_.reset(nullptr);
});
}
rtc::AsyncPacketSocket* EmulatedTURNServer::Wrap(EmulatedEndpoint* endpoint) {
RTC_DCHECK_RUN_ON(thread_.get());
auto port = endpoint->BindReceiver(0, this).value();
auto socket = new AsyncPacketSocketWrapper(this, endpoint, port);
sockets_[rtc::SocketAddress(endpoint->GetPeerLocalAddress(), port)] = socket;
return socket;
}
void EmulatedTURNServer::OnPacketReceived(webrtc::EmulatedIpPacket packet) {
// Copy from EmulatedEndpoint to rtc::AsyncPacketSocket.
thread_->PostTask(RTC_FROM_HERE, [this, packet(std::move(packet))]() {
RTC_DCHECK_RUN_ON(thread_.get());
auto it = sockets_.find(packet.to);
if (it != sockets_.end()) {
it->second->SignalReadPacket(
it->second, reinterpret_cast<const char*>(packet.cdata()),
packet.size(), packet.from, packet.arrival_time.ms());
}
});
}
void EmulatedTURNServer::Unbind(rtc::SocketAddress address) {
RTC_DCHECK_RUN_ON(thread_.get());
if (GetClientEndpoint()->GetPeerLocalAddress() == address.ipaddr()) {
GetClientEndpoint()->UnbindReceiver(address.port());
} else {
GetPeerEndpoint()->UnbindReceiver(address.port());
}
sockets_.erase(address);
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2020 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.
*/
#ifndef TEST_NETWORK_EMULATED_TURN_SERVER_H_
#define TEST_NETWORK_EMULATED_TURN_SERVER_H_
#include <map>
#include <memory>
#include <string>
#include "api/test/network_emulation_manager.h"
#include "api/transport/stun.h"
#include "p2p/base/turn_server.h"
#include "rtc_base/async_packet_socket.h"
namespace webrtc {
namespace test {
// EmulatedTURNServer wraps cricket::TurnServer to be used inside
// a emulated network.
//
// Packets from EmulatedEndpoint (client or peer) are received in
// EmulatedTURNServer::OnPacketReceived which performs a map lookup
// and delivers them into cricket::TurnServer using
// AsyncPacketSocket::SignalReadPacket
//
// Packets from cricket::TurnServer to EmulatedEndpoint are sent into
// using a wrapper around AsyncPacketSocket (no lookup required as the
// wrapper around AsyncPacketSocket keep a pointer to the EmulatedEndpoint).
class EmulatedTURNServer : public EmulatedTURNServerInterface,
public cricket::TurnAuthInterface,
public webrtc::EmulatedNetworkReceiverInterface {
public:
// Create an EmulatedTURNServer.
// |thread| is a thread that will be used to run cricket::TurnServer
// that expects all calls to be made from a single thread.
EmulatedTURNServer(std::unique_ptr<rtc::Thread> thread,
EmulatedEndpoint* client,
EmulatedEndpoint* peer);
~EmulatedTURNServer() override;
IceServerConfig GetIceServerConfig() const override { return ice_config_; }
EmulatedEndpoint* GetClientEndpoint() const override { return client_; }
rtc::SocketAddress GetClientEndpointAddress() const override {
return client_address_;
}
EmulatedEndpoint* GetPeerEndpoint() const override { return peer_; }
// cricket::TurnAuthInterface
bool GetKey(const std::string& username,
const std::string& realm,
std::string* key) override {
return cricket::ComputeStunCredentialHash(username, realm, username, key);
}
rtc::AsyncPacketSocket* CreatePeerSocket() { return Wrap(peer_); }
// This method is called by network emulation when a packet
// comes from an emulated link.
void OnPacketReceived(webrtc::EmulatedIpPacket packet) override;
// This is called when the TURN server deletes a socket.
void Unbind(rtc::SocketAddress address);
// Unbind all sockets.
void Stop();
private:
std::unique_ptr<rtc::Thread> thread_;
rtc::SocketAddress client_address_;
IceServerConfig ice_config_;
EmulatedEndpoint* const client_;
EmulatedEndpoint* const peer_;
std::unique_ptr<cricket::TurnServer> turn_server_ RTC_GUARDED_BY(&thread_);
std::map<rtc::SocketAddress, rtc::AsyncPacketSocket*> sockets_
RTC_GUARDED_BY(&thread_);
// Wraps a EmulatedEndpoint in a AsyncPacketSocket to bridge interaction
// with TurnServer. cricket::TurnServer gets ownership of the socket.
rtc::AsyncPacketSocket* Wrap(EmulatedEndpoint* endpoint);
};
} // namespace test
} // namespace webrtc
#endif // TEST_NETWORK_EMULATED_TURN_SERVER_H_

View File

@ -17,6 +17,7 @@
#include "api/units/timestamp.h"
#include "call/simulated_network.h"
#include "rtc_base/fake_network.h"
#include "test/network/emulated_turn_server.h"
#include "test/time_controller/real_time_controller.h"
#include "test/time_controller/simulated_time_controller.h"
@ -55,7 +56,11 @@ NetworkEmulationManagerImpl::NetworkEmulationManagerImpl(TimeMode mode)
// TODO(srte): Ensure that any pending task that must be run for consistency
// (such as stats collection tasks) are not cancelled when the task queue is
// destroyed.
NetworkEmulationManagerImpl::~NetworkEmulationManagerImpl() = default;
NetworkEmulationManagerImpl::~NetworkEmulationManagerImpl() {
for (auto& turn_server : turn_servers_) {
turn_server->Stop();
}
}
EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode(
BuiltInNetworkBehaviorConfig config) {
@ -332,5 +337,20 @@ Timestamp NetworkEmulationManagerImpl::Now() const {
return clock_->CurrentTime();
}
EmulatedTURNServerInterface* NetworkEmulationManagerImpl::CreateTURNServer(
EmulatedTURNServerConfig config) {
auto* client = CreateEndpoint(config.client_config);
auto* peer = CreateEndpoint(config.client_config);
char buf[128];
rtc::SimpleStringBuilder str(buf);
str.AppendFormat("turn_server_%u",
static_cast<unsigned>(turn_servers_.size()));
auto turn = std::make_unique<EmulatedTURNServer>(
time_controller_->CreateThread(str.str()), client, peer);
auto out = turn.get();
turn_servers_.push_back(std::move(turn));
return out;
}
} // namespace test
} // namespace webrtc

View File

@ -31,6 +31,7 @@
#include "system_wrappers/include/clock.h"
#include "test/network/cross_traffic.h"
#include "test/network/emulated_network_manager.h"
#include "test/network/emulated_turn_server.h"
#include "test/network/fake_network_socket_server.h"
#include "test/network/network_emulation.h"
#include "test/network/traffic_route.h"
@ -92,6 +93,9 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
Timestamp Now() const;
EmulatedTURNServerInterface* CreateTURNServer(
EmulatedTURNServerConfig config) override;
private:
absl::optional<rtc::IPAddress> GetNextIPv4Address();
const std::unique_ptr<TimeController> time_controller_;
@ -114,6 +118,7 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
std::list<std::unique_ptr<TcpMessageRouteImpl>> tcp_message_routes_;
std::vector<std::unique_ptr<EndpointsContainer>> endpoints_containers_;
std::vector<std::unique_ptr<EmulatedNetworkManager>> network_managers_;
std::vector<std::unique_ptr<EmulatedTURNServer>> turn_servers_;
std::map<EmulatedEndpoint*, EmulatedNetworkManager*>
endpoint_to_network_manager_;

View File

@ -78,7 +78,8 @@ rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
const rtc::scoped_refptr<PeerConnectionFactoryInterface>& pcf,
PeerConnectionObserver* observer,
rtc::NetworkManager* network_manager) {
rtc::NetworkManager* network_manager,
EmulatedTURNServerInterface* turn_server = nullptr) {
PeerConnectionDependencies pc_deps(observer);
auto port_allocator =
std::make_unique<cricket::BasicPortAllocator>(network_manager);
@ -90,6 +91,13 @@ rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
pc_deps.allocator = std::move(port_allocator);
PeerConnectionInterface::RTCConfiguration rtc_configuration;
rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
if (turn_server != nullptr) {
webrtc::PeerConnectionInterface::IceServer server;
server.username = turn_server->GetIceServerConfig().username;
server.password = turn_server->GetIceServerConfig().username;
server.urls.push_back(turn_server->GetIceServerConfig().url);
rtc_configuration.servers.push_back(server);
}
return pcf->CreatePeerConnection(rtc_configuration, std::move(pc_deps));
}
@ -185,5 +193,114 @@ TEST(NetworkEmulationManagerPCTest, Run) {
});
}
TEST(NetworkEmulationManagerPCTest, RunTURN) {
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
signaling_thread->SetName(kSignalThreadName, nullptr);
signaling_thread->Start();
// Setup emulated network
NetworkEmulationManagerImpl emulation(TimeMode::kRealTime);
EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode(
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
EmulatedNetworkNode* bob_node = emulation.CreateEmulatedNode(
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
EmulatedNetworkNode* turn_node = emulation.CreateEmulatedNode(
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
EmulatedEndpoint* alice_endpoint =
emulation.CreateEndpoint(EmulatedEndpointConfig());
EmulatedEndpoint* bob_endpoint =
emulation.CreateEndpoint(EmulatedEndpointConfig());
EmulatedTURNServerInterface* alice_turn =
emulation.CreateTURNServer(EmulatedTURNServerConfig());
EmulatedTURNServerInterface* bob_turn =
emulation.CreateTURNServer(EmulatedTURNServerConfig());
emulation.CreateRoute(alice_endpoint, {alice_node},
alice_turn->GetClientEndpoint());
emulation.CreateRoute(alice_turn->GetClientEndpoint(), {alice_node},
alice_endpoint);
emulation.CreateRoute(bob_endpoint, {bob_node},
bob_turn->GetClientEndpoint());
emulation.CreateRoute(bob_turn->GetClientEndpoint(), {bob_node},
bob_endpoint);
emulation.CreateRoute(alice_turn->GetPeerEndpoint(), {turn_node},
bob_turn->GetPeerEndpoint());
emulation.CreateRoute(bob_turn->GetPeerEndpoint(), {turn_node},
alice_turn->GetPeerEndpoint());
EmulatedNetworkManagerInterface* alice_network =
emulation.CreateEmulatedNetworkManagerInterface({alice_endpoint});
EmulatedNetworkManagerInterface* bob_network =
emulation.CreateEmulatedNetworkManagerInterface({bob_endpoint});
// Setup peer connections.
rtc::scoped_refptr<PeerConnectionFactoryInterface> alice_pcf;
rtc::scoped_refptr<PeerConnectionInterface> alice_pc;
std::unique_ptr<MockPeerConnectionObserver> alice_observer =
std::make_unique<MockPeerConnectionObserver>();
rtc::scoped_refptr<PeerConnectionFactoryInterface> bob_pcf;
rtc::scoped_refptr<PeerConnectionInterface> bob_pc;
std::unique_ptr<MockPeerConnectionObserver> bob_observer =
std::make_unique<MockPeerConnectionObserver>();
signaling_thread->Invoke<void>(RTC_FROM_HERE, [&]() {
alice_pcf = CreatePeerConnectionFactory(signaling_thread.get(),
alice_network->network_thread());
alice_pc =
CreatePeerConnection(alice_pcf, alice_observer.get(),
alice_network->network_manager(), alice_turn);
bob_pcf = CreatePeerConnectionFactory(signaling_thread.get(),
bob_network->network_thread());
bob_pc = CreatePeerConnection(bob_pcf, bob_observer.get(),
bob_network->network_manager(), bob_turn);
});
std::unique_ptr<PeerConnectionWrapper> alice =
std::make_unique<PeerConnectionWrapper>(alice_pcf, alice_pc,
std::move(alice_observer));
std::unique_ptr<PeerConnectionWrapper> bob =
std::make_unique<PeerConnectionWrapper>(bob_pcf, bob_pc,
std::move(bob_observer));
signaling_thread->Invoke<void>(RTC_FROM_HERE, [&]() {
rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
alice_pcf->CreateAudioSource(cricket::AudioOptions());
rtc::scoped_refptr<AudioTrackInterface> track =
alice_pcf->CreateAudioTrack("audio", source);
alice->AddTransceiver(track);
// Connect peers.
ASSERT_TRUE(alice->ExchangeOfferAnswerWith(bob.get()));
// Do the SDP negotiation, and also exchange ice candidates.
ASSERT_TRUE_WAIT(
alice->signaling_state() == PeerConnectionInterface::kStable,
kDefaultTimeoutMs);
ASSERT_TRUE_WAIT(alice->IsIceGatheringDone(), kDefaultTimeoutMs);
ASSERT_TRUE_WAIT(bob->IsIceGatheringDone(), kDefaultTimeoutMs);
// Connect an ICE candidate pairs.
ASSERT_TRUE(
AddIceCandidates(bob.get(), alice->observer()->GetAllCandidates()));
ASSERT_TRUE(
AddIceCandidates(alice.get(), bob->observer()->GetAllCandidates()));
// This means that ICE and DTLS are connected.
ASSERT_TRUE_WAIT(bob->IsIceConnected(), kDefaultTimeoutMs);
ASSERT_TRUE_WAIT(alice->IsIceConnected(), kDefaultTimeoutMs);
// Close peer connections
alice->pc()->Close();
bob->pc()->Close();
// Delete peers.
alice.reset();
bob.reset();
});
}
} // namespace test
} // namespace webrtc

View File

@ -568,5 +568,42 @@ TEST(NetworkEmulationManagerTest, EndpointLoopback) {
network_manager.time_controller()->AdvanceTime(TimeDelta::Seconds(1));
}
TEST(NetworkEmulationManagerTURNTest, GetIceServerConfig) {
NetworkEmulationManagerImpl network_manager(TimeMode::kRealTime);
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);
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;
ping.SetType(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