• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
WriteUnblockedAlarm(PacketDroppingTestWriter * writer)21   explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
22       : writer_(writer) {}
23 
OnAlarm()24   virtual 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:
DelayAlarm(PacketDroppingTestWriter * writer)38   explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
39 
OnAlarm()40   virtual QuicTime OnAlarm() OVERRIDE {
41     return writer_->ReleaseOldPackets();
42   }
43 
44  private:
45   PacketDroppingTestWriter* writer_;
46 };
47 
PacketDroppingTestWriter()48 PacketDroppingTestWriter::PacketDroppingTestWriter()
49     : clock_(NULL),
50       cur_buffer_size_(0),
51       config_mutex_(),
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()),
57       buffer_size_(0) {
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);
61 }
62 
~PacketDroppingTestWriter()63 PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
64 
Initialize(QuicEpollConnectionHelper * helper,Delegate * on_can_write)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)));
71   delay_alarm_.reset(
72         helper->CreateAlarm(new DelayAlarm(this)));
73   on_can_write_.reset(on_can_write);
74 }
75 
WritePacket(const char * buffer,size_t buf_len,const net::IPAddressNumber & self_address,const net::IPEndPoint & peer_address)76 WriteResult PacketDroppingTestWriter::WritePacket(
77     const char* buffer,
78     size_t buf_len,
79     const net::IPAddressNumber& self_address,
80     const net::IPEndPoint& peer_address) {
81   ReleaseOldPackets();
82 
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);
89   }
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());
98     }
99     return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
100   }
101 
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);
107     }
108 
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);
119     }
120     delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address,
121                                             peer_address, send_time));
122     cur_buffer_size_ += buf_len;
123 
124     // Set the alarm if it's not yet set.
125     if (!delay_alarm_->IsSet()) {
126       delay_alarm_->Set(send_time);
127     }
128 
129     return WriteResult(WRITE_STATUS_OK, buf_len);
130   }
131 
132   return QuicPacketWriterWrapper::WritePacket(
133       buffer, buf_len, self_address, peer_address);
134 }
135 
IsWriteBlocked() const136 bool PacketDroppingTestWriter::IsWriteBlocked() const {
137   if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
138     return true;
139   }
140   return QuicPacketWriterWrapper::IsWriteBlocked();
141 }
142 
SetWritable()143 void PacketDroppingTestWriter::SetWritable() {
144   if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
145     write_unblocked_alarm_->Cancel();
146   }
147   QuicPacketWriterWrapper::SetWritable();
148 }
149 
ReleaseNextPacket()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 
ReleaseOldPackets()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 
OnCanWrite()194 void PacketDroppingTestWriter::OnCanWrite() {
195   on_can_write_->OnCanWrite();
196 }
197 
DelayedWrite(const char * buffer,size_t buf_len,const net::IPAddressNumber & self_address,const net::IPEndPoint & peer_address,QuicTime send_time)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 
~DelayedWrite()209 PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
210 
211 }  // namespace test
212 }  // namespace tools
213 }  // namespace net
214