summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
blob: c15b5de01b5c89dfecace107c282d36967be9644 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 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 "absl/base/attributes.h"
#include "quic/core/quic_alarm.h"
#include "quic/core/quic_clock.h"
#include "quic/core/quic_packet_writer_wrapper.h"
#include "quic/test_tools/quic_test_client.h"
#include "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;

  QuicPacketBuffer 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, 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.
  // If |fake_packet_loss_percentage| is 100, then all packages are lost.
  // Otherwise actual percentage will be lower than
  // |fake_packet_loss_percentage|, because every dropped package is followed by
  // a minimum number of successfully written packets.
  void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) {
    QuicWriterMutexLock lock(&config_mutex_);
    fake_packet_loss_percentage_ = 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) {
    QUICHE_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) {
    QUICHE_DCHECK(clock_);
    QuicWriterMutexLock lock(&config_mutex_);
    QUICHE_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) {
    QUICHE_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) {
    QUICHE_DCHECK(clock_);
    QuicWriterMutexLock lock(&config_mutex_);
    fake_bandwidth_ = fake_bandwidth;
    buffer_size_ = buffer_size;
  }

  // Useful for reproducing very flaky issues.
  ABSL_ATTRIBUTE_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;
  };

  using DelayedPacketList = std::list<DelayedWrite>;

  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_;
  int32_t num_consecutive_succesful_writes_;

  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_);
};

}  // namespace test
}  // namespace quic

#endif  // QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_