diff options
Diffstat (limited to '')
9 files changed, 1056 insertions, 0 deletions
diff --git a/third_party/libwebrtc/api/test/network_emulation/BUILD.gn b/third_party/libwebrtc/api/test/network_emulation/BUILD.gn new file mode 100644 index 0000000000..d009d39a21 --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/BUILD.gn @@ -0,0 +1,52 @@ +# Copyright (c) 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. + +import("../../../webrtc.gni") + +rtc_library("network_emulation") { + visibility = [ "*" ] + + sources = [ + "cross_traffic.h", + "network_emulation_interfaces.cc", + "network_emulation_interfaces.h", + ] + + deps = [ + "../..:array_view", + "../../../rtc_base:checks", + "../../../rtc_base:copy_on_write_buffer", + "../../../rtc_base:ip_address", + "../../../rtc_base:net_helper", + "../../../rtc_base:socket_address", + "../../numerics", + "../../task_queue", + "../../units:data_rate", + "../../units:data_size", + "../../units:time_delta", + "../../units:timestamp", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("create_cross_traffic") { + visibility = [ "*" ] + testonly = true + + sources = [ + "create_cross_traffic.cc", + "create_cross_traffic.h", + ] + + deps = [ + ":network_emulation", + "../..:network_emulation_manager_api", + "../../../rtc_base/task_utils:repeating_task", + "../../../test/network:emulated_network", + ] +} diff --git a/third_party/libwebrtc/api/test/network_emulation/DEPS b/third_party/libwebrtc/api/test/network_emulation/DEPS new file mode 100644 index 0000000000..0cf128849d --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/DEPS @@ -0,0 +1,7 @@ +specific_include_rules = { + ".*": [ + "+rtc_base/socket_address.h", + "+rtc_base/ip_address.h", + "+rtc_base/copy_on_write_buffer.h", + ], +} diff --git a/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc new file mode 100644 index 0000000000..36a535cec6 --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "api/test/network_emulation/create_cross_traffic.h" + +#include <memory> + +#include "rtc_base/task_utils/repeating_task.h" +#include "test/network/cross_traffic.h" + +namespace webrtc { + +std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic( + CrossTrafficRoute* traffic_route, + RandomWalkConfig config) { + return std::make_unique<test::RandomWalkCrossTraffic>(config, traffic_route); +} + +std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic( + CrossTrafficRoute* traffic_route, + PulsedPeaksConfig config) { + return std::make_unique<test::PulsedPeaksCrossTraffic>(config, traffic_route); +} + +std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic( + EmulatedRoute* send_route, + EmulatedRoute* ret_route, + FakeTcpConfig config) { + return std::make_unique<test::FakeTcpCrossTraffic>(config, send_route, + ret_route); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h new file mode 100644 index 0000000000..42fc855392 --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/create_cross_traffic.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_ +#define API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_ + +#include <memory> + +#include "api/test/network_emulation/cross_traffic.h" +#include "api/test/network_emulation_manager.h" + +namespace webrtc { + +// This API is still in development and can be changed without prior notice. + +std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic( + CrossTrafficRoute* traffic_route, + RandomWalkConfig config); + +std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic( + CrossTrafficRoute* traffic_route, + PulsedPeaksConfig config); + +std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic( + EmulatedRoute* send_route, + EmulatedRoute* ret_route, + FakeTcpConfig config); + +} // namespace webrtc + +#endif // API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_ diff --git a/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h b/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h new file mode 100644 index 0000000000..737a93c2fd --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/cross_traffic.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_ +#define API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_ + +#include "api/task_queue/task_queue_base.h" +#include "api/test/network_emulation/network_emulation_interfaces.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" + +namespace webrtc { + +// This API is still in development and can be changed without prior notice. + +// Represents the endpoint for cross traffic that is going through the network. +// It can be used to emulate unexpected network load. +class CrossTrafficRoute { + public: + virtual ~CrossTrafficRoute() = default; + + // Triggers sending of dummy packets with size `packet_size` bytes. + virtual void TriggerPacketBurst(size_t num_packets, size_t packet_size) = 0; + // Sends a packet over the nodes. The content of the packet is unspecified; + // only the size metter for the emulation purposes. + virtual void SendPacket(size_t packet_size) = 0; + // Sends a packet over the nodes and runs `action` when it has been delivered. + virtual void NetworkDelayedAction(size_t packet_size, + std::function<void()> action) = 0; +}; + +// Describes a way of generating cross traffic on some route. Used by +// NetworkEmulationManager to produce cross traffic during some period of time. +class CrossTrafficGenerator { + public: + virtual ~CrossTrafficGenerator() = default; + + // Time between Process calls. + virtual TimeDelta GetProcessInterval() const = 0; + + // Called periodically by NetworkEmulationManager. Generates traffic on the + // route. + virtual void Process(Timestamp at_time) = 0; +}; + +// Config of a cross traffic generator. Generated traffic rises and falls +// randomly. +struct RandomWalkConfig { + int random_seed = 1; + DataRate peak_rate = DataRate::KilobitsPerSec(100); + DataSize min_packet_size = DataSize::Bytes(200); + TimeDelta min_packet_interval = TimeDelta::Millis(1); + TimeDelta update_interval = TimeDelta::Millis(200); + double variance = 0.6; + double bias = -0.1; +}; + +// Config of a cross traffic generator. Generated traffic has form of periodic +// peaks alternating with periods of silence. +struct PulsedPeaksConfig { + DataRate peak_rate = DataRate::KilobitsPerSec(100); + DataSize min_packet_size = DataSize::Bytes(200); + TimeDelta min_packet_interval = TimeDelta::Millis(1); + TimeDelta send_duration = TimeDelta::Millis(100); + TimeDelta hold_duration = TimeDelta::Millis(2000); +}; + +struct FakeTcpConfig { + DataSize packet_size = DataSize::Bytes(1200); + DataSize send_limit = DataSize::PlusInfinity(); + TimeDelta process_interval = TimeDelta::Millis(200); + TimeDelta packet_timeout = TimeDelta::Seconds(1); +}; + +} // namespace webrtc + +#endif // API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_ diff --git a/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc new file mode 100644 index 0000000000..0f3a7f8ffd --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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 "api/test/network_emulation/network_emulation_interfaces.h" + +#include "rtc_base/net_helper.h" + +namespace webrtc { + +EmulatedIpPacket::EmulatedIpPacket(const rtc::SocketAddress& from, + const rtc::SocketAddress& to, + rtc::CopyOnWriteBuffer data, + Timestamp arrival_time, + uint16_t application_overhead) + : from(from), + to(to), + data(data), + headers_size(to.ipaddr().overhead() + application_overhead + + cricket::kUdpHeaderSize), + arrival_time(arrival_time) { + RTC_DCHECK(to.family() == AF_INET || to.family() == AF_INET6); +} + +DataRate EmulatedNetworkOutgoingStats::AverageSendRate() const { + RTC_DCHECK_GE(packets_sent, 2); + RTC_DCHECK(first_packet_sent_time.IsFinite()); + RTC_DCHECK(last_packet_sent_time.IsFinite()); + return (bytes_sent - first_sent_packet_size) / + (last_packet_sent_time - first_packet_sent_time); +} + +DataRate EmulatedNetworkIncomingStats::AverageReceiveRate() const { + RTC_DCHECK_GE(packets_received, 2); + RTC_DCHECK(first_packet_received_time.IsFinite()); + RTC_DCHECK(last_packet_received_time.IsFinite()); + return (bytes_received - first_received_packet_size) / + (last_packet_received_time - first_packet_received_time); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h new file mode 100644 index 0000000000..7cab07b75d --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation/network_emulation_interfaces.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 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. + */ +#ifndef API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ +#define API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/numerics/samples_stats_counter.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/socket_address.h" + +namespace webrtc { + +struct EmulatedIpPacket { + public: + EmulatedIpPacket(const rtc::SocketAddress& from, + const rtc::SocketAddress& to, + rtc::CopyOnWriteBuffer data, + Timestamp arrival_time, + uint16_t application_overhead = 0); + ~EmulatedIpPacket() = default; + // This object is not copyable or assignable. + EmulatedIpPacket(const EmulatedIpPacket&) = delete; + EmulatedIpPacket& operator=(const EmulatedIpPacket&) = delete; + // This object is only moveable. + EmulatedIpPacket(EmulatedIpPacket&&) = default; + EmulatedIpPacket& operator=(EmulatedIpPacket&&) = default; + + size_t size() const { return data.size(); } + const uint8_t* cdata() const { return data.cdata(); } + + size_t ip_packet_size() const { return size() + headers_size; } + rtc::SocketAddress from; + rtc::SocketAddress to; + // Holds the UDP payload. + rtc::CopyOnWriteBuffer data; + uint16_t headers_size; + Timestamp arrival_time; +}; + +// Interface for handling IP packets from an emulated network. This is used with +// EmulatedEndpoint to receive packets on a specific port. +class EmulatedNetworkReceiverInterface { + public: + virtual ~EmulatedNetworkReceiverInterface() = default; + + virtual void OnPacketReceived(EmulatedIpPacket packet) = 0; +}; + +struct EmulatedNetworkOutgoingStats { + int64_t packets_sent = 0; + + DataSize bytes_sent = DataSize::Zero(); + + // Sizes of all sent packets. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter sent_packets_size; + + DataSize first_sent_packet_size = DataSize::Zero(); + + // Time of the first packet sent or infinite value if no packets were sent. + Timestamp first_packet_sent_time = Timestamp::PlusInfinity(); + + // Time of the last packet sent or infinite value if no packets were sent. + Timestamp last_packet_sent_time = Timestamp::MinusInfinity(); + + // Returns average send rate. Requires that at least 2 packets were sent. + DataRate AverageSendRate() const; +}; + +struct EmulatedNetworkIncomingStats { + // Total amount of packets received with or without destination. + int64_t packets_received = 0; + + // Total amount of bytes in received packets. + DataSize bytes_received = DataSize::Zero(); + + // Sizes of all received packets. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter received_packets_size; + + // Total amount of packets that were received, but no destination was found. + int64_t packets_discarded_no_receiver = 0; + + // Total amount of bytes in discarded packets. + DataSize bytes_discarded_no_receiver = DataSize::Zero(); + + // Sizes of all packets that were received, but no destination was found. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter packets_discarded_no_receiver_size; + + DataSize first_received_packet_size = DataSize::Zero(); + + // Time of the first packet received or infinite value if no packets were + // received. + Timestamp first_packet_received_time = Timestamp::PlusInfinity(); + + // Time of the last packet received or infinite value if no packets were + // received. + Timestamp last_packet_received_time = Timestamp::MinusInfinity(); + + DataRate AverageReceiveRate() const; +}; + +struct EmulatedNetworkStats { + int64_t PacketsSent() const { return overall_outgoing_stats.packets_sent; } + + DataSize BytesSent() const { return overall_outgoing_stats.bytes_sent; } + + // Returns the timestamped sizes of all sent packets. + // Returned reference is valid until the next call to a non-const method. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + const SamplesStatsCounter& SentPacketsSizeCounter() const { + return overall_outgoing_stats.sent_packets_size; + } + + DataSize FirstSentPacketSize() const { + return overall_outgoing_stats.first_sent_packet_size; + } + + // Returns time of the first packet sent or infinite value if no packets were + // sent. + Timestamp FirstPacketSentTime() const { + return overall_outgoing_stats.first_packet_sent_time; + } + + // Returns time of the last packet sent or infinite value if no packets were + // sent. + Timestamp LastPacketSentTime() const { + return overall_outgoing_stats.last_packet_sent_time; + } + + DataRate AverageSendRate() const { + return overall_outgoing_stats.AverageSendRate(); + } + + // Total amount of packets received regardless of the destination address. + int64_t PacketsReceived() const { + return overall_incoming_stats.packets_received; + } + + // Total amount of bytes in received packets. + DataSize BytesReceived() const { + return overall_incoming_stats.bytes_received; + } + + // Returns the timestamped sizes of all received packets. + // Returned reference is valid until the next call to a non-const method. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + const SamplesStatsCounter& ReceivedPacketsSizeCounter() const { + return overall_incoming_stats.received_packets_size; + } + + // Total amount of packets that were received, but no destination was found. + int64_t PacketsDiscardedNoReceiver() const { + return overall_incoming_stats.packets_discarded_no_receiver; + } + + // Total amount of bytes in dropped packets. + DataSize BytesDiscardedNoReceiver() const { + return overall_incoming_stats.bytes_discarded_no_receiver; + } + + // Returns counter with timestamped sizes of all packets that were received, + // but no destination was found. + // Returned reference is valid until the next call to a non-const method. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + const SamplesStatsCounter& PacketsDiscardedNoReceiverSizeCounter() const { + return overall_incoming_stats.packets_discarded_no_receiver_size; + } + + DataSize FirstReceivedPacketSize() const { + return overall_incoming_stats.first_received_packet_size; + } + + // Returns time of the first packet received or infinite value if no packets + // were received. + Timestamp FirstPacketReceivedTime() const { + return overall_incoming_stats.first_packet_received_time; + } + + // Returns time of the last packet received or infinite value if no packets + // were received. + Timestamp LastPacketReceivedTime() const { + return overall_incoming_stats.last_packet_received_time; + } + + DataRate AverageReceiveRate() const { + return overall_incoming_stats.AverageReceiveRate(); + } + + // List of IP addresses that were used to send data considered in this stats + // object. + std::vector<rtc::IPAddress> local_addresses; + + // Overall outgoing stats for all IP addresses which were requested. + EmulatedNetworkOutgoingStats overall_outgoing_stats; + + // Overall incoming stats for all IP addresses from which data was received + // on requested interfaces. + EmulatedNetworkIncomingStats overall_incoming_stats; + + std::map<rtc::IPAddress, EmulatedNetworkOutgoingStats> + outgoing_stats_per_destination; + std::map<rtc::IPAddress, EmulatedNetworkIncomingStats> + incoming_stats_per_source; + + // Duration between packet was received on network interface and was + // dispatched to the network in microseconds. + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter sent_packets_queue_wait_time_us; +}; + +struct EmulatedNetworkNodeStats { + // Amount of time each packet spent in the emulated network node for which + // stats were collected. + // + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter packet_transport_time; + + // For each packet contains its size divided on the amount of time which it + // spent in the emulated network node for which stats were collected. + // + // Collected iff EmulatedNetworkStatsGatheringMode::kDebug is enabled. + SamplesStatsCounter size_to_packet_transport_time; +}; + +// EmulatedEndpoint is an abstraction for network interface on device. Instances +// of this are created by NetworkEmulationManager::CreateEndpoint and +// thread safe. +class EmulatedEndpoint : public EmulatedNetworkReceiverInterface { + public: + // Send packet into network. + // `from` will be used to set source address for the packet in destination + // socket. + // `to` will be used for routing verification and picking right socket by port + // on destination endpoint. + virtual void SendPacket(const rtc::SocketAddress& from, + const rtc::SocketAddress& to, + rtc::CopyOnWriteBuffer packet_data, + uint16_t application_overhead = 0) = 0; + + // Binds receiver to this endpoint to send and receive data. + // `desired_port` is a port that should be used. If it is equal to 0, + // endpoint will pick the first available port starting from + // `kFirstEphemeralPort`. + // + // Returns the port, that should be used (it will be equals to desired, if + // `desired_port` != 0 and is free or will be the one, selected by endpoint) + // or absl::nullopt if desired_port in used. Also fails if there are no more + // free ports to bind to. + // + // The Bind- and Unbind-methods must not be called from within a bound + // receiver's OnPacketReceived method. + 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 + // bound before. After this method returns, no more packets can be delivered + // to the receiver, and it is safe to destroy it. + virtual void UnbindReceiver(uint16_t port) = 0; + // Binds receiver that will accept all packets which arrived on any port + // for which there are no bound receiver. + virtual void BindDefaultReceiver( + EmulatedNetworkReceiverInterface* receiver) = 0; + // Unbinds default receiver. Do nothing if no default receiver was bound + // before. + virtual void UnbindDefaultReceiver() = 0; + virtual rtc::IPAddress GetPeerLocalAddress() const = 0; + + private: + // Ensure that there can be no other subclass than EmulatedEndpointImpl. This + // means that it's always safe to downcast EmulatedEndpoint instances to + // EmulatedEndpointImpl. + friend class EmulatedEndpointImpl; + EmulatedEndpoint() = default; +}; + +// Simulates a TCP connection, this roughly implements the Reno algorithm. In +// difference from TCP this only support sending messages with a fixed length, +// no streaming. This is useful to simulate signaling and cross traffic using +// message based protocols such as HTTP. It differs from UDP messages in that +// they are guranteed to be delivered eventually, even on lossy networks. +class TcpMessageRoute { + public: + // Sends a TCP message of the given `size` over the route, `on_received` is + // called when the message has been delivered. Note that the connection + // parameters are reset iff there's no currently pending message on the route. + virtual void SendMessage(size_t size, std::function<void()> on_received) = 0; + + protected: + ~TcpMessageRoute() = default; +}; +} // namespace webrtc + +#endif // API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ diff --git a/third_party/libwebrtc/api/test/network_emulation_manager.cc b/third_party/libwebrtc/api/test/network_emulation_manager.cc new file mode 100644 index 0000000000..236e2f0e17 --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation_manager.cc @@ -0,0 +1,122 @@ +/* + * Copyright (c) 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 "api/test/network_emulation_manager.h" + +#include <utility> + +#include "call/simulated_network.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +bool AbslParseFlag(absl::string_view text, TimeMode* mode, std::string* error) { + if (text == "realtime") { + *mode = TimeMode::kRealTime; + return true; + } + if (text == "simulated") { + *mode = TimeMode::kSimulated; + return true; + } + *error = + "Unknown value for TimeMode enum. Options are 'realtime' or 'simulated'"; + return false; +} + +std::string AbslUnparseFlag(TimeMode mode) { + switch (mode) { + case TimeMode::kRealTime: + return "realtime"; + case TimeMode::kSimulated: + return "simulated"; + } + RTC_CHECK_NOTREACHED(); + return "unknown"; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::config( + BuiltInNetworkBehaviorConfig config) { + config_ = config; + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::delay_ms( + int queue_delay_ms) { + config_.queue_delay_ms = queue_delay_ms; + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::capacity_kbps( + int link_capacity_kbps) { + config_.link_capacity_kbps = link_capacity_kbps; + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::capacity_Mbps( + int link_capacity_Mbps) { + config_.link_capacity_kbps = link_capacity_Mbps * 1000; + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::loss(double loss_rate) { + config_.loss_percent = std::round(loss_rate * 100); + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode::Builder& +NetworkEmulationManager::SimulatedNetworkNode::Builder::packet_queue_length( + int max_queue_length_in_packets) { + config_.queue_length_packets = max_queue_length_in_packets; + return *this; +} + +NetworkEmulationManager::SimulatedNetworkNode +NetworkEmulationManager::SimulatedNetworkNode::Builder::Build( + uint64_t random_seed) const { + RTC_CHECK(net_); + return Build(net_, random_seed); +} + +NetworkEmulationManager::SimulatedNetworkNode +NetworkEmulationManager::SimulatedNetworkNode::Builder::Build( + NetworkEmulationManager* net, + uint64_t random_seed) const { + RTC_CHECK(net); + RTC_CHECK(net_ == nullptr || net_ == net); + SimulatedNetworkNode res; + auto behavior = std::make_unique<SimulatedNetwork>(config_, random_seed); + res.simulation = behavior.get(); + res.node = net->CreateEmulatedNode(std::move(behavior)); + return res; +} + +std::pair<EmulatedNetworkManagerInterface*, EmulatedNetworkManagerInterface*> +NetworkEmulationManager::CreateEndpointPairWithTwoWayRoutes( + const BuiltInNetworkBehaviorConfig& config) { + auto* alice_node = CreateEmulatedNode(config); + auto* bob_node = CreateEmulatedNode(config); + + auto* alice_endpoint = CreateEndpoint(EmulatedEndpointConfig()); + auto* bob_endpoint = CreateEndpoint(EmulatedEndpointConfig()); + + CreateRoute(alice_endpoint, {alice_node}, bob_endpoint); + CreateRoute(bob_endpoint, {bob_node}, alice_endpoint); + + return { + CreateEmulatedNetworkManagerInterface({alice_endpoint}), + CreateEmulatedNetworkManagerInterface({bob_endpoint}), + }; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/api/test/network_emulation_manager.h b/third_party/libwebrtc/api/test/network_emulation_manager.h new file mode 100644 index 0000000000..bc9279d306 --- /dev/null +++ b/third_party/libwebrtc/api/test/network_emulation_manager.h @@ -0,0 +1,357 @@ +/* + * Copyright (c) 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. + */ + +#ifndef API_TEST_NETWORK_EMULATION_MANAGER_H_ +#define API_TEST_NETWORK_EMULATION_MANAGER_H_ + +#include <functional> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "api/array_view.h" +#include "api/packet_socket_factory.h" +#include "api/test/network_emulation/cross_traffic.h" +#include "api/test/network_emulation/network_emulation_interfaces.h" +#include "api/test/peer_network_dependencies.h" +#include "api/test/simulated_network.h" +#include "api/test/time_controller.h" +#include "api/units/timestamp.h" +#include "rtc_base/network.h" +#include "rtc_base/network_constants.h" +#include "rtc_base/thread.h" + +namespace webrtc { + +// This API is still in development and can be changed without prior notice. + +// These classes are forward declared here, because they used as handles, to +// make it possible for client code to operate with these abstractions and build +// required network configuration. With forward declaration here implementation +// is more readable, than with interfaces approach and cause user needn't any +// API methods on these abstractions it is acceptable here. + +// EmulatedNetworkNode is an abstraction for some network in the real world, +// like 3G network between peers, or Wi-Fi for one peer and LTE for another. +// Multiple networks can be joined into chain emulating a network path from +// one peer to another. +class EmulatedNetworkNode; + +// EmulatedRoute is handle for single route from one network interface on one +// peer device to another network interface on another peer device. +class EmulatedRoute; + +enum class EmulatedNetworkStatsGatheringMode { + // Gather main network stats counters. See more details on which particular + // metrics are collected in the `EmulatedNetworkStats` and + // `EmulatedNetworkNodeStats` documentation. + kDefault, + // kDefault + also gather per packet statistics. In this mode more memory + // will be used. + kDebug +}; + +struct EmulatedEndpointConfig { + enum class IpAddressFamily { kIpv4, kIpv6 }; + + // If specified will be used to name endpoint for logging purposes. + absl::optional<std::string> name = absl::nullopt; + IpAddressFamily generated_ip_family = IpAddressFamily::kIpv4; + // If specified will be used as IP address for endpoint node. Must be unique + // among all created nodes. + absl::optional<rtc::IPAddress> ip; + // Should endpoint be enabled or not, when it will be created. + // Enabled endpoints will be available for webrtc to send packets. + bool start_as_enabled = true; + // Network type which will be used to represent endpoint to WebRTC. + rtc::AdapterType type = rtc::AdapterType::ADAPTER_TYPE_UNKNOWN; + // 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 { + 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 +// accessible by PeerConnection. +class EmulatedNetworkManagerInterface { + public: + virtual ~EmulatedNetworkManagerInterface() = default; + + // Returns non-null pointer to thread that have to be used as network thread + // for WebRTC to properly setup network emulation. Returned thread is owned + // by EmulatedNetworkManagerInterface implementation. + virtual rtc::Thread* network_thread() = 0; + // Returns non-null pointer to network manager that have to be injected into + // WebRTC to properly setup network emulation. Returned manager is owned by + // EmulatedNetworkManagerInterface implementation. + virtual rtc::NetworkManager* network_manager() = 0; + // Returns non-null pointer to packet socket factory that have to be injected + // into WebRTC to properly setup network emulation. Returned factory is owned + // by EmulatedNetworkManagerInterface implementation. + virtual rtc::PacketSocketFactory* packet_socket_factory() = 0; + webrtc::webrtc_pc_e2e::PeerNetworkDependencies network_dependencies() { + return {network_thread(), network_manager(), packet_socket_factory()}; + } + // Returns list of endpoints that are associated with this instance. Pointers + // are guaranteed to be non-null and are owned by NetworkEmulationManager. + virtual std::vector<EmulatedEndpoint*> endpoints() const = 0; + + // Passes summarized network stats for endpoints for this manager into + // specified `stats_callback`. Callback will be executed on network emulation + // internal task queue. + virtual void GetStats( + std::function<void(EmulatedNetworkStats)> stats_callback) const = 0; +}; + +enum class TimeMode { kRealTime, kSimulated }; + +// Called implicitly when parsing an ABSL_FLAG of type TimeMode. +// from the command line flag value `text`. +// Returns `true` and sets `*mode` on success; +// returns `false` and sets `*error` on failure. +bool AbslParseFlag(absl::string_view text, TimeMode* mode, std::string* error); + +// AbslUnparseFlag returns a textual flag value corresponding to the TimeMode +// `mode`. +std::string AbslUnparseFlag(TimeMode mode); + +// Provides an API for creating and configuring emulated network layer. +// All objects returned by this API are owned by NetworkEmulationManager itself +// and will be deleted when manager will be deleted. +class NetworkEmulationManager { + public: + // Helper struct to simplify creation of simulated network behaviors. Contains + // non-owning pointers as the underlying instances are owned by the manager. + struct SimulatedNetworkNode { + SimulatedNetworkInterface* simulation; + EmulatedNetworkNode* node; + + class Builder { + public: + explicit Builder(NetworkEmulationManager* net) : net_(net) {} + Builder() : net_(nullptr) {} + Builder(const Builder&) = default; + // Sets the config state, note that this will replace any previously set + // values. + Builder& config(BuiltInNetworkBehaviorConfig config); + Builder& delay_ms(int queue_delay_ms); + Builder& capacity_kbps(int link_capacity_kbps); + Builder& capacity_Mbps(int link_capacity_Mbps); + Builder& loss(double loss_rate); + Builder& packet_queue_length(int max_queue_length_in_packets); + SimulatedNetworkNode Build(uint64_t random_seed = 1) const; + SimulatedNetworkNode Build(NetworkEmulationManager* net, + uint64_t random_seed = 1) const; + + private: + NetworkEmulationManager* const net_; + BuiltInNetworkBehaviorConfig config_; + }; + }; + virtual ~NetworkEmulationManager() = default; + + virtual TimeController* time_controller() = 0; + // Returns a mode in which underlying time controller operates. + virtual TimeMode time_mode() const = 0; + + // Creates an emulated network node, which represents ideal network with + // unlimited capacity, no delay and no packet loss. + EmulatedNetworkNode* CreateUnconstrainedEmulatedNode() { + return CreateEmulatedNode(BuiltInNetworkBehaviorConfig()); + } + // Creates an emulated network node, which represents single network in + // the emulated network layer. Uses default implementation on network behavior + // which can be configured with `config`. `random_seed` can be provided to + // alter randomization behavior. + virtual EmulatedNetworkNode* CreateEmulatedNode( + BuiltInNetworkBehaviorConfig config, + uint64_t random_seed = 1) = 0; + // Creates an emulated network node, which represents single network in + // the emulated network layer. `network_behavior` determines how created node + // will forward incoming packets to the next receiver. + virtual EmulatedNetworkNode* CreateEmulatedNode( + std::unique_ptr<NetworkBehaviorInterface> network_behavior) = 0; + + virtual SimulatedNetworkNode::Builder NodeBuilder() = 0; + + // Creates an emulated endpoint, which represents single network interface on + // the peer's device. + virtual EmulatedEndpoint* CreateEndpoint(EmulatedEndpointConfig config) = 0; + // Enable emulated endpoint to make it available for webrtc. + // Caller mustn't enable currently enabled endpoint. + virtual void EnableEndpoint(EmulatedEndpoint* endpoint) = 0; + // Disable emulated endpoint to make it unavailable for webrtc. + // Caller mustn't disable currently disabled endpoint. + virtual void DisableEndpoint(EmulatedEndpoint* endpoint) = 0; + + // Creates a route between endpoints going through specified network nodes. + // This route is single direction only and describe how traffic that was + // sent by network interface `from` have to be delivered to the network + // interface `to`. 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. + virtual EmulatedRoute* CreateRoute( + EmulatedEndpoint* from, + const std::vector<EmulatedNetworkNode*>& via_nodes, + EmulatedEndpoint* to) = 0; + + // Creates a route over the given `via_nodes` creating the required endpoints + // in the process. The returned EmulatedRoute pointer can be used in other + // calls as a transport route for message or cross traffic. + 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 + // packets being dropped. + virtual void ClearRoute(EmulatedRoute* route) = 0; + + // Creates a simulated TCP connection using `send_route` for traffic and + // `ret_route` for feedback. This can be used to emulate HTTP cross traffic + // and to implement realistic reliable signaling over lossy networks. + // TODO(srte): Handle clearing of the routes involved. + virtual TcpMessageRoute* CreateTcpRoute(EmulatedRoute* send_route, + EmulatedRoute* ret_route) = 0; + + // Creates a route over the given `via_nodes`. Returns an object that can be + // used to emulate network load with cross traffic over the created route. + virtual CrossTrafficRoute* CreateCrossTrafficRoute( + const std::vector<EmulatedNetworkNode*>& via_nodes) = 0; + + // Starts generating cross traffic using given `generator`. Takes ownership + // over the generator. + virtual CrossTrafficGenerator* StartCrossTraffic( + std::unique_ptr<CrossTrafficGenerator> generator) = 0; + + // Stops generating cross traffic that was started using given `generator`. + // The `generator` shouldn't be used after and the reference may be invalid. + virtual void StopCrossTraffic(CrossTrafficGenerator* generator) = 0; + + // Creates EmulatedNetworkManagerInterface which can be used then to inject + // network emulation layer into PeerConnection. `endpoints` - are available + // network interfaces for PeerConnection. If endpoint is enabled, it will be + // immediately available for PeerConnection, otherwise user will be able to + // enable endpoint later to make it available for PeerConnection. + virtual EmulatedNetworkManagerInterface* + CreateEmulatedNetworkManagerInterface( + const std::vector<EmulatedEndpoint*>& endpoints) = 0; + + // Passes combined network stats for all specified `endpoints` into specified + // `stats_callback`. Callback will be executed on network emulation + // internal task queue. + virtual void GetStats( + rtc::ArrayView<EmulatedEndpoint* const> endpoints, + std::function<void(EmulatedNetworkStats)> stats_callback) = 0; + + // Passes combined network stats for all specified `nodes` into specified + // `stats_callback`. Callback will be executed on network emulation + // internal task queue. + virtual void GetStats( + rtc::ArrayView<EmulatedNetworkNode* const> nodes, + std::function<void(EmulatedNetworkNodeStats)> 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; + + // Create a pair of EmulatedNetworkManagerInterfaces connected to each other. + std::pair<EmulatedNetworkManagerInterface*, EmulatedNetworkManagerInterface*> + CreateEndpointPairWithTwoWayRoutes( + const BuiltInNetworkBehaviorConfig& config); +}; + +} // namespace webrtc + +#endif // API_TEST_NETWORK_EMULATION_MANAGER_H_ |