xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/simulator/link.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/test_tools/simulator/link.h"
6 
7 #include "absl/strings/str_cat.h"
8 #include "absl/strings/str_format.h"
9 #include "quiche/quic/test_tools/simulator/simulator.h"
10 
11 namespace quic {
12 namespace simulator {
13 
14 // Parameters for random noise delay.
15 const uint64_t kMaxRandomDelayUs = 10;
16 
OneWayLink(Simulator * simulator,std::string name,UnconstrainedPortInterface * sink,QuicBandwidth bandwidth,QuicTime::Delta propagation_delay)17 OneWayLink::OneWayLink(Simulator* simulator, std::string name,
18                        UnconstrainedPortInterface* sink,
19                        QuicBandwidth bandwidth,
20                        QuicTime::Delta propagation_delay)
21     : Actor(simulator, name),
22       sink_(sink),
23       bandwidth_(bandwidth),
24       propagation_delay_(propagation_delay),
25       next_write_at_(QuicTime::Zero()) {}
26 
~OneWayLink()27 OneWayLink::~OneWayLink() {}
28 
QueuedPacket(std::unique_ptr<Packet> packet,QuicTime dequeue_time)29 OneWayLink::QueuedPacket::QueuedPacket(std::unique_ptr<Packet> packet,
30                                        QuicTime dequeue_time)
31     : packet(std::move(packet)), dequeue_time(dequeue_time) {}
32 
33 OneWayLink::QueuedPacket::QueuedPacket(QueuedPacket&& other) = default;
34 
~QueuedPacket()35 OneWayLink::QueuedPacket::~QueuedPacket() {}
36 
AcceptPacket(std::unique_ptr<Packet> packet)37 void OneWayLink::AcceptPacket(std::unique_ptr<Packet> packet) {
38   QUICHE_DCHECK(TimeUntilAvailable().IsZero());
39   QuicTime::Delta transfer_time = bandwidth_.TransferTime(packet->size);
40   next_write_at_ = clock_->Now() + transfer_time;
41 
42   packets_in_transit_.emplace_back(
43       std::move(packet),
44       // Ensure that packets are delivered in order.
45       std::max(
46           next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time),
47           packets_in_transit_.empty()
48               ? QuicTime::Zero()
49               : packets_in_transit_.back().dequeue_time));
50   ScheduleNextPacketDeparture();
51 }
52 
TimeUntilAvailable()53 QuicTime::Delta OneWayLink::TimeUntilAvailable() {
54   const QuicTime now = clock_->Now();
55   if (next_write_at_ <= now) {
56     return QuicTime::Delta::Zero();
57   }
58 
59   return next_write_at_ - now;
60 }
61 
Act()62 void OneWayLink::Act() {
63   QUICHE_DCHECK(!packets_in_transit_.empty());
64   QUICHE_DCHECK(packets_in_transit_.front().dequeue_time >= clock_->Now());
65 
66   sink_->AcceptPacket(std::move(packets_in_transit_.front().packet));
67   packets_in_transit_.pop_front();
68 
69   ScheduleNextPacketDeparture();
70 }
71 
ScheduleNextPacketDeparture()72 void OneWayLink::ScheduleNextPacketDeparture() {
73   if (packets_in_transit_.empty()) {
74     return;
75   }
76 
77   Schedule(packets_in_transit_.front().dequeue_time);
78 }
79 
GetRandomDelay(QuicTime::Delta transfer_time)80 QuicTime::Delta OneWayLink::GetRandomDelay(QuicTime::Delta transfer_time) {
81   if (!simulator_->enable_random_delays()) {
82     return QuicTime::Delta::Zero();
83   }
84 
85   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(
86       simulator_->GetRandomGenerator()->RandUint64() % (kMaxRandomDelayUs + 1));
87   // Have an upper bound on the delay to ensure packets do not go out of order.
88   delta = std::min(delta, transfer_time * 0.5);
89   return delta;
90 }
91 
SymmetricLink(Simulator * simulator,std::string name,UnconstrainedPortInterface * sink_a,UnconstrainedPortInterface * sink_b,QuicBandwidth bandwidth,QuicTime::Delta propagation_delay)92 SymmetricLink::SymmetricLink(Simulator* simulator, std::string name,
93                              UnconstrainedPortInterface* sink_a,
94                              UnconstrainedPortInterface* sink_b,
95                              QuicBandwidth bandwidth,
96                              QuicTime::Delta propagation_delay)
97     : a_to_b_link_(simulator, absl::StrCat(name, " (A-to-B)"), sink_b,
98                    bandwidth, propagation_delay),
99       b_to_a_link_(simulator, absl::StrCat(name, " (B-to-A)"), sink_a,
100                    bandwidth, propagation_delay) {}
101 
SymmetricLink(Endpoint * endpoint_a,Endpoint * endpoint_b,QuicBandwidth bandwidth,QuicTime::Delta propagation_delay)102 SymmetricLink::SymmetricLink(Endpoint* endpoint_a, Endpoint* endpoint_b,
103                              QuicBandwidth bandwidth,
104                              QuicTime::Delta propagation_delay)
105     : SymmetricLink(endpoint_a->simulator(),
106                     absl::StrFormat("Link [%s]<->[%s]", endpoint_a->name(),
107                                     endpoint_b->name()),
108                     endpoint_a->GetRxPort(), endpoint_b->GetRxPort(), bandwidth,
109                     propagation_delay) {
110   endpoint_a->SetTxPort(&a_to_b_link_);
111   endpoint_b->SetTxPort(&b_to_a_link_);
112 }
113 
114 }  // namespace simulator
115 }  // namespace quic
116