Index: net/quic/core/congestion_control/simulation/link.cc |
diff --git a/net/quic/core/congestion_control/simulation/link.cc b/net/quic/core/congestion_control/simulation/link.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ae1faf36f2bce05eae08f2d9f434b31dbbb7d377 |
--- /dev/null |
+++ b/net/quic/core/congestion_control/simulation/link.cc |
@@ -0,0 +1,116 @@ |
+// 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 "base/strings/stringprintf.h" |
+#include "net/quic/core/congestion_control/simulation/link.h" |
+#include "net/quic/core/congestion_control/simulation/simulator.h" |
+ |
+using base::StringPrintf; |
+ |
+namespace net { |
+namespace simulation { |
+ |
+// 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() {} |
+ |
+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( |
+ std::move(packet), |
+ next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_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(); |
+ |
+ 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) { |
+ 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, |
+ StringPrintf("%s (A-to-B)", name.c_str()), |
+ sink_b, |
+ bandwidth, |
+ propagation_delay), |
+ b_to_a_link_(simulator, |
+ StringPrintf("%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(), |
+ StringPrintf("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 simulation |
+} // namespace net |