You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
10 KiB
293 lines
10 KiB
/*
|
|
* Copyright (c) 2018 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_NETWORK_EMULATION_H_
|
|
#define TEST_NETWORK_NETWORK_EMULATION_H_
|
|
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "api/test/network_emulation_manager.h"
|
|
#include "api/test/simulated_network.h"
|
|
#include "api/units/timestamp.h"
|
|
#include "rtc_base/copy_on_write_buffer.h"
|
|
#include "rtc_base/network.h"
|
|
#include "rtc_base/network_constants.h"
|
|
#include "rtc_base/socket_address.h"
|
|
#include "rtc_base/task_queue_for_test.h"
|
|
#include "rtc_base/task_utils/repeating_task.h"
|
|
#include "rtc_base/thread_checker.h"
|
|
#include "system_wrappers/include/clock.h"
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
class LinkEmulation : public EmulatedNetworkReceiverInterface {
|
|
public:
|
|
LinkEmulation(Clock* clock,
|
|
rtc::TaskQueue* task_queue,
|
|
std::unique_ptr<NetworkBehaviorInterface> network_behavior,
|
|
EmulatedNetworkReceiverInterface* receiver)
|
|
: clock_(clock),
|
|
task_queue_(task_queue),
|
|
network_behavior_(std::move(network_behavior)),
|
|
receiver_(receiver) {}
|
|
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
|
|
private:
|
|
struct StoredPacket {
|
|
uint64_t id;
|
|
EmulatedIpPacket packet;
|
|
bool removed;
|
|
};
|
|
void Process(Timestamp at_time) RTC_RUN_ON(task_queue_);
|
|
|
|
Clock* const clock_;
|
|
rtc::TaskQueue* const task_queue_;
|
|
const std::unique_ptr<NetworkBehaviorInterface> network_behavior_
|
|
RTC_GUARDED_BY(task_queue_);
|
|
EmulatedNetworkReceiverInterface* const receiver_;
|
|
RepeatingTaskHandle process_task_ RTC_GUARDED_BY(task_queue_);
|
|
std::deque<StoredPacket> packets_ RTC_GUARDED_BY(task_queue_);
|
|
uint64_t next_packet_id_ RTC_GUARDED_BY(task_queue_) = 1;
|
|
};
|
|
|
|
class NetworkRouterNode : public EmulatedNetworkReceiverInterface {
|
|
public:
|
|
explicit NetworkRouterNode(rtc::TaskQueue* task_queue);
|
|
|
|
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
void SetReceiver(const rtc::IPAddress& dest_ip,
|
|
EmulatedNetworkReceiverInterface* receiver);
|
|
void RemoveReceiver(const rtc::IPAddress& dest_ip);
|
|
void SetWatcher(std::function<void(const EmulatedIpPacket&)> watcher);
|
|
void SetFilter(std::function<bool(const EmulatedIpPacket&)> filter);
|
|
|
|
private:
|
|
rtc::TaskQueue* const task_queue_;
|
|
std::map<rtc::IPAddress, EmulatedNetworkReceiverInterface*> routing_
|
|
RTC_GUARDED_BY(task_queue_);
|
|
std::function<void(const EmulatedIpPacket&)> watcher_
|
|
RTC_GUARDED_BY(task_queue_);
|
|
std::function<bool(const EmulatedIpPacket&)> filter_
|
|
RTC_GUARDED_BY(task_queue_);
|
|
};
|
|
|
|
// Represents node in the emulated network. Nodes can be connected with each
|
|
// other to form different networks with different behavior. The behavior of
|
|
// the node itself is determined by a concrete implementation of
|
|
// NetworkBehaviorInterface that is provided on construction.
|
|
class EmulatedNetworkNode : public EmulatedNetworkReceiverInterface {
|
|
public:
|
|
// Creates node based on |network_behavior|. The specified |packet_overhead|
|
|
// is added to the size of each packet in the information provided to
|
|
// |network_behavior|.
|
|
// |task_queue| is used to process packets and to forward the packets when
|
|
// they are ready.
|
|
EmulatedNetworkNode(
|
|
Clock* clock,
|
|
rtc::TaskQueue* task_queue,
|
|
std::unique_ptr<NetworkBehaviorInterface> network_behavior);
|
|
~EmulatedNetworkNode() override;
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(EmulatedNetworkNode);
|
|
|
|
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
|
|
LinkEmulation* link() { return &link_; }
|
|
NetworkRouterNode* router() { return &router_; }
|
|
|
|
// Creates a route for the given receiver_ip over all the given nodes to the
|
|
// given receiver.
|
|
static void CreateRoute(const rtc::IPAddress& receiver_ip,
|
|
std::vector<EmulatedNetworkNode*> nodes,
|
|
EmulatedNetworkReceiverInterface* receiver);
|
|
static void ClearRoute(const rtc::IPAddress& receiver_ip,
|
|
std::vector<EmulatedNetworkNode*> nodes);
|
|
|
|
private:
|
|
NetworkRouterNode router_;
|
|
LinkEmulation link_;
|
|
};
|
|
|
|
// Represents single network interface on the device.
|
|
// It will be used as sender from socket side to send data to the network and
|
|
// will act as packet receiver from emulated network side to receive packets
|
|
// from other EmulatedNetworkNodes.
|
|
class EmulatedEndpointImpl : public EmulatedEndpoint {
|
|
public:
|
|
EmulatedEndpointImpl(uint64_t id,
|
|
const rtc::IPAddress& ip,
|
|
bool is_enabled,
|
|
rtc::AdapterType type,
|
|
rtc::TaskQueue* task_queue,
|
|
Clock* clock);
|
|
~EmulatedEndpointImpl() override;
|
|
|
|
uint64_t GetId() const;
|
|
|
|
NetworkRouterNode* router() { return &router_; }
|
|
|
|
void SendPacket(const rtc::SocketAddress& from,
|
|
const rtc::SocketAddress& to,
|
|
rtc::CopyOnWriteBuffer packet_data,
|
|
uint16_t application_overhead = 0) override;
|
|
|
|
absl::optional<uint16_t> BindReceiver(
|
|
uint16_t desired_port,
|
|
EmulatedNetworkReceiverInterface* receiver) override;
|
|
void UnbindReceiver(uint16_t port) override;
|
|
|
|
rtc::IPAddress GetPeerLocalAddress() const override;
|
|
|
|
// Will be called to deliver packet into endpoint from network node.
|
|
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
|
|
void Enable();
|
|
void Disable();
|
|
bool Enabled() const;
|
|
|
|
const rtc::Network& network() const { return *network_.get(); }
|
|
|
|
EmulatedNetworkStats stats() override;
|
|
|
|
private:
|
|
static constexpr uint16_t kFirstEphemeralPort = 49152;
|
|
uint16_t NextPort() RTC_EXCLUSIVE_LOCKS_REQUIRED(receiver_lock_);
|
|
void UpdateReceiveStats(const EmulatedIpPacket& packet);
|
|
|
|
rtc::RecursiveCriticalSection receiver_lock_;
|
|
rtc::ThreadChecker enabled_state_checker_;
|
|
|
|
uint64_t id_;
|
|
// Peer's local IP address for this endpoint network interface.
|
|
const rtc::IPAddress peer_local_addr_;
|
|
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_);
|
|
std::map<uint16_t, EmulatedNetworkReceiverInterface*> port_to_receiver_
|
|
RTC_GUARDED_BY(receiver_lock_);
|
|
|
|
EmulatedNetworkStats stats_ RTC_GUARDED_BY(task_queue_);
|
|
};
|
|
|
|
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* from;
|
|
std::vector<EmulatedNetworkNode*> via_nodes;
|
|
EmulatedEndpointImpl* to;
|
|
bool active;
|
|
};
|
|
|
|
class EndpointsContainer {
|
|
public:
|
|
explicit EndpointsContainer(
|
|
const std::vector<EmulatedEndpointImpl*>& endpoints);
|
|
|
|
EmulatedEndpointImpl* LookupByLocalAddress(
|
|
const rtc::IPAddress& local_ip) const;
|
|
bool HasEndpoint(EmulatedEndpointImpl* endpoint) const;
|
|
// Returns list of networks for enabled endpoints. Caller takes ownership of
|
|
// returned rtc::Network objects.
|
|
std::vector<std::unique_ptr<rtc::Network>> GetEnabledNetworks() const;
|
|
EmulatedNetworkStats GetStats() const;
|
|
|
|
private:
|
|
const std::vector<EmulatedEndpointImpl*> endpoints_;
|
|
};
|
|
|
|
template <typename FakePacketType>
|
|
class FakePacketRoute : public EmulatedNetworkReceiverInterface {
|
|
public:
|
|
FakePacketRoute(EmulatedRoute* route,
|
|
std::function<void(FakePacketType, Timestamp)> action)
|
|
: route_(route),
|
|
action_(std::move(action)),
|
|
send_addr_(route_->from->GetPeerLocalAddress(), 0),
|
|
recv_addr_(route_->to->GetPeerLocalAddress(),
|
|
*route_->to->BindReceiver(0, this)) {}
|
|
|
|
~FakePacketRoute() { route_->to->UnbindReceiver(recv_addr_.port()); }
|
|
|
|
void SendPacket(size_t size, FakePacketType packet) {
|
|
RTC_CHECK_GE(size, sizeof(int));
|
|
sent_.emplace(next_packet_id_, packet);
|
|
rtc::CopyOnWriteBuffer buf(size);
|
|
reinterpret_cast<int*>(buf.data())[0] = next_packet_id_++;
|
|
route_->from->SendPacket(send_addr_, recv_addr_, buf);
|
|
}
|
|
|
|
void OnPacketReceived(EmulatedIpPacket packet) override {
|
|
int packet_id = reinterpret_cast<int*>(packet.data.data())[0];
|
|
action_(std::move(sent_[packet_id]), packet.arrival_time);
|
|
sent_.erase(packet_id);
|
|
}
|
|
|
|
private:
|
|
EmulatedRoute* const route_;
|
|
const std::function<void(FakePacketType, Timestamp)> action_;
|
|
const rtc::SocketAddress send_addr_;
|
|
const rtc::SocketAddress recv_addr_;
|
|
int next_packet_id_ = 0;
|
|
std::map<int, FakePacketType> sent_;
|
|
};
|
|
|
|
template <typename RequestPacketType, typename ResponsePacketType>
|
|
class TwoWayFakeTrafficRoute {
|
|
public:
|
|
class TrafficHandlerInterface {
|
|
public:
|
|
virtual void OnRequest(RequestPacketType, Timestamp) = 0;
|
|
virtual void OnResponse(ResponsePacketType, Timestamp) = 0;
|
|
virtual ~TrafficHandlerInterface() = default;
|
|
};
|
|
TwoWayFakeTrafficRoute(TrafficHandlerInterface* handler,
|
|
EmulatedRoute* send_route,
|
|
EmulatedRoute* ret_route)
|
|
: handler_(handler),
|
|
request_handler_{send_route,
|
|
[&](RequestPacketType packet, Timestamp arrival_time) {
|
|
handler_->OnRequest(std::move(packet), arrival_time);
|
|
}},
|
|
response_handler_{
|
|
ret_route, [&](ResponsePacketType packet, Timestamp arrival_time) {
|
|
handler_->OnResponse(std::move(packet), arrival_time);
|
|
}} {}
|
|
void SendRequest(size_t size, RequestPacketType packet) {
|
|
request_handler_.SendPacket(size, std::move(packet));
|
|
}
|
|
void SendResponse(size_t size, ResponsePacketType packet) {
|
|
response_handler_.SendPacket(size, std::move(packet));
|
|
}
|
|
|
|
private:
|
|
TrafficHandlerInterface* handler_;
|
|
FakePacketRoute<RequestPacketType> request_handler_;
|
|
FakePacketRoute<ResponsePacketType> response_handler_;
|
|
};
|
|
} // namespace webrtc
|
|
|
|
#endif // TEST_NETWORK_NETWORK_EMULATION_H_
|