blob: 079b2286d40e6e79db0ce88b5d404309fb9cf97d [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/test_tools/packet_dropping_test_writer.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
QUICHE team5be974e2020-12-29 18:35:24 -05007#include "quic/core/quic_epoll_connection_helper.h"
8#include "quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05009
10namespace quic {
11namespace test {
12
bnced1fe4f2020-07-01 04:48:53 -070013// Every dropped packet must be followed by this number of succesfully written
14// packets. This is to avoid flaky test failures and timeouts, for example, in
15// case both the client and the server drop every other packet (which is
16// statistically possible even if drop percentage is less than 50%).
17const int32_t kMinSuccesfulWritesAfterPacketLoss = 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -050018
19// An alarm that is scheduled if a blocked socket is simulated to indicate
20// it's writable again.
wubf9e025b2021-09-01 07:53:35 -070021class WriteUnblockedAlarm : public QuicAlarm::DelegateWithoutContext {
QUICHE teama6ef0a62019-03-07 20:34:33 -050022 public:
23 explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
24 : writer_(writer) {}
25
26 void OnAlarm() override {
27 QUIC_DLOG(INFO) << "Unblocking socket.";
28 writer_->OnCanWrite();
29 }
30
31 private:
32 PacketDroppingTestWriter* writer_;
33};
34
35// An alarm that is scheduled every time a new packet is to be written at a
36// later point.
wubf9e025b2021-09-01 07:53:35 -070037class DelayAlarm : public QuicAlarm::DelegateWithoutContext {
QUICHE teama6ef0a62019-03-07 20:34:33 -050038 public:
39 explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
40
41 void OnAlarm() override {
42 QuicTime new_deadline = writer_->ReleaseOldPackets();
43 if (new_deadline.IsInitialized()) {
44 writer_->SetDelayAlarm(new_deadline);
45 }
46 }
47
48 private:
49 PacketDroppingTestWriter* writer_;
50};
51
52PacketDroppingTestWriter::PacketDroppingTestWriter()
53 : clock_(nullptr),
54 cur_buffer_size_(0),
55 num_calls_to_write_(0),
bnced1fe4f2020-07-01 04:48:53 -070056 // Do not require any number of successful writes before the first dropped
57 // packet.
58 num_consecutive_succesful_writes_(kMinSuccesfulWritesAfterPacketLoss),
QUICHE teama6ef0a62019-03-07 20:34:33 -050059 fake_packet_loss_percentage_(0),
60 fake_drop_first_n_packets_(0),
61 fake_blocked_socket_percentage_(0),
62 fake_packet_reorder_percentage_(0),
63 fake_packet_delay_(QuicTime::Delta::Zero()),
64 fake_bandwidth_(QuicBandwidth::Zero()),
bnced1fe4f2020-07-01 04:48:53 -070065 buffer_size_(0) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050066 uint64_t seed = QuicRandom::GetInstance()->RandUint64();
67 QUIC_LOG(INFO) << "Seeding packet loss with " << seed;
68 simple_random_.set_seed(seed);
69}
70
wubd44ad7c2021-08-02 15:16:59 -070071PacketDroppingTestWriter::~PacketDroppingTestWriter() {
72 if (write_unblocked_alarm_ != nullptr) {
73 write_unblocked_alarm_->PermanentCancel();
74 }
75 if (delay_alarm_ != nullptr) {
76 delay_alarm_->PermanentCancel();
77 }
78}
QUICHE teama6ef0a62019-03-07 20:34:33 -050079
80void PacketDroppingTestWriter::Initialize(
81 QuicConnectionHelperInterface* helper,
82 QuicAlarmFactory* alarm_factory,
83 std::unique_ptr<Delegate> on_can_write) {
84 clock_ = helper->GetClock();
85 write_unblocked_alarm_.reset(
86 alarm_factory->CreateAlarm(new WriteUnblockedAlarm(this)));
87 delay_alarm_.reset(alarm_factory->CreateAlarm(new DelayAlarm(this)));
88 on_can_write_ = std::move(on_can_write);
89}
90
91WriteResult PacketDroppingTestWriter::WritePacket(
92 const char* buffer,
93 size_t buf_len,
94 const QuicIpAddress& self_address,
95 const QuicSocketAddress& peer_address,
96 PerPacketOptions* options) {
97 ++num_calls_to_write_;
98 ReleaseOldPackets();
99
100 QuicWriterMutexLock lock(&config_mutex_);
101 if (fake_drop_first_n_packets_ > 0 &&
102 num_calls_to_write_ <=
103 static_cast<uint64_t>(fake_drop_first_n_packets_)) {
104 QUIC_DVLOG(1) << "Dropping first " << fake_drop_first_n_packets_
105 << " packets (packet number " << num_calls_to_write_ << ")";
bnced1fe4f2020-07-01 04:48:53 -0700106 num_consecutive_succesful_writes_ = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500107 return WriteResult(WRITE_STATUS_OK, buf_len);
108 }
bnced1fe4f2020-07-01 04:48:53 -0700109
110 // Drop every packet at 100%, otherwise always succeed for at least
111 // kMinSuccesfulWritesAfterPacketLoss packets between two dropped ones.
112 if (fake_packet_loss_percentage_ == 100 ||
113 (fake_packet_loss_percentage_ > 0 &&
114 num_consecutive_succesful_writes_ >=
115 kMinSuccesfulWritesAfterPacketLoss &&
116 (simple_random_.RandUint64() % 100 <
117 static_cast<uint64_t>(fake_packet_loss_percentage_)))) {
118 QUIC_DVLOG(1) << "Dropping packet " << num_calls_to_write_;
119 num_consecutive_succesful_writes_ = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 return WriteResult(WRITE_STATUS_OK, buf_len);
121 } else {
bnced1fe4f2020-07-01 04:48:53 -0700122 ++num_consecutive_succesful_writes_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123 }
bnced1fe4f2020-07-01 04:48:53 -0700124
QUICHE teama6ef0a62019-03-07 20:34:33 -0500125 if (fake_blocked_socket_percentage_ > 0 &&
126 simple_random_.RandUint64() % 100 <
127 static_cast<uint64_t>(fake_blocked_socket_percentage_)) {
vasilvvf8035162021-02-01 14:49:14 -0800128 QUICHE_CHECK(on_can_write_ != nullptr);
bnced1fe4f2020-07-01 04:48:53 -0700129 QUIC_DVLOG(1) << "Blocking socket for packet " << num_calls_to_write_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500130 if (!write_unblocked_alarm_->IsSet()) {
131 // Set the alarm to fire immediately.
132 write_unblocked_alarm_->Set(clock_->ApproximateNow());
133 }
bnced1fe4f2020-07-01 04:48:53 -0700134
135 // Dropping this packet on retry could result in PTO timeout,
136 // make sure to avoid this.
137 num_consecutive_succesful_writes_ = 0;
138
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
140 }
141
142 if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
143 if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
144 // Drop packets which do not fit into the buffer.
145 QUIC_DVLOG(1) << "Dropping packet because the buffer is full.";
146 return WriteResult(WRITE_STATUS_OK, buf_len);
147 }
148
149 // Queue it to be sent.
150 QuicTime send_time = clock_->ApproximateNow() + fake_packet_delay_;
151 if (!fake_bandwidth_.IsZero()) {
152 // Calculate a time the bandwidth limit would impose.
153 QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
154 (buf_len * kNumMicrosPerSecond) / fake_bandwidth_.ToBytesPerSecond());
155 send_time = delayed_packets_.empty()
156 ? send_time + bandwidth_delay
157 : delayed_packets_.back().send_time + bandwidth_delay;
158 }
159 std::unique_ptr<PerPacketOptions> delayed_options;
160 if (options != nullptr) {
161 delayed_options = options->Clone();
162 }
163 delayed_packets_.push_back(
164 DelayedWrite(buffer, buf_len, self_address, peer_address,
165 std::move(delayed_options), send_time));
166 cur_buffer_size_ += buf_len;
167
168 // Set the alarm if it's not yet set.
169 if (!delay_alarm_->IsSet()) {
170 delay_alarm_->Set(send_time);
171 }
172
173 return WriteResult(WRITE_STATUS_OK, buf_len);
174 }
175
176 return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address,
177 peer_address, options);
178}
179
180bool PacketDroppingTestWriter::IsWriteBlocked() const {
181 if (write_unblocked_alarm_ != nullptr && write_unblocked_alarm_->IsSet()) {
182 return true;
183 }
184 return QuicPacketWriterWrapper::IsWriteBlocked();
185}
186
187void PacketDroppingTestWriter::SetWritable() {
188 if (write_unblocked_alarm_ != nullptr && write_unblocked_alarm_->IsSet()) {
189 write_unblocked_alarm_->Cancel();
190 }
191 QuicPacketWriterWrapper::SetWritable();
192}
193
194QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
195 if (delayed_packets_.empty()) {
196 return QuicTime::Zero();
197 }
198 QuicReaderMutexLock lock(&config_mutex_);
199 auto iter = delayed_packets_.begin();
200 // Determine if we should re-order.
201 if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
202 simple_random_.RandUint64() % 100 <
203 static_cast<uint64_t>(fake_packet_reorder_percentage_)) {
204 QUIC_DLOG(INFO) << "Reordering packets.";
205 ++iter;
206 // Swap the send times when re-ordering packets.
207 delayed_packets_.begin()->send_time = iter->send_time;
208 }
209
210 QUIC_DVLOG(1) << "Releasing packet. " << (delayed_packets_.size() - 1)
211 << " remaining.";
212 // Grab the next one off the queue and send it.
213 QuicPacketWriterWrapper::WritePacket(
214 iter->buffer.data(), iter->buffer.length(), iter->self_address,
215 iter->peer_address, iter->options.get());
vasilvvf8035162021-02-01 14:49:14 -0800216 QUICHE_DCHECK_GE(cur_buffer_size_, iter->buffer.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500217 cur_buffer_size_ -= iter->buffer.length();
218 delayed_packets_.erase(iter);
219
220 // If there are others, find the time for the next to be sent.
221 if (delayed_packets_.empty()) {
222 return QuicTime::Zero();
223 }
224 return delayed_packets_.begin()->send_time;
225}
226
227QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
228 while (!delayed_packets_.empty()) {
229 QuicTime next_send_time = delayed_packets_.front().send_time;
230 if (next_send_time > clock_->Now()) {
231 return next_send_time;
232 }
233 ReleaseNextPacket();
234 }
235 return QuicTime::Zero();
236}
237
238void PacketDroppingTestWriter::SetDelayAlarm(QuicTime new_deadline) {
239 delay_alarm_->Set(new_deadline);
240}
241
242void PacketDroppingTestWriter::OnCanWrite() {
243 on_can_write_->OnCanWrite();
244}
245
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
247 const char* buffer,
248 size_t buf_len,
249 const QuicIpAddress& self_address,
250 const QuicSocketAddress& peer_address,
251 std::unique_ptr<PerPacketOptions> options,
252 QuicTime send_time)
253 : buffer(buffer, buf_len),
254 self_address(self_address),
255 peer_address(peer_address),
256 options(std::move(options)),
257 send_time(send_time) {}
258
259PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() = default;
260
261} // namespace test
262} // namespace quic