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