Home | History | Annotate | Download | only in quic
      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 std::make_pair;
     22 
     23 namespace net {
     24 namespace tools {
     25 
     26 namespace {
     27 
     28 // Time period for which the guid should live in time wait state..
     29 const int kTimeWaitSeconds = 5;
     30 
     31 }  // namespace
     32 
     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) {
     40   }
     41 
     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;
     47   }
     48 
     49  private:
     50   // Not owned.
     51   QuicTimeWaitListManager* time_wait_list_manager_;
     52 };
     53 
     54 struct QuicTimeWaitListManager::GuidAddTime {
     55   GuidAddTime(QuicGuid guid, const QuicTime& time)
     56       : guid(guid),
     57         time_added(time) {
     58   }
     59 
     60   QuicGuid guid;
     61   QuicTime time_added;
     62 };
     63 
     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) {
     79   }
     80 
     81   const IPEndPoint& server_address() const { return server_address_; }
     82   const IPEndPoint& client_address() const { return client_address_; }
     83   QuicEncryptedPacket* packet() { return packet_.get(); }
     84 
     85  private:
     86   const IPEndPoint server_address_;
     87   const IPEndPoint client_address_;
     88   scoped_ptr<QuicEncryptedPacket> packet_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
     91 };
     92 
     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();
    107 }
    108 
    109 QuicTimeWaitListManager::~QuicTimeWaitListManager() {
    110   guid_clean_up_alarm_->UnregisterIfRegistered();
    111   STLDeleteElements(&time_ordered_guid_list_);
    112   STLDeleteElements(&pending_packets_queue_);
    113 }
    114 
    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()));
    123 }
    124 
    125 bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
    126   return guid_map_.find(guid) != guid_map_.end();
    127 }
    128 
    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;
    137 
    138   // Set the framer to the appropriate version for this GUID, before processing.
    139   QuicVersion version = GetQuicVersionFromGuid(guid);
    140   framer_.set_version(version);
    141 
    142   framer_.ProcessPacket(packet);
    143 }
    144 
    145 QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
    146   GuidMapIterator it = guid_map_.find(guid);
    147   DCHECK(it != guid_map_.end());
    148   return (it->second).version;
    149 }
    150 
    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;
    159     }
    160   }
    161 
    162   return !is_write_blocked_;
    163 }
    164 
    165 void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
    166   DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
    167 }
    168 
    169 bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
    170     QuicVersion received_version) {
    171   // Drop such packets whose version don't match.
    172   return false;
    173 }
    174 
    175 bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& frame) {
    176   return false;
    177 }
    178 
    179 bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& frame) {
    180   return false;
    181 }
    182 
    183 bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
    184     const QuicCongestionFeedbackFrame& frame) {
    185   return false;
    186 }
    187 
    188 bool QuicTimeWaitListManager::OnRstStreamFrame(
    189     const QuicRstStreamFrame& frame) {
    190   return false;
    191 }
    192 
    193 bool QuicTimeWaitListManager::OnConnectionCloseFrame(
    194     const QuicConnectionCloseFrame & frame) {
    195   return false;
    196 }
    197 
    198 bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
    199   return false;
    200 }
    201 
    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);
    216   }
    217   // Never process the body of the packet in time wait state.
    218   return false;
    219 }
    220 
    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;
    225 }
    226 
    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);
    245 }
    246 
    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);
    254   }
    255 
    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;
    261   }
    262 }
    263 
    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);
    273 
    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);
    281     }
    282   }
    283 }
    284 
    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();
    299   }
    300 
    301   epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
    302                                                guid_clean_up_alarm_.get());
    303 }
    304 
    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;
    312     }
    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;
    317   }
    318   SetGuidCleanUpAlarm();
    319 }
    320 
    321 }  // namespace tools
    322 }  // namespace net
    323