Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / net / tools / quic / quic_time_wait_list_manager.cc
blobc9e589c9dbec9715fa91b6b37eb8a1d71f64ca7a
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.
5 #include "net/tools/quic/quic_time_wait_list_manager.h"
7 #include <errno.h>
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_flags.h"
18 #include "net/quic/quic_framer.h"
19 #include "net/quic/quic_protocol.h"
20 #include "net/quic/quic_utils.h"
21 #include "net/tools/epoll_server/epoll_server.h"
22 #include "net/tools/quic/quic_server_session.h"
24 using base::StringPiece;
26 namespace net {
27 namespace tools {
29 // TODO(rtenneti): Remove the duplicated code in this file. Share code with
30 // "net/quic/quic_time_wait_list_manager.cc"
32 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
33 // up old connection_ids. This alarm should be unregistered and deleted before
34 // the QuicTimeWaitListManager is deleted.
35 class ConnectionIdCleanUpAlarm : public EpollAlarm {
36 public:
37 explicit ConnectionIdCleanUpAlarm(
38 QuicTimeWaitListManager* time_wait_list_manager)
39 : time_wait_list_manager_(time_wait_list_manager) {
42 int64 OnAlarm() override {
43 EpollAlarm::OnAlarm();
44 time_wait_list_manager_->CleanUpOldConnectionIds();
45 // Let the time wait manager register the alarm at appropriate time.
46 return 0;
49 private:
50 // Not owned.
51 QuicTimeWaitListManager* time_wait_list_manager_;
54 // This class stores pending public reset packets to be sent to clients.
55 // server_address - server address on which a packet what was received for
56 // a connection_id in time wait state.
57 // client_address - address of the client that sent that packet. Needed to send
58 // the public reset packet back to the client.
59 // packet - the pending public reset packet that is to be sent to the client.
60 // created instance takes the ownership of this packet.
61 class QuicTimeWaitListManager::QueuedPacket {
62 public:
63 QueuedPacket(const IPEndPoint& server_address,
64 const IPEndPoint& client_address,
65 QuicEncryptedPacket* packet)
66 : server_address_(server_address),
67 client_address_(client_address),
68 packet_(packet) {
71 const IPEndPoint& server_address() const { return server_address_; }
72 const IPEndPoint& client_address() const { return client_address_; }
73 QuicEncryptedPacket* packet() { return packet_.get(); }
75 private:
76 const IPEndPoint server_address_;
77 const IPEndPoint client_address_;
78 scoped_ptr<QuicEncryptedPacket> packet_;
80 DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
83 QuicTimeWaitListManager::QuicTimeWaitListManager(
84 QuicPacketWriter* writer,
85 QuicServerSessionVisitor* visitor,
86 EpollServer* epoll_server,
87 const QuicVersionVector& supported_versions)
88 : epoll_server_(epoll_server),
89 kTimeWaitPeriod_(
90 QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
91 connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
92 clock_(epoll_server_),
93 writer_(writer),
94 visitor_(visitor) {
95 SetConnectionIdCleanUpAlarm();
98 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
99 connection_id_clean_up_alarm_->UnregisterIfRegistered();
100 STLDeleteElements(&pending_packets_queue_);
101 for (ConnectionIdMap::iterator it = connection_id_map_.begin();
102 it != connection_id_map_.end();
103 ++it) {
104 delete it->second.close_packet;
108 void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
109 QuicConnectionId connection_id,
110 QuicVersion version,
111 QuicEncryptedPacket* close_packet) {
112 int num_packets = 0;
113 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
114 const bool new_connection_id = it == connection_id_map_.end();
115 if (!new_connection_id) { // Replace record if it is reinserted.
116 num_packets = it->second.num_packets;
117 delete it->second.close_packet;
118 connection_id_map_.erase(it);
120 TrimTimeWaitListIfNeeded();
121 if (FLAGS_quic_limit_time_wait_list_size) {
122 DCHECK_LT(num_connections(),
123 static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections));
125 ConnectionIdData data(num_packets,
126 version,
127 clock_.ApproximateNow(),
128 close_packet);
129 connection_id_map_.insert(std::make_pair(connection_id, data));
130 if (new_connection_id) {
131 visitor_->OnConnectionAddedToTimeWaitList(connection_id);
135 bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
136 QuicConnectionId connection_id) const {
137 return ContainsKey(connection_id_map_, connection_id);
140 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
141 QuicConnectionId connection_id) {
142 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
143 DCHECK(it != connection_id_map_.end());
144 return (it->second).version;
147 void QuicTimeWaitListManager::OnCanWrite() {
148 while (!pending_packets_queue_.empty()) {
149 QueuedPacket* queued_packet = pending_packets_queue_.front();
150 if (!WriteToWire(queued_packet)) {
151 return;
153 pending_packets_queue_.pop_front();
154 delete queued_packet;
158 void QuicTimeWaitListManager::ProcessPacket(
159 const IPEndPoint& server_address,
160 const IPEndPoint& client_address,
161 QuicConnectionId connection_id,
162 QuicPacketSequenceNumber sequence_number,
163 const QuicEncryptedPacket& /*packet*/) {
164 DCHECK(IsConnectionIdInTimeWait(connection_id));
165 DVLOG(1) << "Processing " << connection_id << " in time wait state.";
166 // TODO(satyamshekhar): Think about handling packets from different client
167 // addresses.
168 ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
169 DCHECK(it != connection_id_map_.end());
170 // Increment the received packet count.
171 ++((it->second).num_packets);
172 if (!ShouldSendResponse((it->second).num_packets)) {
173 return;
175 if (it->second.close_packet) {
176 QueuedPacket* queued_packet =
177 new QueuedPacket(server_address,
178 client_address,
179 it->second.close_packet->Clone());
180 // Takes ownership of the packet.
181 SendOrQueuePacket(queued_packet);
182 } else {
183 SendPublicReset(server_address,
184 client_address,
185 connection_id,
186 sequence_number);
190 // Returns true if the number of packets received for this connection_id is a
191 // power of 2 to throttle the number of public reset packets we send to a
192 // client.
193 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
194 return (received_packet_count & (received_packet_count - 1)) == 0;
197 void QuicTimeWaitListManager::SendPublicReset(
198 const IPEndPoint& server_address,
199 const IPEndPoint& client_address,
200 QuicConnectionId connection_id,
201 QuicPacketSequenceNumber rejected_sequence_number) {
202 QuicPublicResetPacket packet;
203 packet.public_header.connection_id = connection_id;
204 packet.public_header.reset_flag = true;
205 packet.public_header.version_flag = false;
206 packet.rejected_sequence_number = rejected_sequence_number;
207 // TODO(satyamshekhar): generate a valid nonce for this connection_id.
208 packet.nonce_proof = 1010101;
209 packet.client_address = client_address;
210 QueuedPacket* queued_packet = new QueuedPacket(
211 server_address,
212 client_address,
213 BuildPublicReset(packet));
214 // Takes ownership of the packet.
215 SendOrQueuePacket(queued_packet);
218 QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset(
219 const QuicPublicResetPacket& packet) {
220 return QuicFramer::BuildPublicResetPacket(packet);
223 // Either sends the packet and deletes it or makes pending queue the
224 // owner of the packet.
225 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
226 if (WriteToWire(packet)) {
227 delete packet;
228 } else {
229 // pending_packets_queue takes the ownership of the queued packet.
230 pending_packets_queue_.push_back(packet);
234 bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
235 if (writer_->IsWriteBlocked()) {
236 visitor_->OnWriteBlocked(this);
237 return false;
239 WriteResult result = writer_->WritePacket(
240 queued_packet->packet()->data(),
241 queued_packet->packet()->length(),
242 queued_packet->server_address().address(),
243 queued_packet->client_address());
244 if (result.status == WRITE_STATUS_BLOCKED) {
245 // If blocked and unbuffered, return false to retry sending.
246 DCHECK(writer_->IsWriteBlocked());
247 visitor_->OnWriteBlocked(this);
248 return writer_->IsWriteBlockedDataBuffered();
249 } else if (result.status == WRITE_STATUS_ERROR) {
250 LOG(WARNING) << "Received unknown error while sending reset packet to "
251 << queued_packet->client_address().ToString() << ": "
252 << strerror(result.error_code);
254 return true;
257 void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
258 connection_id_clean_up_alarm_->UnregisterIfRegistered();
259 int64 next_alarm_interval;
260 if (!connection_id_map_.empty()) {
261 QuicTime oldest_connection_id =
262 connection_id_map_.begin()->second.time_added;
263 QuicTime now = clock_.ApproximateNow();
264 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
265 next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_)
266 .Subtract(now)
267 .ToMicroseconds();
268 } else {
269 LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
270 next_alarm_interval = 0;
272 } else {
273 // No connection_ids added so none will expire before kTimeWaitPeriod_.
274 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
277 epoll_server_->RegisterAlarmApproximateDelta(
278 next_alarm_interval, connection_id_clean_up_alarm_.get());
281 bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
282 QuicTime expiration_time) {
283 if (connection_id_map_.empty()) {
284 return false;
286 ConnectionIdMap::iterator it = connection_id_map_.begin();
287 QuicTime oldest_connection_id_time = it->second.time_added;
288 if (oldest_connection_id_time > expiration_time) {
289 // Too recent, don't retire.
290 return false;
292 // This connection_id has lived its age, retire it now.
293 const QuicConnectionId connection_id = it->first;
294 delete it->second.close_packet;
295 connection_id_map_.erase(it);
296 visitor_->OnConnectionRemovedFromTimeWaitList(connection_id);
297 return true;
300 void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
301 QuicTime now = clock_.ApproximateNow();
302 QuicTime expiration = now.Subtract(kTimeWaitPeriod_);
303 if (FLAGS_quic_limit_time_wait_list_size) {
304 while (MaybeExpireOldestConnection(expiration)) {
306 } else {
307 while (!connection_id_map_.empty()) {
308 ConnectionIdMap::iterator it = connection_id_map_.begin();
309 QuicTime oldest_connection_id = it->second.time_added;
310 if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
311 break;
313 const QuicConnectionId connection_id = it->first;
314 // This connection_id has lived its age, retire it now.
315 delete it->second.close_packet;
316 connection_id_map_.erase(it);
317 visitor_->OnConnectionRemovedFromTimeWaitList(connection_id);
321 SetConnectionIdCleanUpAlarm();
324 void QuicTimeWaitListManager::TrimTimeWaitListIfNeeded() {
325 if (FLAGS_quic_limit_time_wait_list_size) {
326 if (FLAGS_quic_time_wait_list_max_connections < 0) {
327 return;
329 while (num_connections() >=
330 static_cast<size_t>(FLAGS_quic_time_wait_list_max_connections)) {
331 MaybeExpireOldestConnection(QuicTime::Infinite());
336 } // namespace tools
337 } // namespace net