| 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..b03c38828b74c6a4f4860868361ca680daddd8c3
|
| --- /dev/null
|
| +++ b/net/quic/core/congestion_control/simulation/link.cc
|
| @@ -0,0 +1,107 @@
|
| +#include "net/quic/core/congestion_control/simulation/link.h"
|
| +#include "net/quic/core/congestion_control/simulation/simulator.h"
|
| +
|
| +namespace net {
|
| +namespace simulation {
|
| +
|
| +// Parameters for random noise delay.
|
| +const double kDelayModelMeanUs = 18;
|
| +const double kDelayModelStandardDeviationUs = 3.7;
|
| +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::QueuedPacket::QueuedPacket(std::unique_ptr<Packet> packet,
|
| + QuicTime dequeue_time)
|
| + : packet(std::move(packet)), dequeue_time(dequeue_time) {}
|
| +
|
| +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
|
|
|