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" |
(...skipping 21 matching lines...) Expand all Loading... |
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 connection_ids. This alarm should be unregistered and deleted before | 36 // up old connection_ids. This alarm should be unregistered and deleted before |
37 // the QuicTimeWaitListManager is deleted. | 37 // the QuicTimeWaitListManager is deleted. |
38 class ConnectionIdCleanUpAlarm : public EpollAlarm { | 38 class ConnectionIdCleanUpAlarm : public EpollAlarm { |
39 public: | 39 public: |
40 explicit ConnectionIdCleanUpAlarm( | 40 explicit ConnectionIdCleanUpAlarm( |
41 QuicTimeWaitListManager* time_wait_list_manager) | 41 QuicTimeWaitListManager* time_wait_list_manager) |
42 : time_wait_list_manager_(time_wait_list_manager) { | 42 : time_wait_list_manager_(time_wait_list_manager) {} |
43 } | |
44 | 43 |
45 virtual int64 OnAlarm() OVERRIDE { | 44 virtual int64 OnAlarm() OVERRIDE { |
46 EpollAlarm::OnAlarm(); | 45 EpollAlarm::OnAlarm(); |
47 time_wait_list_manager_->CleanUpOldConnectionIds(); | 46 time_wait_list_manager_->CleanUpOldConnectionIds(); |
48 // Let the time wait manager register the alarm at appropriate time. | 47 // Let the time wait manager register the alarm at appropriate time. |
49 return 0; | 48 return 0; |
50 } | 49 } |
51 | 50 |
52 private: | 51 private: |
53 // Not owned. | 52 // Not owned. |
54 QuicTimeWaitListManager* time_wait_list_manager_; | 53 QuicTimeWaitListManager* time_wait_list_manager_; |
55 }; | 54 }; |
56 | 55 |
57 // This class stores pending public reset packets to be sent to clients. | 56 // This class stores pending public reset packets to be sent to clients. |
58 // server_address - server address on which a packet what was received for | 57 // server_address - server address on which a packet what was received for |
59 // a connection_id in time wait state. | 58 // a connection_id in time wait state. |
60 // client_address - address of the client that sent that packet. Needed to send | 59 // client_address - address of the client that sent that packet. Needed to send |
61 // the public reset packet back to the client. | 60 // the public reset packet back to the client. |
62 // packet - the pending public reset packet that is to be sent to the client. | 61 // packet - the pending public reset packet that is to be sent to the client. |
63 // created instance takes the ownership of this packet. | 62 // created instance takes the ownership of this packet. |
64 class QuicTimeWaitListManager::QueuedPacket { | 63 class QuicTimeWaitListManager::QueuedPacket { |
65 public: | 64 public: |
66 QueuedPacket(const IPEndPoint& server_address, | 65 QueuedPacket(const IPEndPoint& server_address, |
67 const IPEndPoint& client_address, | 66 const IPEndPoint& client_address, |
68 QuicEncryptedPacket* packet) | 67 QuicEncryptedPacket* packet) |
69 : server_address_(server_address), | 68 : server_address_(server_address), |
70 client_address_(client_address), | 69 client_address_(client_address), |
71 packet_(packet) { | 70 packet_(packet) {} |
72 } | |
73 | 71 |
74 const IPEndPoint& server_address() const { return server_address_; } | 72 const IPEndPoint& server_address() const { return server_address_; } |
75 const IPEndPoint& client_address() const { return client_address_; } | 73 const IPEndPoint& client_address() const { return client_address_; } |
76 QuicEncryptedPacket* packet() { return packet_.get(); } | 74 QuicEncryptedPacket* packet() { return packet_.get(); } |
77 | 75 |
78 private: | 76 private: |
79 const IPEndPoint server_address_; | 77 const IPEndPoint server_address_; |
80 const IPEndPoint client_address_; | 78 const IPEndPoint client_address_; |
81 scoped_ptr<QuicEncryptedPacket> packet_; | 79 scoped_ptr<QuicEncryptedPacket> packet_; |
82 | 80 |
(...skipping 29 matching lines...) Expand all Loading... |
112 QuicVersion version, | 110 QuicVersion version, |
113 QuicEncryptedPacket* close_packet) { | 111 QuicEncryptedPacket* close_packet) { |
114 DVLOG(1) << "Adding " << connection_id << " to the time wait list."; | 112 DVLOG(1) << "Adding " << connection_id << " to the time wait list."; |
115 int num_packets = 0; | 113 int num_packets = 0; |
116 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); | 114 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); |
117 if (it != connection_id_map_.end()) { // Replace record if it is reinserted. | 115 if (it != connection_id_map_.end()) { // Replace record if it is reinserted. |
118 num_packets = it->second.num_packets; | 116 num_packets = it->second.num_packets; |
119 delete it->second.close_packet; | 117 delete it->second.close_packet; |
120 connection_id_map_.erase(it); | 118 connection_id_map_.erase(it); |
121 } | 119 } |
122 ConnectionIdData data(num_packets, version, clock_.ApproximateNow(), | 120 ConnectionIdData data( |
123 close_packet); | 121 num_packets, version, clock_.ApproximateNow(), close_packet); |
124 connection_id_map_.insert(make_pair(connection_id, data)); | 122 connection_id_map_.insert(make_pair(connection_id, data)); |
125 } | 123 } |
126 | 124 |
127 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait( | 125 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait( |
128 QuicConnectionId connection_id) const { | 126 QuicConnectionId connection_id) const { |
129 return ContainsKey(connection_id_map_, connection_id); | 127 return ContainsKey(connection_id_map_, connection_id); |
130 } | 128 } |
131 | 129 |
132 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( | 130 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( |
133 QuicConnectionId connection_id) { | 131 QuicConnectionId connection_id) { |
(...skipping 24 matching lines...) Expand all Loading... |
158 // TODO(satyamshekhar): Think about handling packets from different client | 156 // TODO(satyamshekhar): Think about handling packets from different client |
159 // addresses. | 157 // addresses. |
160 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); | 158 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); |
161 DCHECK(it != connection_id_map_.end()); | 159 DCHECK(it != connection_id_map_.end()); |
162 // Increment the received packet count. | 160 // Increment the received packet count. |
163 ++((it->second).num_packets); | 161 ++((it->second).num_packets); |
164 if (!ShouldSendResponse((it->second).num_packets)) { | 162 if (!ShouldSendResponse((it->second).num_packets)) { |
165 return; | 163 return; |
166 } | 164 } |
167 if (it->second.close_packet) { | 165 if (it->second.close_packet) { |
168 QueuedPacket* queued_packet = | 166 QueuedPacket* queued_packet = new QueuedPacket( |
169 new QueuedPacket(server_address, | 167 server_address, client_address, it->second.close_packet->Clone()); |
170 client_address, | 168 // Takes ownership of the packet. |
171 it->second.close_packet->Clone()); | 169 SendOrQueuePacket(queued_packet); |
172 // Takes ownership of the packet. | |
173 SendOrQueuePacket(queued_packet); | |
174 } else { | 170 } else { |
175 SendPublicReset(server_address, | 171 SendPublicReset( |
176 client_address, | 172 server_address, client_address, connection_id, sequence_number); |
177 connection_id, | |
178 sequence_number); | |
179 } | 173 } |
180 } | 174 } |
181 | 175 |
182 // Returns true if the number of packets received for this connection_id is a | 176 // Returns true if the number of packets received for this connection_id is a |
183 // power of 2 to throttle the number of public reset packets we send to a | 177 // power of 2 to throttle the number of public reset packets we send to a |
184 // client. | 178 // client. |
185 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) { | 179 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) { |
186 return (received_packet_count & (received_packet_count - 1)) == 0; | 180 return (received_packet_count & (received_packet_count - 1)) == 0; |
187 } | 181 } |
188 | 182 |
189 void QuicTimeWaitListManager::SendPublicReset( | 183 void QuicTimeWaitListManager::SendPublicReset( |
190 const IPEndPoint& server_address, | 184 const IPEndPoint& server_address, |
191 const IPEndPoint& client_address, | 185 const IPEndPoint& client_address, |
192 QuicConnectionId connection_id, | 186 QuicConnectionId connection_id, |
193 QuicPacketSequenceNumber rejected_sequence_number) { | 187 QuicPacketSequenceNumber rejected_sequence_number) { |
194 QuicPublicResetPacket packet; | 188 QuicPublicResetPacket packet; |
195 packet.public_header.connection_id = connection_id; | 189 packet.public_header.connection_id = connection_id; |
196 packet.public_header.reset_flag = true; | 190 packet.public_header.reset_flag = true; |
197 packet.public_header.version_flag = false; | 191 packet.public_header.version_flag = false; |
198 packet.rejected_sequence_number = rejected_sequence_number; | 192 packet.rejected_sequence_number = rejected_sequence_number; |
199 // TODO(satyamshekhar): generate a valid nonce for this connection_id. | 193 // TODO(satyamshekhar): generate a valid nonce for this connection_id. |
200 packet.nonce_proof = 1010101; | 194 packet.nonce_proof = 1010101; |
201 packet.client_address = client_address; | 195 packet.client_address = client_address; |
202 QueuedPacket* queued_packet = new QueuedPacket( | 196 QueuedPacket* queued_packet = new QueuedPacket( |
203 server_address, | 197 server_address, client_address, BuildPublicReset(packet)); |
204 client_address, | |
205 BuildPublicReset(packet)); | |
206 // Takes ownership of the packet. | 198 // Takes ownership of the packet. |
207 SendOrQueuePacket(queued_packet); | 199 SendOrQueuePacket(queued_packet); |
208 } | 200 } |
209 | 201 |
210 QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset( | 202 QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset( |
211 const QuicPublicResetPacket& packet) { | 203 const QuicPublicResetPacket& packet) { |
212 return QuicFramer::BuildPublicResetPacket(packet); | 204 return QuicFramer::BuildPublicResetPacket(packet); |
213 } | 205 } |
214 | 206 |
215 // Either sends the packet and deletes it or makes pending queue the | 207 // Either sends the packet and deletes it or makes pending queue the |
216 // owner of the packet. | 208 // owner of the packet. |
217 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) { | 209 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) { |
218 if (WriteToWire(packet)) { | 210 if (WriteToWire(packet)) { |
219 delete packet; | 211 delete packet; |
220 } else { | 212 } else { |
221 // pending_packets_queue takes the ownership of the queued packet. | 213 // pending_packets_queue takes the ownership of the queued packet. |
222 pending_packets_queue_.push_back(packet); | 214 pending_packets_queue_.push_back(packet); |
223 } | 215 } |
224 } | 216 } |
225 | 217 |
226 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { | 218 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { |
227 if (writer_->IsWriteBlocked()) { | 219 if (writer_->IsWriteBlocked()) { |
228 visitor_->OnWriteBlocked(this); | 220 visitor_->OnWriteBlocked(this); |
229 return false; | 221 return false; |
230 } | 222 } |
231 WriteResult result = writer_->WritePacket( | 223 WriteResult result = |
232 queued_packet->packet()->data(), | 224 writer_->WritePacket(queued_packet->packet()->data(), |
233 queued_packet->packet()->length(), | 225 queued_packet->packet()->length(), |
234 queued_packet->server_address().address(), | 226 queued_packet->server_address().address(), |
235 queued_packet->client_address()); | 227 queued_packet->client_address()); |
236 if (result.status == WRITE_STATUS_BLOCKED) { | 228 if (result.status == WRITE_STATUS_BLOCKED) { |
237 // If blocked and unbuffered, return false to retry sending. | 229 // If blocked and unbuffered, return false to retry sending. |
238 DCHECK(writer_->IsWriteBlocked()); | 230 DCHECK(writer_->IsWriteBlocked()); |
239 visitor_->OnWriteBlocked(this); | 231 visitor_->OnWriteBlocked(this); |
240 return writer_->IsWriteBlockedDataBuffered(); | 232 return writer_->IsWriteBlockedDataBuffered(); |
241 } else if (result.status == WRITE_STATUS_ERROR) { | 233 } else if (result.status == WRITE_STATUS_ERROR) { |
242 LOG(WARNING) << "Received unknown error while sending reset packet to " | 234 LOG(WARNING) << "Received unknown error while sending reset packet to " |
243 << queued_packet->client_address().ToString() << ": " | 235 << queued_packet->client_address().ToString() << ": " |
244 << strerror(result.error_code); | 236 << strerror(result.error_code); |
245 } | 237 } |
246 return true; | 238 return true; |
247 } | 239 } |
248 | 240 |
249 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() { | 241 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() { |
250 connection_id_clean_up_alarm_->UnregisterIfRegistered(); | 242 connection_id_clean_up_alarm_->UnregisterIfRegistered(); |
251 int64 next_alarm_interval; | 243 int64 next_alarm_interval; |
252 if (!connection_id_map_.empty()) { | 244 if (!connection_id_map_.empty()) { |
253 QuicTime oldest_connection_id = | 245 QuicTime oldest_connection_id = |
254 connection_id_map_.begin()->second.time_added; | 246 connection_id_map_.begin()->second.time_added; |
255 QuicTime now = clock_.ApproximateNow(); | 247 QuicTime now = clock_.ApproximateNow(); |
256 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { | 248 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) { |
257 next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_) | 249 next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_) |
258 .Subtract(now) | 250 .Subtract(now) |
259 .ToMicroseconds(); | 251 .ToMicroseconds(); |
260 } else { | 252 } else { |
261 LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod"; | 253 LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod"; |
262 next_alarm_interval = 0; | 254 next_alarm_interval = 0; |
263 } | 255 } |
264 } else { | 256 } else { |
265 // No connection_ids added so none will expire before kTimeWaitPeriod_. | 257 // No connection_ids added so none will expire before kTimeWaitPeriod_. |
266 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds(); | 258 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds(); |
267 } | 259 } |
268 | 260 |
269 epoll_server_->RegisterAlarmApproximateDelta( | 261 epoll_server_->RegisterAlarmApproximateDelta( |
(...skipping 10 matching lines...) Expand all Loading... |
280 } | 272 } |
281 // This connection_id has lived its age, retire it now. | 273 // This connection_id has lived its age, retire it now. |
282 delete it->second.close_packet; | 274 delete it->second.close_packet; |
283 connection_id_map_.erase(it); | 275 connection_id_map_.erase(it); |
284 } | 276 } |
285 SetConnectionIdCleanUpAlarm(); | 277 SetConnectionIdCleanUpAlarm(); |
286 } | 278 } |
287 | 279 |
288 } // namespace tools | 280 } // namespace tools |
289 } // namespace net | 281 } // namespace net |
OLD | NEW |