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