| 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 |