1 // Copyright (c) 2012 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/quic_time_wait_list_manager.h" 6 7 #include <errno.h> 8 9 #include "base/containers/hash_tables.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/stl_util.h" 12 #include "net/base/ip_endpoint.h" 13 #include "net/quic/crypto/crypto_protocol.h" 14 #include "net/quic/crypto/quic_decrypter.h" 15 #include "net/quic/crypto/quic_encrypter.h" 16 #include "net/quic/quic_clock.h" 17 #include "net/quic/quic_framer.h" 18 #include "net/quic/quic_protocol.h" 19 #include "net/quic/quic_utils.h" 20 21 using std::make_pair; 22 23 namespace net { 24 namespace tools { 25 26 namespace { 27 28 // Time period for which the guid should live in time wait state.. 29 const int kTimeWaitSeconds = 5; 30 31 } // namespace 32 33 // A very simple alarm that just informs the QuicTimeWaitListManager to clean 34 // up old guids. This alarm should be unregistered and deleted before the 35 // QuicTimeWaitListManager is deleted. 36 class GuidCleanUpAlarm : public EpollAlarm { 37 public: 38 explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager) 39 : time_wait_list_manager_(time_wait_list_manager) { 40 } 41 42 virtual int64 OnAlarm() OVERRIDE { 43 EpollAlarm::OnAlarm(); 44 time_wait_list_manager_->CleanUpOldGuids(); 45 // Let the time wait manager register the alarm at appropriate time. 46 return 0; 47 } 48 49 private: 50 // Not owned. 51 QuicTimeWaitListManager* time_wait_list_manager_; 52 }; 53 54 struct QuicTimeWaitListManager::GuidAddTime { 55 GuidAddTime(QuicGuid guid, const QuicTime& time) 56 : guid(guid), 57 time_added(time) { 58 } 59 60 QuicGuid guid; 61 QuicTime time_added; 62 }; 63 64 // This class stores pending public reset packets to be sent to clients. 65 // server_address - server address on which a packet what was received for 66 // a guid in time wait state. 67 // client_address - address of the client that sent that packet. Needed to send 68 // the public reset packet back to the client. 69 // packet - the pending public reset packet that is to be sent to the client. 70 // created instance takes the ownership of this packet. 71 class QuicTimeWaitListManager::QueuedPacket { 72 public: 73 QueuedPacket(const IPEndPoint& server_address, 74 const IPEndPoint& client_address, 75 QuicEncryptedPacket* packet) 76 : server_address_(server_address), 77 client_address_(client_address), 78 packet_(packet) { 79 } 80 81 const IPEndPoint& server_address() const { return server_address_; } 82 const IPEndPoint& client_address() const { return client_address_; } 83 QuicEncryptedPacket* packet() { return packet_.get(); } 84 85 private: 86 const IPEndPoint server_address_; 87 const IPEndPoint client_address_; 88 scoped_ptr<QuicEncryptedPacket> packet_; 89 90 DISALLOW_COPY_AND_ASSIGN(QueuedPacket); 91 }; 92 93 QuicTimeWaitListManager::QuicTimeWaitListManager( 94 QuicPacketWriter* writer, 95 EpollServer* epoll_server) 96 : framer_(QuicVersionMax(), 97 QuicTime::Zero(), // unused 98 true), 99 epoll_server_(epoll_server), 100 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), 101 guid_clean_up_alarm_(new GuidCleanUpAlarm(this)), 102 clock_(epoll_server), 103 writer_(writer), 104 is_write_blocked_(false) { 105 framer_.set_visitor(this); 106 SetGuidCleanUpAlarm(); 107 } 108 109 QuicTimeWaitListManager::~QuicTimeWaitListManager() { 110 guid_clean_up_alarm_->UnregisterIfRegistered(); 111 STLDeleteElements(&time_ordered_guid_list_); 112 STLDeleteElements(&pending_packets_queue_); 113 } 114 115 void QuicTimeWaitListManager::AddGuidToTimeWait(QuicGuid guid, 116 QuicVersion version) { 117 DCHECK(!IsGuidInTimeWait(guid)); 118 // Initialize the guid with 0 packets received. 119 GuidData data(0, version); 120 guid_map_.insert(make_pair(guid, data)); 121 time_ordered_guid_list_.push_back(new GuidAddTime(guid, 122 clock_.ApproximateNow())); 123 } 124 125 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const { 126 return guid_map_.find(guid) != guid_map_.end(); 127 } 128 129 void QuicTimeWaitListManager::ProcessPacket( 130 const IPEndPoint& server_address, 131 const IPEndPoint& client_address, 132 QuicGuid guid, 133 const QuicEncryptedPacket& packet) { 134 DCHECK(IsGuidInTimeWait(guid)); 135 server_address_ = server_address; 136 client_address_ = client_address; 137 138 // Set the framer to the appropriate version for this GUID, before processing. 139 QuicVersion version = GetQuicVersionFromGuid(guid); 140 framer_.set_version(version); 141 142 framer_.ProcessPacket(packet); 143 } 144 145 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) { 146 GuidMapIterator it = guid_map_.find(guid); 147 DCHECK(it != guid_map_.end()); 148 return (it->second).version; 149 } 150 151 bool QuicTimeWaitListManager::OnCanWrite() { 152 is_write_blocked_ = false; 153 while (!is_write_blocked_ && !pending_packets_queue_.empty()) { 154 QueuedPacket* queued_packet = pending_packets_queue_.front(); 155 WriteToWire(queued_packet); 156 if (!is_write_blocked_) { 157 pending_packets_queue_.pop_front(); 158 delete queued_packet; 159 } 160 } 161 162 return !is_write_blocked_; 163 } 164 165 void QuicTimeWaitListManager::OnError(QuicFramer* framer) { 166 DLOG(INFO) << QuicUtils::ErrorToString(framer->error()); 167 } 168 169 bool QuicTimeWaitListManager::OnProtocolVersionMismatch( 170 QuicVersion received_version) { 171 // Drop such packets whose version don't match. 172 return false; 173 } 174 175 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& frame) { 176 return false; 177 } 178 179 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& frame) { 180 return false; 181 } 182 183 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame( 184 const QuicCongestionFeedbackFrame& frame) { 185 return false; 186 } 187 188 bool QuicTimeWaitListManager::OnRstStreamFrame( 189 const QuicRstStreamFrame& frame) { 190 return false; 191 } 192 193 bool QuicTimeWaitListManager::OnConnectionCloseFrame( 194 const QuicConnectionCloseFrame & frame) { 195 return false; 196 } 197 198 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& frame) { 199 return false; 200 } 201 202 bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) { 203 // TODO(satyamshekhar): Think about handling packets from different client 204 // addresses. 205 GuidMapIterator it = guid_map_.find(header.public_header.guid); 206 DCHECK(it != guid_map_.end()); 207 // Increment the received packet count. 208 ++((it->second).num_packets); 209 if (ShouldSendPublicReset((it->second).num_packets)) { 210 // We don't need the packet anymore. Just tell the client what sequence 211 // number we rejected. 212 SendPublicReset(server_address_, 213 client_address_, 214 header.public_header.guid, 215 header.packet_sequence_number); 216 } 217 // Never process the body of the packet in time wait state. 218 return false; 219 } 220 221 // Returns true if the number of packets received for this guid is a power of 2 222 // to throttle the number of public reset packets we send to a client. 223 bool QuicTimeWaitListManager::ShouldSendPublicReset(int received_packet_count) { 224 return (received_packet_count & (received_packet_count - 1)) == 0; 225 } 226 227 void QuicTimeWaitListManager::SendPublicReset( 228 const IPEndPoint& server_address, 229 const IPEndPoint& client_address, 230 QuicGuid guid, 231 QuicPacketSequenceNumber rejected_sequence_number) { 232 QuicPublicResetPacket packet; 233 packet.public_header.guid = guid; 234 packet.public_header.reset_flag = true; 235 packet.public_header.version_flag = false; 236 packet.rejected_sequence_number = rejected_sequence_number; 237 // TODO(satyamshekhar): generate a valid nonce for this guid. 238 packet.nonce_proof = 1010101; 239 QueuedPacket* queued_packet = new QueuedPacket( 240 server_address, 241 client_address, 242 framer_.BuildPublicResetPacket(packet)); 243 // Takes ownership of the packet. 244 SendOrQueuePacket(queued_packet); 245 } 246 247 // Either sends the packet and deletes it or makes pending queue the 248 // owner of the packet. 249 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) { 250 if (!is_write_blocked_) { 251 // TODO(satyamshekhar): Handle packets that fail due to error other than 252 // EAGAIN or EWOULDBLOCK. 253 WriteToWire(packet); 254 } 255 256 if (is_write_blocked_) { 257 // pending_packets_queue takes the ownership of the queued packet. 258 pending_packets_queue_.push_back(packet); 259 } else { 260 delete packet; 261 } 262 } 263 264 void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { 265 DCHECK(!is_write_blocked_); 266 int error; 267 int rc = writer_->WritePacket(queued_packet->packet()->data(), 268 queued_packet->packet()->length(), 269 queued_packet->server_address().address(), 270 queued_packet->client_address(), 271 this, 272 &error); 273 274 if (rc == -1) { 275 if (error == EAGAIN || error == EWOULDBLOCK) { 276 is_write_blocked_ = true; 277 } else { 278 LOG(WARNING) << "Received unknown error while sending reset packet to " 279 << queued_packet->client_address().ToString() << ": " 280 << strerror(error); 281 } 282 } 283 } 284 285 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() { 286 guid_clean_up_alarm_->UnregisterIfRegistered(); 287 int64 next_alarm_interval; 288 if (!time_ordered_guid_list_.empty()) { 289 GuidAddTime* oldest_guid = time_ordered_guid_list_.front(); 290 QuicTime now = clock_.ApproximateNow(); 291 DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_); 292 next_alarm_interval = oldest_guid->time_added 293 .Add(kTimeWaitPeriod_) 294 .Subtract(now) 295 .ToMicroseconds(); 296 } else { 297 // No guids added so none will expire before kTimeWaitPeriod_. 298 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds(); 299 } 300 301 epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval, 302 guid_clean_up_alarm_.get()); 303 } 304 305 void QuicTimeWaitListManager::CleanUpOldGuids() { 306 QuicTime now = clock_.ApproximateNow(); 307 while (time_ordered_guid_list_.size() > 0) { 308 DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size()); 309 GuidAddTime* oldest_guid = time_ordered_guid_list_.front(); 310 if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) { 311 break; 312 } 313 // This guid has lived its age, retire it now. 314 guid_map_.erase(oldest_guid->guid); 315 time_ordered_guid_list_.pop_front(); 316 delete oldest_guid; 317 } 318 SetGuidCleanUpAlarm(); 319 } 320 321 } // namespace tools 322 } // namespace net 323