• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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