Home | History | Annotate | Download | only in quic
      1 // Copyright 2014 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/quic/quic_dispatcher.h"
      6 
      7 #include <errno.h>
      8 
      9 #include "base/debug/stack_trace.h"
     10 #include "base/logging.h"
     11 #include "base/stl_util.h"
     12 #include "net/quic/quic_blocked_writer_interface.h"
     13 #include "net/quic/quic_connection_helper.h"
     14 #include "net/quic/quic_flags.h"
     15 #include "net/quic/quic_time_wait_list_manager.h"
     16 #include "net/quic/quic_utils.h"
     17 
     18 namespace net {
     19 
     20 using base::StringPiece;
     21 using std::make_pair;
     22 using std::find;
     23 
     24 class DeleteSessionsAlarm : public QuicAlarm::Delegate {
     25  public:
     26   explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
     27       : dispatcher_(dispatcher) {
     28   }
     29 
     30   virtual QuicTime OnAlarm() OVERRIDE {
     31     dispatcher_->DeleteSessions();
     32     return QuicTime::Zero();
     33   }
     34 
     35  private:
     36   QuicDispatcher* dispatcher_;
     37 };
     38 
     39 class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface {
     40  public:
     41   explicit QuicFramerVisitor(QuicDispatcher* dispatcher)
     42       : dispatcher_(dispatcher),
     43         connection_id_(0) {}
     44 
     45   // QuicFramerVisitorInterface implementation
     46   virtual void OnPacket() OVERRIDE {}
     47   virtual bool OnUnauthenticatedPublicHeader(
     48       const QuicPacketPublicHeader& header) OVERRIDE {
     49     connection_id_ = header.connection_id;
     50     return dispatcher_->OnUnauthenticatedPublicHeader(header);
     51   }
     52   virtual bool OnUnauthenticatedHeader(
     53       const QuicPacketHeader& header) OVERRIDE {
     54     dispatcher_->OnUnauthenticatedHeader(header);
     55     return false;
     56   }
     57   virtual void OnError(QuicFramer* framer) OVERRIDE {
     58     DVLOG(1) << QuicUtils::ErrorToString(framer->error());
     59   }
     60 
     61   virtual bool OnProtocolVersionMismatch(
     62       QuicVersion /*received_version*/) OVERRIDE {
     63     if (dispatcher_->time_wait_list_manager()->IsConnectionIdInTimeWait(
     64             connection_id_)) {
     65       // Keep processing after protocol mismatch - this will be dealt with by
     66       // the TimeWaitListManager.
     67       return true;
     68     } else {
     69       DLOG(DFATAL) << "Version mismatch, connection ID (" << connection_id_
     70                    << ") not in time wait list.";
     71       return false;
     72     }
     73   }
     74 
     75   // The following methods should never get called because we always return
     76   // false from OnUnauthenticatedHeader().  As a result, we never process the
     77   // payload of the packet.
     78   virtual void OnPublicResetPacket(
     79       const QuicPublicResetPacket& /*packet*/) OVERRIDE {
     80     DCHECK(false);
     81   }
     82   virtual void OnVersionNegotiationPacket(
     83       const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE {
     84     DCHECK(false);
     85   }
     86   virtual void OnDecryptedPacket(EncryptionLevel level) OVERRIDE {
     87     DCHECK(false);
     88   }
     89   virtual bool OnPacketHeader(const QuicPacketHeader& /*header*/) OVERRIDE {
     90     DCHECK(false);
     91     return false;
     92   }
     93   virtual void OnRevivedPacket() OVERRIDE {
     94     DCHECK(false);
     95   }
     96   virtual void OnFecProtectedPayload(StringPiece /*payload*/) OVERRIDE {
     97     DCHECK(false);
     98   }
     99   virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE {
    100     DCHECK(false);
    101     return false;
    102   }
    103   virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE {
    104     DCHECK(false);
    105     return false;
    106   }
    107   virtual bool OnCongestionFeedbackFrame(
    108       const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE {
    109     DCHECK(false);
    110     return false;
    111   }
    112   virtual bool OnStopWaitingFrame(
    113       const QuicStopWaitingFrame& /*frame*/) OVERRIDE {
    114     DCHECK(false);
    115     return false;
    116   }
    117   virtual bool OnPingFrame(const QuicPingFrame& /*frame*/) OVERRIDE {
    118     DCHECK(false);
    119     return false;
    120   }
    121   virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE {
    122     DCHECK(false);
    123     return false;
    124   }
    125   virtual bool OnConnectionCloseFrame(
    126       const QuicConnectionCloseFrame & /*frame*/) OVERRIDE {
    127     DCHECK(false);
    128     return false;
    129   }
    130   virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE {
    131     DCHECK(false);
    132     return false;
    133   }
    134   virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/)
    135       OVERRIDE {
    136     DCHECK(false);
    137     return false;
    138   }
    139   virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) OVERRIDE {
    140     DCHECK(false);
    141     return false;
    142   }
    143   virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE {
    144     DCHECK(false);
    145   }
    146   virtual void OnPacketComplete() OVERRIDE {
    147     DCHECK(false);
    148   }
    149 
    150  private:
    151   QuicDispatcher* dispatcher_;
    152 
    153   // Latched in OnUnauthenticatedPublicHeader for use later.
    154   QuicConnectionId connection_id_;
    155 };
    156 
    157 QuicDispatcher::QuicDispatcher(const QuicConfig& config,
    158                                const QuicCryptoServerConfig& crypto_config,
    159                                const QuicVersionVector& supported_versions,
    160                                QuicConnectionHelperInterface* helper)
    161     : config_(config),
    162       crypto_config_(crypto_config),
    163       helper_(helper),
    164       delete_sessions_alarm_(
    165           helper_->CreateAlarm(new DeleteSessionsAlarm(this))),
    166       supported_versions_(supported_versions),
    167       supported_versions_no_flow_control_(supported_versions),
    168       supported_versions_no_connection_flow_control_(supported_versions),
    169       current_packet_(NULL),
    170       framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
    171       framer_visitor_(new QuicFramerVisitor(this)) {
    172   framer_.set_visitor(framer_visitor_.get());
    173 }
    174 
    175 QuicDispatcher::~QuicDispatcher() {
    176   STLDeleteValues(&session_map_);
    177   STLDeleteElements(&closed_session_list_);
    178 }
    179 
    180 void QuicDispatcher::Initialize(QuicPacketWriter* writer) {
    181   DCHECK(writer_ == NULL);
    182   writer_.reset(writer);
    183   time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
    184 
    185   // Remove all versions > QUIC_VERSION_16 from the
    186   // supported_versions_no_flow_control_ vector.
    187   QuicVersionVector::iterator it =
    188       find(supported_versions_no_flow_control_.begin(),
    189            supported_versions_no_flow_control_.end(), QUIC_VERSION_17);
    190   if (it != supported_versions_no_flow_control_.end()) {
    191     supported_versions_no_flow_control_.erase(
    192         supported_versions_no_flow_control_.begin(), it + 1);
    193   }
    194   CHECK(!supported_versions_no_flow_control_.empty());
    195 
    196   // Remove all versions > QUIC_VERSION_18 from the
    197   // supported_versions_no_connection_flow_control_ vector.
    198   QuicVersionVector::iterator connection_it =
    199       find(supported_versions_no_connection_flow_control_.begin(),
    200            supported_versions_no_connection_flow_control_.end(),
    201            QUIC_VERSION_19);
    202   if (connection_it != supported_versions_no_connection_flow_control_.end()) {
    203     supported_versions_no_connection_flow_control_.erase(
    204         supported_versions_no_connection_flow_control_.begin(),
    205         connection_it + 1);
    206   }
    207   CHECK(!supported_versions_no_connection_flow_control_.empty());
    208 }
    209 
    210 void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
    211                                    const IPEndPoint& client_address,
    212                                    const QuicEncryptedPacket& packet) {
    213   current_server_address_ = server_address;
    214   current_client_address_ = client_address;
    215   current_packet_ = &packet;
    216   // ProcessPacket will cause the packet to be dispatched in
    217   // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
    218   // in OnAuthenticatedHeader.
    219   framer_.ProcessPacket(packet);
    220   // TODO(rjshade): Return a status describing if/why a packet was dropped,
    221   //                and log somehow.  Maybe expose as a varz.
    222 }
    223 
    224 bool QuicDispatcher::OnUnauthenticatedPublicHeader(
    225     const QuicPacketPublicHeader& header) {
    226   QuicSession* session = NULL;
    227 
    228   QuicConnectionId connection_id = header.connection_id;
    229   SessionMap::iterator it = session_map_.find(connection_id);
    230   if (it == session_map_.end()) {
    231     if (header.reset_flag) {
    232       return false;
    233     }
    234     if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
    235       return HandlePacketForTimeWait(header);
    236     }
    237 
    238     // Ensure the packet has a version negotiation bit set before creating a new
    239     // session for it.  All initial packets for a new connection are required to
    240     // have the flag set.  Otherwise it may be a stray packet.
    241     if (header.version_flag) {
    242       session = CreateQuicSession(connection_id, current_server_address_,
    243                                   current_client_address_);
    244     }
    245 
    246     if (session == NULL) {
    247       DVLOG(1) << "Failed to create session for " << connection_id;
    248       // Add this connection_id fo the time-wait state, to safely reject future
    249       // packets.
    250 
    251       if (header.version_flag &&
    252           !framer_.IsSupportedVersion(header.versions.front())) {
    253         // TODO(ianswett): Produce a no-version version negotiation packet.
    254         return false;
    255       }
    256 
    257       // Use the version in the packet if possible, otherwise assume the latest.
    258       QuicVersion version = header.version_flag ? header.versions.front() :
    259           supported_versions_.front();
    260       time_wait_list_manager_->AddConnectionIdToTimeWait(
    261           connection_id, version, NULL);
    262       DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
    263       return HandlePacketForTimeWait(header);
    264     }
    265     DVLOG(1) << "Created new session for " << connection_id;
    266     session_map_.insert(make_pair(connection_id, session));
    267   } else {
    268     session = it->second;
    269   }
    270 
    271   session->connection()->ProcessUdpPacket(
    272       current_server_address_, current_client_address_, *current_packet_);
    273 
    274   // Do not parse the packet further.  The session will process it completely.
    275   return false;
    276 }
    277 
    278 void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
    279   DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
    280       header.public_header.connection_id));
    281   time_wait_list_manager_->ProcessPacket(current_server_address_,
    282                                          current_client_address_,
    283                                          header.public_header.connection_id,
    284                                          header.packet_sequence_number,
    285                                          *current_packet_);
    286 }
    287 
    288 void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
    289   QuicConnection* connection = it->second->connection();
    290   QuicEncryptedPacket* connection_close_packet =
    291       connection->ReleaseConnectionClosePacket();
    292   write_blocked_list_.erase(connection);
    293   time_wait_list_manager_->AddConnectionIdToTimeWait(it->first,
    294                                                      connection->version(),
    295                                                      connection_close_packet);
    296   session_map_.erase(it);
    297 }
    298 
    299 void QuicDispatcher::DeleteSessions() {
    300   STLDeleteElements(&closed_session_list_);
    301 }
    302 
    303 void QuicDispatcher::OnCanWrite() {
    304   // We got an EPOLLOUT: the socket should not be blocked.
    305   writer_->SetWritable();
    306 
    307   // Give each writer one attempt to write.
    308   int num_writers = write_blocked_list_.size();
    309   for (int i = 0; i < num_writers; ++i) {
    310     if (write_blocked_list_.empty()) {
    311       return;
    312     }
    313     QuicBlockedWriterInterface* blocked_writer =
    314         write_blocked_list_.begin()->first;
    315     write_blocked_list_.erase(write_blocked_list_.begin());
    316     blocked_writer->OnCanWrite();
    317     if (writer_->IsWriteBlocked()) {
    318       // We were unable to write.  Wait for the next EPOLLOUT. The writer is
    319       // responsible for adding itself to the blocked list via OnWriteBlocked().
    320       return;
    321     }
    322   }
    323 }
    324 
    325 bool QuicDispatcher::HasPendingWrites() const {
    326   return !write_blocked_list_.empty();
    327 }
    328 
    329 void QuicDispatcher::Shutdown() {
    330   while (!session_map_.empty()) {
    331     QuicSession* session = session_map_.begin()->second;
    332     session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
    333     // Validate that the session removes itself from the session map on close.
    334     DCHECK(session_map_.empty() || session_map_.begin()->second != session);
    335   }
    336   DeleteSessions();
    337 }
    338 
    339 void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
    340                                         QuicErrorCode error) {
    341   SessionMap::iterator it = session_map_.find(connection_id);
    342   if (it == session_map_.end()) {
    343     LOG(DFATAL) << "ConnectionId " << connection_id
    344                 << " does not exist in the session map.  "
    345                 << "Error: " << QuicUtils::ErrorToString(error);
    346     LOG(DFATAL) << base::debug::StackTrace().ToString();
    347     return;
    348   }
    349   DVLOG_IF(1, error != QUIC_NO_ERROR) << "Closing connection ("
    350                                       << connection_id
    351                                       << ") due to error: "
    352                                       << QuicUtils::ErrorToString(error);
    353   if (closed_session_list_.empty()) {
    354     delete_sessions_alarm_->Set(helper_->GetClock()->ApproximateNow());
    355   }
    356   closed_session_list_.push_back(it->second);
    357   CleanUpSession(it);
    358 }
    359 
    360 void QuicDispatcher::OnWriteBlocked(QuicBlockedWriterInterface* writer) {
    361   DCHECK(writer_->IsWriteBlocked());
    362   write_blocked_list_.insert(make_pair(writer, true));
    363 }
    364 
    365 QuicSession* QuicDispatcher::CreateQuicSession(
    366     QuicConnectionId connection_id,
    367     const IPEndPoint& server_address,
    368     const IPEndPoint& client_address) {
    369   QuicServerSession* session = new QuicServerSession(
    370       config_,
    371       CreateQuicConnection(connection_id, server_address, client_address),
    372       this);
    373   session->InitializeSession(crypto_config_);
    374   return session;
    375 }
    376 
    377 QuicConnection* QuicDispatcher::CreateQuicConnection(
    378     QuicConnectionId connection_id,
    379     const IPEndPoint& server_address,
    380     const IPEndPoint& client_address) {
    381   if (FLAGS_enable_quic_stream_flow_control_2 &&
    382       FLAGS_enable_quic_connection_flow_control_2) {
    383     DVLOG(1) << "Creating QuicDispatcher with all versions.";
    384     return new QuicConnection(connection_id, client_address, helper_,
    385                               writer_.get(), true, supported_versions_);
    386   }
    387 
    388   if (FLAGS_enable_quic_stream_flow_control_2 &&
    389       !FLAGS_enable_quic_connection_flow_control_2) {
    390     DVLOG(1) << "Connection flow control disabled, creating QuicDispatcher "
    391              << "WITHOUT version 19 or higher.";
    392     return new QuicConnection(connection_id, client_address, helper_,
    393                               writer_.get(), true,
    394                               supported_versions_no_connection_flow_control_);
    395   }
    396 
    397   DVLOG(1) << "Flow control disabled, creating QuicDispatcher WITHOUT "
    398            << "version 17 or higher.";
    399   return new QuicConnection(connection_id, client_address, helper_,
    400                             writer_.get(), true,
    401                             supported_versions_no_flow_control_);
    402 }
    403 
    404 QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
    405   return new QuicTimeWaitListManager(
    406       writer_.get(), this, helper_, supported_versions());
    407 }
    408 
    409 bool QuicDispatcher::HandlePacketForTimeWait(
    410     const QuicPacketPublicHeader& header) {
    411   if (header.reset_flag) {
    412     // Public reset packets do not have sequence numbers, so ignore the packet.
    413     return false;
    414   }
    415 
    416   // Switch the framer to the correct version, so that the sequence number can
    417   // be parsed correctly.
    418   framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId(
    419       header.connection_id));
    420 
    421   // Continue parsing the packet to extract the sequence number.  Then
    422   // send it to the time wait manager in OnUnathenticatedHeader.
    423   return true;
    424 }
    425 
    426 }  // namespace net
    427