| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" | 
 |  | 
 | #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" | 
 | #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" | 
 |  | 
 | namespace quic { | 
 | namespace simulator { | 
 |  | 
 | // Parameters for random noise delay. | 
 | const uint64_t kMaxRandomDelayUs = 10; | 
 |  | 
 | OneWayLink::OneWayLink(Simulator* simulator, | 
 |                        std::string name, | 
 |                        UnconstrainedPortInterface* sink, | 
 |                        QuicBandwidth bandwidth, | 
 |                        QuicTime::Delta propagation_delay) | 
 |     : Actor(simulator, name), | 
 |       sink_(sink), | 
 |       bandwidth_(bandwidth), | 
 |       propagation_delay_(propagation_delay), | 
 |       next_write_at_(QuicTime::Zero()) {} | 
 |  | 
 | OneWayLink::~OneWayLink() {} | 
 |  | 
 | OneWayLink::QueuedPacket::QueuedPacket(std::unique_ptr<Packet> packet, | 
 |                                        QuicTime dequeue_time) | 
 |     : packet(std::move(packet)), dequeue_time(dequeue_time) {} | 
 |  | 
 | OneWayLink::QueuedPacket::QueuedPacket(QueuedPacket&& other) = default; | 
 |  | 
 | OneWayLink::QueuedPacket::~QueuedPacket() {} | 
 |  | 
 | void OneWayLink::AcceptPacket(std::unique_ptr<Packet> packet) { | 
 |   DCHECK(TimeUntilAvailable().IsZero()); | 
 |   QuicTime::Delta transfer_time = bandwidth_.TransferTime(packet->size); | 
 |   next_write_at_ = clock_->Now() + transfer_time; | 
 |  | 
 |   packets_in_transit_.emplace_back( | 
 |       std::move(packet), | 
 |       // Ensure that packets are delivered in order. | 
 |       std::max( | 
 |           next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time), | 
 |           packets_in_transit_.empty() | 
 |               ? QuicTime::Zero() | 
 |               : packets_in_transit_.back().dequeue_time)); | 
 |   ScheduleNextPacketDeparture(); | 
 | } | 
 |  | 
 | QuicTime::Delta OneWayLink::TimeUntilAvailable() { | 
 |   const QuicTime now = clock_->Now(); | 
 |   if (next_write_at_ <= now) { | 
 |     return QuicTime::Delta::Zero(); | 
 |   } | 
 |  | 
 |   return next_write_at_ - now; | 
 | } | 
 |  | 
 | void OneWayLink::Act() { | 
 |   DCHECK(!packets_in_transit_.empty()); | 
 |   DCHECK(packets_in_transit_.front().dequeue_time >= clock_->Now()); | 
 |  | 
 |   sink_->AcceptPacket(std::move(packets_in_transit_.front().packet)); | 
 |   packets_in_transit_.pop_front(); | 
 |  | 
 |   ScheduleNextPacketDeparture(); | 
 | } | 
 |  | 
 | void OneWayLink::ScheduleNextPacketDeparture() { | 
 |   if (packets_in_transit_.empty()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   Schedule(packets_in_transit_.front().dequeue_time); | 
 | } | 
 |  | 
 | QuicTime::Delta OneWayLink::GetRandomDelay(QuicTime::Delta transfer_time) { | 
 |   if (!simulator_->enable_random_delays()) { | 
 |     return QuicTime::Delta::Zero(); | 
 |   } | 
 |  | 
 |   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds( | 
 |       simulator_->GetRandomGenerator()->RandUint64() % (kMaxRandomDelayUs + 1)); | 
 |   // Have an upper bound on the delay to ensure packets do not go out of order. | 
 |   delta = std::min(delta, transfer_time * 0.5); | 
 |   return delta; | 
 | } | 
 |  | 
 | SymmetricLink::SymmetricLink(Simulator* simulator, | 
 |                              std::string name, | 
 |                              UnconstrainedPortInterface* sink_a, | 
 |                              UnconstrainedPortInterface* sink_b, | 
 |                              QuicBandwidth bandwidth, | 
 |                              QuicTime::Delta propagation_delay) | 
 |     : a_to_b_link_(simulator, | 
 |                    quiche::QuicheStringPrintf("%s (A-to-B)", name.c_str()), | 
 |                    sink_b, | 
 |                    bandwidth, | 
 |                    propagation_delay), | 
 |       b_to_a_link_(simulator, | 
 |                    quiche::QuicheStringPrintf("%s (B-to-A)", name.c_str()), | 
 |                    sink_a, | 
 |                    bandwidth, | 
 |                    propagation_delay) {} | 
 |  | 
 | SymmetricLink::SymmetricLink(Endpoint* endpoint_a, | 
 |                              Endpoint* endpoint_b, | 
 |                              QuicBandwidth bandwidth, | 
 |                              QuicTime::Delta propagation_delay) | 
 |     : SymmetricLink(endpoint_a->simulator(), | 
 |                     quiche::QuicheStringPrintf("Link [%s]<->[%s]", | 
 |                                                endpoint_a->name().c_str(), | 
 |                                                endpoint_b->name().c_str()), | 
 |                     endpoint_a->GetRxPort(), | 
 |                     endpoint_b->GetRxPort(), | 
 |                     bandwidth, | 
 |                     propagation_delay) { | 
 |   endpoint_a->SetTxPort(&a_to_b_link_); | 
 |   endpoint_b->SetTxPort(&b_to_a_link_); | 
 | } | 
 |  | 
 | }  // namespace simulator | 
 | }  // namespace quic |