blob: 04ac7445fd238f8bbef1339180f18aecd86f995d [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
Niels Möller7536bc52019-10-04 13:54:39 +020023namespace {
24constexpr size_t kIPv4HeaderSize = 20;
25constexpr size_t kIPv6HeaderSize = 40;
26} // namespace
27
Artem Titov40f51152019-01-04 15:45:01 +010028EmulatedIpPacket::EmulatedIpPacket(const rtc::SocketAddress& from,
29 const rtc::SocketAddress& to,
Artem Titov40f51152019-01-04 15:45:01 +010030 rtc::CopyOnWriteBuffer data,
31 Timestamp arrival_time)
Niels Möller7536bc52019-10-04 13:54:39 +020032 : from(from),
33 to(to),
34 data(data),
35 ip_header_size((to.family() == AF_INET) ? kIPv4HeaderSize
36 : kIPv6HeaderSize),
37 arrival_time(arrival_time) {
38 RTC_DCHECK(to.family() == AF_INET || to.family() == AF_INET6);
39}
Artem Titov40f51152019-01-04 15:45:01 +010040
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020041void LinkEmulation::OnPacketReceived(EmulatedIpPacket packet) {
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +020042 task_queue_->PostTask([this, packet = std::move(packet)]() mutable {
43 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Jansson4124dab2019-04-01 14:33:53 +020044
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +020045 uint64_t packet_id = next_packet_id_++;
Niels Möller7536bc52019-10-04 13:54:39 +020046 bool sent = network_behavior_->EnqueuePacket(PacketInFlightInfo(
47 packet.ip_packet_size(), packet.arrival_time.us(), packet_id));
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +020048 if (sent) {
49 packets_.emplace_back(StoredPacket{packet_id, std::move(packet), false});
50 }
51 if (process_task_.Running())
52 return;
53 absl::optional<int64_t> next_time_us =
54 network_behavior_->NextDeliveryTimeUs();
55 if (!next_time_us)
56 return;
57 Timestamp current_time = clock_->CurrentTime();
58 process_task_ = RepeatingTaskHandle::DelayedStart(
59 task_queue_->Get(),
60 std::max(TimeDelta::Zero(),
61 Timestamp::us(*next_time_us) - current_time),
62 [this]() {
63 RTC_DCHECK_RUN_ON(task_queue_);
64 Timestamp current_time = clock_->CurrentTime();
65 Process(current_time);
66 absl::optional<int64_t> next_time_us =
67 network_behavior_->NextDeliveryTimeUs();
68 if (!next_time_us) {
69 process_task_.Stop();
70 return TimeDelta::Zero(); // This is ignored.
71 }
72 RTC_DCHECK_GE(*next_time_us, current_time.us());
73 return Timestamp::us(*next_time_us) - current_time;
74 });
75 });
Artem Titov37d18482019-01-08 15:41:45 +010076}
77
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020078void LinkEmulation::Process(Timestamp at_time) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +020079 std::vector<PacketDeliveryInfo> delivery_infos =
80 network_behavior_->DequeueDeliverablePackets(at_time.us());
Artem Titov37d18482019-01-08 15:41:45 +010081 for (PacketDeliveryInfo& delivery_info : delivery_infos) {
82 StoredPacket* packet = nullptr;
Sebastian Jansson4124dab2019-04-01 14:33:53 +020083 for (auto& stored_packet : packets_) {
84 if (stored_packet.id == delivery_info.packet_id) {
85 packet = &stored_packet;
86 break;
Artem Titov37d18482019-01-08 15:41:45 +010087 }
Artem Titov37d18482019-01-08 15:41:45 +010088 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020089 RTC_CHECK(packet);
90 RTC_DCHECK(!packet->removed);
Sebastian Jansson4124dab2019-04-01 14:33:53 +020091 packet->removed = true;
92
Johannes Krona8f9e252019-01-24 15:38:23 +010093 if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) {
94 packet->packet.arrival_time =
95 Timestamp::us(delivery_info.receive_time_us);
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020096 receiver_->OnPacketReceived(std::move(packet->packet));
Johannes Krona8f9e252019-01-24 15:38:23 +010097 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020098 while (!packets_.empty() && packets_.front().removed) {
99 packets_.pop_front();
Artem Titov37d18482019-01-08 15:41:45 +0100100 }
101 }
102}
103
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200104NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue)
105 : task_queue_(task_queue) {}
106
107void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) {
108 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Jansson71c6b562019-08-14 11:31:02 +0200109 if (watcher_) {
110 watcher_(packet);
111 }
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200112 auto receiver_it = routing_.find(packet.to.ipaddr());
113 if (receiver_it == routing_.end()) {
114 return;
115 }
116 RTC_CHECK(receiver_it != routing_.end());
117
118 receiver_it->second->OnPacketReceived(std::move(packet));
119}
120
121void NetworkRouterNode::SetReceiver(
Artem Titov4cd433e2019-04-01 11:01:16 +0200122 rtc::IPAddress dest_ip,
Artem Titov37d18482019-01-08 15:41:45 +0100123 EmulatedNetworkReceiverInterface* receiver) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200124 task_queue_->PostTask([=] {
125 RTC_DCHECK_RUN_ON(task_queue_);
126 EmulatedNetworkReceiverInterface* cur_receiver = routing_[dest_ip];
127 RTC_CHECK(cur_receiver == nullptr || cur_receiver == receiver)
128 << "Routing for dest_ip=" << dest_ip.ToString() << " already exists";
129 routing_[dest_ip] = receiver;
130 });
Artem Titov37d18482019-01-08 15:41:45 +0100131}
132
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200133void NetworkRouterNode::RemoveReceiver(rtc::IPAddress dest_ip) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200134 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200135 routing_.erase(dest_ip);
Artem Titov37d18482019-01-08 15:41:45 +0100136}
137
Sebastian Jansson71c6b562019-08-14 11:31:02 +0200138void NetworkRouterNode::SetWatcher(
139 std::function<void(const EmulatedIpPacket&)> watcher) {
140 task_queue_->PostTask([=] {
141 RTC_DCHECK_RUN_ON(task_queue_);
142 watcher_ = watcher;
143 });
144}
145
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200146EmulatedNetworkNode::EmulatedNetworkNode(
147 Clock* clock,
148 rtc::TaskQueue* task_queue,
149 std::unique_ptr<NetworkBehaviorInterface> network_behavior)
150 : router_(task_queue),
151 link_(clock, task_queue, std::move(network_behavior), &router_) {}
152
153void EmulatedNetworkNode::OnPacketReceived(EmulatedIpPacket packet) {
154 link_.OnPacketReceived(std::move(packet));
155}
156
157void EmulatedNetworkNode::CreateRoute(
158 rtc::IPAddress receiver_ip,
159 std::vector<EmulatedNetworkNode*> nodes,
160 EmulatedNetworkReceiverInterface* receiver) {
161 RTC_CHECK(!nodes.empty());
162 for (size_t i = 0; i + 1 < nodes.size(); ++i)
163 nodes[i]->router()->SetReceiver(receiver_ip, nodes[i + 1]);
164 nodes.back()->router()->SetReceiver(receiver_ip, receiver);
165}
166
167void EmulatedNetworkNode::ClearRoute(rtc::IPAddress receiver_ip,
168 std::vector<EmulatedNetworkNode*> nodes) {
169 for (EmulatedNetworkNode* node : nodes)
170 node->router()->RemoveReceiver(receiver_ip);
171}
172
173EmulatedNetworkNode::~EmulatedNetworkNode() = default;
174
Artem Titove5cc85b2019-03-28 12:11:09 +0100175EmulatedEndpoint::EmulatedEndpoint(uint64_t id,
Artem Titov612e1792019-04-01 14:43:38 +0200176 const rtc::IPAddress& ip,
Artem Titove5cc85b2019-03-28 12:11:09 +0100177 bool is_enabled,
Artem Titovff393122019-04-05 11:19:52 +0200178 rtc::TaskQueue* task_queue,
Artem Titove5cc85b2019-03-28 12:11:09 +0100179 Clock* clock)
Artem Titov0774bd92019-01-30 15:26:05 +0100180 : id_(id),
181 peer_local_addr_(ip),
Artem Titove5cc85b2019-03-28 12:11:09 +0100182 is_enabled_(is_enabled),
Artem Titov0774bd92019-01-30 15:26:05 +0100183 clock_(clock),
Artem Titovff393122019-04-05 11:19:52 +0200184 task_queue_(task_queue),
185 router_(task_queue_),
Artem Titov4cd433e2019-04-01 11:01:16 +0200186 next_port_(kFirstEphemeralPort) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100187 constexpr int kIPv4NetworkPrefixLength = 24;
188 constexpr int kIPv6NetworkPrefixLength = 64;
189
190 int prefix_length = 0;
191 if (ip.family() == AF_INET) {
192 prefix_length = kIPv4NetworkPrefixLength;
193 } else if (ip.family() == AF_INET6) {
194 prefix_length = kIPv6NetworkPrefixLength;
195 }
196 rtc::IPAddress prefix = TruncateIP(ip, prefix_length);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200197 network_ = std::make_unique<rtc::Network>(
Artem Titove5cc85b2019-03-28 12:11:09 +0100198 ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix,
199 prefix_length, rtc::AdapterType::ADAPTER_TYPE_UNKNOWN);
200 network_->AddIP(ip);
201
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200202 enabled_state_checker_.Detach();
Artem Titove5cc85b2019-03-28 12:11:09 +0100203}
Artem Titovaba8dc22019-03-11 10:08:40 +0100204EmulatedEndpoint::~EmulatedEndpoint() = default;
Artem Titov0774bd92019-01-30 15:26:05 +0100205
Artem Titovaba8dc22019-03-11 10:08:40 +0100206uint64_t EmulatedEndpoint::GetId() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100207 return id_;
208}
209
Artem Titovaba8dc22019-03-11 10:08:40 +0100210void EmulatedEndpoint::SendPacket(const rtc::SocketAddress& from,
211 const rtc::SocketAddress& to,
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200212 rtc::CopyOnWriteBuffer packet_data) {
Artem Titov0774bd92019-01-30 15:26:05 +0100213 RTC_CHECK(from.ipaddr() == peer_local_addr_);
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200214 EmulatedIpPacket packet(from, to, std::move(packet_data),
215 clock_->CurrentTime());
216 task_queue_->PostTask([this, packet = std::move(packet)]() mutable {
217 RTC_DCHECK_RUN_ON(task_queue_);
218 Timestamp current_time = clock_->CurrentTime();
219 if (stats_.first_packet_sent_time.IsInfinite()) {
220 stats_.first_packet_sent_time = current_time;
Niels Möller7536bc52019-10-04 13:54:39 +0200221 stats_.first_sent_packet_size = DataSize::bytes(packet.ip_packet_size());
Artem Titov806299e2019-04-12 12:17:19 +0200222 }
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200223 stats_.last_packet_sent_time = current_time;
224 stats_.packets_sent++;
Niels Möller7536bc52019-10-04 13:54:39 +0200225 stats_.bytes_sent += DataSize::bytes(packet.ip_packet_size());
Sebastian Janssonee5ec9a2019-09-17 20:34:03 +0200226
227 router_.OnPacketReceived(std::move(packet));
228 });
Artem Titov0774bd92019-01-30 15:26:05 +0100229}
230
Artem Titovaba8dc22019-03-11 10:08:40 +0100231absl::optional<uint16_t> EmulatedEndpoint::BindReceiver(
Artem Titov0774bd92019-01-30 15:26:05 +0100232 uint16_t desired_port,
233 EmulatedNetworkReceiverInterface* receiver) {
234 rtc::CritScope crit(&receiver_lock_);
235 uint16_t port = desired_port;
236 if (port == 0) {
237 // Because client can specify its own port, next_port_ can be already in
238 // use, so we need to find next available port.
239 int ports_pool_size =
240 std::numeric_limits<uint16_t>::max() - kFirstEphemeralPort + 1;
241 for (int i = 0; i < ports_pool_size; ++i) {
242 uint16_t next_port = NextPort();
243 if (port_to_receiver_.find(next_port) == port_to_receiver_.end()) {
244 port = next_port;
245 break;
246 }
247 }
248 }
249 RTC_CHECK(port != 0) << "Can't find free port for receiver in endpoint "
250 << id_;
251 bool result = port_to_receiver_.insert({port, receiver}).second;
252 if (!result) {
253 RTC_LOG(INFO) << "Can't bind receiver to used port " << desired_port
254 << " in endpoint " << id_;
255 return absl::nullopt;
256 }
257 RTC_LOG(INFO) << "New receiver is binded to endpoint " << id_ << " on port "
258 << port;
259 return port;
260}
261
Artem Titovaba8dc22019-03-11 10:08:40 +0100262uint16_t EmulatedEndpoint::NextPort() {
Artem Titov0774bd92019-01-30 15:26:05 +0100263 uint16_t out = next_port_;
264 if (next_port_ == std::numeric_limits<uint16_t>::max()) {
265 next_port_ = kFirstEphemeralPort;
266 } else {
267 next_port_++;
268 }
269 return out;
270}
271
Artem Titovaba8dc22019-03-11 10:08:40 +0100272void EmulatedEndpoint::UnbindReceiver(uint16_t port) {
Artem Titov0774bd92019-01-30 15:26:05 +0100273 rtc::CritScope crit(&receiver_lock_);
274 port_to_receiver_.erase(port);
275}
276
Artem Titovaba8dc22019-03-11 10:08:40 +0100277rtc::IPAddress EmulatedEndpoint::GetPeerLocalAddress() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100278 return peer_local_addr_;
279}
280
Artem Titovaba8dc22019-03-11 10:08:40 +0100281void EmulatedEndpoint::OnPacketReceived(EmulatedIpPacket packet) {
Artem Titov806299e2019-04-12 12:17:19 +0200282 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200283 RTC_CHECK(packet.to.ipaddr() == peer_local_addr_)
284 << "Routing error: wrong destination endpoint. Packet.to.ipaddr()=: "
285 << packet.to.ipaddr().ToString()
286 << "; Receiver peer_local_addr_=" << peer_local_addr_.ToString();
Artem Titov0774bd92019-01-30 15:26:05 +0100287 rtc::CritScope crit(&receiver_lock_);
Artem Titov806299e2019-04-12 12:17:19 +0200288 UpdateReceiveStats(packet);
Artem Titov0774bd92019-01-30 15:26:05 +0100289 auto it = port_to_receiver_.find(packet.to.port());
290 if (it == port_to_receiver_.end()) {
291 // It can happen, that remote peer closed connection, but there still some
292 // packets, that are going to it. It can happen during peer connection close
293 // process: one peer closed connection, second still sending data.
Artem Titov806299e2019-04-12 12:17:19 +0200294 RTC_LOG(INFO) << "Drop packet: no receiver registered in " << id_
295 << " on port " << packet.to.port();
296 stats_.packets_dropped++;
Niels Möller7536bc52019-10-04 13:54:39 +0200297 stats_.bytes_dropped += DataSize::bytes(packet.ip_packet_size());
Artem Titov0774bd92019-01-30 15:26:05 +0100298 return;
299 }
300 // Endpoint assumes frequent calls to bind and unbind methods, so it holds
301 // lock during packet processing to ensure that receiver won't be deleted
302 // before call to OnPacketReceived.
303 it->second->OnPacketReceived(std::move(packet));
304}
305
Artem Titove5cc85b2019-03-28 12:11:09 +0100306void EmulatedEndpoint::Enable() {
307 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
308 RTC_CHECK(!is_enabled_);
309 is_enabled_ = true;
310}
311
312void EmulatedEndpoint::Disable() {
313 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
314 RTC_CHECK(is_enabled_);
315 is_enabled_ = false;
316}
317
318bool EmulatedEndpoint::Enabled() const {
319 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
320 return is_enabled_;
321}
322
Artem Titov806299e2019-04-12 12:17:19 +0200323EmulatedNetworkStats EmulatedEndpoint::stats() {
324 RTC_DCHECK_RUN_ON(task_queue_);
325 return stats_;
326}
327
Artem Titov806299e2019-04-12 12:17:19 +0200328void EmulatedEndpoint::UpdateReceiveStats(const EmulatedIpPacket& packet) {
329 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200330 Timestamp current_time = clock_->CurrentTime();
Artem Titov806299e2019-04-12 12:17:19 +0200331 if (stats_.first_packet_received_time.IsInfinite()) {
332 stats_.first_packet_received_time = current_time;
Niels Möller7536bc52019-10-04 13:54:39 +0200333 stats_.first_received_packet_size =
334 DataSize::bytes(packet.ip_packet_size());
Artem Titov806299e2019-04-12 12:17:19 +0200335 }
336 stats_.last_packet_received_time = current_time;
337 stats_.packets_received++;
Niels Möller7536bc52019-10-04 13:54:39 +0200338 stats_.bytes_received += DataSize::bytes(packet.ip_packet_size());
Artem Titov806299e2019-04-12 12:17:19 +0200339}
340
Artem Titove5cc85b2019-03-28 12:11:09 +0100341EndpointsContainer::EndpointsContainer(
342 const std::vector<EmulatedEndpoint*>& endpoints)
343 : endpoints_(endpoints) {}
344
345EmulatedEndpoint* EndpointsContainer::LookupByLocalAddress(
346 const rtc::IPAddress& local_ip) const {
347 for (auto* endpoint : endpoints_) {
Artem Titov4cd433e2019-04-01 11:01:16 +0200348 rtc::IPAddress peer_local_address = endpoint->GetPeerLocalAddress();
349 if (peer_local_address == local_ip) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100350 return endpoint;
351 }
352 }
353 RTC_CHECK(false) << "No network found for address" << local_ip.ToString();
354}
355
356bool EndpointsContainer::HasEndpoint(EmulatedEndpoint* endpoint) const {
357 for (auto* e : endpoints_) {
358 if (e->GetId() == endpoint->GetId()) {
359 return true;
360 }
361 }
362 return false;
363}
364
365std::vector<std::unique_ptr<rtc::Network>>
366EndpointsContainer::GetEnabledNetworks() const {
367 std::vector<std::unique_ptr<rtc::Network>> networks;
368 for (auto* endpoint : endpoints_) {
369 if (endpoint->Enabled()) {
370 networks.emplace_back(
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200371 std::make_unique<rtc::Network>(endpoint->network()));
Artem Titove5cc85b2019-03-28 12:11:09 +0100372 }
373 }
374 return networks;
375}
376
Artem Titov806299e2019-04-12 12:17:19 +0200377EmulatedNetworkStats EndpointsContainer::GetStats() const {
378 EmulatedNetworkStats stats;
379 for (auto* endpoint : endpoints_) {
380 EmulatedNetworkStats endpoint_stats = endpoint->stats();
381 stats.packets_sent += endpoint_stats.packets_sent;
382 stats.bytes_sent += endpoint_stats.bytes_sent;
383 stats.packets_received += endpoint_stats.packets_received;
384 stats.bytes_received += endpoint_stats.bytes_received;
385 stats.packets_dropped += endpoint_stats.packets_dropped;
386 stats.bytes_dropped += endpoint_stats.bytes_dropped;
387 if (stats.first_packet_received_time >
388 endpoint_stats.first_packet_received_time) {
389 stats.first_packet_received_time =
390 endpoint_stats.first_packet_received_time;
391 stats.first_received_packet_size =
392 endpoint_stats.first_received_packet_size;
393 }
394 if (stats.first_packet_sent_time > endpoint_stats.first_packet_sent_time) {
395 stats.first_packet_sent_time = endpoint_stats.first_packet_sent_time;
396 stats.first_sent_packet_size = endpoint_stats.first_sent_packet_size;
397 }
398 if (stats.last_packet_received_time.IsInfinite() ||
399 stats.last_packet_received_time <
400 endpoint_stats.last_packet_received_time) {
401 stats.last_packet_received_time =
402 endpoint_stats.last_packet_received_time;
403 }
404 if (stats.last_packet_sent_time.IsInfinite() ||
405 stats.last_packet_sent_time < endpoint_stats.last_packet_sent_time) {
406 stats.last_packet_sent_time = endpoint_stats.last_packet_sent_time;
407 }
408 }
409 return stats;
410}
411
Artem Titov40f51152019-01-04 15:45:01 +0100412} // namespace webrtc