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.
5 #include "net/tools/quic/test_tools/packet_dropping_test_writer.h"
9 #include "base/rand_util.h"
10 #include "net/tools/quic/quic_epoll_connection_helper.h"
11 #include "net/tools/quic/quic_socket_utils.h"
17 // An alarm that is scheduled if a blocked socket is simulated to indicate
18 // it's writable again.
19 class WriteUnblockedAlarm
: public QuicAlarm::Delegate
{
21 explicit WriteUnblockedAlarm(PacketDroppingTestWriter
* writer
)
24 virtual QuicTime
OnAlarm() OVERRIDE
{
25 DVLOG(1) << "Unblocking socket.";
26 writer_
->OnCanWrite();
27 return QuicTime::Zero();
31 PacketDroppingTestWriter
* writer_
;
34 // An alarm that is scheduled every time a new packet is to be written at a
36 class DelayAlarm
: public QuicAlarm::Delegate
{
38 explicit DelayAlarm(PacketDroppingTestWriter
* writer
) : writer_(writer
) {}
40 virtual QuicTime
OnAlarm() OVERRIDE
{
41 return writer_
->ReleaseOldPackets();
45 PacketDroppingTestWriter
* writer_
;
48 PacketDroppingTestWriter::PacketDroppingTestWriter()
52 fake_packet_loss_percentage_(0),
53 fake_blocked_socket_percentage_(0),
54 fake_packet_reorder_percentage_(0),
55 fake_packet_delay_(QuicTime::Delta::Zero()),
56 fake_bandwidth_(QuicBandwidth::Zero()),
58 uint32 seed
= base::RandInt(0, std::numeric_limits
<int32
>::max());
59 VLOG(1) << "Seeding packet loss with " << seed
;
60 simple_random_
.set_seed(seed
);
63 PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
65 void PacketDroppingTestWriter::Initialize(
66 QuicEpollConnectionHelper
* helper
,
67 Delegate
* on_can_write
) {
68 clock_
= helper
->GetClock();
69 write_unblocked_alarm_
.reset(
70 helper
->CreateAlarm(new WriteUnblockedAlarm(this)));
72 helper
->CreateAlarm(new DelayAlarm(this)));
73 on_can_write_
.reset(on_can_write
);
76 WriteResult
PacketDroppingTestWriter::WritePacket(
79 const net::IPAddressNumber
& self_address
,
80 const net::IPEndPoint
& peer_address
) {
83 base::AutoLock
locked(config_mutex_
);
84 if (fake_packet_loss_percentage_
> 0 &&
85 simple_random_
.RandUint64() % 100 <
86 static_cast<uint64
>(fake_packet_loss_percentage_
)) {
87 DVLOG(1) << "Dropping packet.";
88 return WriteResult(WRITE_STATUS_OK
, buf_len
);
90 if (fake_blocked_socket_percentage_
> 0 &&
91 simple_random_
.RandUint64() % 100 <
92 static_cast<uint64
>(fake_blocked_socket_percentage_
)) {
93 CHECK(on_can_write_
.get() != NULL
);
94 DVLOG(1) << "Blocking socket.";
95 if (!write_unblocked_alarm_
->IsSet()) {
96 // Set the alarm to fire immediately.
97 write_unblocked_alarm_
->Set(clock_
->ApproximateNow());
99 return WriteResult(WRITE_STATUS_BLOCKED
, EAGAIN
);
102 if (!fake_packet_delay_
.IsZero() || !fake_bandwidth_
.IsZero()) {
103 if (buffer_size_
> 0 && buf_len
+ cur_buffer_size_
> buffer_size_
) {
104 // Drop packets which do not fit into the buffer.
105 DVLOG(1) << "Dropping packet because the buffer is full.";
106 return WriteResult(WRITE_STATUS_OK
, buf_len
);
109 // Queue it to be sent.
110 QuicTime send_time
= clock_
->ApproximateNow().Add(fake_packet_delay_
);
111 if (!fake_bandwidth_
.IsZero()) {
112 // Calculate a time the bandwidth limit would impose.
113 QuicTime::Delta bandwidth_delay
= QuicTime::Delta::FromMicroseconds(
114 (buf_len
* kNumMicrosPerSecond
) /
115 fake_bandwidth_
.ToBytesPerSecond());
116 send_time
= delayed_packets_
.empty() ?
117 send_time
.Add(bandwidth_delay
) :
118 delayed_packets_
.back().send_time
.Add(bandwidth_delay
);
120 delayed_packets_
.push_back(DelayedWrite(buffer
, buf_len
, self_address
,
121 peer_address
, send_time
));
122 cur_buffer_size_
+= buf_len
;
124 // Set the alarm if it's not yet set.
125 if (!delay_alarm_
->IsSet()) {
126 delay_alarm_
->Set(send_time
);
129 return WriteResult(WRITE_STATUS_OK
, buf_len
);
132 return QuicPacketWriterWrapper::WritePacket(
133 buffer
, buf_len
, self_address
, peer_address
);
136 bool PacketDroppingTestWriter::IsWriteBlocked() const {
137 if (write_unblocked_alarm_
.get() != NULL
&& write_unblocked_alarm_
->IsSet()) {
140 return QuicPacketWriterWrapper::IsWriteBlocked();
143 void PacketDroppingTestWriter::SetWritable() {
144 if (write_unblocked_alarm_
.get() != NULL
&& write_unblocked_alarm_
->IsSet()) {
145 write_unblocked_alarm_
->Cancel();
147 QuicPacketWriterWrapper::SetWritable();
150 QuicTime
PacketDroppingTestWriter::ReleaseNextPacket() {
151 if (delayed_packets_
.empty()) {
152 return QuicTime::Zero();
154 base::AutoLock
locked(config_mutex_
);
155 DelayedPacketList::iterator iter
= delayed_packets_
.begin();
156 // Determine if we should re-order.
157 if (delayed_packets_
.size() > 1 && fake_packet_reorder_percentage_
> 0 &&
158 simple_random_
.RandUint64() % 100 <
159 static_cast<uint64
>(fake_packet_reorder_percentage_
)) {
160 DVLOG(1) << "Reordering packets.";
162 // Swap the send times when re-ordering packets.
163 delayed_packets_
.begin()->send_time
= iter
->send_time
;
166 DVLOG(1) << "Releasing packet. " << (delayed_packets_
.size() - 1)
168 // Grab the next one off the queue and send it.
169 QuicPacketWriterWrapper::WritePacket(
170 iter
->buffer
.data(), iter
->buffer
.length(),
171 iter
->self_address
, iter
->peer_address
);
172 DCHECK_GE(cur_buffer_size_
, iter
->buffer
.length());
173 cur_buffer_size_
-= iter
->buffer
.length();
174 delayed_packets_
.erase(iter
);
176 // If there are others, find the time for the next to be sent.
177 if (delayed_packets_
.empty()) {
178 return QuicTime::Zero();
180 return delayed_packets_
.begin()->send_time
;
183 QuicTime
PacketDroppingTestWriter::ReleaseOldPackets() {
184 while (!delayed_packets_
.empty()) {
185 QuicTime next_send_time
= delayed_packets_
.front().send_time
;
186 if (next_send_time
> clock_
->Now()) {
187 return next_send_time
;
191 return QuicTime::Zero();
194 void PacketDroppingTestWriter::OnCanWrite() {
195 on_can_write_
->OnCanWrite();
198 PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
201 const net::IPAddressNumber
& self_address
,
202 const net::IPEndPoint
& peer_address
,
204 : buffer(buffer
, buf_len
),
205 self_address(self_address
),
206 peer_address(peer_address
),
207 send_time(send_time
) {}
209 PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}