OLD | NEW |
| (Empty) |
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 #include "net/tools/quic/test_tools/packet_dropping_test_writer.h" | |
6 | |
7 #include <limits> | |
8 | |
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" | |
12 | |
13 namespace net { | |
14 namespace tools { | |
15 namespace test { | |
16 | |
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 { | |
20 public: | |
21 explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer) | |
22 : writer_(writer) {} | |
23 | |
24 QuicTime OnAlarm() override { | |
25 DVLOG(1) << "Unblocking socket."; | |
26 writer_->OnCanWrite(); | |
27 return QuicTime::Zero(); | |
28 } | |
29 | |
30 private: | |
31 PacketDroppingTestWriter* writer_; | |
32 }; | |
33 | |
34 // An alarm that is scheduled every time a new packet is to be written at a | |
35 // later point. | |
36 class DelayAlarm : public QuicAlarm::Delegate { | |
37 public: | |
38 explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {} | |
39 | |
40 QuicTime OnAlarm() override { return writer_->ReleaseOldPackets(); } | |
41 | |
42 private: | |
43 PacketDroppingTestWriter* writer_; | |
44 }; | |
45 | |
46 PacketDroppingTestWriter::PacketDroppingTestWriter() | |
47 : clock_(nullptr), | |
48 cur_buffer_size_(0), | |
49 config_mutex_(), | |
50 fake_packet_loss_percentage_(0), | |
51 fake_blocked_socket_percentage_(0), | |
52 fake_packet_reorder_percentage_(0), | |
53 fake_packet_delay_(QuicTime::Delta::Zero()), | |
54 fake_bandwidth_(QuicBandwidth::Zero()), | |
55 buffer_size_(0) { | |
56 uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max()); | |
57 VLOG(1) << "Seeding packet loss with " << seed; | |
58 simple_random_.set_seed(seed); | |
59 } | |
60 | |
61 PacketDroppingTestWriter::~PacketDroppingTestWriter() {} | |
62 | |
63 void PacketDroppingTestWriter::Initialize( | |
64 QuicEpollConnectionHelper* helper, | |
65 Delegate* on_can_write) { | |
66 clock_ = helper->GetClock(); | |
67 write_unblocked_alarm_.reset( | |
68 helper->CreateAlarm(new WriteUnblockedAlarm(this))); | |
69 delay_alarm_.reset( | |
70 helper->CreateAlarm(new DelayAlarm(this))); | |
71 on_can_write_.reset(on_can_write); | |
72 } | |
73 | |
74 WriteResult PacketDroppingTestWriter::WritePacket( | |
75 const char* buffer, | |
76 size_t buf_len, | |
77 const net::IPAddressNumber& self_address, | |
78 const net::IPEndPoint& peer_address) { | |
79 ReleaseOldPackets(); | |
80 | |
81 base::AutoLock locked(config_mutex_); | |
82 if (fake_packet_loss_percentage_ > 0 && | |
83 simple_random_.RandUint64() % 100 < | |
84 static_cast<uint64>(fake_packet_loss_percentage_)) { | |
85 DVLOG(1) << "Dropping packet."; | |
86 return WriteResult(WRITE_STATUS_OK, buf_len); | |
87 } | |
88 if (fake_blocked_socket_percentage_ > 0 && | |
89 simple_random_.RandUint64() % 100 < | |
90 static_cast<uint64>(fake_blocked_socket_percentage_)) { | |
91 CHECK(on_can_write_.get() != nullptr); | |
92 DVLOG(1) << "Blocking socket."; | |
93 if (!write_unblocked_alarm_->IsSet()) { | |
94 // Set the alarm to fire immediately. | |
95 write_unblocked_alarm_->Set(clock_->ApproximateNow()); | |
96 } | |
97 return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN); | |
98 } | |
99 | |
100 if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) { | |
101 if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) { | |
102 // Drop packets which do not fit into the buffer. | |
103 DVLOG(1) << "Dropping packet because the buffer is full."; | |
104 return WriteResult(WRITE_STATUS_OK, buf_len); | |
105 } | |
106 | |
107 // Queue it to be sent. | |
108 QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_); | |
109 if (!fake_bandwidth_.IsZero()) { | |
110 // Calculate a time the bandwidth limit would impose. | |
111 QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds( | |
112 (buf_len * kNumMicrosPerSecond) / | |
113 fake_bandwidth_.ToBytesPerSecond()); | |
114 send_time = delayed_packets_.empty() ? | |
115 send_time.Add(bandwidth_delay) : | |
116 delayed_packets_.back().send_time.Add(bandwidth_delay); | |
117 } | |
118 delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address, | |
119 peer_address, send_time)); | |
120 cur_buffer_size_ += buf_len; | |
121 | |
122 // Set the alarm if it's not yet set. | |
123 if (!delay_alarm_->IsSet()) { | |
124 delay_alarm_->Set(send_time); | |
125 } | |
126 | |
127 return WriteResult(WRITE_STATUS_OK, buf_len); | |
128 } | |
129 | |
130 return QuicPacketWriterWrapper::WritePacket( | |
131 buffer, buf_len, self_address, peer_address); | |
132 } | |
133 | |
134 bool PacketDroppingTestWriter::IsWriteBlocked() const { | |
135 if (write_unblocked_alarm_.get() != nullptr && | |
136 write_unblocked_alarm_->IsSet()) { | |
137 return true; | |
138 } | |
139 return QuicPacketWriterWrapper::IsWriteBlocked(); | |
140 } | |
141 | |
142 void PacketDroppingTestWriter::SetWritable() { | |
143 if (write_unblocked_alarm_.get() != nullptr && | |
144 write_unblocked_alarm_->IsSet()) { | |
145 write_unblocked_alarm_->Cancel(); | |
146 } | |
147 QuicPacketWriterWrapper::SetWritable(); | |
148 } | |
149 | |
150 QuicTime PacketDroppingTestWriter::ReleaseNextPacket() { | |
151 if (delayed_packets_.empty()) { | |
152 return QuicTime::Zero(); | |
153 } | |
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."; | |
161 ++iter; | |
162 // Swap the send times when re-ordering packets. | |
163 delayed_packets_.begin()->send_time = iter->send_time; | |
164 } | |
165 | |
166 DVLOG(1) << "Releasing packet. " << (delayed_packets_.size() - 1) | |
167 << " remaining."; | |
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); | |
175 | |
176 // If there are others, find the time for the next to be sent. | |
177 if (delayed_packets_.empty()) { | |
178 return QuicTime::Zero(); | |
179 } | |
180 return delayed_packets_.begin()->send_time; | |
181 } | |
182 | |
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; | |
188 } | |
189 ReleaseNextPacket(); | |
190 } | |
191 return QuicTime::Zero(); | |
192 } | |
193 | |
194 void PacketDroppingTestWriter::OnCanWrite() { | |
195 on_can_write_->OnCanWrite(); | |
196 } | |
197 | |
198 PacketDroppingTestWriter::DelayedWrite::DelayedWrite( | |
199 const char* buffer, | |
200 size_t buf_len, | |
201 const net::IPAddressNumber& self_address, | |
202 const net::IPEndPoint& peer_address, | |
203 QuicTime send_time) | |
204 : buffer(buffer, buf_len), | |
205 self_address(self_address), | |
206 peer_address(peer_address), | |
207 send_time(send_time) {} | |
208 | |
209 PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {} | |
210 | |
211 } // namespace test | |
212 } // namespace tools | |
213 } // namespace net | |
OLD | NEW |