| // 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. | 
 |  | 
 | #ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_ | 
 | #define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_ | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "quic/core/crypto/quic_random.h" | 
 | #include "quic/core/quic_bandwidth.h" | 
 | #include "quic/test_tools/simulator/actor.h" | 
 | #include "quic/test_tools/simulator/port.h" | 
 | #include "common/quiche_circular_deque.h" | 
 |  | 
 | namespace quic { | 
 | namespace simulator { | 
 |  | 
 | // A reliable simplex link between two endpoints with constrained bandwidth.  A | 
 | // few microseconds of random delay are added for every packet to avoid | 
 | // synchronization issues. | 
 | class OneWayLink : public Actor, public ConstrainedPortInterface { | 
 |  public: | 
 |   OneWayLink(Simulator* simulator, | 
 |              std::string name, | 
 |              UnconstrainedPortInterface* sink, | 
 |              QuicBandwidth bandwidth, | 
 |              QuicTime::Delta propagation_delay); | 
 |   OneWayLink(const OneWayLink&) = delete; | 
 |   OneWayLink& operator=(const OneWayLink&) = delete; | 
 |   ~OneWayLink() override; | 
 |  | 
 |   void AcceptPacket(std::unique_ptr<Packet> packet) override; | 
 |   QuicTime::Delta TimeUntilAvailable() override; | 
 |   void Act() override; | 
 |  | 
 |   inline QuicBandwidth bandwidth() const { return bandwidth_; } | 
 |   inline void set_bandwidth(QuicBandwidth new_bandwidth) { | 
 |     bandwidth_ = new_bandwidth; | 
 |   } | 
 |  | 
 |  protected: | 
 |   // Get the value of a random delay imposed on each packet.  By default, this | 
 |   // is a short random delay in order to avoid artifical synchronization | 
 |   // artifacts during the simulation.  Subclasses may override this behavior | 
 |   // (for example, to provide a random component of delay). | 
 |   virtual QuicTime::Delta GetRandomDelay(QuicTime::Delta transfer_time); | 
 |  | 
 |  private: | 
 |   struct QueuedPacket { | 
 |     std::unique_ptr<Packet> packet; | 
 |     QuicTime dequeue_time; | 
 |  | 
 |     QueuedPacket(std::unique_ptr<Packet> packet, QuicTime dequeue_time); | 
 |     QueuedPacket(QueuedPacket&& other); | 
 |     ~QueuedPacket(); | 
 |   }; | 
 |  | 
 |   // Schedule the next packet to be egressed out of the link if there are | 
 |   // packets on the link. | 
 |   void ScheduleNextPacketDeparture(); | 
 |  | 
 |   UnconstrainedPortInterface* sink_; | 
 |   quiche::QuicheCircularDeque<QueuedPacket> packets_in_transit_; | 
 |  | 
 |   QuicBandwidth bandwidth_; | 
 |   const QuicTime::Delta propagation_delay_; | 
 |  | 
 |   QuicTime next_write_at_; | 
 | }; | 
 |  | 
 | // A full-duplex link between two endpoints, functionally equivalent to two | 
 | // OneWayLink objects tied together. | 
 | class SymmetricLink { | 
 |  public: | 
 |   SymmetricLink(Simulator* simulator, | 
 |                 std::string name, | 
 |                 UnconstrainedPortInterface* sink_a, | 
 |                 UnconstrainedPortInterface* sink_b, | 
 |                 QuicBandwidth bandwidth, | 
 |                 QuicTime::Delta propagation_delay); | 
 |   SymmetricLink(Endpoint* endpoint_a, | 
 |                 Endpoint* endpoint_b, | 
 |                 QuicBandwidth bandwidth, | 
 |                 QuicTime::Delta propagation_delay); | 
 |   SymmetricLink(const SymmetricLink&) = delete; | 
 |   SymmetricLink& operator=(const SymmetricLink&) = delete; | 
 |  | 
 |   inline QuicBandwidth bandwidth() { return a_to_b_link_.bandwidth(); } | 
 |   inline void set_bandwidth(QuicBandwidth new_bandwidth) { | 
 |     a_to_b_link_.set_bandwidth(new_bandwidth); | 
 |     b_to_a_link_.set_bandwidth(new_bandwidth); | 
 |   } | 
 |  | 
 |  private: | 
 |   OneWayLink a_to_b_link_; | 
 |   OneWayLink b_to_a_link_; | 
 | }; | 
 |  | 
 | }  // namespace simulator | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_ |