Introduce default routes for network emulation
Change-Id: If9bc941d54844e0f22147fb13e148ced1bc49c71 Bug: b/180750880 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/208227 Reviewed-by: Andrey Logvin <landrey@webrtc.org> Commit-Queue: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33310}
This commit is contained in:
parent
1dd94a023a
commit
3d37e06fed
@ -225,7 +225,16 @@ class EmulatedEndpoint : public EmulatedNetworkReceiverInterface {
|
||||
virtual absl::optional<uint16_t> BindReceiver(
|
||||
uint16_t desired_port,
|
||||
EmulatedNetworkReceiverInterface* receiver) = 0;
|
||||
// Unbinds receiver from the specified port. Do nothing if no receiver was
|
||||
// binded before.
|
||||
virtual void UnbindReceiver(uint16_t port) = 0;
|
||||
// Binds receiver that will accept all packets which arrived on any port
|
||||
// for which there are no binded receiver.
|
||||
virtual void BindDefaultReceiver(
|
||||
EmulatedNetworkReceiverInterface* receiver) = 0;
|
||||
// Unbinds default receiver. Do nothing if no default receiver was binded
|
||||
// before.
|
||||
virtual void UnbindDefaultReceiver() = 0;
|
||||
virtual rtc::IPAddress GetPeerLocalAddress() const = 0;
|
||||
|
||||
private:
|
||||
|
||||
@ -68,6 +68,14 @@ struct EmulatedEndpointConfig {
|
||||
// Network type which will be used to represent endpoint to WebRTC.
|
||||
rtc::AdapterType type = rtc::AdapterType::ADAPTER_TYPE_UNKNOWN;
|
||||
StatsGatheringMode stats_gathering_mode = StatsGatheringMode::kDefault;
|
||||
// Allow endpoint to send packets specifying source IP address different to
|
||||
// the current endpoint IP address. If false endpoint will crash if attempt
|
||||
// to send such packet will be done.
|
||||
bool allow_send_packet_with_different_source_ip = false;
|
||||
// Allow endpoint to receive packet with destination IP address different to
|
||||
// the current endpoint IP address. If false endpoint will crash if such
|
||||
// packet will arrive.
|
||||
bool allow_receive_packets_with_different_dest_ip = false;
|
||||
};
|
||||
|
||||
struct EmulatedTURNServerConfig {
|
||||
@ -226,6 +234,35 @@ class NetworkEmulationManager {
|
||||
virtual EmulatedRoute* CreateRoute(
|
||||
const std::vector<EmulatedNetworkNode*>& via_nodes) = 0;
|
||||
|
||||
// Creates a default route between endpoints going through specified network
|
||||
// nodes. Default route is used for packet when there is no known route for
|
||||
// packet's destination IP.
|
||||
//
|
||||
// This route is single direction only and describe how traffic that was
|
||||
// sent by network interface |from| have to be delivered in case if routing
|
||||
// was unspecified. Return object can be used to remove created route. The
|
||||
// route must contains at least one network node inside it.
|
||||
//
|
||||
// Assume that E{0-9} are endpoints and N{0-9} are network nodes, then
|
||||
// creation of the route have to follow these rules:
|
||||
// 1. A route consists of a source endpoint, an ordered list of one or
|
||||
// more network nodes, and a destination endpoint.
|
||||
// 2. If (E1, ..., E2) is a route, then E1 != E2.
|
||||
// In other words, the source and the destination may not be the same.
|
||||
// 3. Given two simultaneously existing routes (E1, ..., E2) and
|
||||
// (E3, ..., E4), either E1 != E3 or E2 != E4.
|
||||
// In other words, there may be at most one route from any given source
|
||||
// endpoint to any given destination endpoint.
|
||||
// 4. Given two simultaneously existing routes (E1, ..., N1, ..., E2)
|
||||
// and (E3, ..., N2, ..., E4), either N1 != N2 or E2 != E4.
|
||||
// In other words, a network node may not belong to two routes that lead
|
||||
// to the same destination endpoint.
|
||||
// 5. Any node N can belong to only one default route.
|
||||
virtual EmulatedRoute* CreateDefaultRoute(
|
||||
EmulatedEndpoint* from,
|
||||
const std::vector<EmulatedNetworkNode*>& via_nodes,
|
||||
EmulatedEndpoint* to) = 0;
|
||||
|
||||
// Removes route previously created by CreateRoute(...).
|
||||
// Caller mustn't call this function with route, that have been already
|
||||
// removed earlier. Removing a route that is currently in use will lead to
|
||||
|
||||
@ -46,6 +46,7 @@ rtc_library("emulated_network") {
|
||||
"../../api:simulated_network_api",
|
||||
"../../api:time_controller",
|
||||
"../../api/numerics",
|
||||
"../../api/test/network_emulation",
|
||||
"../../api/transport:stun_types",
|
||||
"../../api/units:data_rate",
|
||||
"../../api/units:data_size",
|
||||
|
||||
@ -49,15 +49,12 @@ struct TrafficCounterFixture {
|
||||
SimulatedClock clock{0};
|
||||
CountingReceiver counter;
|
||||
TaskQueueForTest task_queue_;
|
||||
EmulatedEndpointImpl endpoint{
|
||||
/*id=*/1,
|
||||
absl::nullopt,
|
||||
rtc::IPAddress(kTestIpAddress),
|
||||
EmulatedEndpointConfig::StatsGatheringMode::kDefault,
|
||||
/*is_enabled=*/true,
|
||||
/*type=*/rtc::AdapterType::ADAPTER_TYPE_UNKNOWN,
|
||||
&task_queue_,
|
||||
&clock};
|
||||
EmulatedEndpointImpl endpoint{EmulatedEndpointImpl::Options{
|
||||
/*id=*/1,
|
||||
rtc::IPAddress(kTestIpAddress),
|
||||
EmulatedEndpointConfig(),
|
||||
},
|
||||
/*is_enabled=*/true, &task_queue_, &clock};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -13,9 +13,11 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/numerics/samples_stats_counter.h"
|
||||
#include "api/test/network_emulation/network_emulation_interfaces.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
@ -346,6 +348,9 @@ void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) {
|
||||
}
|
||||
auto receiver_it = routing_.find(packet.to.ipaddr());
|
||||
if (receiver_it == routing_.end()) {
|
||||
if (default_receiver_.has_value()) {
|
||||
(*default_receiver_)->OnPacketReceived(std::move(packet));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RTC_CHECK(receiver_it != routing_.end());
|
||||
@ -370,6 +375,23 @@ void NetworkRouterNode::RemoveReceiver(const rtc::IPAddress& dest_ip) {
|
||||
routing_.erase(dest_ip);
|
||||
}
|
||||
|
||||
void NetworkRouterNode::SetDefaultReceiver(
|
||||
EmulatedNetworkReceiverInterface* receiver) {
|
||||
task_queue_->PostTask([=] {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
if (default_receiver_.has_value()) {
|
||||
RTC_CHECK_EQ(*default_receiver_, receiver)
|
||||
<< "Router already default receiver";
|
||||
}
|
||||
default_receiver_ = receiver;
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkRouterNode::RemoveDefaultReceiver() {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
default_receiver_ = absl::nullopt;
|
||||
}
|
||||
|
||||
void NetworkRouterNode::SetWatcher(
|
||||
std::function<void(const EmulatedIpPacket&)> watcher) {
|
||||
task_queue_->PostTask([=] {
|
||||
@ -415,64 +437,72 @@ void EmulatedNetworkNode::ClearRoute(const rtc::IPAddress& receiver_ip,
|
||||
|
||||
EmulatedNetworkNode::~EmulatedNetworkNode() = default;
|
||||
|
||||
EmulatedEndpointImpl::EmulatedEndpointImpl(
|
||||
uint64_t id,
|
||||
absl::optional<std::string> name,
|
||||
const rtc::IPAddress& ip,
|
||||
EmulatedEndpointConfig::StatsGatheringMode stats_gathering_mode,
|
||||
bool is_enabled,
|
||||
rtc::AdapterType type,
|
||||
rtc::TaskQueue* task_queue,
|
||||
Clock* clock)
|
||||
: id_(id),
|
||||
log_name_(ip.ToString() + " (" + name.value_or("") + ")"),
|
||||
peer_local_addr_(ip),
|
||||
stats_gathering_mode_(stats_gathering_mode),
|
||||
EmulatedEndpointImpl::Options::Options(uint64_t id,
|
||||
const rtc::IPAddress& ip,
|
||||
const EmulatedEndpointConfig& config)
|
||||
: id(id),
|
||||
ip(ip),
|
||||
stats_gathering_mode(config.stats_gathering_mode),
|
||||
type(config.type),
|
||||
allow_send_packet_with_different_source_ip(
|
||||
config.allow_send_packet_with_different_source_ip),
|
||||
allow_receive_packets_with_different_dest_ip(
|
||||
config.allow_send_packet_with_different_source_ip),
|
||||
log_name(ip.ToString() + " (" + config.name.value_or("") + ")") {}
|
||||
|
||||
EmulatedEndpointImpl::EmulatedEndpointImpl(const Options& options,
|
||||
bool is_enabled,
|
||||
rtc::TaskQueue* task_queue,
|
||||
Clock* clock)
|
||||
: options_(options),
|
||||
is_enabled_(is_enabled),
|
||||
type_(type),
|
||||
clock_(clock),
|
||||
task_queue_(task_queue),
|
||||
router_(task_queue_),
|
||||
next_port_(kFirstEphemeralPort),
|
||||
stats_builder_(peer_local_addr_) {
|
||||
stats_builder_(options_.ip) {
|
||||
constexpr int kIPv4NetworkPrefixLength = 24;
|
||||
constexpr int kIPv6NetworkPrefixLength = 64;
|
||||
|
||||
int prefix_length = 0;
|
||||
if (ip.family() == AF_INET) {
|
||||
if (options_.ip.family() == AF_INET) {
|
||||
prefix_length = kIPv4NetworkPrefixLength;
|
||||
} else if (ip.family() == AF_INET6) {
|
||||
} else if (options_.ip.family() == AF_INET6) {
|
||||
prefix_length = kIPv6NetworkPrefixLength;
|
||||
}
|
||||
rtc::IPAddress prefix = TruncateIP(ip, prefix_length);
|
||||
rtc::IPAddress prefix = TruncateIP(options_.ip, prefix_length);
|
||||
network_ = std::make_unique<rtc::Network>(
|
||||
ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix,
|
||||
prefix_length, type_);
|
||||
network_->AddIP(ip);
|
||||
options_.ip.ToString(), "Endpoint id=" + std::to_string(options_.id),
|
||||
prefix, prefix_length, options_.type);
|
||||
network_->AddIP(options_.ip);
|
||||
|
||||
enabled_state_checker_.Detach();
|
||||
RTC_LOG(INFO) << "Created emulated endpoint " << log_name_ << "; id=" << id_;
|
||||
RTC_LOG(INFO) << "Created emulated endpoint " << options_.log_name
|
||||
<< "; id=" << options_.id;
|
||||
}
|
||||
EmulatedEndpointImpl::~EmulatedEndpointImpl() = default;
|
||||
|
||||
uint64_t EmulatedEndpointImpl::GetId() const {
|
||||
return id_;
|
||||
return options_.id;
|
||||
}
|
||||
|
||||
void EmulatedEndpointImpl::SendPacket(const rtc::SocketAddress& from,
|
||||
const rtc::SocketAddress& to,
|
||||
rtc::CopyOnWriteBuffer packet_data,
|
||||
uint16_t application_overhead) {
|
||||
RTC_CHECK(from.ipaddr() == peer_local_addr_);
|
||||
if (!options_.allow_send_packet_with_different_source_ip) {
|
||||
RTC_CHECK(from.ipaddr() == options_.ip);
|
||||
}
|
||||
EmulatedIpPacket packet(from, to, std::move(packet_data),
|
||||
clock_->CurrentTime(), application_overhead);
|
||||
task_queue_->PostTask([this, packet = std::move(packet)]() mutable {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
stats_builder_.OnPacketSent(
|
||||
packet.arrival_time, clock_->CurrentTime(), packet.to.ipaddr(),
|
||||
DataSize::Bytes(packet.ip_packet_size()), stats_gathering_mode_);
|
||||
stats_builder_.OnPacketSent(packet.arrival_time, clock_->CurrentTime(),
|
||||
packet.to.ipaddr(),
|
||||
DataSize::Bytes(packet.ip_packet_size()),
|
||||
options_.stats_gathering_mode);
|
||||
|
||||
if (packet.to.ipaddr() == peer_local_addr_) {
|
||||
if (packet.to.ipaddr() == options_.ip) {
|
||||
OnPacketReceived(std::move(packet));
|
||||
} else {
|
||||
router_.OnPacketReceived(std::move(packet));
|
||||
@ -499,15 +529,16 @@ absl::optional<uint16_t> EmulatedEndpointImpl::BindReceiver(
|
||||
}
|
||||
}
|
||||
RTC_CHECK(port != 0) << "Can't find free port for receiver in endpoint "
|
||||
<< log_name_ << "; id=" << id_;
|
||||
<< options_.log_name << "; id=" << options_.id;
|
||||
bool result = port_to_receiver_.insert({port, receiver}).second;
|
||||
if (!result) {
|
||||
RTC_LOG(INFO) << "Can't bind receiver to used port " << desired_port
|
||||
<< " in endpoint " << log_name_ << "; id=" << id_;
|
||||
<< " in endpoint " << options_.log_name
|
||||
<< "; id=" << options_.id;
|
||||
return absl::nullopt;
|
||||
}
|
||||
RTC_LOG(INFO) << "New receiver is binded to endpoint " << log_name_
|
||||
<< "; id=" << id_ << " on port " << port;
|
||||
RTC_LOG(INFO) << "New receiver is binded to endpoint " << options_.log_name
|
||||
<< "; id=" << options_.id << " on port " << port;
|
||||
return port;
|
||||
}
|
||||
|
||||
@ -523,33 +554,60 @@ uint16_t EmulatedEndpointImpl::NextPort() {
|
||||
|
||||
void EmulatedEndpointImpl::UnbindReceiver(uint16_t port) {
|
||||
rtc::CritScope crit(&receiver_lock_);
|
||||
RTC_LOG(INFO) << "Receiver is removed on port " << port << " from endpoint "
|
||||
<< options_.log_name << "; id=" << options_.id;
|
||||
port_to_receiver_.erase(port);
|
||||
}
|
||||
|
||||
void EmulatedEndpointImpl::BindDefaultReceiver(
|
||||
EmulatedNetworkReceiverInterface* receiver) {
|
||||
rtc::CritScope crit(&receiver_lock_);
|
||||
RTC_CHECK(!default_receiver_.has_value())
|
||||
<< "Endpoint " << options_.log_name << "; id=" << options_.id
|
||||
<< " already has default receiver";
|
||||
RTC_LOG(INFO) << "Default receiver is binded to endpoint "
|
||||
<< options_.log_name << "; id=" << options_.id;
|
||||
default_receiver_ = receiver;
|
||||
}
|
||||
|
||||
void EmulatedEndpointImpl::UnbindDefaultReceiver() {
|
||||
rtc::CritScope crit(&receiver_lock_);
|
||||
RTC_LOG(INFO) << "Default receiver is removed from endpoint "
|
||||
<< options_.log_name << "; id=" << options_.id;
|
||||
default_receiver_ = absl::nullopt;
|
||||
}
|
||||
|
||||
rtc::IPAddress EmulatedEndpointImpl::GetPeerLocalAddress() const {
|
||||
return peer_local_addr_;
|
||||
return options_.ip;
|
||||
}
|
||||
|
||||
void EmulatedEndpointImpl::OnPacketReceived(EmulatedIpPacket packet) {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
RTC_CHECK(packet.to.ipaddr() == peer_local_addr_)
|
||||
<< "Routing error: wrong destination endpoint. Packet.to.ipaddr()=: "
|
||||
<< packet.to.ipaddr().ToString()
|
||||
<< "; Receiver peer_local_addr_=" << peer_local_addr_.ToString();
|
||||
if (options_.allow_receive_packets_with_different_dest_ip) {
|
||||
RTC_CHECK(packet.to.ipaddr() == options_.ip)
|
||||
<< "Routing error: wrong destination endpoint. Packet.to.ipaddr()=: "
|
||||
<< packet.to.ipaddr().ToString()
|
||||
<< "; Receiver options_.ip=" << options_.ip.ToString();
|
||||
}
|
||||
rtc::CritScope crit(&receiver_lock_);
|
||||
stats_builder_.OnPacketReceived(clock_->CurrentTime(), packet.from.ipaddr(),
|
||||
DataSize::Bytes(packet.ip_packet_size()),
|
||||
stats_gathering_mode_);
|
||||
options_.stats_gathering_mode);
|
||||
auto it = port_to_receiver_.find(packet.to.port());
|
||||
if (it == port_to_receiver_.end()) {
|
||||
if (default_receiver_.has_value()) {
|
||||
(*default_receiver_)->OnPacketReceived(std::move(packet));
|
||||
return;
|
||||
}
|
||||
// It can happen, that remote peer closed connection, but there still some
|
||||
// packets, that are going to it. It can happen during peer connection close
|
||||
// process: one peer closed connection, second still sending data.
|
||||
RTC_LOG(INFO) << "Drop packet: no receiver registered in " << log_name_
|
||||
<< "; id=" << id_ << " on port " << packet.to.port();
|
||||
RTC_LOG(INFO) << "Drop packet: no receiver registered in "
|
||||
<< options_.log_name << "; id=" << options_.id << " on port "
|
||||
<< packet.to.port();
|
||||
stats_builder_.OnPacketDropped(packet.from.ipaddr(),
|
||||
DataSize::Bytes(packet.ip_packet_size()),
|
||||
stats_gathering_mode_);
|
||||
options_.stats_gathering_mode);
|
||||
return;
|
||||
}
|
||||
// Endpoint assumes frequent calls to bind and unbind methods, so it holds
|
||||
|
||||
@ -418,6 +418,10 @@ class LinkEmulation : public EmulatedNetworkReceiverInterface {
|
||||
uint64_t next_packet_id_ RTC_GUARDED_BY(task_queue_) = 1;
|
||||
};
|
||||
|
||||
// Represents a component responsible for routing packets based on their IP
|
||||
// address. All possible routes have to be set explicitly before packet for
|
||||
// desired destination will be seen for the first time. If route is unknown
|
||||
// the packet will be silently dropped.
|
||||
class NetworkRouterNode : public EmulatedNetworkReceiverInterface {
|
||||
public:
|
||||
explicit NetworkRouterNode(rtc::TaskQueue* task_queue);
|
||||
@ -426,11 +430,17 @@ class NetworkRouterNode : public EmulatedNetworkReceiverInterface {
|
||||
void SetReceiver(const rtc::IPAddress& dest_ip,
|
||||
EmulatedNetworkReceiverInterface* receiver);
|
||||
void RemoveReceiver(const rtc::IPAddress& dest_ip);
|
||||
// Sets a default receive that will be used for all incoming packets for which
|
||||
// there is no specific receiver binded to their destination port.
|
||||
void SetDefaultReceiver(EmulatedNetworkReceiverInterface* receiver);
|
||||
void RemoveDefaultReceiver();
|
||||
void SetWatcher(std::function<void(const EmulatedIpPacket&)> watcher);
|
||||
void SetFilter(std::function<bool(const EmulatedIpPacket&)> filter);
|
||||
|
||||
private:
|
||||
rtc::TaskQueue* const task_queue_;
|
||||
absl::optional<EmulatedNetworkReceiverInterface*> default_receiver_
|
||||
RTC_GUARDED_BY(task_queue_);
|
||||
std::map<rtc::IPAddress, EmulatedNetworkReceiverInterface*> routing_
|
||||
RTC_GUARDED_BY(task_queue_);
|
||||
std::function<void(const EmulatedIpPacket&)> watcher_
|
||||
@ -481,15 +491,33 @@ class EmulatedNetworkNode : public EmulatedNetworkReceiverInterface {
|
||||
// from other EmulatedNetworkNodes.
|
||||
class EmulatedEndpointImpl : public EmulatedEndpoint {
|
||||
public:
|
||||
EmulatedEndpointImpl(
|
||||
uint64_t id,
|
||||
absl::optional<std::string> name,
|
||||
const rtc::IPAddress& ip,
|
||||
EmulatedEndpointConfig::StatsGatheringMode stats_gathering_mode,
|
||||
bool is_enabled,
|
||||
rtc::AdapterType type,
|
||||
rtc::TaskQueue* task_queue,
|
||||
Clock* clock);
|
||||
struct Options {
|
||||
Options(uint64_t id,
|
||||
const rtc::IPAddress& ip,
|
||||
const EmulatedEndpointConfig& config);
|
||||
|
||||
// TODO(titovartem) check if we can remove id.
|
||||
uint64_t id;
|
||||
// Endpoint local IP address.
|
||||
rtc::IPAddress ip;
|
||||
EmulatedEndpointConfig::StatsGatheringMode stats_gathering_mode;
|
||||
rtc::AdapterType type;
|
||||
// Allow endpoint to send packets specifying source IP address different to
|
||||
// the current endpoint IP address. If false endpoint will crash if attempt
|
||||
// to send such packet will be done.
|
||||
bool allow_send_packet_with_different_source_ip;
|
||||
// Allow endpoint to receive packet with destination IP address different to
|
||||
// the current endpoint IP address. If false endpoint will crash if such
|
||||
// packet will arrive.
|
||||
bool allow_receive_packets_with_different_dest_ip;
|
||||
// Name of the endpoint used for logging purposes.
|
||||
std::string log_name;
|
||||
};
|
||||
|
||||
EmulatedEndpointImpl(const Options& options,
|
||||
bool is_enabled,
|
||||
rtc::TaskQueue* task_queue,
|
||||
Clock* clock);
|
||||
~EmulatedEndpointImpl() override;
|
||||
|
||||
uint64_t GetId() const;
|
||||
@ -505,6 +533,8 @@ class EmulatedEndpointImpl : public EmulatedEndpoint {
|
||||
uint16_t desired_port,
|
||||
EmulatedNetworkReceiverInterface* receiver) override;
|
||||
void UnbindReceiver(uint16_t port) override;
|
||||
void BindDefaultReceiver(EmulatedNetworkReceiverInterface* receiver) override;
|
||||
void UnbindDefaultReceiver() override;
|
||||
|
||||
rtc::IPAddress GetPeerLocalAddress() const override;
|
||||
|
||||
@ -526,19 +556,16 @@ class EmulatedEndpointImpl : public EmulatedEndpoint {
|
||||
rtc::RecursiveCriticalSection receiver_lock_;
|
||||
SequenceChecker enabled_state_checker_;
|
||||
|
||||
const uint64_t id_;
|
||||
const std::string log_name_;
|
||||
// Peer's local IP address for this endpoint network interface.
|
||||
const rtc::IPAddress peer_local_addr_;
|
||||
const EmulatedEndpointConfig::StatsGatheringMode stats_gathering_mode_;
|
||||
const Options options_;
|
||||
bool is_enabled_ RTC_GUARDED_BY(enabled_state_checker_);
|
||||
const rtc::AdapterType type_;
|
||||
Clock* const clock_;
|
||||
rtc::TaskQueue* const task_queue_;
|
||||
std::unique_ptr<rtc::Network> network_;
|
||||
NetworkRouterNode router_;
|
||||
|
||||
uint16_t next_port_ RTC_GUARDED_BY(receiver_lock_);
|
||||
absl::optional<EmulatedNetworkReceiverInterface*> default_receiver_
|
||||
RTC_GUARDED_BY(receiver_lock_);
|
||||
std::map<uint16_t, EmulatedNetworkReceiverInterface*> port_to_receiver_
|
||||
RTC_GUARDED_BY(receiver_lock_);
|
||||
|
||||
@ -549,13 +576,19 @@ class EmulatedRoute {
|
||||
public:
|
||||
EmulatedRoute(EmulatedEndpointImpl* from,
|
||||
std::vector<EmulatedNetworkNode*> via_nodes,
|
||||
EmulatedEndpointImpl* to)
|
||||
: from(from), via_nodes(std::move(via_nodes)), to(to), active(true) {}
|
||||
EmulatedEndpointImpl* to,
|
||||
bool is_default)
|
||||
: from(from),
|
||||
via_nodes(std::move(via_nodes)),
|
||||
to(to),
|
||||
active(true),
|
||||
is_default(is_default) {}
|
||||
|
||||
EmulatedEndpointImpl* from;
|
||||
std::vector<EmulatedNetworkNode*> via_nodes;
|
||||
EmulatedEndpointImpl* to;
|
||||
bool active;
|
||||
bool is_default;
|
||||
};
|
||||
|
||||
// This object is immutable and so thread safe.
|
||||
|
||||
@ -107,8 +107,8 @@ EmulatedEndpoint* NetworkEmulationManagerImpl::CreateEndpoint(
|
||||
bool res = used_ip_addresses_.insert(*ip).second;
|
||||
RTC_CHECK(res) << "IP=" << ip->ToString() << " already in use";
|
||||
auto node = std::make_unique<EmulatedEndpointImpl>(
|
||||
next_node_id_++, config.name, *ip, config.stats_gathering_mode,
|
||||
config.start_as_enabled, config.type, &task_queue_, clock_);
|
||||
EmulatedEndpointImpl::Options(next_node_id_++, *ip, config),
|
||||
config.start_as_enabled, &task_queue_, clock_);
|
||||
EmulatedEndpoint* out = node.get();
|
||||
endpoints_.push_back(std::move(node));
|
||||
return out;
|
||||
@ -148,7 +148,7 @@ EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute(
|
||||
|
||||
std::unique_ptr<EmulatedRoute> route = std::make_unique<EmulatedRoute>(
|
||||
static_cast<EmulatedEndpointImpl*>(from), std::move(via_nodes),
|
||||
static_cast<EmulatedEndpointImpl*>(to));
|
||||
static_cast<EmulatedEndpointImpl*>(to), /*is_default=*/false);
|
||||
EmulatedRoute* out = route.get();
|
||||
routes_.push_back(std::move(route));
|
||||
return out;
|
||||
@ -161,16 +161,50 @@ EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute(
|
||||
return CreateRoute(from, via_nodes, to);
|
||||
}
|
||||
|
||||
EmulatedRoute* NetworkEmulationManagerImpl::CreateDefaultRoute(
|
||||
EmulatedEndpoint* from,
|
||||
const std::vector<EmulatedNetworkNode*>& via_nodes,
|
||||
EmulatedEndpoint* to) {
|
||||
// Because endpoint has no send node by default at least one should be
|
||||
// provided here.
|
||||
RTC_CHECK(!via_nodes.empty());
|
||||
|
||||
static_cast<EmulatedEndpointImpl*>(from)->router()->SetDefaultReceiver(
|
||||
via_nodes[0]);
|
||||
EmulatedNetworkNode* cur_node = via_nodes[0];
|
||||
for (size_t i = 1; i < via_nodes.size(); ++i) {
|
||||
cur_node->router()->SetDefaultReceiver(via_nodes[i]);
|
||||
cur_node = via_nodes[i];
|
||||
}
|
||||
cur_node->router()->SetDefaultReceiver(to);
|
||||
|
||||
std::unique_ptr<EmulatedRoute> route = std::make_unique<EmulatedRoute>(
|
||||
static_cast<EmulatedEndpointImpl*>(from), std::move(via_nodes),
|
||||
static_cast<EmulatedEndpointImpl*>(to), /*is_default=*/true);
|
||||
EmulatedRoute* out = route.get();
|
||||
routes_.push_back(std::move(route));
|
||||
return out;
|
||||
}
|
||||
|
||||
void NetworkEmulationManagerImpl::ClearRoute(EmulatedRoute* route) {
|
||||
RTC_CHECK(route->active) << "Route already cleared";
|
||||
task_queue_.SendTask(
|
||||
[route]() {
|
||||
// Remove receiver from intermediate nodes.
|
||||
for (auto* node : route->via_nodes) {
|
||||
node->router()->RemoveReceiver(route->to->GetPeerLocalAddress());
|
||||
if (route->is_default) {
|
||||
node->router()->RemoveDefaultReceiver();
|
||||
} else {
|
||||
node->router()->RemoveReceiver(route->to->GetPeerLocalAddress());
|
||||
}
|
||||
}
|
||||
// Remove destination endpoint from source endpoint's router.
|
||||
route->from->router()->RemoveReceiver(route->to->GetPeerLocalAddress());
|
||||
if (route->is_default) {
|
||||
route->from->router()->RemoveDefaultReceiver();
|
||||
} else {
|
||||
route->from->router()->RemoveReceiver(
|
||||
route->to->GetPeerLocalAddress());
|
||||
}
|
||||
|
||||
route->active = false;
|
||||
},
|
||||
|
||||
@ -61,6 +61,11 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
|
||||
EmulatedRoute* CreateRoute(
|
||||
const std::vector<EmulatedNetworkNode*>& via_nodes) override;
|
||||
|
||||
EmulatedRoute* CreateDefaultRoute(
|
||||
EmulatedEndpoint* from,
|
||||
const std::vector<EmulatedNetworkNode*>& via_nodes,
|
||||
EmulatedEndpoint* to) override;
|
||||
|
||||
void ClearRoute(EmulatedRoute* route) override;
|
||||
|
||||
TcpMessageRoute* CreateTcpRoute(EmulatedRoute* send_route,
|
||||
|
||||
@ -587,6 +587,51 @@ TEST(NetworkEmulationManagerTest, EndpointLoopback) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
auto turn = network_manager.CreateTURNServer(EmulatedTURNServerConfig());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user