| // Copyright 2013 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_PACKET_DROPPING_TEST_WRITER_H_ | 
 | #define QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ | 
 |  | 
 | #include <cstdint> | 
 | #include <list> | 
 | #include <memory> | 
 |  | 
 | #include "net/third_party/quiche/src/quic/core/quic_alarm.h" | 
 | #include "net/third_party/quiche/src/quic/core/quic_clock.h" | 
 | #include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" | 
 | #include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h" | 
 | #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" | 
 |  | 
 | namespace quic { | 
 | namespace test { | 
 |  | 
 | // Simulates a connection that drops packets a configured percentage of the time | 
 | // and has a blocked socket a configured percentage of the time.  Also provides | 
 | // the options to delay packets and reorder packets if delay is enabled. | 
 | class PacketDroppingTestWriter : public QuicPacketWriterWrapper { | 
 |  public: | 
 |   class Delegate { | 
 |    public: | 
 |     virtual ~Delegate() {} | 
 |     virtual void OnCanWrite() = 0; | 
 |   }; | 
 |  | 
 |   PacketDroppingTestWriter(); | 
 |   PacketDroppingTestWriter(const PacketDroppingTestWriter&) = delete; | 
 |   PacketDroppingTestWriter& operator=(const PacketDroppingTestWriter&) = delete; | 
 |  | 
 |   ~PacketDroppingTestWriter() override; | 
 |  | 
 |   // Must be called before blocking, reordering or delaying (loss is OK). May be | 
 |   // called after connecting if the helper is not available before. | 
 |   // |on_can_write| will be triggered when fake-unblocking. | 
 |   void Initialize(QuicConnectionHelperInterface* helper, | 
 |                   QuicAlarmFactory* alarm_factory, | 
 |                   std::unique_ptr<Delegate> on_can_write); | 
 |  | 
 |   // QuicPacketWriter methods: | 
 |   WriteResult WritePacket(const char* buffer, | 
 |                           size_t buf_len, | 
 |                           const QuicIpAddress& self_address, | 
 |                           const QuicSocketAddress& peer_address, | 
 |                           PerPacketOptions* options) override; | 
 |  | 
 |   bool IsWriteBlocked() const override; | 
 |  | 
 |   void SetWritable() override; | 
 |  | 
 |   char* GetNextWriteLocation( | 
 |       const QuicIpAddress& /*self_address*/, | 
 |       const QuicSocketAddress& /*peer_address*/) override { | 
 |     // If the wrapped writer supports zero-copy, disable it, because it is not | 
 |     // compatible with delayed writes in this class. | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Writes out any packet which should have been sent by now | 
 |   // to the contained writer and returns the time | 
 |   // for the next delayed packet to be written. | 
 |   QuicTime ReleaseOldPackets(); | 
 |  | 
 |   // Sets |delay_alarm_| to fire at |new_deadline|. | 
 |   void SetDelayAlarm(QuicTime new_deadline); | 
 |  | 
 |   void OnCanWrite(); | 
 |  | 
 |   // The percent of time a packet is simulated as being lost. | 
 |   void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage); | 
 |  | 
 |   // Simulate dropping the first n packets unconditionally. | 
 |   // Subsequent packets will be lost at fake_packet_loss_percentage_ if set. | 
 |   void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) { | 
 |     QuicWriterMutexLock lock(&config_mutex_); | 
 |     fake_drop_first_n_packets_ = fake_drop_first_n_packets; | 
 |   } | 
 |  | 
 |   // The percent of time WritePacket will block and set WriteResult's status | 
 |   // to WRITE_STATUS_BLOCKED. | 
 |   void set_fake_blocked_socket_percentage( | 
 |       int32_t fake_blocked_socket_percentage) { | 
 |     DCHECK(clock_); | 
 |     QuicWriterMutexLock lock(&config_mutex_); | 
 |     fake_blocked_socket_percentage_ = fake_blocked_socket_percentage; | 
 |   } | 
 |  | 
 |   // The percent of time a packet is simulated as being reordered. | 
 |   void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) { | 
 |     DCHECK(clock_); | 
 |     QuicWriterMutexLock lock(&config_mutex_); | 
 |     DCHECK(!fake_packet_delay_.IsZero()); | 
 |     fake_packet_reorder_percentage_ = fake_packet_reorder_percentage; | 
 |   } | 
 |  | 
 |   // The delay before writing this packet. | 
 |   void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) { | 
 |     DCHECK(clock_); | 
 |     QuicWriterMutexLock lock(&config_mutex_); | 
 |     fake_packet_delay_ = fake_packet_delay; | 
 |   } | 
 |  | 
 |   // The maximum bandwidth and buffer size of the connection.  When these are | 
 |   // set, packets will be delayed until a connection with that bandwidth would | 
 |   // transmit it.  Once the |buffer_size| is reached, all new packets are | 
 |   // dropped. | 
 |   void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth, | 
 |                                          QuicByteCount buffer_size) { | 
 |     DCHECK(clock_); | 
 |     QuicWriterMutexLock lock(&config_mutex_); | 
 |     fake_bandwidth_ = fake_bandwidth; | 
 |     buffer_size_ = buffer_size; | 
 |   } | 
 |  | 
 |   // Useful for reproducing very flaky issues. | 
 |   QUIC_UNUSED void set_seed(uint64_t seed) { simple_random_.set_seed(seed); } | 
 |  | 
 |  private: | 
 |   // Writes out the next packet to the contained writer and returns the time | 
 |   // for the next delayed packet to be written. | 
 |   QuicTime ReleaseNextPacket(); | 
 |  | 
 |   // A single packet which will be sent at the supplied send_time. | 
 |   struct DelayedWrite { | 
 |    public: | 
 |     DelayedWrite(const char* buffer, | 
 |                  size_t buf_len, | 
 |                  const QuicIpAddress& self_address, | 
 |                  const QuicSocketAddress& peer_address, | 
 |                  std::unique_ptr<PerPacketOptions> options, | 
 |                  QuicTime send_time); | 
 |     DelayedWrite(const DelayedWrite&) = delete; | 
 |     DelayedWrite(DelayedWrite&&) = default; | 
 |     DelayedWrite& operator=(const DelayedWrite&) = delete; | 
 |     DelayedWrite& operator=(DelayedWrite&&) = default; | 
 |     ~DelayedWrite(); | 
 |  | 
 |     std::string buffer; | 
 |     QuicIpAddress self_address; | 
 |     QuicSocketAddress peer_address; | 
 |     std::unique_ptr<PerPacketOptions> options; | 
 |     QuicTime send_time; | 
 |   }; | 
 |  | 
 |   typedef std::list<DelayedWrite> DelayedPacketList; | 
 |  | 
 |   const QuicClock* clock_; | 
 |   std::unique_ptr<QuicAlarm> write_unblocked_alarm_; | 
 |   std::unique_ptr<QuicAlarm> delay_alarm_; | 
 |   std::unique_ptr<Delegate> on_can_write_; | 
 |   SimpleRandom simple_random_; | 
 |   // Stored packets delayed by fake packet delay or bandwidth restrictions. | 
 |   DelayedPacketList delayed_packets_; | 
 |   QuicByteCount cur_buffer_size_; | 
 |   uint64_t num_calls_to_write_; | 
 |  | 
 |   QuicMutex config_mutex_; | 
 |   int32_t fake_packet_loss_percentage_ QUIC_GUARDED_BY(config_mutex_); | 
 |   int32_t fake_drop_first_n_packets_ QUIC_GUARDED_BY(config_mutex_); | 
 |   int32_t fake_blocked_socket_percentage_ QUIC_GUARDED_BY(config_mutex_); | 
 |   int32_t fake_packet_reorder_percentage_ QUIC_GUARDED_BY(config_mutex_); | 
 |   QuicTime::Delta fake_packet_delay_ QUIC_GUARDED_BY(config_mutex_); | 
 |   QuicBandwidth fake_bandwidth_ QUIC_GUARDED_BY(config_mutex_); | 
 |   QuicByteCount buffer_size_ QUIC_GUARDED_BY(config_mutex_); | 
 |   int32_t num_consecutive_packet_lost_ QUIC_GUARDED_BY(config_mutex_); | 
 | }; | 
 |  | 
 | }  // namespace test | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ |