Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / quic / quic_time_wait_list_manager.cc
bloba2fc4f84cb6f67b3b498ace6334e015db0f84af4
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"
21 using std::make_pair;
23 namespace net {
24 namespace tools {
26 namespace {
28 // Time period for which the guid should live in time wait state..
29 const int kTimeWaitSeconds = 5;
31 } // namespace
33 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
34 // up old guids. This alarm should be unregistered and deleted before the
35 // QuicTimeWaitListManager is deleted.
36 class GuidCleanUpAlarm : public EpollAlarm {
37 public:
38 explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
39 : time_wait_list_manager_(time_wait_list_manager) {
42 virtual int64 OnAlarm() OVERRIDE {
43 EpollAlarm::OnAlarm();
44 time_wait_list_manager_->CleanUpOldGuids();
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 struct QuicTimeWaitListManager::GuidAddTime {
55 GuidAddTime(QuicGuid guid, const QuicTime& time)
56 : guid(guid),
57 time_added(time) {
60 QuicGuid guid;
61 QuicTime time_added;
64 // This class stores pending public reset packets to be sent to clients.
65 // server_address - server address on which a packet what was received for
66 // a guid in time wait state.
67 // client_address - address of the client that sent that packet. Needed to send
68 // the public reset packet back to the client.
69 // packet - the pending public reset packet that is to be sent to the client.
70 // created instance takes the ownership of this packet.
71 class QuicTimeWaitListManager::QueuedPacket {
72 public:
73 QueuedPacket(const IPEndPoint& server_address,
74 const IPEndPoint& client_address,
75 QuicEncryptedPacket* packet)
76 : server_address_(server_address),
77 client_address_(client_address),
78 packet_(packet) {
81 const IPEndPoint& server_address() const { return server_address_; }
82 const IPEndPoint& client_address() const { return client_address_; }
83 QuicEncryptedPacket* packet() { return packet_.get(); }
85 private:
86 const IPEndPoint server_address_;
87 const IPEndPoint client_address_;
88 scoped_ptr<QuicEncryptedPacket> packet_;
90 DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
93 QuicTimeWaitListManager::QuicTimeWaitListManager(
94 QuicPacketWriter* writer,
95 EpollServer* epoll_server)
96 : framer_(QuicVersionMax(),
97 QuicTime::Zero(), // unused
98 true),
99 epoll_server_(epoll_server),
100 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
101 guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
102 clock_(epoll_server),
103 writer_(writer),
104 is_write_blocked_(false) {
105 framer_.set_visitor(this);
106 SetGuidCleanUpAlarm();
109 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
110 guid_clean_up_alarm_->UnregisterIfRegistered();
111 STLDeleteElements(&time_ordered_guid_list_);
112 STLDeleteElements(&pending_packets_queue_);
115 void QuicTimeWaitListManager::AddGuidToTimeWait(QuicGuid guid,
116 QuicVersion version) {
117 DCHECK(!IsGuidInTimeWait(guid));
118 // Initialize the guid with 0 packets received.
119 GuidData data(0, version);
120 guid_map_.insert(make_pair(guid, data));
121 time_ordered_guid_list_.push_back(new GuidAddTime(guid,
122 clock_.ApproximateNow()));
125 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
126 return guid_map_.find(guid) != guid_map_.end();
129 void QuicTimeWaitListManager::ProcessPacket(
130 const IPEndPoint& server_address,
131 const IPEndPoint& client_address,
132 QuicGuid guid,
133 const QuicEncryptedPacket& packet) {
134 DCHECK(IsGuidInTimeWait(guid));
135 server_address_ = server_address;
136 client_address_ = client_address;
138 // Set the framer to the appropriate version for this GUID, before processing.
139 QuicVersion version = GetQuicVersionFromGuid(guid);
140 framer_.set_version(version);
142 framer_.ProcessPacket(packet);
145 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
146 GuidMapIterator it = guid_map_.find(guid);
147 DCHECK(it != guid_map_.end());
148 return (it->second).version;
151 bool QuicTimeWaitListManager::OnCanWrite() {
152 is_write_blocked_ = false;
153 while (!is_write_blocked_ && !pending_packets_queue_.empty()) {
154 QueuedPacket* queued_packet = pending_packets_queue_.front();
155 WriteToWire(queued_packet);
156 if (!is_write_blocked_) {
157 pending_packets_queue_.pop_front();
158 delete queued_packet;
162 return !is_write_blocked_;
165 void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
166 DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
169 bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
170 QuicVersion received_version) {
171 // Drop such packets whose version don't match.
172 return false;
175 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& frame) {
176 return false;
179 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& frame) {
180 return false;
183 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
184 const QuicCongestionFeedbackFrame& frame) {
185 return false;
188 bool QuicTimeWaitListManager::OnRstStreamFrame(
189 const QuicRstStreamFrame& frame) {
190 return false;
193 bool QuicTimeWaitListManager::OnConnectionCloseFrame(
194 const QuicConnectionCloseFrame & frame) {
195 return false;
198 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
199 return false;
202 bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) {
203 // TODO(satyamshekhar): Think about handling packets from different client
204 // addresses.
205 GuidMapIterator it = guid_map_.find(header.public_header.guid);
206 DCHECK(it != guid_map_.end());
207 // Increment the received packet count.
208 ++((it->second).num_packets);
209 if (ShouldSendPublicReset((it->second).num_packets)) {
210 // We don't need the packet anymore. Just tell the client what sequence
211 // number we rejected.
212 SendPublicReset(server_address_,
213 client_address_,
214 header.public_header.guid,
215 header.packet_sequence_number);
217 // Never process the body of the packet in time wait state.
218 return false;
221 // Returns true if the number of packets received for this guid is a power of 2
222 // to throttle the number of public reset packets we send to a client.
223 bool QuicTimeWaitListManager::ShouldSendPublicReset(int received_packet_count) {
224 return (received_packet_count & (received_packet_count - 1)) == 0;
227 void QuicTimeWaitListManager::SendPublicReset(
228 const IPEndPoint& server_address,
229 const IPEndPoint& client_address,
230 QuicGuid guid,
231 QuicPacketSequenceNumber rejected_sequence_number) {
232 QuicPublicResetPacket packet;
233 packet.public_header.guid = guid;
234 packet.public_header.reset_flag = true;
235 packet.public_header.version_flag = false;
236 packet.rejected_sequence_number = rejected_sequence_number;
237 // TODO(satyamshekhar): generate a valid nonce for this guid.
238 packet.nonce_proof = 1010101;
239 QueuedPacket* queued_packet = new QueuedPacket(
240 server_address,
241 client_address,
242 framer_.BuildPublicResetPacket(packet));
243 // Takes ownership of the packet.
244 SendOrQueuePacket(queued_packet);
247 // Either sends the packet and deletes it or makes pending queue the
248 // owner of the packet.
249 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
250 if (!is_write_blocked_) {
251 // TODO(satyamshekhar): Handle packets that fail due to error other than
252 // EAGAIN or EWOULDBLOCK.
253 WriteToWire(packet);
256 if (is_write_blocked_) {
257 // pending_packets_queue takes the ownership of the queued packet.
258 pending_packets_queue_.push_back(packet);
259 } else {
260 delete packet;
264 void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
265 DCHECK(!is_write_blocked_);
266 int error;
267 int rc = writer_->WritePacket(queued_packet->packet()->data(),
268 queued_packet->packet()->length(),
269 queued_packet->server_address().address(),
270 queued_packet->client_address(),
271 this,
272 &error);
274 if (rc == -1) {
275 if (error == EAGAIN || error == EWOULDBLOCK) {
276 is_write_blocked_ = true;
277 } else {
278 LOG(WARNING) << "Received unknown error while sending reset packet to "
279 << queued_packet->client_address().ToString() << ": "
280 << strerror(error);
285 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
286 guid_clean_up_alarm_->UnregisterIfRegistered();
287 int64 next_alarm_interval;
288 if (!time_ordered_guid_list_.empty()) {
289 GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
290 QuicTime now = clock_.ApproximateNow();
291 DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_);
292 next_alarm_interval = oldest_guid->time_added
293 .Add(kTimeWaitPeriod_)
294 .Subtract(now)
295 .ToMicroseconds();
296 } else {
297 // No guids added so none will expire before kTimeWaitPeriod_.
298 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
301 epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
302 guid_clean_up_alarm_.get());
305 void QuicTimeWaitListManager::CleanUpOldGuids() {
306 QuicTime now = clock_.ApproximateNow();
307 while (time_ordered_guid_list_.size() > 0) {
308 DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size());
309 GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
310 if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) {
311 break;
313 // This guid has lived its age, retire it now.
314 guid_map_.erase(oldest_guid->guid);
315 time_ordered_guid_list_.pop_front();
316 delete oldest_guid;
318 SetGuidCleanUpAlarm();
321 } // namespace tools
322 } // namespace net