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