blob: 2d4a057f93ca5f605aa4b2d728a38643899f4baf [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 Jansson4124dab2019-04-01 14:33:53 +020030 struct Closure {
31 void operator()() {
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020032 RTC_DCHECK_RUN_ON(link->task_queue_);
33 link->HandlePacketReceived(std::move(packet));
Sebastian Jansson4124dab2019-04-01 14:33:53 +020034 }
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020035 LinkEmulation* link;
Sebastian Jansson4124dab2019-04-01 14:33:53 +020036 EmulatedIpPacket packet;
37 };
38 task_queue_->PostTask(Closure{this, std::move(packet)});
39}
40
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020041void LinkEmulation::HandlePacketReceived(EmulatedIpPacket packet) {
Artem Titov37d18482019-01-08 15:41:45 +010042 uint64_t packet_id = next_packet_id_++;
Sebastian Jansson8c8feb92019-01-29 15:59:17 +010043 bool sent = network_behavior_->EnqueuePacket(
44 PacketInFlightInfo(packet.size(), packet.arrival_time.us(), packet_id));
Artem Titov37d18482019-01-08 15:41:45 +010045 if (sent) {
46 packets_.emplace_back(StoredPacket{packet_id, std::move(packet), false});
47 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020048 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 Janssonb64ad0e2019-06-19 09:39:34 +020054 Timestamp current_time = clock_->CurrentTime();
Sebastian Jansson4124dab2019-04-01 14:33:53 +020055 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 Janssonb64ad0e2019-06-19 09:39:34 +020060 Timestamp current_time = clock_->CurrentTime();
Sebastian Jansson4124dab2019-04-01 14:33:53 +020061 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 Titov37d18482019-01-08 15:41:45 +010071}
72
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020073void LinkEmulation::Process(Timestamp at_time) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +020074 std::vector<PacketDeliveryInfo> delivery_infos =
75 network_behavior_->DequeueDeliverablePackets(at_time.us());
Artem Titov37d18482019-01-08 15:41:45 +010076 for (PacketDeliveryInfo& delivery_info : delivery_infos) {
77 StoredPacket* packet = nullptr;
Sebastian Jansson4124dab2019-04-01 14:33:53 +020078 for (auto& stored_packet : packets_) {
79 if (stored_packet.id == delivery_info.packet_id) {
80 packet = &stored_packet;
81 break;
Artem Titov37d18482019-01-08 15:41:45 +010082 }
Artem Titov37d18482019-01-08 15:41:45 +010083 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020084 RTC_CHECK(packet);
85 RTC_DCHECK(!packet->removed);
Sebastian Jansson4124dab2019-04-01 14:33:53 +020086 packet->removed = true;
87
Johannes Krona8f9e252019-01-24 15:38:23 +010088 if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) {
89 packet->packet.arrival_time =
90 Timestamp::us(delivery_info.receive_time_us);
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020091 receiver_->OnPacketReceived(std::move(packet->packet));
Johannes Krona8f9e252019-01-24 15:38:23 +010092 }
Sebastian Jansson4124dab2019-04-01 14:33:53 +020093 while (!packets_.empty() && packets_.front().removed) {
94 packets_.pop_front();
Artem Titov37d18482019-01-08 15:41:45 +010095 }
96 }
97}
98
Sebastian Jansson62bb47f2019-04-01 18:23:58 +020099NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue)
100 : task_queue_(task_queue) {}
101
102void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) {
103 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Jansson71c6b562019-08-14 11:31:02 +0200104 if (watcher_) {
105 watcher_(packet);
106 }
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200107 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
116void NetworkRouterNode::SetReceiver(
Artem Titov4cd433e2019-04-01 11:01:16 +0200117 rtc::IPAddress dest_ip,
Artem Titov37d18482019-01-08 15:41:45 +0100118 EmulatedNetworkReceiverInterface* receiver) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200119 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 Titov37d18482019-01-08 15:41:45 +0100126}
127
Sebastian Jansson62bb47f2019-04-01 18:23:58 +0200128void NetworkRouterNode::RemoveReceiver(rtc::IPAddress dest_ip) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +0200129 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200130 routing_.erase(dest_ip);
Artem Titov37d18482019-01-08 15:41:45 +0100131}
132
Sebastian Jansson71c6b562019-08-14 11:31:02 +0200133void 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 Jansson62bb47f2019-04-01 18:23:58 +0200141EmulatedNetworkNode::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
148void EmulatedNetworkNode::OnPacketReceived(EmulatedIpPacket packet) {
149 link_.OnPacketReceived(std::move(packet));
150}
151
152void 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
162void EmulatedNetworkNode::ClearRoute(rtc::IPAddress receiver_ip,
163 std::vector<EmulatedNetworkNode*> nodes) {
164 for (EmulatedNetworkNode* node : nodes)
165 node->router()->RemoveReceiver(receiver_ip);
166}
167
168EmulatedNetworkNode::~EmulatedNetworkNode() = default;
169
Artem Titove5cc85b2019-03-28 12:11:09 +0100170EmulatedEndpoint::EmulatedEndpoint(uint64_t id,
Artem Titov612e1792019-04-01 14:43:38 +0200171 const rtc::IPAddress& ip,
Artem Titove5cc85b2019-03-28 12:11:09 +0100172 bool is_enabled,
Artem Titovff393122019-04-05 11:19:52 +0200173 rtc::TaskQueue* task_queue,
Artem Titove5cc85b2019-03-28 12:11:09 +0100174 Clock* clock)
Artem Titov0774bd92019-01-30 15:26:05 +0100175 : id_(id),
176 peer_local_addr_(ip),
Artem Titove5cc85b2019-03-28 12:11:09 +0100177 is_enabled_(is_enabled),
Artem Titov0774bd92019-01-30 15:26:05 +0100178 clock_(clock),
Artem Titovff393122019-04-05 11:19:52 +0200179 task_queue_(task_queue),
180 router_(task_queue_),
Artem Titov4cd433e2019-04-01 11:01:16 +0200181 next_port_(kFirstEphemeralPort) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100182 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 Bonadei317a1f02019-09-17 17:06:18 +0200192 network_ = std::make_unique<rtc::Network>(
Artem Titove5cc85b2019-03-28 12:11:09 +0100193 ip.ToString(), "Endpoint id=" + std::to_string(id_), prefix,
194 prefix_length, rtc::AdapterType::ADAPTER_TYPE_UNKNOWN);
195 network_->AddIP(ip);
196
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200197 enabled_state_checker_.Detach();
Artem Titove5cc85b2019-03-28 12:11:09 +0100198}
Artem Titovaba8dc22019-03-11 10:08:40 +0100199EmulatedEndpoint::~EmulatedEndpoint() = default;
Artem Titov0774bd92019-01-30 15:26:05 +0100200
Artem Titovaba8dc22019-03-11 10:08:40 +0100201uint64_t EmulatedEndpoint::GetId() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100202 return id_;
203}
204
Artem Titovaba8dc22019-03-11 10:08:40 +0100205void EmulatedEndpoint::SendPacket(const rtc::SocketAddress& from,
206 const rtc::SocketAddress& to,
207 rtc::CopyOnWriteBuffer packet) {
Artem Titov0774bd92019-01-30 15:26:05 +0100208 RTC_CHECK(from.ipaddr() == peer_local_addr_);
Artem Titovff393122019-04-05 11:19:52 +0200209 struct Closure {
Artem Titov806299e2019-04-12 12:17:19 +0200210 void operator()() {
211 endpoint->UpdateSendStats(packet);
212 endpoint->router_.OnPacketReceived(std::move(packet));
213 }
Artem Titovff393122019-04-05 11:19:52 +0200214 EmulatedEndpoint* endpoint;
215 EmulatedIpPacket packet;
216 };
217 task_queue_->PostTask(Closure{
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200218 this,
219 EmulatedIpPacket(from, to, std::move(packet), clock_->CurrentTime())});
Artem Titov0774bd92019-01-30 15:26:05 +0100220}
221
Artem Titovaba8dc22019-03-11 10:08:40 +0100222absl::optional<uint16_t> EmulatedEndpoint::BindReceiver(
Artem Titov0774bd92019-01-30 15:26:05 +0100223 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 Titovaba8dc22019-03-11 10:08:40 +0100253uint16_t EmulatedEndpoint::NextPort() {
Artem Titov0774bd92019-01-30 15:26:05 +0100254 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 Titovaba8dc22019-03-11 10:08:40 +0100263void EmulatedEndpoint::UnbindReceiver(uint16_t port) {
Artem Titov0774bd92019-01-30 15:26:05 +0100264 rtc::CritScope crit(&receiver_lock_);
265 port_to_receiver_.erase(port);
266}
267
Artem Titovaba8dc22019-03-11 10:08:40 +0100268rtc::IPAddress EmulatedEndpoint::GetPeerLocalAddress() const {
Artem Titov0774bd92019-01-30 15:26:05 +0100269 return peer_local_addr_;
270}
271
Artem Titovaba8dc22019-03-11 10:08:40 +0100272void EmulatedEndpoint::OnPacketReceived(EmulatedIpPacket packet) {
Artem Titov806299e2019-04-12 12:17:19 +0200273 RTC_DCHECK_RUN_ON(task_queue_);
Artem Titov4cd433e2019-04-01 11:01:16 +0200274 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 Titov0774bd92019-01-30 15:26:05 +0100278 rtc::CritScope crit(&receiver_lock_);
Artem Titov806299e2019-04-12 12:17:19 +0200279 UpdateReceiveStats(packet);
Artem Titov0774bd92019-01-30 15:26:05 +0100280 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 Titov806299e2019-04-12 12:17:19 +0200285 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 Titov0774bd92019-01-30 15:26:05 +0100289 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 Titove5cc85b2019-03-28 12:11:09 +0100297void EmulatedEndpoint::Enable() {
298 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
299 RTC_CHECK(!is_enabled_);
300 is_enabled_ = true;
301}
302
303void EmulatedEndpoint::Disable() {
304 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
305 RTC_CHECK(is_enabled_);
306 is_enabled_ = false;
307}
308
309bool EmulatedEndpoint::Enabled() const {
310 RTC_DCHECK_RUN_ON(&enabled_state_checker_);
311 return is_enabled_;
312}
313
Artem Titov806299e2019-04-12 12:17:19 +0200314EmulatedNetworkStats EmulatedEndpoint::stats() {
315 RTC_DCHECK_RUN_ON(task_queue_);
316 return stats_;
317}
318
319void EmulatedEndpoint::UpdateSendStats(const EmulatedIpPacket& packet) {
320 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200321 Timestamp current_time = clock_->CurrentTime();
Artem Titov806299e2019-04-12 12:17:19 +0200322 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
331void EmulatedEndpoint::UpdateReceiveStats(const EmulatedIpPacket& packet) {
332 RTC_DCHECK_RUN_ON(task_queue_);
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200333 Timestamp current_time = clock_->CurrentTime();
Artem Titov806299e2019-04-12 12:17:19 +0200334 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 Titove5cc85b2019-03-28 12:11:09 +0100343EndpointsContainer::EndpointsContainer(
344 const std::vector<EmulatedEndpoint*>& endpoints)
345 : endpoints_(endpoints) {}
346
347EmulatedEndpoint* EndpointsContainer::LookupByLocalAddress(
348 const rtc::IPAddress& local_ip) const {
349 for (auto* endpoint : endpoints_) {
Artem Titov4cd433e2019-04-01 11:01:16 +0200350 rtc::IPAddress peer_local_address = endpoint->GetPeerLocalAddress();
351 if (peer_local_address == local_ip) {
Artem Titove5cc85b2019-03-28 12:11:09 +0100352 return endpoint;
353 }
354 }
355 RTC_CHECK(false) << "No network found for address" << local_ip.ToString();
356}
357
358bool 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
367std::vector<std::unique_ptr<rtc::Network>>
368EndpointsContainer::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 Bonadei317a1f02019-09-17 17:06:18 +0200373 std::make_unique<rtc::Network>(endpoint->network()));
Artem Titove5cc85b2019-03-28 12:11:09 +0100374 }
375 }
376 return networks;
377}
378
Artem Titov806299e2019-04-12 12:17:19 +0200379EmulatedNetworkStats 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 Titov40f51152019-01-04 15:45:01 +0100414} // namespace webrtc