| // 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_QUEUE_H_ | 
 | #define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_ | 
 |  | 
 | #include "quic/core/quic_alarm.h" | 
 | #include "quic/test_tools/simulator/link.h" | 
 | #include "common/quiche_circular_deque.h" | 
 |  | 
 | namespace quic { | 
 | namespace simulator { | 
 |  | 
 | // A finitely sized queue which egresses packets onto a constrained link.  The | 
 | // capacity of the queue is measured in bytes as opposed to packets. | 
 | class Queue : public Actor, public UnconstrainedPortInterface { | 
 |  public: | 
 |   class ListenerInterface { | 
 |    public: | 
 |     virtual ~ListenerInterface(); | 
 |  | 
 |     // Called whenever a packet is removed from the queue. | 
 |     virtual void OnPacketDequeued() = 0; | 
 |   }; | 
 |  | 
 |   Queue(Simulator* simulator, std::string name, QuicByteCount capacity); | 
 |   Queue(const Queue&) = delete; | 
 |   Queue& operator=(const Queue&) = delete; | 
 |   ~Queue() override; | 
 |  | 
 |   void set_tx_port(ConstrainedPortInterface* port); | 
 |  | 
 |   void AcceptPacket(std::unique_ptr<Packet> packet) override; | 
 |  | 
 |   void Act() override; | 
 |  | 
 |   inline QuicByteCount capacity() const { return capacity_; } | 
 |   inline QuicByteCount bytes_queued() const { return bytes_queued_; } | 
 |   inline QuicPacketCount packets_queued() const { return queue_.size(); } | 
 |  | 
 |   inline void set_listener_interface(ListenerInterface* listener) { | 
 |     listener_ = listener; | 
 |   } | 
 |  | 
 |   // Enables packet aggregation on the queue.  Packet aggregation makes the | 
 |   // queue bundle packets up until they reach certain size.  When the | 
 |   // aggregation is enabled, the packets are not dequeued until the total size | 
 |   // of packets in the queue reaches |aggregation_threshold|.  The packets are | 
 |   // automatically flushed from the queue if the oldest packet has been in it | 
 |   // for |aggregation_timeout|. | 
 |   // | 
 |   // This method may only be called when the queue is empty.  Once enabled, | 
 |   // aggregation cannot be disabled. | 
 |   void EnableAggregation(QuicByteCount aggregation_threshold, | 
 |                          QuicTime::Delta aggregation_timeout); | 
 |  | 
 |  private: | 
 |   using AggregationBundleNumber = uint64_t; | 
 |  | 
 |   // In order to implement packet aggregation, each packet is tagged with a | 
 |   // bundle number.  The queue keeps a bundle counter, and whenever a bundle is | 
 |   // ready, it increments the number of the current bundle.  Only the packets | 
 |   // outside of the current bundle are allowed to leave the queue. | 
 |   struct EnqueuedPacket { | 
 |     EnqueuedPacket(std::unique_ptr<Packet> packet, | 
 |                    AggregationBundleNumber bundle); | 
 |     EnqueuedPacket(EnqueuedPacket&& other); | 
 |     ~EnqueuedPacket(); | 
 |  | 
 |     std::unique_ptr<Packet> packet; | 
 |     AggregationBundleNumber bundle; | 
 |   }; | 
 |  | 
 |   // Alarm handler for aggregation timeout. | 
 |   class AggregationAlarmDelegate : public QuicAlarm::DelegateWithoutContext { | 
 |    public: | 
 |     explicit AggregationAlarmDelegate(Queue* queue); | 
 |  | 
 |     void OnAlarm() override; | 
 |  | 
 |    private: | 
 |     Queue* queue_; | 
 |   }; | 
 |  | 
 |   inline bool IsAggregationEnabled() const { | 
 |     return aggregation_threshold_ > 0; | 
 |   } | 
 |  | 
 |   // Increment the bundle counter and reset the bundle state.  This causes all | 
 |   // packets currently in the bundle to be flushed onto the link. | 
 |   void NextBundle(); | 
 |  | 
 |   void ScheduleNextPacketDequeue(); | 
 |  | 
 |   const QuicByteCount capacity_; | 
 |   QuicByteCount bytes_queued_; | 
 |  | 
 |   QuicByteCount aggregation_threshold_; | 
 |   QuicTime::Delta aggregation_timeout_; | 
 |   // The number of the current aggregation bundle.  Monotonically increasing. | 
 |   // All packets in the previous bundles are allowed to leave the queue, and | 
 |   // none of the packets in the current one are. | 
 |   AggregationBundleNumber current_bundle_; | 
 |   // Size of the current bundle.  Whenever it exceeds |aggregation_threshold_|, | 
 |   // the next bundle is created. | 
 |   QuicByteCount current_bundle_bytes_; | 
 |   // Alarm responsible for flushing the current bundle upon timeout.  Set when | 
 |   // the first packet in the bundle is enqueued. | 
 |   std::unique_ptr<QuicAlarm> aggregation_timeout_alarm_; | 
 |  | 
 |   ConstrainedPortInterface* tx_port_; | 
 |   quiche::QuicheCircularDeque<EnqueuedPacket> queue_; | 
 |  | 
 |   ListenerInterface* listener_; | 
 | }; | 
 |  | 
 | }  // namespace simulator | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_ |