blob: f41f266668134fb1b53de2c6e5f4454f9eb74141 [file] [log] [blame]
Artem Titov40f51152019-01-04 15:45:01 +01001/*
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 Titov386802e2019-07-05 10:48:17 +020011#include "test/network/network_emulation.h"
Artem Titov40f51152019-01-04 15:45:01 +010012
Artem Titov386802e2019-07-05 10:48:17 +020013#include <algorithm>
Artem Titov0774bd92019-01-30 15:26:05 +010014#include <limits>
Artem Titov40f51152019-01-04 15:45:01 +010015#include <memory>
16
Artem Titov806299e2019-04-12 12:17:19 +020017#include "api/units/data_size.h"
Artem Titov0774bd92019-01-30 15:26:05 +010018#include "rtc_base/bind.h"
Artem Titov37d18482019-01-08 15:41:45 +010019#include "rtc_base/logging.h"
20
Artem Titov40f51152019-01-04 15:45:01 +010021namespace webrtc {
22
23EmulatedIpPacket::EmulatedIpPacket(const rtc::SocketAddress& from,
24 const rtc::SocketAddress& to,
Artem Titov40f51152019-01-04 15:45:01 +010025 rtc::CopyOnWriteBuffer data,
26 Timestamp arrival_time)
Artem Titov386802e2019-07-05 10:48:17 +020027 : from(from), to(to), data(data), arrival_time(arrival_time) {}
Artem Titov40f51152019-01-04 15:45:01 +010028
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020029void LinkEmulation::OnPacketReceived(EmulatedIpPacket packet) {
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +020030 task_queue_->PostTask([this, packet = std::move(packet)]() mutable {
31 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Jansson4124dab2019-04-01 14:33:53 +020032
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +020033 uint64_t packet_id = next_packet_id_++;
34 bool sent = network_behavior_->EnqueuePacket(
35 PacketInFlightInfo(packet.size(), packet.arrival_time.us(), packet_id));
36 if (sent) {
37 packets_.emplace_back(StoredPacket{packet_id, std::move(packet), false});
38 }
39 if (process_task_.Running())
40 return;
41 absl::optional<int64_t> next_time_us =
42 network_behavior_->NextDeliveryTimeUs();
43 if (!next_time_us)
44 return;
45 Timestamp current_time = clock_->CurrentTime();
46 process_task_ = RepeatingTaskHandle::DelayedStart(
47 task_queue_->Get(),
48 std::max(TimeDelta::Zero(),
49 Timestamp::us(*next_time_us) - current_time),
50 [this]() {
51 RTC_DCHECK_RUN_ON(task_queue_);
52 Timestamp current_time = clock_->CurrentTime();
53 Process(current_time);
54 absl::optional<int64_t> next_time_us =
55 network_behavior_->NextDeliveryTimeUs();
56 if (!next_time_us) {
57 process_task_.Stop();
58 return TimeDelta::Zero(); // This is ignored.
59 }
60 RTC_DCHECK_GE(*next_time_us, current_time.us());
61 return Timestamp::us(*next_time_us) - current_time;
62 });
63 });
Artem Titov37d18482019-01-08 15:41:45 +010064}
65
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020066void LinkEmulation::Process(Timestamp at_time) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +020067 std::vector<PacketDeliveryInfo> delivery_infos =
68 network_behavior_->DequeueDeliverablePackets(at_time.us());
Artem Titov37d18482019-01-08 15:41:45 +010069 for (PacketDeliveryInfo& delivery_info : delivery_infos) {
70 StoredPacket* packet = nullptr;
Sebastian Jansson4124dab2019-04-01 14:33:53 +020071 for (auto& stored_packet : packets_) {
72 if (stored_packet.id == delivery_info.packet_id) {
73 packet = &stored_packet;
74 break;
Artem Titov37d18482019-01-08 15:41:45 +010075 }
Artem Titov37d18482019-01-08 15:41:45 +010076 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020077 RTC_CHECK(packet);
78 RTC_DCHECK(!packet->removed);
Sebastian Jansson4124dab2019-04-01 14:33:53 +020079 packet->removed = true;
80
Johannes Krona8f9e252019-01-24 15:38:23 +010081 if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) {
82 packet->packet.arrival_time =
83 Timestamp::us(delivery_info.receive_time_us);
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020084 receiver_->OnPacketReceived(std::move(packet->packet));
Johannes Krona8f9e252019-01-24 15:38:23 +010085 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020086 while (!packets_.empty() && packets_.front().removed) {
87 packets_.pop_front();
Artem Titov37d18482019-01-08 15:41:45 +010088 }
89 }
90}
91
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020092NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue)
93 : task_queue_(task_queue) {}
94
95void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) {
96 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Jansson71c6b562019-08-14 11:31:02 +020097 if (watcher_) {
98 watcher_(packet);
99 }
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200100 auto receiver_it = routing_.find(packet.to.ipaddr());
101 if (receiver_it == routing_.end()) {
102 return;
103 }
104 RTC_CHECK(receiver_it != routing_.end());
105
106 receiver_it->second->OnPacketReceived(std::move(packet));
107}
108
109void NetworkRouterNode::SetReceiver(
Artem Titov4cd433e2019-04-01 11:01:16 +0200110 rtc::IPAddress dest_ip,
Artem Titov37d18482019-01-08 15:41:45 +0100111 EmulatedNetworkReceiverInterface* receiver) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200112 task_queue_->PostTask([=] {
113 RTC_DCHECK_RUN_ON(task_queue_);
114 EmulatedNetworkReceiverInterface* cur_receiver = routing_[dest_ip];
115 RTC_CHECK(cur_receiver == nullptr || cur_receiver == receiver)
116 << "Routing for dest_ip=" << dest_ip.ToString() << " already exists";
117 routing_[dest_ip] = receiver;
118 });
Artem Titov37d18482019-01-08 15:41:45 +0100119}
120
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200121void NetworkRouterNode::RemoveReceiver(rtc::IPAddress dest_ip) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200122 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200123 routing_.erase(dest_ip);
Artem Titov37d18482019-01-08 15:41:45 +0100124}
125
Sebastian Jansson71c6b562019-08-14 11:31:02 +0200126void NetworkRouterNode::SetWatcher(
127 std::function<void(const EmulatedIpPacket&)> watcher) {
128 task_queue_->PostTask([=] {
129 RTC_DCHECK_RUN_ON(task_queue_);
130 watcher_ = watcher;
131 });
132}
133
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200134EmulatedNetworkNode::EmulatedNetworkNode(
135 Clock* clock,
136 rtc::TaskQueue* task_queue,
137 std::unique_ptr<NetworkBehaviorInterface> network_behavior)
138 : router_(task_queue),
139 link_(clock, task_queue, std::move(network_behavior), &router_) {}
140
141void EmulatedNetworkNode::OnPacketReceived(EmulatedIpPacket packet) {
142 link_.OnPacketReceived(std::move(packet));
143}
144
145void EmulatedNetworkNode::CreateRoute(
146 rtc::IPAddress receiver_ip,
147 std::vector<EmulatedNetworkNode*> nodes,
148 EmulatedNetworkReceiverInterface* receiver) {
149 RTC_CHECK(!nodes.empty());
150 for (size_t i = 0; i + 1 < nodes.size(); ++i)
151 nodes[i]->router()->SetReceiver(receiver_ip, nodes[i + 1]);
152 nodes.back()->router()->SetReceiver(receiver_ip, receiver);
153}
154
155void EmulatedNetworkNode::ClearRoute(rtc::IPAddress receiver_ip,
156 std::vector<EmulatedNetworkNode*> nodes) {
157 for (EmulatedNetworkNode* node : nodes)
158 node->router()->RemoveReceiver(receiver_ip);
159}
160
161EmulatedNetworkNode::~EmulatedNetworkNode() = default;
162
Artem Titove5cc85b2019-03-28 12:11:09 +0100163EmulatedEndpoint::EmulatedEndpoint(uint64_t id,
Artem Titov612e1792019-04-01 14:43:38 +0200164 const rtc::IPAddress& ip,
Artem Titove5cc85b2019-03-28 12:11:09 +0100165 bool is_enabled,
Artem Titovff393122019-04-05 11:19:52 +0200166 rtc::TaskQueue* task_queue,
Artem Titove5cc85b2019-03-28 12:11:09 +0100167 Clock* clock)
Artem Titov0774bd92019-01-30 15:26:05 +0100168 : id_(id),
169 peer_local_addr_(ip),
Artem Titove5cc85b2019-03-28 12:11:09 +0100170 is_enabled_(is_enabled),
Artem Titov0774bd92019-01-30 15:26:05 +0100171 clock_(clock),
Artem Titovff393122019-04-05 11:19:52 +0200172 task_queue_(task_queue),
173 router_(task_queue_),
Artem Titov4cd433e2019-04-01 11:01:16 +0200174 next_port_(kFirstEphemeralPort) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100175 constexpr int kIPv4NetworkPrefixLength = 24;
176 constexpr int kIPv6NetworkPrefixLength = 64;
177
178 int prefix_length = 0;
179 if (ip.family() == AF_INET) {
180 prefix_length = kIPv4NetworkPrefixLength;
181 } else if (ip.family() == AF_INET6) {
182 prefix_length = kIPv6NetworkPrefixLength;
183 }
184 rtc::IPAddress prefix = TruncateIP(ip, prefix_length);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200185 network_ = std::make_unique<rtc::Network>(
Artem Titove5cc85b2019-03-28 12:11:09 +0100186 ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix,
187 prefix_length, rtc::AdapterType::ADAPTER_TYPE_UNKNOWN);
188 network_->AddIP(ip);
189
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200190 enabled_state_checker_.Detach();
Artem Titove5cc85b2019-03-28 12:11:09 +0100191}
Artem Titovaba8dc22019-03-11 10:08:40 +0100192EmulatedEndpoint::~EmulatedEndpoint() = default;
Artem Titov0774bd92019-01-30 15:26:05 +0100193
Artem Titovaba8dc22019-03-11 10:08:40 +0100194uint64_t EmulatedEndpoint::GetId() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100195 return id_;
196}
197
Artem Titovaba8dc22019-03-11 10:08:40 +0100198void EmulatedEndpoint::SendPacket(const rtc::SocketAddress& from,
199 const rtc::SocketAddress& to,
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200200 rtc::CopyOnWriteBuffer packet_data) {
Artem Titov0774bd92019-01-30 15:26:05 +0100201 RTC_CHECK(from.ipaddr() == peer_local_addr_);
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200202 EmulatedIpPacket packet(from, to, std::move(packet_data),
203 clock_->CurrentTime());
204 task_queue_->PostTask([this, packet = std::move(packet)]() mutable {
205 RTC_DCHECK_RUN_ON(task_queue_);
206 Timestamp current_time = clock_->CurrentTime();
207 if (stats_.first_packet_sent_time.IsInfinite()) {
208 stats_.first_packet_sent_time = current_time;
209 stats_.first_sent_packet_size = DataSize::bytes(packet.size());
Artem Titov806299e2019-04-12 12:17:19 +0200210 }
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200211 stats_.last_packet_sent_time = current_time;
212 stats_.packets_sent++;
213 stats_.bytes_sent += DataSize::bytes(packet.size());
214
215 router_.OnPacketReceived(std::move(packet));
216 });
Artem Titov0774bd92019-01-30 15:26:05 +0100217}
218
Artem Titovaba8dc22019-03-11 10:08:40 +0100219absl::optional<uint16_t> EmulatedEndpoint::BindReceiver(
Artem Titov0774bd92019-01-30 15:26:05 +0100220 uint16_t desired_port,
221 EmulatedNetworkReceiverInterface* receiver) {
222 rtc::CritScope crit(&receiver_lock_);
223 uint16_t port = desired_port;
224 if (port == 0) {
225 // Because client can specify its own port, next_port_ can be already in
226 // use, so we need to find next available port.
227 int ports_pool_size =
228 std::numeric_limits<uint16_t>::max() - kFirstEphemeralPort + 1;
229 for (int i = 0; i < ports_pool_size; ++i) {
230 uint16_t next_port = NextPort();
231 if (port_to_receiver_.find(next_port) == port_to_receiver_.end()) {
232 port = next_port;
233 break;
234 }
235 }
236 }
237 RTC_CHECK(port != 0) << "Can't find free port for receiver in endpoint "
238 << id_;
239 bool result = port_to_receiver_.insert({port, receiver}).second;
240 if (!result) {
241 RTC_LOG(INFO) << "Can't bind receiver to used port " << desired_port
242 << " in endpoint " << id_;
243 return absl::nullopt;
244 }
245 RTC_LOG(INFO) << "New receiver is binded to endpoint " << id_ << " on port "
246 << port;
247 return port;
248}
249
Artem Titovaba8dc22019-03-11 10:08:40 +0100250uint16_t EmulatedEndpoint::NextPort() {
Artem Titov0774bd92019-01-30 15:26:05 +0100251 uint16_t out = next_port_;
252 if (next_port_ == std::numeric_limits<uint16_t>::max()) {
253 next_port_ = kFirstEphemeralPort;
254 } else {
255 next_port_++;
256 }
257 return out;
258}
259
Artem Titovaba8dc22019-03-11 10:08:40 +0100260void EmulatedEndpoint::UnbindReceiver(uint16_t port) {
Artem Titov0774bd92019-01-30 15:26:05 +0100261 rtc::CritScope crit(&receiver_lock_);
262 port_to_receiver_.erase(port);
263}
264
Artem Titovaba8dc22019-03-11 10:08:40 +0100265rtc::IPAddress EmulatedEndpoint::GetPeerLocalAddress() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100266 return peer_local_addr_;
267}
268
Artem Titovaba8dc22019-03-11 10:08:40 +0100269void EmulatedEndpoint::OnPacketReceived(EmulatedIpPacket packet) {
Artem Titov806299e2019-04-12 12:17:19 +0200270 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200271 RTC_CHECK(packet.to.ipaddr() == peer_local_addr_)
272 << "Routing error: wrong destination endpoint. Packet.to.ipaddr()=: "
273 << packet.to.ipaddr().ToString()
274 << "; Receiver peer_local_addr_=" << peer_local_addr_.ToString();
Artem Titov0774bd92019-01-30 15:26:05 +0100275 rtc::CritScope crit(&receiver_lock_);
Artem Titov806299e2019-04-12 12:17:19 +0200276 UpdateReceiveStats(packet);
Artem Titov0774bd92019-01-30 15:26:05 +0100277 auto it = port_to_receiver_.find(packet.to.port());
278 if (it == port_to_receiver_.end()) {
279 // It can happen, that remote peer closed connection, but there still some
280 // packets, that are going to it. It can happen during peer connection close
281 // process: one peer closed connection, second still sending data.
Artem Titov806299e2019-04-12 12:17:19 +0200282 RTC_LOG(INFO) << "Drop packet: no receiver registered in " << id_
283 << " on port " << packet.to.port();
284 stats_.packets_dropped++;
285 stats_.bytes_dropped += DataSize::bytes(packet.size());
Artem Titov0774bd92019-01-30 15:26:05 +0100286 return;
287 }
288 // Endpoint assumes frequent calls to bind and unbind methods, so it holds
289 // lock during packet processing to ensure that receiver won't be deleted
290 // before call to OnPacketReceived.
291 it->second->OnPacketReceived(std::move(packet));
292}
293
Artem Titove5cc85b2019-03-28 12:11:09 +0100294void EmulatedEndpoint::Enable() {
295 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
296 RTC_CHECK(!is_enabled_);
297 is_enabled_ = true;
298}
299
300void EmulatedEndpoint::Disable() {
301 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
302 RTC_CHECK(is_enabled_);
303 is_enabled_ = false;
304}
305
306bool EmulatedEndpoint::Enabled() const {
307 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
308 return is_enabled_;
309}
310
Artem Titov806299e2019-04-12 12:17:19 +0200311EmulatedNetworkStats EmulatedEndpoint::stats() {
312 RTC_DCHECK_RUN_ON(task_queue_);
313 return stats_;
314}
315
Artem Titov806299e2019-04-12 12:17:19 +0200316void EmulatedEndpoint::UpdateReceiveStats(const EmulatedIpPacket& packet) {
317 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200318 Timestamp current_time = clock_->CurrentTime();
Artem Titov806299e2019-04-12 12:17:19 +0200319 if (stats_.first_packet_received_time.IsInfinite()) {
320 stats_.first_packet_received_time = current_time;
321 stats_.first_received_packet_size = DataSize::bytes(packet.size());
322 }
323 stats_.last_packet_received_time = current_time;
324 stats_.packets_received++;
325 stats_.bytes_received += DataSize::bytes(packet.size());
326}
327
Artem Titove5cc85b2019-03-28 12:11:09 +0100328EndpointsContainer::EndpointsContainer(
329 const std::vector<EmulatedEndpoint*>& endpoints)
330 : endpoints_(endpoints) {}
331
332EmulatedEndpoint* EndpointsContainer::LookupByLocalAddress(
333 const rtc::IPAddress& local_ip) const {
334 for (auto* endpoint : endpoints_) {
Artem Titov4cd433e2019-04-01 11:01:16 +0200335 rtc::IPAddress peer_local_address = endpoint->GetPeerLocalAddress();
336 if (peer_local_address == local_ip) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100337 return endpoint;
338 }
339 }
340 RTC_CHECK(false) << "No network found for address" << local_ip.ToString();
341}
342
343bool EndpointsContainer::HasEndpoint(EmulatedEndpoint* endpoint) const {
344 for (auto* e : endpoints_) {
345 if (e->GetId() == endpoint->GetId()) {
346 return true;
347 }
348 }
349 return false;
350}
351
352std::vector<std::unique_ptr<rtc::Network>>
353EndpointsContainer::GetEnabledNetworks() const {
354 std::vector<std::unique_ptr<rtc::Network>> networks;
355 for (auto* endpoint : endpoints_) {
356 if (endpoint->Enabled()) {
357 networks.emplace_back(
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200358 std::make_unique<rtc::Network>(endpoint->network()));
Artem Titove5cc85b2019-03-28 12:11:09 +0100359 }
360 }
361 return networks;
362}
363
Artem Titov806299e2019-04-12 12:17:19 +0200364EmulatedNetworkStats EndpointsContainer::GetStats() const {
365 EmulatedNetworkStats stats;
366 for (auto* endpoint : endpoints_) {
367 EmulatedNetworkStats endpoint_stats = endpoint->stats();
368 stats.packets_sent += endpoint_stats.packets_sent;
369 stats.bytes_sent += endpoint_stats.bytes_sent;
370 stats.packets_received += endpoint_stats.packets_received;
371 stats.bytes_received += endpoint_stats.bytes_received;
372 stats.packets_dropped += endpoint_stats.packets_dropped;
373 stats.bytes_dropped += endpoint_stats.bytes_dropped;
374 if (stats.first_packet_received_time >
375 endpoint_stats.first_packet_received_time) {
376 stats.first_packet_received_time =
377 endpoint_stats.first_packet_received_time;
378 stats.first_received_packet_size =
379 endpoint_stats.first_received_packet_size;
380 }
381 if (stats.first_packet_sent_time > endpoint_stats.first_packet_sent_time) {
382 stats.first_packet_sent_time = endpoint_stats.first_packet_sent_time;
383 stats.first_sent_packet_size = endpoint_stats.first_sent_packet_size;
384 }
385 if (stats.last_packet_received_time.IsInfinite() ||
386 stats.last_packet_received_time <
387 endpoint_stats.last_packet_received_time) {
388 stats.last_packet_received_time =
389 endpoint_stats.last_packet_received_time;
390 }
391 if (stats.last_packet_sent_time.IsInfinite() ||
392 stats.last_packet_sent_time < endpoint_stats.last_packet_sent_time) {
393 stats.last_packet_sent_time = endpoint_stats.last_packet_sent_time;
394 }
395 }
396 return stats;
397}
398
Artem Titov40f51152019-01-04 15:45:01 +0100399} // namespace webrtc