Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / tools / quic / test_tools / packet_dropping_test_writer.cc
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   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:
38   explicit DelayAlarm(PacketDroppingTestWriter* writer)
39       : writer_(writer) { }
40
41   virtual QuicTime OnAlarm() OVERRIDE {
42     return writer_->ReleaseOldPackets();
43   }
44
45  private:
46   PacketDroppingTestWriter* writer_;
47 };
48
49 PacketDroppingTestWriter::PacketDroppingTestWriter()
50     : clock_(NULL),
51       cur_buffer_size_(0),
52       config_mutex_(),
53       fake_packet_loss_percentage_(0),
54       fake_blocked_socket_percentage_(0),
55       fake_packet_reorder_percentage_(0),
56       fake_packet_delay_(QuicTime::Delta::Zero()),
57       fake_bandwidth_(QuicBandwidth::Zero()),
58       buffer_size_(0) {
59   uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
60   VLOG(1) << "Seeding packet loss with " << seed;
61   simple_random_.set_seed(seed);
62 }
63
64 PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
65
66 void PacketDroppingTestWriter::Initialize(
67     QuicEpollConnectionHelper* helper,
68     Delegate* on_can_write) {
69   clock_ = helper->GetClock();
70   write_unblocked_alarm_.reset(
71       helper->CreateAlarm(new WriteUnblockedAlarm(this)));
72   delay_alarm_.reset(
73         helper->CreateAlarm(new DelayAlarm(this)));
74   on_can_write_.reset(on_can_write);
75 }
76
77 WriteResult PacketDroppingTestWriter::WritePacket(
78     const char* buffer,
79     size_t buf_len,
80     const net::IPAddressNumber& self_address,
81     const net::IPEndPoint& peer_address) {
82   ReleaseOldPackets();
83
84   base::AutoLock locked(config_mutex_);
85   if (fake_packet_loss_percentage_ > 0 &&
86       simple_random_.RandUint64() % 100 <
87           static_cast<uint64>(fake_packet_loss_percentage_)) {
88     DVLOG(1) << "Dropping packet.";
89     return WriteResult(WRITE_STATUS_OK, buf_len);
90   }
91   if (fake_blocked_socket_percentage_ > 0 &&
92       simple_random_.RandUint64() % 100 <
93           static_cast<uint64>(fake_blocked_socket_percentage_)) {
94     CHECK(on_can_write_.get() != NULL);
95     DVLOG(1) << "Blocking socket.";
96     if (!write_unblocked_alarm_->IsSet()) {
97       // Set the alarm to fire immediately.
98       write_unblocked_alarm_->Set(clock_->ApproximateNow());
99     }
100     return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
101   }
102
103   if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
104     if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
105       // Drop packets which do not fit into the buffer.
106       DVLOG(1) << "Dropping packet because the buffer is full.";
107       return WriteResult(WRITE_STATUS_OK, buf_len);
108     }
109
110     // Queue it to be sent.
111     QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
112     if (!fake_bandwidth_.IsZero()) {
113       // Calculate a time the bandwidth limit would impose.
114       QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
115           (buf_len * kNumMicrosPerSecond) /
116           fake_bandwidth_.ToBytesPerSecond());
117       send_time = delayed_packets_.empty() ?
118           send_time.Add(bandwidth_delay) :
119           delayed_packets_.back().send_time.Add(bandwidth_delay);
120     }
121     delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address,
122                                             peer_address, send_time));
123     cur_buffer_size_ += buf_len;
124
125     // Set the alarm if it's not yet set.
126     if (!delay_alarm_->IsSet()) {
127       delay_alarm_->Set(send_time);
128     }
129
130     return WriteResult(WRITE_STATUS_OK, buf_len);
131   }
132
133   return QuicPacketWriterWrapper::WritePacket(
134       buffer, buf_len, self_address, peer_address);
135 }
136
137 bool PacketDroppingTestWriter::IsWriteBlocked() const {
138   if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
139     return true;
140   }
141   return QuicPacketWriterWrapper::IsWriteBlocked();
142 }
143
144 void PacketDroppingTestWriter::SetWritable() {
145   if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
146     write_unblocked_alarm_->Cancel();
147   }
148   QuicPacketWriterWrapper::SetWritable();
149 }
150
151 QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
152   if (delayed_packets_.empty()) {
153     return QuicTime::Zero();
154   }
155   base::AutoLock locked(config_mutex_);
156   DelayedPacketList::iterator iter = delayed_packets_.begin();
157   // Determine if we should re-order.
158   if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
159       simple_random_.RandUint64() % 100 <
160           static_cast<uint64>(fake_packet_reorder_percentage_)) {
161     DVLOG(1) << "Reordering packets.";
162     ++iter;
163     // Swap the send times when re-ordering packets.
164     delayed_packets_.begin()->send_time = iter->send_time;
165   }
166
167   DVLOG(1) << "Releasing packet.  " << (delayed_packets_.size() - 1)
168            << " remaining.";
169   // Grab the next one off the queue and send it.
170   QuicPacketWriterWrapper::WritePacket(
171       iter->buffer.data(), iter->buffer.length(),
172       iter->self_address, iter->peer_address);
173   DCHECK_GE(cur_buffer_size_, iter->buffer.length());
174   cur_buffer_size_ -= iter->buffer.length();
175   delayed_packets_.erase(iter);
176
177   // If there are others, find the time for the next to be sent.
178   if (delayed_packets_.empty()) {
179     return QuicTime::Zero();
180   }
181   return delayed_packets_.begin()->send_time;
182 }
183
184 QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
185   while (!delayed_packets_.empty()) {
186     QuicTime next_send_time = delayed_packets_.front().send_time;
187     if (next_send_time > clock_->Now()) {
188       return next_send_time;
189     }
190     ReleaseNextPacket();
191   }
192   return QuicTime::Zero();
193 }
194
195 void PacketDroppingTestWriter::OnCanWrite() {
196   on_can_write_->OnCanWrite();
197 }
198
199 PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
200     const char* buffer,
201     size_t buf_len,
202     const net::IPAddressNumber& self_address,
203     const net::IPEndPoint& peer_address,
204     QuicTime send_time)
205     : buffer(buffer, buf_len),
206       self_address(self_address),
207       peer_address(peer_address),
208       send_time(send_time) {}
209
210 PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
211
212 }  // namespace test
213 }  // namespace tools
214 }  // namespace net