Home | History | Annotate | Download | only in test_tools
      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 using net::test::QuicTestWriter;
     14 
     15 namespace net {
     16 namespace tools {
     17 namespace test {
     18 
     19 // An alarm that is scheduled if a blocked socket is simulated to indicate
     20 // it's writable again.
     21 class WriteUnblockedAlarm : public QuicAlarm::Delegate {
     22  public:
     23   explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
     24       : writer_(writer) { }
     25 
     26   virtual QuicTime OnAlarm() OVERRIDE {
     27     DCHECK(writer_->blocked_writer());
     28     writer_->blocked_writer()->OnCanWrite();
     29     return QuicTime::Zero();
     30   }
     31 
     32  private:
     33   PacketDroppingTestWriter* writer_;
     34 };
     35 
     36 // An alarm that is scheduled every time a new packet is to be written at a
     37 // later point.
     38 class DelayAlarm : public QuicAlarm::Delegate {
     39  public:
     40   explicit DelayAlarm(PacketDroppingTestWriter* writer)
     41       : writer_(writer) { }
     42 
     43   virtual QuicTime OnAlarm() OVERRIDE {
     44     return writer_->ReleaseOldPackets();
     45   }
     46 
     47  private:
     48   PacketDroppingTestWriter* writer_;
     49 };
     50 
     51 PacketDroppingTestWriter::PacketDroppingTestWriter()
     52     : clock_(NULL),
     53       blocked_writer_(NULL),
     54       cur_buffer_size_(0),
     55       config_mutex_(),
     56       fake_packet_loss_percentage_(0),
     57       fake_blocked_socket_percentage_(0),
     58       fake_packet_reorder_percentage_(0),
     59       fake_packet_delay_(QuicTime::Delta::Zero()),
     60       fake_bandwidth_(QuicBandwidth::Zero()),
     61       buffer_size_(0) {
     62   uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
     63   LOG(INFO) << "Seeding packet loss with " << seed;
     64   simple_random_.set_seed(seed);
     65 }
     66 
     67 PacketDroppingTestWriter::~PacketDroppingTestWriter() { }
     68 
     69 void PacketDroppingTestWriter::SetConnectionHelper(
     70     QuicEpollConnectionHelper* helper) {
     71   clock_ = helper->GetClock();
     72   write_unblocked_alarm_.reset(
     73       helper->CreateAlarm(new WriteUnblockedAlarm(this)));
     74   delay_alarm_.reset(
     75         helper->CreateAlarm(new DelayAlarm(this)));
     76 }
     77 
     78 WriteResult PacketDroppingTestWriter::WritePacket(
     79     const char* buffer, size_t buf_len,
     80     const net::IPAddressNumber& self_address,
     81     const net::IPEndPoint& peer_address,
     82     QuicBlockedWriterInterface* blocked_writer) {
     83   ReleaseOldPackets();
     84 
     85   base::AutoLock locked(config_mutex_);
     86   if (fake_packet_loss_percentage_ > 0 &&
     87       simple_random_.RandUint64() % 100 <
     88           static_cast<uint64>(fake_packet_loss_percentage_)) {
     89     DLOG(INFO) << "Dropping packet.";
     90     return WriteResult(WRITE_STATUS_OK, buf_len);
     91   }
     92   if (fake_blocked_socket_percentage_ > 0 &&
     93       simple_random_.RandUint64() % 100 <
     94           static_cast<uint64>(fake_blocked_socket_percentage_)) {
     95     DLOG(INFO) << "Blocking socket.";
     96     if (!write_unblocked_alarm_->IsSet()) {
     97       blocked_writer_ = blocked_writer;
     98       // Set the alarm for 1ms in the future.
     99       write_unblocked_alarm_->Set(
    100           clock_->ApproximateNow().Add(
    101               QuicTime::Delta::FromMilliseconds(1)));
    102     }
    103     return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
    104   }
    105 
    106   if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
    107     if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
    108       // Drop packets which do not fit into the buffer.
    109       DLOG(INFO) << "Dropping packet because the buffer is full.";
    110       return WriteResult(WRITE_STATUS_OK, buf_len);
    111     }
    112 
    113     // Queue it to be sent.
    114     QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
    115     if (!fake_bandwidth_.IsZero()) {
    116       // Calculate a time the bandwidth limit would impose.
    117       QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
    118           (buf_len * kNumMicrosPerSecond) /
    119           fake_bandwidth_.ToBytesPerSecond());
    120       send_time = delayed_packets_.empty() ?
    121           send_time.Add(bandwidth_delay) :
    122           delayed_packets_.back().send_time.Add(bandwidth_delay);
    123     }
    124     delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address,
    125                                             peer_address, send_time));
    126     cur_buffer_size_ += buf_len;
    127 
    128     // Set the alarm if it's not yet set.
    129     if (!delay_alarm_->IsSet()) {
    130       delay_alarm_->Set(send_time);
    131     }
    132 
    133     return WriteResult(WRITE_STATUS_OK, buf_len);
    134   }
    135 
    136   return writer()->WritePacket(buffer, buf_len, self_address, peer_address,
    137                                blocked_writer);
    138 }
    139 
    140 bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const {
    141   return false;
    142 }
    143 
    144 QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
    145   if (delayed_packets_.empty()) {
    146     return QuicTime::Zero();
    147   }
    148   base::AutoLock locked(config_mutex_);
    149   DelayedPacketList::iterator iter = delayed_packets_.begin();
    150   // Determine if we should re-order.
    151   if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
    152       simple_random_.RandUint64() % 100 <
    153           static_cast<uint64>(fake_packet_reorder_percentage_)) {
    154     DLOG(INFO) << "Reordering packets.";
    155     ++iter;
    156     // Swap the send times when re-ordering packets.
    157     delayed_packets_.begin()->send_time = iter->send_time;
    158   }
    159 
    160   DLOG(INFO) << "Releasing packet.  " << (delayed_packets_.size() - 1)
    161              << " remaining.";
    162   // Grab the next one off the queue and send it.
    163   writer()->WritePacket(iter->buffer.data(), iter->buffer.length(),
    164                         iter->self_address, iter->peer_address, NULL);
    165   DCHECK_GE(cur_buffer_size_, iter->buffer.length());
    166   cur_buffer_size_ -= iter->buffer.length();
    167   delayed_packets_.erase(iter);
    168 
    169   // If there are others, find the time for the next to be sent.
    170   if (delayed_packets_.empty()) {
    171     return QuicTime::Zero();
    172   }
    173   return delayed_packets_.begin()->send_time;
    174 }
    175 
    176 QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
    177   while (!delayed_packets_.empty()) {
    178     QuicTime next_send_time = delayed_packets_.front().send_time;
    179     if (next_send_time > clock_->Now()) {
    180       return next_send_time;
    181     }
    182     ReleaseNextPacket();
    183   }
    184   return QuicTime::Zero();
    185 }
    186 
    187 PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
    188     const char* buffer,
    189     size_t buf_len,
    190     const net::IPAddressNumber& self_address,
    191     const net::IPEndPoint& peer_address,
    192     QuicTime send_time)
    193     : buffer(buffer, buf_len),
    194       self_address(self_address),
    195       peer_address(peer_address),
    196       send_time(send_time) {
    197 }
    198 
    199 PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
    200 
    201 }  // namespace test
    202 }  // namespace tools
    203 }  // namespace net
    204