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.
4
5 #include "net/tools/quic/quic_time_wait_list_manager.h"
6
7 #include <errno.h>
8
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
21 using base::StringPiece;
22 using std::make_pair;
23
24 namespace net {
25 namespace tools {
26
27 namespace {
28
29 // Time period for which the guid should live in time wait state..
30 const int kTimeWaitSeconds = 5;
31
32 } // namespace
33
34 // A very simple alarm that just informs the QuicTimeWaitListManager to clean
35 // up old guids. This alarm should be unregistered and deleted before the
36 // QuicTimeWaitListManager is deleted.
37 class GuidCleanUpAlarm : public EpollAlarm {
38 public:
GuidCleanUpAlarm(QuicTimeWaitListManager * time_wait_list_manager)39 explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
40 : time_wait_list_manager_(time_wait_list_manager) {
41 }
42
OnAlarm()43 virtual int64 OnAlarm() OVERRIDE {
44 EpollAlarm::OnAlarm();
45 time_wait_list_manager_->CleanUpOldGuids();
46 // Let the time wait manager register the alarm at appropriate time.
47 return 0;
48 }
49
50 private:
51 // Not owned.
52 QuicTimeWaitListManager* time_wait_list_manager_;
53 };
54
55 struct QuicTimeWaitListManager::GuidAddTime {
GuidAddTimenet::tools::QuicTimeWaitListManager::GuidAddTime56 GuidAddTime(QuicGuid guid, const QuicTime& time)
57 : guid(guid),
58 time_added(time) {
59 }
60
61 QuicGuid guid;
62 QuicTime time_added;
63 };
64
65 // This class stores pending public reset packets to be sent to clients.
66 // server_address - server address on which a packet what was received for
67 // a guid in time wait state.
68 // client_address - address of the client that sent that packet. Needed to send
69 // the public reset packet back to the client.
70 // packet - the pending public reset packet that is to be sent to the client.
71 // created instance takes the ownership of this packet.
72 class QuicTimeWaitListManager::QueuedPacket {
73 public:
QueuedPacket(const IPEndPoint & server_address,const IPEndPoint & client_address,QuicEncryptedPacket * packet)74 QueuedPacket(const IPEndPoint& server_address,
75 const IPEndPoint& client_address,
76 QuicEncryptedPacket* packet)
77 : server_address_(server_address),
78 client_address_(client_address),
79 packet_(packet) {
80 }
81
server_address() const82 const IPEndPoint& server_address() const { return server_address_; }
client_address() const83 const IPEndPoint& client_address() const { return client_address_; }
packet()84 QuicEncryptedPacket* packet() { return packet_.get(); }
85
86 private:
87 const IPEndPoint server_address_;
88 const IPEndPoint client_address_;
89 scoped_ptr<QuicEncryptedPacket> packet_;
90
91 DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
92 };
93
QuicTimeWaitListManager(QuicPacketWriter * writer,EpollServer * epoll_server,const QuicVersionVector & supported_versions)94 QuicTimeWaitListManager::QuicTimeWaitListManager(
95 QuicPacketWriter* writer,
96 EpollServer* epoll_server,
97 const QuicVersionVector& supported_versions)
98 : framer_(supported_versions,
99 QuicTime::Zero(), // unused
100 true),
101 epoll_server_(epoll_server),
102 kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
103 guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
104 clock_(epoll_server),
105 writer_(writer),
106 is_write_blocked_(false) {
107 framer_.set_visitor(this);
108 SetGuidCleanUpAlarm();
109 }
110
~QuicTimeWaitListManager()111 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
112 guid_clean_up_alarm_->UnregisterIfRegistered();
113 STLDeleteElements(&time_ordered_guid_list_);
114 STLDeleteElements(&pending_packets_queue_);
115 for (GuidMapIterator it = guid_map_.begin(); it != guid_map_.end(); ++it) {
116 delete it->second.close_packet;
117 }
118 }
119
AddGuidToTimeWait(QuicGuid guid,QuicVersion version,QuicEncryptedPacket * close_packet)120 void QuicTimeWaitListManager::AddGuidToTimeWait(
121 QuicGuid guid,
122 QuicVersion version,
123 QuicEncryptedPacket* close_packet) {
124 DCHECK(!IsGuidInTimeWait(guid));
125 // Initialize the guid with 0 packets received.
126 GuidData data(0, version, close_packet);
127 guid_map_.insert(make_pair(guid, data));
128 time_ordered_guid_list_.push_back(new GuidAddTime(guid,
129 clock_.ApproximateNow()));
130 }
131
IsGuidInTimeWait(QuicGuid guid) const132 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
133 return guid_map_.find(guid) != guid_map_.end();
134 }
135
ProcessPacket(const IPEndPoint & server_address,const IPEndPoint & client_address,QuicGuid guid,const QuicEncryptedPacket & packet)136 void QuicTimeWaitListManager::ProcessPacket(
137 const IPEndPoint& server_address,
138 const IPEndPoint& client_address,
139 QuicGuid guid,
140 const QuicEncryptedPacket& packet) {
141 DCHECK(IsGuidInTimeWait(guid));
142 server_address_ = server_address;
143 client_address_ = client_address;
144
145 // Set the framer to the appropriate version for this GUID, before processing.
146 QuicVersion version = GetQuicVersionFromGuid(guid);
147 framer_.set_version(version);
148
149 framer_.ProcessPacket(packet);
150 }
151
GetQuicVersionFromGuid(QuicGuid guid)152 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
153 GuidMapIterator it = guid_map_.find(guid);
154 DCHECK(it != guid_map_.end());
155 return (it->second).version;
156 }
157
OnCanWrite()158 bool QuicTimeWaitListManager::OnCanWrite() {
159 is_write_blocked_ = false;
160 while (!is_write_blocked_ && !pending_packets_queue_.empty()) {
161 QueuedPacket* queued_packet = pending_packets_queue_.front();
162 WriteToWire(queued_packet);
163 if (!is_write_blocked_) {
164 pending_packets_queue_.pop_front();
165 delete queued_packet;
166 }
167 }
168
169 return !is_write_blocked_;
170 }
171
OnError(QuicFramer * framer)172 void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
173 DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
174 }
175
OnProtocolVersionMismatch(QuicVersion received_version)176 bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
177 QuicVersion received_version) {
178 // Drop such packets whose version don't match.
179 return false;
180 }
181
OnUnauthenticatedHeader(const QuicPacketHeader & header)182 bool QuicTimeWaitListManager::OnUnauthenticatedHeader(
183 const QuicPacketHeader& header) {
184 // TODO(satyamshekhar): Think about handling packets from different client
185 // addresses.
186 GuidMapIterator it = guid_map_.find(header.public_header.guid);
187 DCHECK(it != guid_map_.end());
188 // Increment the received packet count.
189 ++((it->second).num_packets);
190 if (!ShouldSendResponse((it->second).num_packets)) {
191 return false;
192 }
193 if (it->second.close_packet) {
194 QueuedPacket* queued_packet =
195 new QueuedPacket(server_address_,
196 client_address_,
197 it->second.close_packet->Clone());
198 // Takes ownership of the packet.
199 SendOrQueuePacket(queued_packet);
200 } else {
201 // We don't need the packet anymore. Just tell the client what sequence
202 // number we rejected.
203 SendPublicReset(server_address_,
204 client_address_,
205 header.public_header.guid,
206 header.packet_sequence_number);
207 }
208 // Never process the body of the packet in time wait state.
209 return false;
210 }
211
OnPacketHeader(const QuicPacketHeader & header)212 bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) {
213 DCHECK(false);
214 return false;
215 }
216
OnRevivedPacket()217 void QuicTimeWaitListManager::OnRevivedPacket() {
218 DCHECK(false);
219 }
220
OnFecProtectedPayload(StringPiece)221 void QuicTimeWaitListManager::OnFecProtectedPayload(StringPiece /*payload*/) {
222 DCHECK(false);
223 }
224
OnStreamFrame(const QuicStreamFrame &)225 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
226 DCHECK(false);
227 return false;
228 }
229
OnAckFrame(const QuicAckFrame &)230 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& /*frame*/) {
231 DCHECK(false);
232 return false;
233 }
234
OnCongestionFeedbackFrame(const QuicCongestionFeedbackFrame &)235 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
236 const QuicCongestionFeedbackFrame& /*frame*/) {
237 DCHECK(false);
238 return false;
239 }
240
OnRstStreamFrame(const QuicRstStreamFrame &)241 bool QuicTimeWaitListManager::OnRstStreamFrame(
242 const QuicRstStreamFrame& /*frame*/) {
243 DCHECK(false);
244 return false;
245 }
246
OnConnectionCloseFrame(const QuicConnectionCloseFrame &)247 bool QuicTimeWaitListManager::OnConnectionCloseFrame(
248 const QuicConnectionCloseFrame & /*frame*/) {
249 DCHECK(false);
250 return false;
251 }
252
OnGoAwayFrame(const QuicGoAwayFrame &)253 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
254 DCHECK(false);
255 return false;
256 }
257
OnFecData(const QuicFecData &)258 void QuicTimeWaitListManager::OnFecData(const QuicFecData& /*fec*/) {
259 DCHECK(false);
260 }
261
262 // Returns true if the number of packets received for this guid is a power of 2
263 // to throttle the number of public reset packets we send to a client.
ShouldSendResponse(int received_packet_count)264 bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
265 return (received_packet_count & (received_packet_count - 1)) == 0;
266 }
267
SendPublicReset(const IPEndPoint & server_address,const IPEndPoint & client_address,QuicGuid guid,QuicPacketSequenceNumber rejected_sequence_number)268 void QuicTimeWaitListManager::SendPublicReset(
269 const IPEndPoint& server_address,
270 const IPEndPoint& client_address,
271 QuicGuid guid,
272 QuicPacketSequenceNumber rejected_sequence_number) {
273 QuicPublicResetPacket packet;
274 packet.public_header.guid = guid;
275 packet.public_header.reset_flag = true;
276 packet.public_header.version_flag = false;
277 packet.rejected_sequence_number = rejected_sequence_number;
278 // TODO(satyamshekhar): generate a valid nonce for this guid.
279 packet.nonce_proof = 1010101;
280 QueuedPacket* queued_packet = new QueuedPacket(
281 server_address,
282 client_address,
283 QuicFramer::BuildPublicResetPacket(packet));
284 // Takes ownership of the packet.
285 SendOrQueuePacket(queued_packet);
286 }
287
288 // Either sends the packet and deletes it or makes pending queue the
289 // owner of the packet.
SendOrQueuePacket(QueuedPacket * packet)290 void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
291 if (!is_write_blocked_) {
292 // TODO(satyamshekhar): Handle packets that fail due to error other than
293 // EAGAIN or EWOULDBLOCK.
294 WriteToWire(packet);
295 }
296
297 if (is_write_blocked_) {
298 // pending_packets_queue takes the ownership of the queued packet.
299 pending_packets_queue_.push_back(packet);
300 } else {
301 delete packet;
302 }
303 }
304
WriteToWire(QueuedPacket * queued_packet)305 void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
306 DCHECK(!is_write_blocked_);
307 WriteResult result = writer_->WritePacket(
308 queued_packet->packet()->data(),
309 queued_packet->packet()->length(),
310 queued_packet->server_address().address(),
311 queued_packet->client_address(),
312 this);
313
314 if (result.status == WRITE_STATUS_BLOCKED) {
315 is_write_blocked_ = true;
316 } else if (result.status == WRITE_STATUS_ERROR) {
317 LOG(WARNING) << "Received unknown error while sending reset packet to "
318 << queued_packet->client_address().ToString() << ": "
319 << strerror(result.error_code);
320 }
321 }
322
SetGuidCleanUpAlarm()323 void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
324 guid_clean_up_alarm_->UnregisterIfRegistered();
325 int64 next_alarm_interval;
326 if (!time_ordered_guid_list_.empty()) {
327 GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
328 QuicTime now = clock_.ApproximateNow();
329 DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_);
330 next_alarm_interval = oldest_guid->time_added
331 .Add(kTimeWaitPeriod_)
332 .Subtract(now)
333 .ToMicroseconds();
334 } else {
335 // No guids added so none will expire before kTimeWaitPeriod_.
336 next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
337 }
338
339 epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
340 guid_clean_up_alarm_.get());
341 }
342
CleanUpOldGuids()343 void QuicTimeWaitListManager::CleanUpOldGuids() {
344 QuicTime now = clock_.ApproximateNow();
345 while (time_ordered_guid_list_.size() > 0) {
346 DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size());
347 GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
348 if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) {
349 break;
350 }
351 // This guid has lived its age, retire it now.
352 GuidMapIterator it = guid_map_.find(oldest_guid->guid);
353 DCHECK(it != guid_map_.end());
354 delete it->second.close_packet;
355 guid_map_.erase(oldest_guid->guid);
356 time_ordered_guid_list_.pop_front();
357 delete oldest_guid;
358 }
359 SetGuidCleanUpAlarm();
360 }
361
362 } // namespace tools
363 } // namespace net
364