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,
53                           const QuicPacketWriterParams& params) override;
54 
55   bool IsWriteBlocked() const override;
56 
57   void SetWritable() override;
58 
GetNextWriteLocation(const QuicIpAddress &,const QuicSocketAddress &)59   QuicPacketBuffer GetNextWriteLocation(
60       const QuicIpAddress& /*self_address*/,
61       const QuicSocketAddress& /*peer_address*/) override {
62     // If the wrapped writer supports zero-copy, disable it, because it is not
63     // compatible with delayed writes in this class.
64     return {nullptr, nullptr};
65   }
66 
67   // Writes out any packet which should have been sent by now
68   // to the contained writer and returns the time
69   // for the next delayed packet to be written.
70   QuicTime ReleaseOldPackets();
71 
72   // Sets |delay_alarm_| to fire at |new_deadline|.
73   void SetDelayAlarm(QuicTime new_deadline);
74 
75   void OnCanWrite();
76 
77   // The percent of time a packet is simulated as being lost.
78   // If |fake_packet_loss_percentage| is 100, then all packages are lost.
79   // Otherwise actual percentage will be lower than
80   // |fake_packet_loss_percentage|, because every dropped package is followed by
81   // a minimum number of successfully written packets.
set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage)82   void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) {
83     QuicWriterMutexLock lock(&config_mutex_);
84     fake_packet_loss_percentage_ = fake_packet_loss_percentage;
85   }
86 
87   // Once called, the next |passthrough_for_next_n_packets_| WritePacket() calls
88   // will always send the packets immediately, without being affected by the
89   // simulated error conditions.
set_passthrough_for_next_n_packets(uint32_t passthrough_for_next_n_packets)90   void set_passthrough_for_next_n_packets(
91       uint32_t passthrough_for_next_n_packets) {
92     QuicWriterMutexLock lock(&config_mutex_);
93     passthrough_for_next_n_packets_ = passthrough_for_next_n_packets;
94   }
95 
96   // Simulate dropping the first n packets unconditionally.
97   // 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)98   void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) {
99     QuicWriterMutexLock lock(&config_mutex_);
100     fake_drop_first_n_packets_ = fake_drop_first_n_packets;
101   }
102 
103   // The percent of time WritePacket will block and set WriteResult's status
104   // to WRITE_STATUS_BLOCKED.
set_fake_blocked_socket_percentage(int32_t fake_blocked_socket_percentage)105   void set_fake_blocked_socket_percentage(
106       int32_t fake_blocked_socket_percentage) {
107     QUICHE_DCHECK(clock_);
108     QuicWriterMutexLock lock(&config_mutex_);
109     fake_blocked_socket_percentage_ = fake_blocked_socket_percentage;
110   }
111 
112   // The percent of time a packet is simulated as being reordered.
set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage)113   void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) {
114     QUICHE_DCHECK(clock_);
115     QuicWriterMutexLock lock(&config_mutex_);
116     QUICHE_DCHECK(!fake_packet_delay_.IsZero());
117     fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
118   }
119 
120   // The delay before writing this packet.
set_fake_packet_delay(QuicTime::Delta fake_packet_delay)121   void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
122     QUICHE_DCHECK(clock_);
123     QuicWriterMutexLock lock(&config_mutex_);
124     fake_packet_delay_ = fake_packet_delay;
125   }
126 
127   // The maximum bandwidth and buffer size of the connection.  When these are
128   // set, packets will be delayed until a connection with that bandwidth would
129   // transmit it.  Once the |buffer_size| is reached, all new packets are
130   // dropped.
set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,QuicByteCount buffer_size)131   void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,
132                                          QuicByteCount buffer_size) {
133     QUICHE_DCHECK(clock_);
134     QuicWriterMutexLock lock(&config_mutex_);
135     fake_bandwidth_ = fake_bandwidth;
136     buffer_size_ = buffer_size;
137   }
138 
139   // Useful for reproducing very flaky issues.
set_seed(uint64_t seed)140   ABSL_ATTRIBUTE_UNUSED void set_seed(uint64_t seed) {
141     simple_random_.set_seed(seed);
142   }
143 
144  private:
145   // Writes out the next packet to the contained writer and returns the time
146   // for the next delayed packet to be written.
147   QuicTime ReleaseNextPacket();
148 
149   // A single packet which will be sent at the supplied send_time.
150   struct DelayedWrite {
151    public:
152     DelayedWrite(const char* buffer, size_t buf_len,
153                  const QuicIpAddress& self_address,
154                  const QuicSocketAddress& peer_address,
155                  std::unique_ptr<PerPacketOptions> options,
156                  const QuicPacketWriterParams& params, QuicTime send_time);
157     DelayedWrite(const DelayedWrite&) = delete;
158     DelayedWrite(DelayedWrite&&) = default;
159     DelayedWrite& operator=(const DelayedWrite&) = delete;
160     DelayedWrite& operator=(DelayedWrite&&) = default;
161     ~DelayedWrite();
162 
163     std::string buffer;
164     QuicIpAddress self_address;
165     QuicSocketAddress peer_address;
166     std::unique_ptr<PerPacketOptions> options;
167     QuicPacketWriterParams params;
168     QuicTime send_time;
169   };
170 
171   using DelayedPacketList = std::list<DelayedWrite>;
172 
173   const QuicClock* clock_;
174   std::unique_ptr<QuicAlarm> write_unblocked_alarm_;
175   std::unique_ptr<QuicAlarm> delay_alarm_;
176   std::unique_ptr<Delegate> on_can_write_;
177   SimpleRandom simple_random_;
178   // Stored packets delayed by fake packet delay or bandwidth restrictions.
179   DelayedPacketList delayed_packets_;
180   QuicByteCount cur_buffer_size_;
181   uint64_t num_calls_to_write_;
182   uint32_t passthrough_for_next_n_packets_ QUIC_GUARDED_BY(config_mutex_);
183   int32_t num_consecutive_succesful_writes_;
184 
185   QuicMutex config_mutex_;
186   int32_t fake_packet_loss_percentage_ QUIC_GUARDED_BY(config_mutex_);
187   int32_t fake_drop_first_n_packets_ QUIC_GUARDED_BY(config_mutex_);
188   int32_t fake_blocked_socket_percentage_ QUIC_GUARDED_BY(config_mutex_);
189   int32_t fake_packet_reorder_percentage_ QUIC_GUARDED_BY(config_mutex_);
190   QuicTime::Delta fake_packet_delay_ QUIC_GUARDED_BY(config_mutex_);
191   QuicBandwidth fake_bandwidth_ QUIC_GUARDED_BY(config_mutex_);
192   QuicByteCount buffer_size_ QUIC_GUARDED_BY(config_mutex_);
193 };
194 
195 }  // namespace test
196 }  // namespace quic
197 
198 #endif  // QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
199