Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Artem Titov | 386802e | 2019-07-05 10:48:17 +0200 | [diff] [blame] | 11 | #include "test/network/network_emulation.h" |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 12 | |
Artem Titov | 386802e | 2019-07-05 10:48:17 +0200 | [diff] [blame] | 13 | #include <algorithm> |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 14 | #include <limits> |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 15 | #include <memory> |
| 16 | |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 17 | #include "api/units/data_size.h" |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 18 | #include "rtc_base/bind.h" |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 19 | #include "rtc_base/logging.h" |
| 20 | |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 21 | namespace webrtc { |
| 22 | |
| 23 | EmulatedIpPacket::EmulatedIpPacket(const rtc::SocketAddress& from, |
| 24 | const rtc::SocketAddress& to, |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 25 | rtc::CopyOnWriteBuffer data, |
| 26 | Timestamp arrival_time) |
Artem Titov | 386802e | 2019-07-05 10:48:17 +0200 | [diff] [blame] | 27 | : from(from), to(to), data(data), arrival_time(arrival_time) {} |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 28 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 29 | void LinkEmulation::OnPacketReceived(EmulatedIpPacket packet) { |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 30 | struct Closure { |
| 31 | void operator()() { |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 32 | RTC_DCHECK_RUN_ON(link->task_queue_); |
| 33 | link->HandlePacketReceived(std::move(packet)); |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 34 | } |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 35 | LinkEmulation* link; |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 36 | EmulatedIpPacket packet; |
| 37 | }; |
| 38 | task_queue_->PostTask(Closure{this, std::move(packet)}); |
| 39 | } |
| 40 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 41 | void LinkEmulation::HandlePacketReceived(EmulatedIpPacket packet) { |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 42 | uint64_t packet_id = next_packet_id_++; |
Sebastian Jansson | 8c8feb9 | 2019-01-29 15:59:17 +0100 | [diff] [blame] | 43 | bool sent = network_behavior_->EnqueuePacket( |
| 44 | PacketInFlightInfo(packet.size(), packet.arrival_time.us(), packet_id)); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 45 | if (sent) { |
| 46 | packets_.emplace_back(StoredPacket{packet_id, std::move(packet), false}); |
| 47 | } |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 48 | if (process_task_.Running()) |
| 49 | return; |
| 50 | absl::optional<int64_t> next_time_us = |
| 51 | network_behavior_->NextDeliveryTimeUs(); |
| 52 | if (!next_time_us) |
| 53 | return; |
Sebastian Jansson | b64ad0e | 2019-06-19 09:39:34 +0200 | [diff] [blame] | 54 | Timestamp current_time = clock_->CurrentTime(); |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 55 | process_task_ = RepeatingTaskHandle::DelayedStart( |
| 56 | task_queue_->Get(), |
| 57 | std::max(TimeDelta::Zero(), Timestamp::us(*next_time_us) - current_time), |
| 58 | [this]() { |
| 59 | RTC_DCHECK_RUN_ON(task_queue_); |
Sebastian Jansson | b64ad0e | 2019-06-19 09:39:34 +0200 | [diff] [blame] | 60 | Timestamp current_time = clock_->CurrentTime(); |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 61 | Process(current_time); |
| 62 | absl::optional<int64_t> next_time_us = |
| 63 | network_behavior_->NextDeliveryTimeUs(); |
| 64 | if (!next_time_us) { |
| 65 | process_task_.Stop(); |
| 66 | return TimeDelta::Zero(); // This is ignored. |
| 67 | } |
| 68 | RTC_DCHECK_GE(*next_time_us, current_time.us()); |
| 69 | return Timestamp::us(*next_time_us) - current_time; |
| 70 | }); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 71 | } |
| 72 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 73 | void LinkEmulation::Process(Timestamp at_time) { |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 74 | std::vector<PacketDeliveryInfo> delivery_infos = |
| 75 | network_behavior_->DequeueDeliverablePackets(at_time.us()); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 76 | for (PacketDeliveryInfo& delivery_info : delivery_infos) { |
| 77 | StoredPacket* packet = nullptr; |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 78 | for (auto& stored_packet : packets_) { |
| 79 | if (stored_packet.id == delivery_info.packet_id) { |
| 80 | packet = &stored_packet; |
| 81 | break; |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 82 | } |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 83 | } |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 84 | RTC_CHECK(packet); |
| 85 | RTC_DCHECK(!packet->removed); |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 86 | packet->removed = true; |
| 87 | |
Johannes Kron | a8f9e25 | 2019-01-24 15:38:23 +0100 | [diff] [blame] | 88 | if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) { |
| 89 | packet->packet.arrival_time = |
| 90 | Timestamp::us(delivery_info.receive_time_us); |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 91 | receiver_->OnPacketReceived(std::move(packet->packet)); |
Johannes Kron | a8f9e25 | 2019-01-24 15:38:23 +0100 | [diff] [blame] | 92 | } |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 93 | while (!packets_.empty() && packets_.front().removed) { |
| 94 | packets_.pop_front(); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 95 | } |
| 96 | } |
| 97 | } |
| 98 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 99 | NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue) |
| 100 | : task_queue_(task_queue) {} |
| 101 | |
| 102 | void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) { |
| 103 | RTC_DCHECK_RUN_ON(task_queue_); |
Sebastian Jansson | 71c6b56 | 2019-08-14 11:31:02 +0200 | [diff] [blame] | 104 | if (watcher_) { |
| 105 | watcher_(packet); |
| 106 | } |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 107 | auto receiver_it = routing_.find(packet.to.ipaddr()); |
| 108 | if (receiver_it == routing_.end()) { |
| 109 | return; |
| 110 | } |
| 111 | RTC_CHECK(receiver_it != routing_.end()); |
| 112 | |
| 113 | receiver_it->second->OnPacketReceived(std::move(packet)); |
| 114 | } |
| 115 | |
| 116 | void NetworkRouterNode::SetReceiver( |
Artem Titov | 4cd433e | 2019-04-01 11:01:16 +0200 | [diff] [blame] | 117 | rtc::IPAddress dest_ip, |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 118 | EmulatedNetworkReceiverInterface* receiver) { |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 119 | task_queue_->PostTask([=] { |
| 120 | RTC_DCHECK_RUN_ON(task_queue_); |
| 121 | EmulatedNetworkReceiverInterface* cur_receiver = routing_[dest_ip]; |
| 122 | RTC_CHECK(cur_receiver == nullptr || cur_receiver == receiver) |
| 123 | << "Routing for dest_ip=" << dest_ip.ToString() << " already exists"; |
| 124 | routing_[dest_ip] = receiver; |
| 125 | }); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 126 | } |
| 127 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 128 | void NetworkRouterNode::RemoveReceiver(rtc::IPAddress dest_ip) { |
Sebastian Jansson | 4124dab | 2019-04-01 14:33:53 +0200 | [diff] [blame] | 129 | RTC_DCHECK_RUN_ON(task_queue_); |
Artem Titov | 4cd433e | 2019-04-01 11:01:16 +0200 | [diff] [blame] | 130 | routing_.erase(dest_ip); |
Artem Titov | 37d1848 | 2019-01-08 15:41:45 +0100 | [diff] [blame] | 131 | } |
| 132 | |
Sebastian Jansson | 71c6b56 | 2019-08-14 11:31:02 +0200 | [diff] [blame] | 133 | void NetworkRouterNode::SetWatcher( |
| 134 | std::function<void(const EmulatedIpPacket&)> watcher) { |
| 135 | task_queue_->PostTask([=] { |
| 136 | RTC_DCHECK_RUN_ON(task_queue_); |
| 137 | watcher_ = watcher; |
| 138 | }); |
| 139 | } |
| 140 | |
Sebastian Jansson | 62bb47f | 2019-04-01 18:23:58 +0200 | [diff] [blame] | 141 | EmulatedNetworkNode::EmulatedNetworkNode( |
| 142 | Clock* clock, |
| 143 | rtc::TaskQueue* task_queue, |
| 144 | std::unique_ptr<NetworkBehaviorInterface> network_behavior) |
| 145 | : router_(task_queue), |
| 146 | link_(clock, task_queue, std::move(network_behavior), &router_) {} |
| 147 | |
| 148 | void EmulatedNetworkNode::OnPacketReceived(EmulatedIpPacket packet) { |
| 149 | link_.OnPacketReceived(std::move(packet)); |
| 150 | } |
| 151 | |
| 152 | void EmulatedNetworkNode::CreateRoute( |
| 153 | rtc::IPAddress receiver_ip, |
| 154 | std::vector<EmulatedNetworkNode*> nodes, |
| 155 | EmulatedNetworkReceiverInterface* receiver) { |
| 156 | RTC_CHECK(!nodes.empty()); |
| 157 | for (size_t i = 0; i + 1 < nodes.size(); ++i) |
| 158 | nodes[i]->router()->SetReceiver(receiver_ip, nodes[i + 1]); |
| 159 | nodes.back()->router()->SetReceiver(receiver_ip, receiver); |
| 160 | } |
| 161 | |
| 162 | void EmulatedNetworkNode::ClearRoute(rtc::IPAddress receiver_ip, |
| 163 | std::vector<EmulatedNetworkNode*> nodes) { |
| 164 | for (EmulatedNetworkNode* node : nodes) |
| 165 | node->router()->RemoveReceiver(receiver_ip); |
| 166 | } |
| 167 | |
| 168 | EmulatedNetworkNode::~EmulatedNetworkNode() = default; |
| 169 | |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 170 | EmulatedEndpoint::EmulatedEndpoint(uint64_t id, |
Artem Titov | 612e179 | 2019-04-01 14:43:38 +0200 | [diff] [blame] | 171 | const rtc::IPAddress& ip, |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 172 | bool is_enabled, |
Artem Titov | ff39312 | 2019-04-05 11:19:52 +0200 | [diff] [blame] | 173 | rtc::TaskQueue* task_queue, |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 174 | Clock* clock) |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 175 | : id_(id), |
| 176 | peer_local_addr_(ip), |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 177 | is_enabled_(is_enabled), |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 178 | clock_(clock), |
Artem Titov | ff39312 | 2019-04-05 11:19:52 +0200 | [diff] [blame] | 179 | task_queue_(task_queue), |
| 180 | router_(task_queue_), |
Artem Titov | 4cd433e | 2019-04-01 11:01:16 +0200 | [diff] [blame] | 181 | next_port_(kFirstEphemeralPort) { |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 182 | constexpr int kIPv4NetworkPrefixLength = 24; |
| 183 | constexpr int kIPv6NetworkPrefixLength = 64; |
| 184 | |
| 185 | int prefix_length = 0; |
| 186 | if (ip.family() == AF_INET) { |
| 187 | prefix_length = kIPv4NetworkPrefixLength; |
| 188 | } else if (ip.family() == AF_INET6) { |
| 189 | prefix_length = kIPv6NetworkPrefixLength; |
| 190 | } |
| 191 | rtc::IPAddress prefix = TruncateIP(ip, prefix_length); |
Mirko Bonadei | 317a1f0 | 2019-09-17 17:06:18 +0200 | [diff] [blame^] | 192 | network_ = std::make_unique<rtc::Network>( |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 193 | ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix, |
| 194 | prefix_length, rtc::AdapterType::ADAPTER_TYPE_UNKNOWN); |
| 195 | network_->AddIP(ip); |
| 196 | |
Sebastian Jansson | c01367d | 2019-04-08 15:20:44 +0200 | [diff] [blame] | 197 | enabled_state_checker_.Detach(); |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 198 | } |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 199 | EmulatedEndpoint::~EmulatedEndpoint() = default; |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 200 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 201 | uint64_t EmulatedEndpoint::GetId() const { |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 202 | return id_; |
| 203 | } |
| 204 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 205 | void EmulatedEndpoint::SendPacket(const rtc::SocketAddress& from, |
| 206 | const rtc::SocketAddress& to, |
| 207 | rtc::CopyOnWriteBuffer packet) { |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 208 | RTC_CHECK(from.ipaddr() == peer_local_addr_); |
Artem Titov | ff39312 | 2019-04-05 11:19:52 +0200 | [diff] [blame] | 209 | struct Closure { |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 210 | void operator()() { |
| 211 | endpoint->UpdateSendStats(packet); |
| 212 | endpoint->router_.OnPacketReceived(std::move(packet)); |
| 213 | } |
Artem Titov | ff39312 | 2019-04-05 11:19:52 +0200 | [diff] [blame] | 214 | EmulatedEndpoint* endpoint; |
| 215 | EmulatedIpPacket packet; |
| 216 | }; |
| 217 | task_queue_->PostTask(Closure{ |
Sebastian Jansson | b64ad0e | 2019-06-19 09:39:34 +0200 | [diff] [blame] | 218 | this, |
| 219 | EmulatedIpPacket(from, to, std::move(packet), clock_->CurrentTime())}); |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 220 | } |
| 221 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 222 | absl::optional<uint16_t> EmulatedEndpoint::BindReceiver( |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 223 | uint16_t desired_port, |
| 224 | EmulatedNetworkReceiverInterface* receiver) { |
| 225 | rtc::CritScope crit(&receiver_lock_); |
| 226 | uint16_t port = desired_port; |
| 227 | if (port == 0) { |
| 228 | // Because client can specify its own port, next_port_ can be already in |
| 229 | // use, so we need to find next available port. |
| 230 | int ports_pool_size = |
| 231 | std::numeric_limits<uint16_t>::max() - kFirstEphemeralPort + 1; |
| 232 | for (int i = 0; i < ports_pool_size; ++i) { |
| 233 | uint16_t next_port = NextPort(); |
| 234 | if (port_to_receiver_.find(next_port) == port_to_receiver_.end()) { |
| 235 | port = next_port; |
| 236 | break; |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | RTC_CHECK(port != 0) << "Can't find free port for receiver in endpoint " |
| 241 | << id_; |
| 242 | bool result = port_to_receiver_.insert({port, receiver}).second; |
| 243 | if (!result) { |
| 244 | RTC_LOG(INFO) << "Can't bind receiver to used port " << desired_port |
| 245 | << " in endpoint " << id_; |
| 246 | return absl::nullopt; |
| 247 | } |
| 248 | RTC_LOG(INFO) << "New receiver is binded to endpoint " << id_ << " on port " |
| 249 | << port; |
| 250 | return port; |
| 251 | } |
| 252 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 253 | uint16_t EmulatedEndpoint::NextPort() { |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 254 | uint16_t out = next_port_; |
| 255 | if (next_port_ == std::numeric_limits<uint16_t>::max()) { |
| 256 | next_port_ = kFirstEphemeralPort; |
| 257 | } else { |
| 258 | next_port_++; |
| 259 | } |
| 260 | return out; |
| 261 | } |
| 262 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 263 | void EmulatedEndpoint::UnbindReceiver(uint16_t port) { |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 264 | rtc::CritScope crit(&receiver_lock_); |
| 265 | port_to_receiver_.erase(port); |
| 266 | } |
| 267 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 268 | rtc::IPAddress EmulatedEndpoint::GetPeerLocalAddress() const { |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 269 | return peer_local_addr_; |
| 270 | } |
| 271 | |
Artem Titov | aba8dc2 | 2019-03-11 10:08:40 +0100 | [diff] [blame] | 272 | void EmulatedEndpoint::OnPacketReceived(EmulatedIpPacket packet) { |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 273 | RTC_DCHECK_RUN_ON(task_queue_); |
Artem Titov | 4cd433e | 2019-04-01 11:01:16 +0200 | [diff] [blame] | 274 | RTC_CHECK(packet.to.ipaddr() == peer_local_addr_) |
| 275 | << "Routing error: wrong destination endpoint. Packet.to.ipaddr()=: " |
| 276 | << packet.to.ipaddr().ToString() |
| 277 | << "; Receiver peer_local_addr_=" << peer_local_addr_.ToString(); |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 278 | rtc::CritScope crit(&receiver_lock_); |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 279 | UpdateReceiveStats(packet); |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 280 | auto it = port_to_receiver_.find(packet.to.port()); |
| 281 | if (it == port_to_receiver_.end()) { |
| 282 | // It can happen, that remote peer closed connection, but there still some |
| 283 | // packets, that are going to it. It can happen during peer connection close |
| 284 | // process: one peer closed connection, second still sending data. |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 285 | RTC_LOG(INFO) << "Drop packet: no receiver registered in " << id_ |
| 286 | << " on port " << packet.to.port(); |
| 287 | stats_.packets_dropped++; |
| 288 | stats_.bytes_dropped += DataSize::bytes(packet.size()); |
Artem Titov | 0774bd9 | 2019-01-30 15:26:05 +0100 | [diff] [blame] | 289 | return; |
| 290 | } |
| 291 | // Endpoint assumes frequent calls to bind and unbind methods, so it holds |
| 292 | // lock during packet processing to ensure that receiver won't be deleted |
| 293 | // before call to OnPacketReceived. |
| 294 | it->second->OnPacketReceived(std::move(packet)); |
| 295 | } |
| 296 | |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 297 | void EmulatedEndpoint::Enable() { |
| 298 | RTC_DCHECK_RUN_ON(&enabled_state_checker_); |
| 299 | RTC_CHECK(!is_enabled_); |
| 300 | is_enabled_ = true; |
| 301 | } |
| 302 | |
| 303 | void EmulatedEndpoint::Disable() { |
| 304 | RTC_DCHECK_RUN_ON(&enabled_state_checker_); |
| 305 | RTC_CHECK(is_enabled_); |
| 306 | is_enabled_ = false; |
| 307 | } |
| 308 | |
| 309 | bool EmulatedEndpoint::Enabled() const { |
| 310 | RTC_DCHECK_RUN_ON(&enabled_state_checker_); |
| 311 | return is_enabled_; |
| 312 | } |
| 313 | |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 314 | EmulatedNetworkStats EmulatedEndpoint::stats() { |
| 315 | RTC_DCHECK_RUN_ON(task_queue_); |
| 316 | return stats_; |
| 317 | } |
| 318 | |
| 319 | void EmulatedEndpoint::UpdateSendStats(const EmulatedIpPacket& packet) { |
| 320 | RTC_DCHECK_RUN_ON(task_queue_); |
Sebastian Jansson | b64ad0e | 2019-06-19 09:39:34 +0200 | [diff] [blame] | 321 | Timestamp current_time = clock_->CurrentTime(); |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 322 | if (stats_.first_packet_sent_time.IsInfinite()) { |
| 323 | stats_.first_packet_sent_time = current_time; |
| 324 | stats_.first_sent_packet_size = DataSize::bytes(packet.size()); |
| 325 | } |
| 326 | stats_.last_packet_sent_time = current_time; |
| 327 | stats_.packets_sent++; |
| 328 | stats_.bytes_sent += DataSize::bytes(packet.size()); |
| 329 | } |
| 330 | |
| 331 | void EmulatedEndpoint::UpdateReceiveStats(const EmulatedIpPacket& packet) { |
| 332 | RTC_DCHECK_RUN_ON(task_queue_); |
Sebastian Jansson | b64ad0e | 2019-06-19 09:39:34 +0200 | [diff] [blame] | 333 | Timestamp current_time = clock_->CurrentTime(); |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 334 | if (stats_.first_packet_received_time.IsInfinite()) { |
| 335 | stats_.first_packet_received_time = current_time; |
| 336 | stats_.first_received_packet_size = DataSize::bytes(packet.size()); |
| 337 | } |
| 338 | stats_.last_packet_received_time = current_time; |
| 339 | stats_.packets_received++; |
| 340 | stats_.bytes_received += DataSize::bytes(packet.size()); |
| 341 | } |
| 342 | |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 343 | EndpointsContainer::EndpointsContainer( |
| 344 | const std::vector<EmulatedEndpoint*>& endpoints) |
| 345 | : endpoints_(endpoints) {} |
| 346 | |
| 347 | EmulatedEndpoint* EndpointsContainer::LookupByLocalAddress( |
| 348 | const rtc::IPAddress& local_ip) const { |
| 349 | for (auto* endpoint : endpoints_) { |
Artem Titov | 4cd433e | 2019-04-01 11:01:16 +0200 | [diff] [blame] | 350 | rtc::IPAddress peer_local_address = endpoint->GetPeerLocalAddress(); |
| 351 | if (peer_local_address == local_ip) { |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 352 | return endpoint; |
| 353 | } |
| 354 | } |
| 355 | RTC_CHECK(false) << "No network found for address" << local_ip.ToString(); |
| 356 | } |
| 357 | |
| 358 | bool EndpointsContainer::HasEndpoint(EmulatedEndpoint* endpoint) const { |
| 359 | for (auto* e : endpoints_) { |
| 360 | if (e->GetId() == endpoint->GetId()) { |
| 361 | return true; |
| 362 | } |
| 363 | } |
| 364 | return false; |
| 365 | } |
| 366 | |
| 367 | std::vector<std::unique_ptr<rtc::Network>> |
| 368 | EndpointsContainer::GetEnabledNetworks() const { |
| 369 | std::vector<std::unique_ptr<rtc::Network>> networks; |
| 370 | for (auto* endpoint : endpoints_) { |
| 371 | if (endpoint->Enabled()) { |
| 372 | networks.emplace_back( |
Mirko Bonadei | 317a1f0 | 2019-09-17 17:06:18 +0200 | [diff] [blame^] | 373 | std::make_unique<rtc::Network>(endpoint->network())); |
Artem Titov | e5cc85b | 2019-03-28 12:11:09 +0100 | [diff] [blame] | 374 | } |
| 375 | } |
| 376 | return networks; |
| 377 | } |
| 378 | |
Artem Titov | 806299e | 2019-04-12 12:17:19 +0200 | [diff] [blame] | 379 | EmulatedNetworkStats EndpointsContainer::GetStats() const { |
| 380 | EmulatedNetworkStats stats; |
| 381 | for (auto* endpoint : endpoints_) { |
| 382 | EmulatedNetworkStats endpoint_stats = endpoint->stats(); |
| 383 | stats.packets_sent += endpoint_stats.packets_sent; |
| 384 | stats.bytes_sent += endpoint_stats.bytes_sent; |
| 385 | stats.packets_received += endpoint_stats.packets_received; |
| 386 | stats.bytes_received += endpoint_stats.bytes_received; |
| 387 | stats.packets_dropped += endpoint_stats.packets_dropped; |
| 388 | stats.bytes_dropped += endpoint_stats.bytes_dropped; |
| 389 | if (stats.first_packet_received_time > |
| 390 | endpoint_stats.first_packet_received_time) { |
| 391 | stats.first_packet_received_time = |
| 392 | endpoint_stats.first_packet_received_time; |
| 393 | stats.first_received_packet_size = |
| 394 | endpoint_stats.first_received_packet_size; |
| 395 | } |
| 396 | if (stats.first_packet_sent_time > endpoint_stats.first_packet_sent_time) { |
| 397 | stats.first_packet_sent_time = endpoint_stats.first_packet_sent_time; |
| 398 | stats.first_sent_packet_size = endpoint_stats.first_sent_packet_size; |
| 399 | } |
| 400 | if (stats.last_packet_received_time.IsInfinite() || |
| 401 | stats.last_packet_received_time < |
| 402 | endpoint_stats.last_packet_received_time) { |
| 403 | stats.last_packet_received_time = |
| 404 | endpoint_stats.last_packet_received_time; |
| 405 | } |
| 406 | if (stats.last_packet_sent_time.IsInfinite() || |
| 407 | stats.last_packet_sent_time < endpoint_stats.last_packet_sent_time) { |
| 408 | stats.last_packet_sent_time = endpoint_stats.last_packet_sent_time; |
| 409 | } |
| 410 | } |
| 411 | return stats; |
| 412 | } |
| 413 | |
Artem Titov | 40f5115 | 2019-01-04 15:45:01 +0100 | [diff] [blame] | 414 | } // namespace webrtc |