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_server_session.h"
      6 
      7 #include "base/logging.h"
      8 #include "net/quic/crypto/source_address_token.h"
      9 #include "net/quic/quic_connection.h"
     10 #include "net/quic/quic_flags.h"
     11 #include "net/quic/reliable_quic_stream.h"
     12 #include "net/tools/quic/quic_spdy_server_stream.h"
     13 
     14 namespace net {
     15 namespace tools {
     16 
     17 QuicServerSession::QuicServerSession(const QuicConfig& config,
     18                                      QuicConnection* connection,
     19                                      QuicServerSessionVisitor* visitor)
     20     : QuicSession(connection, config),
     21       visitor_(visitor),
     22       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
     23       last_server_config_update_time_(QuicTime::Zero()) {}
     24 
     25 QuicServerSession::~QuicServerSession() {}
     26 
     27 void QuicServerSession::InitializeSession(
     28     const QuicCryptoServerConfig& crypto_config) {
     29   QuicSession::InitializeSession();
     30   crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
     31 }
     32 
     33 QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
     34     const QuicCryptoServerConfig& crypto_config) {
     35   return new QuicCryptoServerStream(crypto_config, this);
     36 }
     37 
     38 void QuicServerSession::OnConfigNegotiated() {
     39   QuicSession::OnConfigNegotiated();
     40   if (!FLAGS_enable_quic_fec ||
     41       !config()->HasReceivedConnectionOptions() ||
     42       !net::ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
     43     return;
     44   }
     45   // kFHDR config maps to FEC protection always for headers stream.
     46   // TODO(jri): Add crypto stream in addition to headers for kHDR.
     47   headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
     48 }
     49 
     50 void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
     51                                            bool from_peer) {
     52   QuicSession::OnConnectionClosed(error, from_peer);
     53   // In the unlikely event we get a connection close while doing an asynchronous
     54   // crypto event, make sure we cancel the callback.
     55   if (crypto_stream_.get() != NULL) {
     56     crypto_stream_->CancelOutstandingCallbacks();
     57   }
     58   visitor_->OnConnectionClosed(connection()->connection_id(), error);
     59 }
     60 
     61 void QuicServerSession::OnWriteBlocked() {
     62   QuicSession::OnWriteBlocked();
     63   visitor_->OnWriteBlocked(connection());
     64 }
     65 
     66 void QuicServerSession::OnCongestionWindowChange(QuicTime now) {
     67   if (connection()->version() <= QUIC_VERSION_21) {
     68     return;
     69   }
     70 
     71   // If not enough time has passed since the last time we sent an update to the
     72   // client, then return early.
     73   const QuicSentPacketManager& sent_packet_manager =
     74       connection()->sent_packet_manager();
     75   int64 srtt_ms =
     76       sent_packet_manager.GetRttStats()->SmoothedRtt().ToMilliseconds();
     77   int64 now_ms = now.Subtract(last_server_config_update_time_).ToMilliseconds();
     78   if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
     79       now_ms < kMinIntervalBetweenServerConfigUpdatesMs) {
     80     return;
     81   }
     82 
     83   // If the bandwidth recorder does not have a valid estimate, return early.
     84   const QuicSustainedBandwidthRecorder& bandwidth_recorder =
     85       sent_packet_manager.SustainedBandwidthRecorder();
     86   if (!bandwidth_recorder.HasEstimate()) {
     87     return;
     88   }
     89 
     90   // The bandwidth recorder has recorded at least one sustained bandwidth
     91   // estimate. Check that it's substantially different from the last one that
     92   // we sent to the client, and if so, send the new one.
     93   QuicBandwidth new_bandwidth_estimate = bandwidth_recorder.BandwidthEstimate();
     94 
     95   int64 bandwidth_delta =
     96       std::abs(new_bandwidth_estimate.ToBitsPerSecond() -
     97                bandwidth_estimate_sent_to_client_.ToBitsPerSecond());
     98 
     99   // Define "substantial" difference as a 50% increase or decrease from the
    100   // last estimate.
    101   bool substantial_difference =
    102       bandwidth_delta >
    103       0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond();
    104   if (!substantial_difference) {
    105     return;
    106   }
    107 
    108   bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
    109   DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
    110            << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
    111 
    112   // Include max bandwidth in the update.
    113   QuicBandwidth max_bandwidth_estimate =
    114       bandwidth_recorder.MaxBandwidthEstimate();
    115   int32 max_bandwidth_timestamp = bandwidth_recorder.MaxBandwidthTimestamp();
    116 
    117   // Fill the proto before passing it to the crypto stream to send.
    118   CachedNetworkParameters cached_network_params;
    119   cached_network_params.set_bandwidth_estimate_bytes_per_second(
    120       bandwidth_estimate_sent_to_client_.ToBytesPerSecond());
    121   cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
    122       max_bandwidth_estimate.ToBytesPerSecond());
    123   cached_network_params.set_max_bandwidth_timestamp_seconds(
    124       max_bandwidth_timestamp);
    125   cached_network_params.set_min_rtt_ms(
    126       sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
    127   cached_network_params.set_previous_connection_state(
    128       bandwidth_recorder.EstimateRecordedDuringSlowStart()
    129           ? CachedNetworkParameters::SLOW_START
    130           : CachedNetworkParameters::CONGESTION_AVOIDANCE);
    131   if (!serving_region_.empty()) {
    132     cached_network_params.set_serving_region(serving_region_);
    133   }
    134 
    135   crypto_stream_->SendServerConfigUpdate(&cached_network_params);
    136   last_server_config_update_time_ = now;
    137 }
    138 
    139 bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
    140   if (id % 2 == 0) {
    141     DVLOG(1) << "Invalid incoming even stream_id:" << id;
    142     connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
    143     return false;
    144   }
    145   if (GetNumOpenStreams() >= get_max_open_streams()) {
    146     DVLOG(1) << "Failed to create a new incoming stream with id:" << id
    147              << " Already " << GetNumOpenStreams() << " streams open (max "
    148              << get_max_open_streams() << ").";
    149     connection()->SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS);
    150     return false;
    151   }
    152   return true;
    153 }
    154 
    155 QuicDataStream* QuicServerSession::CreateIncomingDataStream(
    156     QuicStreamId id) {
    157   if (!ShouldCreateIncomingDataStream(id)) {
    158     return NULL;
    159   }
    160 
    161   return new QuicSpdyServerStream(id, this);
    162 }
    163 
    164 QuicDataStream* QuicServerSession::CreateOutgoingDataStream() {
    165   DLOG(ERROR) << "Server push not yet supported";
    166   return NULL;
    167 }
    168 
    169 QuicCryptoServerStream* QuicServerSession::GetCryptoStream() {
    170   return crypto_stream_.get();
    171 }
    172 
    173 }  // namespace tools
    174 }  // namespace net
    175