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