• 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_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 
QuicServerSession(const QuicConfig & config,QuicConnection * connection,QuicServerSessionVisitor * visitor)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 
~QuicServerSession()25 QuicServerSession::~QuicServerSession() {}
26 
InitializeSession(const QuicCryptoServerConfig & crypto_config)27 void QuicServerSession::InitializeSession(
28     const QuicCryptoServerConfig& crypto_config) {
29   QuicSession::InitializeSession();
30   crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
31 }
32 
CreateQuicCryptoServerStream(const QuicCryptoServerConfig & crypto_config)33 QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
34     const QuicCryptoServerConfig& crypto_config) {
35   return new QuicCryptoServerStream(crypto_config, this);
36 }
37 
OnConfigNegotiated()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 
OnConnectionClosed(QuicErrorCode error,bool from_peer)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 
OnWriteBlocked()61 void QuicServerSession::OnWriteBlocked() {
62   QuicSession::OnWriteBlocked();
63   visitor_->OnWriteBlocked(connection());
64 }
65 
OnCongestionWindowChange(QuicTime now)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 
ShouldCreateIncomingDataStream(QuicStreamId id)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 
CreateIncomingDataStream(QuicStreamId id)155 QuicDataStream* QuicServerSession::CreateIncomingDataStream(
156     QuicStreamId id) {
157   if (!ShouldCreateIncomingDataStream(id)) {
158     return NULL;
159   }
160 
161   return new QuicSpdyServerStream(id, this);
162 }
163 
CreateOutgoingDataStream()164 QuicDataStream* QuicServerSession::CreateOutgoingDataStream() {
165   DLOG(ERROR) << "Server push not yet supported";
166   return NULL;
167 }
168 
GetCryptoStream()169 QuicCryptoServerStream* QuicServerSession::GetCryptoStream() {
170   return crypto_stream_.get();
171 }
172 
173 }  // namespace tools
174 }  // namespace net
175