| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/quic/quic_time_wait_list_manager.h" | 5 #include "net/tools/quic/quic_time_wait_list_manager.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 | 8 |
| 9 #include "base/containers/hash_tables.h" | 9 #include "base/containers/hash_tables.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "net/base/ip_endpoint.h" | 12 #include "net/base/ip_endpoint.h" |
| 13 #include "net/quic/crypto/crypto_protocol.h" | 13 #include "net/quic/crypto/crypto_protocol.h" |
| 14 #include "net/quic/crypto/quic_decrypter.h" | 14 #include "net/quic/crypto/quic_decrypter.h" |
| 15 #include "net/quic/crypto/quic_encrypter.h" | 15 #include "net/quic/crypto/quic_encrypter.h" |
| 16 #include "net/quic/quic_clock.h" | 16 #include "net/quic/quic_clock.h" |
| 17 #include "net/quic/quic_framer.h" | 17 #include "net/quic/quic_framer.h" |
| 18 #include "net/quic/quic_protocol.h" | 18 #include "net/quic/quic_protocol.h" |
| 19 #include "net/quic/quic_utils.h" | 19 #include "net/quic/quic_utils.h" |
| 20 #include "net/tools/quic/quic_server_session.h" | 20 #include "net/tools/quic/quic_server_session.h" |
| 21 | 21 |
| 22 using base::StringPiece; | 22 using base::StringPiece; |
| 23 using std::make_pair; | 23 using std::make_pair; |
| 24 | 24 |
| 25 namespace net { | 25 namespace net { |
| 26 namespace tools { | 26 namespace tools { |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 // Time period for which the guid should live in time wait state.. | 30 // Time period for which the connection_id should live in time wait state.. |
| 31 const int kTimeWaitSeconds = 5; | 31 const int kTimeWaitSeconds = 5; |
| 32 | 32 |
| 33 } // namespace | 33 } // namespace |
| 34 | 34 |
| 35 // A very simple alarm that just informs the QuicTimeWaitListManager to clean | 35 // A very simple alarm that just informs the QuicTimeWaitListManager to clean |
| 36 // up old guids. This alarm should be unregistered and deleted before the | 36 // up old connection_ids. This alarm should be unregistered and deleted before |
| 37 // QuicTimeWaitListManager is deleted. | 37 // the QuicTimeWaitListManager is deleted. |
| 38 class GuidCleanUpAlarm : public EpollAlarm { | 38 class ConnectionIdCleanUpAlarm : public EpollAlarm { |
| 39 public: | 39 public: |
| 40 explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager) | 40 explicit ConnectionIdCleanUpAlarm( |
| 41 QuicTimeWaitListManager* time_wait_list_manager) |
| 41 : time_wait_list_manager_(time_wait_list_manager) { | 42 : time_wait_list_manager_(time_wait_list_manager) { |
| 42 } | 43 } |
| 43 | 44 |
| 44 virtual int64 OnAlarm() OVERRIDE { | 45 virtual int64 OnAlarm() OVERRIDE { |
| 45 EpollAlarm::OnAlarm(); | 46 EpollAlarm::OnAlarm(); |
| 46 time_wait_list_manager_->CleanUpOldGuids(); | 47 time_wait_list_manager_->CleanUpOldConnectionIds(); |
| 47 // Let the time wait manager register the alarm at appropriate time. | 48 // Let the time wait manager register the alarm at appropriate time. |
| 48 return 0; | 49 return 0; |
| 49 } | 50 } |
| 50 | 51 |
| 51 private: | 52 private: |
| 52 // Not owned. | 53 // Not owned. |
| 53 QuicTimeWaitListManager* time_wait_list_manager_; | 54 QuicTimeWaitListManager* time_wait_list_manager_; |
| 54 }; | 55 }; |
| 55 | 56 |
| 56 // This class stores pending public reset packets to be sent to clients. | 57 // This class stores pending public reset packets to be sent to clients. |
| 57 // server_address - server address on which a packet what was received for | 58 // server_address - server address on which a packet what was received for |
| 58 // a guid in time wait state. | 59 // a connection_id in time wait state. |
| 59 // client_address - address of the client that sent that packet. Needed to send | 60 // client_address - address of the client that sent that packet. Needed to send |
| 60 // the public reset packet back to the client. | 61 // the public reset packet back to the client. |
| 61 // packet - the pending public reset packet that is to be sent to the client. | 62 // packet - the pending public reset packet that is to be sent to the client. |
| 62 // created instance takes the ownership of this packet. | 63 // created instance takes the ownership of this packet. |
| 63 class QuicTimeWaitListManager::QueuedPacket { | 64 class QuicTimeWaitListManager::QueuedPacket { |
| 64 public: | 65 public: |
| 65 QueuedPacket(const IPEndPoint& server_address, | 66 QueuedPacket(const IPEndPoint& server_address, |
| 66 const IPEndPoint& client_address, | 67 const IPEndPoint& client_address, |
| 67 QuicEncryptedPacket* packet) | 68 QuicEncryptedPacket* packet) |
| 68 : server_address_(server_address), | 69 : server_address_(server_address), |
| (...skipping 13 matching lines...) Expand all Loading... |
| 82 DISALLOW_COPY_AND_ASSIGN(QueuedPacket); | 83 DISALLOW_COPY_AND_ASSIGN(QueuedPacket); |
| 83 }; | 84 }; |
| 84 | 85 |
| 85 QuicTimeWaitListManager::QuicTimeWaitListManager( | 86 QuicTimeWaitListManager::QuicTimeWaitListManager( |
| 86 QuicPacketWriter* writer, | 87 QuicPacketWriter* writer, |
| 87 QuicServerSessionVisitor* visitor, | 88 QuicServerSessionVisitor* visitor, |
| 88 EpollServer* epoll_server, | 89 EpollServer* epoll_server, |
| 89 const QuicVersionVector& supported_versions) | 90 const QuicVersionVector& supported_versions) |
| 90 : epoll_server_(epoll_server), | 91 : epoll_server_(epoll_server), |
| 91 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), | 92 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), |
| 92 guid_clean_up_alarm_(new GuidCleanUpAlarm(this)), | 93 connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)), |
| 93 clock_(epoll_server_), | 94 clock_(epoll_server_), |
| 94 writer_(writer), | 95 writer_(writer), |
| 95 visitor_(visitor) { | 96 visitor_(visitor) { |
| 96 SetGuidCleanUpAlarm(); | 97 SetConnectionIdCleanUpAlarm(); |
| 97 } | 98 } |
| 98 | 99 |
| 99 QuicTimeWaitListManager::~QuicTimeWaitListManager() { | 100 QuicTimeWaitListManager::~QuicTimeWaitListManager() { |
| 100 guid_clean_up_alarm_->UnregisterIfRegistered(); | 101 connection_id_clean_up_alarm_->UnregisterIfRegistered(); |
| 101 STLDeleteElements(&pending_packets_queue_); | 102 STLDeleteElements(&pending_packets_queue_); |
| 102 for (GuidMap::iterator it = guid_map_.begin(); it != guid_map_.end(); ++it) { | 103 for (ConnectionIdMap::iterator it = connection_id_map_.begin(); |
| 104 it != connection_id_map_.end(); |
| 105 ++it) { |
| 103 delete it->second.close_packet; | 106 delete it->second.close_packet; |
| 104 } | 107 } |
| 105 } | 108 } |
| 106 | 109 |
| 107 void QuicTimeWaitListManager::AddGuidToTimeWait( | 110 void QuicTimeWaitListManager::AddConnectionIdToTimeWait( |
| 108 QuicGuid guid, | 111 QuicConnectionId connection_id, |
| 109 QuicVersion version, | 112 QuicVersion version, |
| 110 QuicEncryptedPacket* close_packet) { | 113 QuicEncryptedPacket* close_packet) { |
| 111 int num_packets = 0; | 114 int num_packets = 0; |
| 112 GuidMap::iterator it = guid_map_.find(guid); | 115 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); |
| 113 if (it != guid_map_.end()) { // Replace record if it is reinserted. | 116 if (it != connection_id_map_.end()) { // Replace record if it is reinserted. |
| 114 num_packets = it->second.num_packets; | 117 num_packets = it->second.num_packets; |
| 115 delete it->second.close_packet; | 118 delete it->second.close_packet; |
| 116 guid_map_.erase(it); | 119 connection_id_map_.erase(it); |
| 117 } | 120 } |
| 118 GuidData data(num_packets, version, clock_.ApproximateNow(), close_packet); | 121 ConnectionIdData data(num_packets, version, clock_.ApproximateNow(), |
| 119 guid_map_.insert(make_pair(guid, data)); | 122 close_packet); |
| 123 connection_id_map_.insert(make_pair(connection_id, data)); |
| 120 } | 124 } |
| 121 | 125 |
| 122 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const { | 126 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait( |
| 123 return guid_map_.find(guid) != guid_map_.end(); | 127 QuicConnectionId connection_id) const { |
| 128 return ContainsKey(connection_id_map_, connection_id); |
| 124 } | 129 } |
| 125 | 130 |
| 126 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) { | 131 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( |
| 127 GuidMap::iterator it = guid_map_.find(guid); | 132 QuicConnectionId connection_id) { |
| 128 DCHECK(it != guid_map_.end()); | 133 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); |
| 134 DCHECK(it != connection_id_map_.end()); |
| 129 return (it->second).version; | 135 return (it->second).version; |
| 130 } | 136 } |
| 131 | 137 |
| 132 void QuicTimeWaitListManager::OnCanWrite() { | 138 void QuicTimeWaitListManager::OnCanWrite() { |
| 133 while (!pending_packets_queue_.empty()) { | 139 while (!pending_packets_queue_.empty()) { |
| 134 QueuedPacket* queued_packet = pending_packets_queue_.front(); | 140 QueuedPacket* queued_packet = pending_packets_queue_.front(); |
| 135 if (!WriteToWire(queued_packet)) { | 141 if (!WriteToWire(queued_packet)) { |
| 136 return; | 142 return; |
| 137 } | 143 } |
| 138 pending_packets_queue_.pop_front(); | 144 pending_packets_queue_.pop_front(); |
| 139 delete queued_packet; | 145 delete queued_packet; |
| 140 } | 146 } |
| 141 } | 147 } |
| 142 | 148 |
| 143 void QuicTimeWaitListManager::ProcessPacket( | 149 void QuicTimeWaitListManager::ProcessPacket( |
| 144 const IPEndPoint& server_address, | 150 const IPEndPoint& server_address, |
| 145 const IPEndPoint& client_address, | 151 const IPEndPoint& client_address, |
| 146 QuicGuid guid, | 152 QuicConnectionId connection_id, |
| 147 QuicPacketSequenceNumber sequence_number) { | 153 QuicPacketSequenceNumber sequence_number) { |
| 148 DCHECK(IsGuidInTimeWait(guid)); | 154 DCHECK(IsConnectionIdInTimeWait(connection_id)); |
| 149 // TODO(satyamshekhar): Think about handling packets from different client | 155 // TODO(satyamshekhar): Think about handling packets from different client |
| 150 // addresses. | 156 // addresses. |
| 151 GuidMap::iterator it = guid_map_.find(guid); | 157 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); |
| 152 DCHECK(it != guid_map_.end()); | 158 DCHECK(it != connection_id_map_.end()); |
| 153 // Increment the received packet count. | 159 // Increment the received packet count. |
| 154 ++((it->second).num_packets); | 160 ++((it->second).num_packets); |
| 155 if (!ShouldSendResponse((it->second).num_packets)) { | 161 if (!ShouldSendResponse((it->second).num_packets)) { |
| 156 return; | 162 return; |
| 157 } | 163 } |
| 158 if (it->second.close_packet) { | 164 if (it->second.close_packet) { |
| 159 QueuedPacket* queued_packet = | 165 QueuedPacket* queued_packet = |
| 160 new QueuedPacket(server_address, | 166 new QueuedPacket(server_address, |
| 161 client_address, | 167 client_address, |
| 162 it->second.close_packet->Clone()); | 168 it->second.close_packet->Clone()); |
| 163 // Takes ownership of the packet. | 169 // Takes ownership of the packet. |
| 164 SendOrQueuePacket(queued_packet); | 170 SendOrQueuePacket(queued_packet); |
| 165 } else { | 171 } else { |
| 166 SendPublicReset(server_address, client_address, guid, sequence_number); | 172 SendPublicReset(server_address, |
| 173 client_address, |
| 174 connection_id, |
| 175 sequence_number); |
| 167 } | 176 } |
| 168 } | 177 } |
| 169 | 178 |
| 170 // Returns true if the number of packets received for this guid is a power of 2 | 179 // Returns true if the number of packets received for this connection_id is a |
| 171 // to throttle the number of public reset packets we send to a client. | 180 // power of 2 to throttle the number of public reset packets we send to a |
| 181 // client. |
| 172 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) { | 182 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) { |
| 173 return (received_packet_count & (received_packet_count - 1)) == 0; | 183 return (received_packet_count & (received_packet_count - 1)) == 0; |
| 174 } | 184 } |
| 175 | 185 |
| 176 void QuicTimeWaitListManager::SendPublicReset( | 186 void QuicTimeWaitListManager::SendPublicReset( |
| 177 const IPEndPoint& server_address, | 187 const IPEndPoint& server_address, |
| 178 const IPEndPoint& client_address, | 188 const IPEndPoint& client_address, |
| 179 QuicGuid guid, | 189 QuicConnectionId connection_id, |
| 180 QuicPacketSequenceNumber rejected_sequence_number) { | 190 QuicPacketSequenceNumber rejected_sequence_number) { |
| 181 QuicPublicResetPacket packet; | 191 QuicPublicResetPacket packet; |
| 182 packet.public_header.guid = guid; | 192 packet.public_header.connection_id = connection_id; |
| 183 packet.public_header.reset_flag = true; | 193 packet.public_header.reset_flag = true; |
| 184 packet.public_header.version_flag = false; | 194 packet.public_header.version_flag = false; |
| 185 packet.rejected_sequence_number = rejected_sequence_number; | 195 packet.rejected_sequence_number = rejected_sequence_number; |
| 186 // TODO(satyamshekhar): generate a valid nonce for this guid. | 196 // TODO(satyamshekhar): generate a valid nonce for this connection_id. |
| 187 packet.nonce_proof = 1010101; | 197 packet.nonce_proof = 1010101; |
| 188 packet.client_address = client_address; | 198 packet.client_address = client_address; |
| 189 QueuedPacket* queued_packet = new QueuedPacket( | 199 QueuedPacket* queued_packet = new QueuedPacket( |
| 190 server_address, | 200 server_address, |
| 191 client_address, | 201 client_address, |
| 192 QuicFramer::BuildPublicResetPacket(packet)); | 202 QuicFramer::BuildPublicResetPacket(packet)); |
| 193 // Takes ownership of the packet. | 203 // Takes ownership of the packet. |
| 194 SendOrQueuePacket(queued_packet); | 204 SendOrQueuePacket(queued_packet); |
| 195 } | 205 } |
| 196 | 206 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 221 visitor_->OnWriteBlocked(this); | 231 visitor_->OnWriteBlocked(this); |
| 222 return writer_->IsWriteBlockedDataBuffered(); | 232 return writer_->IsWriteBlockedDataBuffered(); |
| 223 } else if (result.status == WRITE_STATUS_ERROR) { | 233 } else if (result.status == WRITE_STATUS_ERROR) { |
| 224 LOG(WARNING) << "Received unknown error while sending reset packet to " | 234 LOG(WARNING) << "Received unknown error while sending reset packet to " |
| 225 << queued_packet->client_address().ToString() << ": " | 235 << queued_packet->client_address().ToString() << ": " |
| 226 << strerror(result.error_code); | 236 << strerror(result.error_code); |
| 227 } | 237 } |
| 228 return true; | 238 return true; |
| 229 } | 239 } |
| 230 | 240 |
| 231 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() { | 241 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() { |
| 232 guid_clean_up_alarm_->UnregisterIfRegistered(); | 242 connection_id_clean_up_alarm_->UnregisterIfRegistered(); |
| 233 int64 next_alarm_interval; | 243 int64 next_alarm_interval; |
| 234 if (!guid_map_.empty()) { | 244 if (!connection_id_map_.empty()) { |
| 235 QuicTime oldest_guid = guid_map_.begin()->second.time_added; | 245 QuicTime oldest_connection_id = |
| 246 connection_id_map_.begin()->second.time_added; |
| 236 QuicTime now = clock_.ApproximateNow(); | 247 QuicTime now = clock_.ApproximateNow(); |
| 237 if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) { | 248 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { |
| 238 next_alarm_interval = oldest_guid.Add(kTimeWaitPeriod_) | 249 next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_) |
| 239 .Subtract(now) | 250 .Subtract(now) |
| 240 .ToMicroseconds(); | 251 .ToMicroseconds(); |
| 241 } else { | 252 } else { |
| 242 LOG(ERROR) << "GUID lingered for longer than kTimeWaitPeriod"; | 253 LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod"; |
| 243 next_alarm_interval = 0; | 254 next_alarm_interval = 0; |
| 244 } | 255 } |
| 245 } else { | 256 } else { |
| 246 // No guids added so none will expire before kTimeWaitPeriod_. | 257 // No connection_ids added so none will expire before kTimeWaitPeriod_. |
| 247 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds(); | 258 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds(); |
| 248 } | 259 } |
| 249 | 260 |
| 250 epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval, | 261 epoll_server_->RegisterAlarmApproximateDelta( |
| 251 guid_clean_up_alarm_.get()); | 262 next_alarm_interval, connection_id_clean_up_alarm_.get()); |
| 252 } | 263 } |
| 253 | 264 |
| 254 void QuicTimeWaitListManager::CleanUpOldGuids() { | 265 void QuicTimeWaitListManager::CleanUpOldConnectionIds() { |
| 255 QuicTime now = clock_.ApproximateNow(); | 266 QuicTime now = clock_.ApproximateNow(); |
| 256 while (!guid_map_.empty()) { | 267 while (!connection_id_map_.empty()) { |
| 257 GuidMap::iterator it = guid_map_.begin(); | 268 ConnectionIdMap::iterator it = connection_id_map_.begin(); |
| 258 QuicTime oldest_guid = it->second.time_added; | 269 QuicTime oldest_connection_id = it->second.time_added; |
| 259 if (now.Subtract(oldest_guid) < kTimeWaitPeriod_) { | 270 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { |
| 260 break; | 271 break; |
| 261 } | 272 } |
| 262 // This guid has lived its age, retire it now. | 273 // This connection_id has lived its age, retire it now. |
| 263 delete it->second.close_packet; | 274 delete it->second.close_packet; |
| 264 guid_map_.erase(it); | 275 connection_id_map_.erase(it); |
| 265 } | 276 } |
| 266 SetGuidCleanUpAlarm(); | 277 SetConnectionIdCleanUpAlarm(); |
| 267 } | 278 } |
| 268 | 279 |
| 269 } // namespace tools | 280 } // namespace tools |
| 270 } // namespace net | 281 } // namespace net |
| OLD | NEW |