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"
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"
28 // Time period for which the guid should live in time wait state..
29 const int kTimeWaitSeconds
= 5;
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
{
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.
51 QuicTimeWaitListManager
* time_wait_list_manager_
;
54 struct QuicTimeWaitListManager::GuidAddTime
{
55 GuidAddTime(QuicGuid guid
, const QuicTime
& time
)
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
{
73 QueuedPacket(const IPEndPoint
& server_address
,
74 const IPEndPoint
& client_address
,
75 QuicEncryptedPacket
* packet
)
76 : server_address_(server_address
),
77 client_address_(client_address
),
81 const IPEndPoint
& server_address() const { return server_address_
; }
82 const IPEndPoint
& client_address() const { return client_address_
; }
83 QuicEncryptedPacket
* packet() { return packet_
.get(); }
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
99 epoll_server_(epoll_server
),
100 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds
)),
101 guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
102 clock_(epoll_server
),
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
,
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.
175 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame
& frame
) {
179 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame
& frame
) {
183 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
184 const QuicCongestionFeedbackFrame
& frame
) {
188 bool QuicTimeWaitListManager::OnRstStreamFrame(
189 const QuicRstStreamFrame
& frame
) {
193 bool QuicTimeWaitListManager::OnConnectionCloseFrame(
194 const QuicConnectionCloseFrame
& frame
) {
198 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame
& frame
) {
202 bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader
& header
) {
203 // TODO(satyamshekhar): Think about handling packets from different client
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_
,
214 header
.public_header
.guid
,
215 header
.packet_sequence_number
);
217 // Never process the body of the packet in time wait state.
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
,
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(
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.
256 if (is_write_blocked_
) {
257 // pending_packets_queue takes the ownership of the queued packet.
258 pending_packets_queue_
.push_back(packet
);
264 void QuicTimeWaitListManager::WriteToWire(QueuedPacket
* queued_packet
) {
265 DCHECK(!is_write_blocked_
);
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(),
275 if (error
== EAGAIN
|| error
== EWOULDBLOCK
) {
276 is_write_blocked_
= true;
278 LOG(WARNING
) << "Received unknown error while sending reset packet to "
279 << queued_packet
->client_address().ToString() << ": "
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_
)
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_
) {
313 // This guid has lived its age, retire it now.
314 guid_map_
.erase(oldest_guid
->guid
);
315 time_ordered_guid_list_
.pop_front();
318 SetGuidCleanUpAlarm();