1 // Copyright 2014 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/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_connection_helper.h" 18 #include "net/quic/quic_framer.h" 19 #include "net/quic/quic_protocol.h" 20 #include "net/quic/quic_server_session.h" 21 #include "net/quic/quic_utils.h" 22 23 using base::StringPiece; 24 using std::make_pair; 25 26 namespace net { 27 28 namespace { 29 30 // Time period for which the connection_id should live in time wait state.. 31 const int kTimeWaitSeconds = 5; 32 33 } // namespace 34 35 // A very simple alarm that just informs the QuicTimeWaitListManager to clean 36 // up old connection_ids. This alarm should be unregistered and deleted before 37 // the QuicTimeWaitListManager is deleted. 38 class ConnectionIdCleanUpAlarm : public QuicAlarm::Delegate { 39 public: 40 explicit ConnectionIdCleanUpAlarm( 41 QuicTimeWaitListManager* time_wait_list_manager) 42 : time_wait_list_manager_(time_wait_list_manager) {} 43 44 virtual QuicTime OnAlarm() OVERRIDE { 45 time_wait_list_manager_->CleanUpOldConnectionIds(); 46 // Let the time wait manager register the alarm at appropriate time. 47 return QuicTime::Zero(); 48 } 49 50 private: 51 // Not owned. 52 QuicTimeWaitListManager* time_wait_list_manager_; 53 }; 54 55 // This class stores pending public reset packets to be sent to clients. 56 // server_address - server address on which a packet what was received for 57 // a connection_id in time wait state. 58 // client_address - address of the client that sent that packet. Needed to send 59 // the public reset packet back to the client. 60 // packet - the pending public reset packet that is to be sent to the client. 61 // created instance takes the ownership of this packet. 62 class QuicTimeWaitListManager::QueuedPacket { 63 public: 64 QueuedPacket(const IPEndPoint& server_address, 65 const IPEndPoint& client_address, 66 QuicEncryptedPacket* packet) 67 : server_address_(server_address), 68 client_address_(client_address), 69 packet_(packet) {} 70 71 const IPEndPoint& server_address() const { return server_address_; } 72 const IPEndPoint& client_address() const { return client_address_; } 73 QuicEncryptedPacket* packet() { return packet_.get(); } 74 75 private: 76 const IPEndPoint server_address_; 77 const IPEndPoint client_address_; 78 scoped_ptr<QuicEncryptedPacket> packet_; 79 80 DISALLOW_COPY_AND_ASSIGN(QueuedPacket); 81 }; 82 83 QuicTimeWaitListManager::QuicTimeWaitListManager( 84 QuicPacketWriter* writer, 85 QuicServerSessionVisitor* visitor, 86 QuicConnectionHelperInterface* helper, 87 const QuicVersionVector& supported_versions) 88 : helper_(helper), 89 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), 90 connection_id_clean_up_alarm_( 91 helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))), 92 writer_(writer), 93 visitor_(visitor) { 94 SetConnectionIdCleanUpAlarm(); 95 } 96 97 QuicTimeWaitListManager::~QuicTimeWaitListManager() { 98 connection_id_clean_up_alarm_->Cancel(); 99 STLDeleteElements(&pending_packets_queue_); 100 for (ConnectionIdMap::iterator it = connection_id_map_.begin(); 101 it != connection_id_map_.end(); 102 ++it) { 103 delete it->second.close_packet; 104 } 105 } 106 107 void QuicTimeWaitListManager::AddConnectionIdToTimeWait( 108 QuicConnectionId connection_id, 109 QuicVersion version, 110 QuicEncryptedPacket* close_packet) { 111 DVLOG(1) << "Adding " << connection_id << " to the time wait list."; 112 int num_packets = 0; 113 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); 114 if (it != connection_id_map_.end()) { // Replace record if it is reinserted. 115 num_packets = it->second.num_packets; 116 delete it->second.close_packet; 117 connection_id_map_.erase(it); 118 } 119 ConnectionIdData data(num_packets, 120 version, 121 helper_->GetClock()->ApproximateNow(), 122 close_packet); 123 connection_id_map_.insert(make_pair(connection_id, data)); 124 } 125 126 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait( 127 QuicConnectionId connection_id) const { 128 return ContainsKey(connection_id_map_, connection_id); 129 } 130 131 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( 132 QuicConnectionId connection_id) { 133 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); 134 DCHECK(it != connection_id_map_.end()); 135 return (it->second).version; 136 } 137 138 void QuicTimeWaitListManager::OnCanWrite() { 139 while (!pending_packets_queue_.empty()) { 140 QueuedPacket* queued_packet = pending_packets_queue_.front(); 141 if (!WriteToWire(queued_packet)) { 142 return; 143 } 144 pending_packets_queue_.pop_front(); 145 delete queued_packet; 146 } 147 } 148 149 void QuicTimeWaitListManager::ProcessPacket( 150 const IPEndPoint& server_address, 151 const IPEndPoint& client_address, 152 QuicConnectionId connection_id, 153 QuicPacketSequenceNumber sequence_number, 154 const QuicEncryptedPacket& /*packet*/) { 155 DCHECK(IsConnectionIdInTimeWait(connection_id)); 156 DVLOG(1) << "Processing " << connection_id << " in time wait state."; 157 // TODO(satyamshekhar): Think about handling packets from different client 158 // addresses. 159 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); 160 DCHECK(it != connection_id_map_.end()); 161 // Increment the received packet count. 162 ++((it->second).num_packets); 163 if (!ShouldSendResponse((it->second).num_packets)) { 164 return; 165 } 166 if (it->second.close_packet) { 167 QueuedPacket* queued_packet = 168 new QueuedPacket(server_address, 169 client_address, 170 it->second.close_packet->Clone()); 171 // Takes ownership of the packet. 172 SendOrQueuePacket(queued_packet); 173 } else { 174 SendPublicReset(server_address, 175 client_address, 176 connection_id, 177 sequence_number); 178 } 179 } 180 181 // Returns true if the number of packets received for this connection_id is a 182 // power of 2 to throttle the number of public reset packets we send to a 183 // client. 184 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) { 185 return (received_packet_count & (received_packet_count - 1)) == 0; 186 } 187 188 void QuicTimeWaitListManager::SendPublicReset( 189 const IPEndPoint& server_address, 190 const IPEndPoint& client_address, 191 QuicConnectionId connection_id, 192 QuicPacketSequenceNumber rejected_sequence_number) { 193 QuicPublicResetPacket packet; 194 packet.public_header.connection_id = connection_id; 195 packet.public_header.reset_flag = true; 196 packet.public_header.version_flag = false; 197 packet.rejected_sequence_number = rejected_sequence_number; 198 // TODO(satyamshekhar): generate a valid nonce for this connection_id. 199 packet.nonce_proof = 1010101; 200 packet.client_address = client_address; 201 QueuedPacket* queued_packet = new QueuedPacket( 202 server_address, 203 client_address, 204 BuildPublicReset(packet)); 205 // Takes ownership of the packet. 206 SendOrQueuePacket(queued_packet); 207 } 208 209 QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset( 210 const QuicPublicResetPacket& packet) { 211 return QuicFramer::BuildPublicResetPacket(packet); 212 } 213 214 // Either sends the packet and deletes it or makes pending queue the 215 // owner of the packet. 216 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) { 217 if (WriteToWire(packet)) { 218 delete packet; 219 } else { 220 // pending_packets_queue takes the ownership of the queued packet. 221 pending_packets_queue_.push_back(packet); 222 } 223 } 224 225 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { 226 if (writer_->IsWriteBlocked()) { 227 visitor_->OnWriteBlocked(this); 228 return false; 229 } 230 WriteResult result = writer_->WritePacket( 231 queued_packet->packet()->data(), 232 queued_packet->packet()->length(), 233 queued_packet->server_address().address(), 234 queued_packet->client_address()); 235 if (result.status == WRITE_STATUS_BLOCKED) { 236 // If blocked and unbuffered, return false to retry sending. 237 DCHECK(writer_->IsWriteBlocked()); 238 visitor_->OnWriteBlocked(this); 239 return writer_->IsWriteBlockedDataBuffered(); 240 } else if (result.status == WRITE_STATUS_ERROR) { 241 LOG(WARNING) << "Received unknown error while sending reset packet to " 242 << queued_packet->client_address().ToString() << ": " 243 << strerror(result.error_code); 244 } 245 return true; 246 } 247 248 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() { 249 connection_id_clean_up_alarm_->Cancel(); 250 QuicTime now = helper_->GetClock()->ApproximateNow(); 251 QuicTime next_alarm_time = now; 252 if (!connection_id_map_.empty()) { 253 QuicTime oldest_connection_id = 254 connection_id_map_.begin()->second.time_added; 255 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { 256 next_alarm_time = oldest_connection_id.Add(kTimeWaitPeriod_); 257 } else { 258 LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod"; 259 } 260 } else { 261 // No connection_ids added so none will expire before kTimeWaitPeriod_. 262 next_alarm_time = now.Add(kTimeWaitPeriod_); 263 } 264 265 connection_id_clean_up_alarm_->Set(next_alarm_time); 266 } 267 268 void QuicTimeWaitListManager::CleanUpOldConnectionIds() { 269 QuicTime now = helper_->GetClock()->ApproximateNow(); 270 while (!connection_id_map_.empty()) { 271 ConnectionIdMap::iterator it = connection_id_map_.begin(); 272 QuicTime oldest_connection_id = it->second.time_added; 273 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { 274 break; 275 } 276 // This connection_id has lived its age, retire it now. 277 delete it->second.close_packet; 278 connection_id_map_.erase(it); 279 } 280 SetConnectionIdCleanUpAlarm(); 281 } 282 283 } // namespace net 284