1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ 6 #define QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ 7 8 #include <cstdint> 9 #include <list> 10 #include <memory> 11 12 #include "absl/base/attributes.h" 13 #include "quiche/quic/core/quic_alarm.h" 14 #include "quiche/quic/core/quic_alarm_factory.h" 15 #include "quiche/quic/core/quic_clock.h" 16 #include "quiche/quic/core/quic_connection.h" 17 #include "quiche/quic/core/quic_packet_writer_wrapper.h" 18 #include "quiche/quic/platform/api/quic_mutex.h" 19 #include "quiche/quic/test_tools/quic_test_utils.h" 20 21 namespace quic { 22 namespace test { 23 24 // Simulates a connection that drops packets a configured percentage of the time 25 // and has a blocked socket a configured percentage of the time. Also provides 26 // the options to delay packets and reorder packets if delay is enabled. 27 class PacketDroppingTestWriter : public QuicPacketWriterWrapper { 28 public: 29 class Delegate { 30 public: ~Delegate()31 virtual ~Delegate() {} 32 virtual void OnCanWrite() = 0; 33 }; 34 35 PacketDroppingTestWriter(); 36 PacketDroppingTestWriter(const PacketDroppingTestWriter&) = delete; 37 PacketDroppingTestWriter& operator=(const PacketDroppingTestWriter&) = delete; 38 39 ~PacketDroppingTestWriter() override; 40 41 // Must be called before blocking, reordering or delaying (loss is OK). May be 42 // called after connecting if the helper is not available before. 43 // |on_can_write| will be triggered when fake-unblocking. 44 void Initialize(QuicConnectionHelperInterface* helper, 45 QuicAlarmFactory* alarm_factory, 46 std::unique_ptr<Delegate> on_can_write); 47 48 // QuicPacketWriter methods: 49 WriteResult WritePacket(const char* buffer, size_t buf_len, 50 const QuicIpAddress& self_address, 51 const QuicSocketAddress& peer_address, 52 PerPacketOptions* options) override; 53 54 bool IsWriteBlocked() const override; 55 56 void SetWritable() override; 57 GetNextWriteLocation(const QuicIpAddress &,const QuicSocketAddress &)58 QuicPacketBuffer GetNextWriteLocation( 59 const QuicIpAddress& /*self_address*/, 60 const QuicSocketAddress& /*peer_address*/) override { 61 // If the wrapped writer supports zero-copy, disable it, because it is not 62 // compatible with delayed writes in this class. 63 return {nullptr, nullptr}; 64 } 65 66 // Writes out any packet which should have been sent by now 67 // to the contained writer and returns the time 68 // for the next delayed packet to be written. 69 QuicTime ReleaseOldPackets(); 70 71 // Sets |delay_alarm_| to fire at |new_deadline|. 72 void SetDelayAlarm(QuicTime new_deadline); 73 74 void OnCanWrite(); 75 76 // The percent of time a packet is simulated as being lost. 77 // If |fake_packet_loss_percentage| is 100, then all packages are lost. 78 // Otherwise actual percentage will be lower than 79 // |fake_packet_loss_percentage|, because every dropped package is followed by 80 // a minimum number of successfully written packets. set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage)81 void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) { 82 QuicWriterMutexLock lock(&config_mutex_); 83 fake_packet_loss_percentage_ = fake_packet_loss_percentage; 84 } 85 86 // Simulate dropping the first n packets unconditionally. 87 // Subsequent packets will be lost at fake_packet_loss_percentage_ if set. set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets)88 void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) { 89 QuicWriterMutexLock lock(&config_mutex_); 90 fake_drop_first_n_packets_ = fake_drop_first_n_packets; 91 } 92 93 // The percent of time WritePacket will block and set WriteResult's status 94 // to WRITE_STATUS_BLOCKED. set_fake_blocked_socket_percentage(int32_t fake_blocked_socket_percentage)95 void set_fake_blocked_socket_percentage( 96 int32_t fake_blocked_socket_percentage) { 97 QUICHE_DCHECK(clock_); 98 QuicWriterMutexLock lock(&config_mutex_); 99 fake_blocked_socket_percentage_ = fake_blocked_socket_percentage; 100 } 101 102 // The percent of time a packet is simulated as being reordered. set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage)103 void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) { 104 QUICHE_DCHECK(clock_); 105 QuicWriterMutexLock lock(&config_mutex_); 106 QUICHE_DCHECK(!fake_packet_delay_.IsZero()); 107 fake_packet_reorder_percentage_ = fake_packet_reorder_percentage; 108 } 109 110 // The delay before writing this packet. set_fake_packet_delay(QuicTime::Delta fake_packet_delay)111 void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) { 112 QUICHE_DCHECK(clock_); 113 QuicWriterMutexLock lock(&config_mutex_); 114 fake_packet_delay_ = fake_packet_delay; 115 } 116 117 // The maximum bandwidth and buffer size of the connection. When these are 118 // set, packets will be delayed until a connection with that bandwidth would 119 // transmit it. Once the |buffer_size| is reached, all new packets are 120 // dropped. set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,QuicByteCount buffer_size)121 void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth, 122 QuicByteCount buffer_size) { 123 QUICHE_DCHECK(clock_); 124 QuicWriterMutexLock lock(&config_mutex_); 125 fake_bandwidth_ = fake_bandwidth; 126 buffer_size_ = buffer_size; 127 } 128 129 // Useful for reproducing very flaky issues. set_seed(uint64_t seed)130 ABSL_ATTRIBUTE_UNUSED void set_seed(uint64_t seed) { 131 simple_random_.set_seed(seed); 132 } 133 134 private: 135 // Writes out the next packet to the contained writer and returns the time 136 // for the next delayed packet to be written. 137 QuicTime ReleaseNextPacket(); 138 139 // A single packet which will be sent at the supplied send_time. 140 struct DelayedWrite { 141 public: 142 DelayedWrite(const char* buffer, size_t buf_len, 143 const QuicIpAddress& self_address, 144 const QuicSocketAddress& peer_address, 145 std::unique_ptr<PerPacketOptions> options, QuicTime send_time); 146 DelayedWrite(const DelayedWrite&) = delete; 147 DelayedWrite(DelayedWrite&&) = default; 148 DelayedWrite& operator=(const DelayedWrite&) = delete; 149 DelayedWrite& operator=(DelayedWrite&&) = default; 150 ~DelayedWrite(); 151 152 std::string buffer; 153 QuicIpAddress self_address; 154 QuicSocketAddress peer_address; 155 std::unique_ptr<PerPacketOptions> options; 156 QuicTime send_time; 157 }; 158 159 using DelayedPacketList = std::list<DelayedWrite>; 160 161 const QuicClock* clock_; 162 std::unique_ptr<QuicAlarm> write_unblocked_alarm_; 163 std::unique_ptr<QuicAlarm> delay_alarm_; 164 std::unique_ptr<Delegate> on_can_write_; 165 SimpleRandom simple_random_; 166 // Stored packets delayed by fake packet delay or bandwidth restrictions. 167 DelayedPacketList delayed_packets_; 168 QuicByteCount cur_buffer_size_; 169 uint64_t num_calls_to_write_; 170 int32_t num_consecutive_succesful_writes_; 171 172 QuicMutex config_mutex_; 173 int32_t fake_packet_loss_percentage_ QUIC_GUARDED_BY(config_mutex_); 174 int32_t fake_drop_first_n_packets_ QUIC_GUARDED_BY(config_mutex_); 175 int32_t fake_blocked_socket_percentage_ QUIC_GUARDED_BY(config_mutex_); 176 int32_t fake_packet_reorder_percentage_ QUIC_GUARDED_BY(config_mutex_); 177 QuicTime::Delta fake_packet_delay_ QUIC_GUARDED_BY(config_mutex_); 178 QuicBandwidth fake_bandwidth_ QUIC_GUARDED_BY(config_mutex_); 179 QuicByteCount buffer_size_ QUIC_GUARDED_BY(config_mutex_); 180 }; 181 182 } // namespace test 183 } // namespace quic 184 185 #endif // QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ 186