• 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 "quiche/quic/core/http/quic_server_session_base.h"
6 
7 #include <string>
8 
9 #include "quiche/quic/core/proto/cached_network_parameters_proto.h"
10 #include "quiche/quic/core/quic_connection.h"
11 #include "quiche/quic/core/quic_stream.h"
12 #include "quiche/quic/core/quic_tag.h"
13 #include "quiche/quic/core/quic_time.h"
14 #include "quiche/quic/core/quic_types.h"
15 #include "quiche/quic/core/quic_utils.h"
16 #include "quiche/quic/platform/api/quic_bug_tracker.h"
17 #include "quiche/quic/platform/api/quic_flag_utils.h"
18 #include "quiche/quic/platform/api/quic_flags.h"
19 #include "quiche/quic/platform/api/quic_logging.h"
20 #include "quiche/common/platform/api/quiche_logging.h"
21 
22 namespace quic {
23 
QuicServerSessionBase(const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QuicConnection * connection,Visitor * visitor,QuicCryptoServerStreamBase::Helper * helper,const QuicCryptoServerConfig * crypto_config,QuicCompressedCertsCache * compressed_certs_cache)24 QuicServerSessionBase::QuicServerSessionBase(
25     const QuicConfig& config, const ParsedQuicVersionVector& supported_versions,
26     QuicConnection* connection, Visitor* visitor,
27     QuicCryptoServerStreamBase::Helper* helper,
28     const QuicCryptoServerConfig* crypto_config,
29     QuicCompressedCertsCache* compressed_certs_cache)
30     : QuicSpdySession(connection, visitor, config, supported_versions),
31       crypto_config_(crypto_config),
32       compressed_certs_cache_(compressed_certs_cache),
33       helper_(helper),
34       bandwidth_resumption_enabled_(false),
35       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
36       last_scup_time_(QuicTime::Zero()) {}
37 
~QuicServerSessionBase()38 QuicServerSessionBase::~QuicServerSessionBase() {}
39 
Initialize()40 void QuicServerSessionBase::Initialize() {
41   crypto_stream_ =
42       CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_);
43   QuicSpdySession::Initialize();
44   SendSettingsToCryptoStream();
45 }
46 
OnConfigNegotiated()47 void QuicServerSessionBase::OnConfigNegotiated() {
48   QuicSpdySession::OnConfigNegotiated();
49 
50   const CachedNetworkParameters* cached_network_params =
51       crypto_stream_->PreviousCachedNetworkParams();
52 
53   // Set the initial rtt from cached_network_params.min_rtt_ms, which comes from
54   // a validated address token. This will override the initial rtt that may have
55   // been set by the transport parameters.
56   if (version().UsesTls() && cached_network_params != nullptr) {
57     if (cached_network_params->serving_region() == serving_region_) {
58       QUIC_CODE_COUNT(quic_server_received_network_params_at_same_region);
59       if (config()->HasReceivedConnectionOptions() &&
60           ContainsQuicTag(config()->ReceivedConnectionOptions(), kTRTT)) {
61         QUIC_DLOG(INFO)
62             << "Server: Setting initial rtt to "
63             << cached_network_params->min_rtt_ms()
64             << "ms which is received from a validated address token";
65         connection()->sent_packet_manager().SetInitialRtt(
66             QuicTime::Delta::FromMilliseconds(
67                 cached_network_params->min_rtt_ms()),
68             /*trusted=*/true);
69       }
70     } else {
71       QUIC_CODE_COUNT(quic_server_received_network_params_at_different_region);
72     }
73   }
74 
75   if (!config()->HasReceivedConnectionOptions()) {
76     return;
77   }
78 
79   if (GetQuicReloadableFlag(quic_enable_disable_resumption) &&
80       version().UsesTls() &&
81       ContainsQuicTag(config()->ReceivedConnectionOptions(), kNRES) &&
82       crypto_stream_->ResumptionAttempted()) {
83     QUIC_RELOADABLE_FLAG_COUNT(quic_enable_disable_resumption);
84     const bool disabled = crypto_stream_->DisableResumption();
85     QUIC_BUG_IF(quic_failed_to_disable_resumption, !disabled)
86         << "Failed to disable resumption";
87   }
88 
89   enable_sending_bandwidth_estimate_when_network_idle_ =
90       GetQuicRestartFlag(
91           quic_enable_sending_bandwidth_estimate_when_network_idle_v2) &&
92       version().HasIetfQuicFrames() &&
93       ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWID);
94 
95   // Enable bandwidth resumption if peer sent correct connection options.
96   const bool last_bandwidth_resumption =
97       ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
98   const bool max_bandwidth_resumption =
99       ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWMX);
100   bandwidth_resumption_enabled_ =
101       last_bandwidth_resumption || max_bandwidth_resumption;
102 
103   // If the client has provided a bandwidth estimate from the same serving
104   // region as this server, then decide whether to use the data for bandwidth
105   // resumption.
106   if (cached_network_params != nullptr &&
107       cached_network_params->serving_region() == serving_region_) {
108     if (!version().UsesTls()) {
109       // Log the received connection parameters, regardless of how they
110       // get used for bandwidth resumption.
111       connection()->OnReceiveConnectionState(*cached_network_params);
112     }
113 
114     if (bandwidth_resumption_enabled_) {
115       // Only do bandwidth resumption if estimate is recent enough.
116       const uint64_t seconds_since_estimate =
117           connection()->clock()->WallNow().ToUNIXSeconds() -
118           cached_network_params->timestamp();
119       if (seconds_since_estimate <= kNumSecondsPerHour) {
120         connection()->ResumeConnectionState(*cached_network_params,
121                                             max_bandwidth_resumption);
122       }
123     }
124   }
125 }
126 
OnConnectionClosed(const QuicConnectionCloseFrame & frame,ConnectionCloseSource source)127 void QuicServerSessionBase::OnConnectionClosed(
128     const QuicConnectionCloseFrame& frame, ConnectionCloseSource source) {
129   QuicSession::OnConnectionClosed(frame, source);
130   // In the unlikely event we get a connection close while doing an asynchronous
131   // crypto event, make sure we cancel the callback.
132   if (crypto_stream_ != nullptr) {
133     crypto_stream_->CancelOutstandingCallbacks();
134   }
135 }
136 
OnBandwidthUpdateTimeout()137 void QuicServerSessionBase::OnBandwidthUpdateTimeout() {
138   if (!enable_sending_bandwidth_estimate_when_network_idle_) {
139     return;
140   }
141   QUIC_DVLOG(1) << "Bandwidth update timed out.";
142   const SendAlgorithmInterface* send_algorithm =
143       connection()->sent_packet_manager().GetSendAlgorithm();
144   if (send_algorithm != nullptr &&
145       send_algorithm->HasGoodBandwidthEstimateForResumption()) {
146     const bool success = MaybeSendAddressToken();
147     QUIC_BUG_IF(QUIC_BUG_25522, !success) << "Failed to send address token.";
148     QUIC_RESTART_FLAG_COUNT_N(
149         quic_enable_sending_bandwidth_estimate_when_network_idle_v2, 2, 3);
150   }
151 }
152 
OnCongestionWindowChange(QuicTime now)153 void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
154   // Sending bandwidth is no longer conditioned on if session does bandwidth
155   // resumption.
156   if (GetQuicRestartFlag(
157           quic_enable_sending_bandwidth_estimate_when_network_idle_v2)) {
158     QUIC_RESTART_FLAG_COUNT_N(
159         quic_enable_sending_bandwidth_estimate_when_network_idle_v2, 3, 3);
160     return;
161   }
162   if (!bandwidth_resumption_enabled_) {
163     return;
164   }
165   // Only send updates when the application has no data to write.
166   if (HasDataToWrite()) {
167     return;
168   }
169 
170   // If not enough time has passed since the last time we sent an update to the
171   // client, or not enough packets have been sent, then return early.
172   const QuicSentPacketManager& sent_packet_manager =
173       connection()->sent_packet_manager();
174   int64_t srtt_ms =
175       sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
176   int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
177   int64_t packets_since_last_scup = 0;
178   const QuicPacketNumber largest_sent_packet =
179       connection()->sent_packet_manager().GetLargestSentPacket();
180   if (largest_sent_packet.IsInitialized()) {
181     packets_since_last_scup =
182         last_scup_packet_number_.IsInitialized()
183             ? largest_sent_packet - last_scup_packet_number_
184             : largest_sent_packet.ToUint64();
185   }
186   if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
187       now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
188       packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
189     return;
190   }
191 
192   // If the bandwidth recorder does not have a valid estimate, return early.
193   const QuicSustainedBandwidthRecorder* bandwidth_recorder =
194       sent_packet_manager.SustainedBandwidthRecorder();
195   if (bandwidth_recorder == nullptr || !bandwidth_recorder->HasEstimate()) {
196     return;
197   }
198 
199   // The bandwidth recorder has recorded at least one sustained bandwidth
200   // estimate. Check that it's substantially different from the last one that
201   // we sent to the client, and if so, send the new one.
202   QuicBandwidth new_bandwidth_estimate =
203       bandwidth_recorder->BandwidthEstimate();
204 
205   int64_t bandwidth_delta =
206       std::abs(new_bandwidth_estimate.ToBitsPerSecond() -
207                bandwidth_estimate_sent_to_client_.ToBitsPerSecond());
208 
209   // Define "substantial" difference as a 50% increase or decrease from the
210   // last estimate.
211   bool substantial_difference =
212       bandwidth_delta >
213       0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond();
214   if (!substantial_difference) {
215     return;
216   }
217 
218   if (version().UsesTls()) {
219     if (version().HasIetfQuicFrames() && MaybeSendAddressToken()) {
220       bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
221     }
222   } else {
223     absl::optional<CachedNetworkParameters> cached_network_params =
224         GenerateCachedNetworkParameters();
225 
226     if (cached_network_params.has_value()) {
227       bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
228       QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
229                     << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
230 
231       QUICHE_DCHECK_EQ(
232           BandwidthToCachedParameterBytesPerSecond(
233               bandwidth_estimate_sent_to_client_),
234           cached_network_params->bandwidth_estimate_bytes_per_second());
235 
236       crypto_stream_->SendServerConfigUpdate(&cached_network_params.value());
237 
238       connection()->OnSendConnectionState(*cached_network_params);
239     }
240   }
241 
242   last_scup_time_ = now;
243   last_scup_packet_number_ =
244       connection()->sent_packet_manager().GetLargestSentPacket();
245 }
246 
ShouldCreateIncomingStream(QuicStreamId id)247 bool QuicServerSessionBase::ShouldCreateIncomingStream(QuicStreamId id) {
248   if (!connection()->connected()) {
249     QUIC_BUG(quic_bug_10393_2)
250         << "ShouldCreateIncomingStream called when disconnected";
251     return false;
252   }
253 
254   if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) {
255     QUIC_BUG(quic_bug_10393_3)
256         << "ShouldCreateIncomingStream called with server initiated "
257            "stream ID.";
258     return false;
259   }
260 
261   if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) {
262     QUIC_DLOG(INFO) << "Invalid incoming even stream_id:" << id;
263     connection()->CloseConnection(
264         QUIC_INVALID_STREAM_ID, "Client created even numbered stream",
265         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
266     return false;
267   }
268   return true;
269 }
270 
ShouldCreateOutgoingBidirectionalStream()271 bool QuicServerSessionBase::ShouldCreateOutgoingBidirectionalStream() {
272   if (!connection()->connected()) {
273     QUIC_BUG(quic_bug_12513_2)
274         << "ShouldCreateOutgoingBidirectionalStream called when disconnected";
275     return false;
276   }
277   if (!crypto_stream_->encryption_established()) {
278     QUIC_BUG(quic_bug_10393_4)
279         << "Encryption not established so no outgoing stream created.";
280     return false;
281   }
282 
283   return CanOpenNextOutgoingBidirectionalStream();
284 }
285 
ShouldCreateOutgoingUnidirectionalStream()286 bool QuicServerSessionBase::ShouldCreateOutgoingUnidirectionalStream() {
287   if (!connection()->connected()) {
288     QUIC_BUG(quic_bug_12513_3)
289         << "ShouldCreateOutgoingUnidirectionalStream called when disconnected";
290     return false;
291   }
292   if (!crypto_stream_->encryption_established()) {
293     QUIC_BUG(quic_bug_10393_5)
294         << "Encryption not established so no outgoing stream created.";
295     return false;
296   }
297 
298   return CanOpenNextOutgoingUnidirectionalStream();
299 }
300 
GetMutableCryptoStream()301 QuicCryptoServerStreamBase* QuicServerSessionBase::GetMutableCryptoStream() {
302   return crypto_stream_.get();
303 }
304 
GetCryptoStream() const305 const QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream()
306     const {
307   return crypto_stream_.get();
308 }
309 
BandwidthToCachedParameterBytesPerSecond(const QuicBandwidth & bandwidth) const310 int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
311     const QuicBandwidth& bandwidth) const {
312   return static_cast<int32_t>(std::min<int64_t>(
313       bandwidth.ToBytesPerSecond(), std::numeric_limits<int32_t>::max()));
314 }
315 
SendSettingsToCryptoStream()316 void QuicServerSessionBase::SendSettingsToCryptoStream() {
317   if (!version().UsesTls()) {
318     return;
319   }
320   std::string settings_frame = HttpEncoder::SerializeSettingsFrame(settings());
321 
322   std::unique_ptr<ApplicationState> serialized_settings =
323       std::make_unique<ApplicationState>(
324           settings_frame.data(),
325           settings_frame.data() + settings_frame.length());
326   GetMutableCryptoStream()->SetServerApplicationStateForResumption(
327       std::move(serialized_settings));
328 }
329 
GetSSLConfig() const330 QuicSSLConfig QuicServerSessionBase::GetSSLConfig() const {
331   QUICHE_DCHECK(crypto_config_ && crypto_config_->proof_source());
332 
333   QuicSSLConfig ssl_config = QuicSpdySession::GetSSLConfig();
334 
335   ssl_config.disable_ticket_support =
336       GetQuicFlag(quic_disable_server_tls_resumption);
337 
338   if (!crypto_config_ || !crypto_config_->proof_source()) {
339     return ssl_config;
340   }
341 
342   absl::InlinedVector<uint16_t, 8> signature_algorithms =
343       crypto_config_->proof_source()->SupportedTlsSignatureAlgorithms();
344   if (!signature_algorithms.empty()) {
345     ssl_config.signing_algorithm_prefs = std::move(signature_algorithms);
346   }
347 
348   return ssl_config;
349 }
350 
351 absl::optional<CachedNetworkParameters>
GenerateCachedNetworkParameters() const352 QuicServerSessionBase::GenerateCachedNetworkParameters() const {
353   const QuicSentPacketManager& sent_packet_manager =
354       connection()->sent_packet_manager();
355   const QuicSustainedBandwidthRecorder* bandwidth_recorder =
356       sent_packet_manager.SustainedBandwidthRecorder();
357 
358   CachedNetworkParameters cached_network_params;
359   cached_network_params.set_timestamp(
360       connection()->clock()->WallNow().ToUNIXSeconds());
361 
362   if (!sent_packet_manager.GetRttStats()->min_rtt().IsZero()) {
363     cached_network_params.set_min_rtt_ms(
364         sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
365   }
366 
367   if (enable_sending_bandwidth_estimate_when_network_idle_) {
368     const SendAlgorithmInterface* send_algorithm =
369         sent_packet_manager.GetSendAlgorithm();
370     if (send_algorithm != nullptr &&
371         send_algorithm->HasGoodBandwidthEstimateForResumption()) {
372       cached_network_params.set_bandwidth_estimate_bytes_per_second(
373           BandwidthToCachedParameterBytesPerSecond(
374               send_algorithm->BandwidthEstimate()));
375       QUIC_CODE_COUNT(quic_send_measured_bandwidth_in_token);
376     } else {
377       const quic::CachedNetworkParameters* previous_cached_network_params =
378           crypto_stream()->PreviousCachedNetworkParams();
379       if (previous_cached_network_params != nullptr &&
380           previous_cached_network_params
381                   ->bandwidth_estimate_bytes_per_second() > 0) {
382         cached_network_params.set_bandwidth_estimate_bytes_per_second(
383             previous_cached_network_params
384                 ->bandwidth_estimate_bytes_per_second());
385         QUIC_CODE_COUNT(quic_send_previous_bandwidth_in_token);
386       } else {
387         QUIC_CODE_COUNT(quic_not_send_bandwidth_in_token);
388       }
389     }
390   } else {
391     // Populate bandwidth estimates if any.
392     if (bandwidth_recorder != nullptr && bandwidth_recorder->HasEstimate()) {
393       const int32_t bw_estimate_bytes_per_second =
394           BandwidthToCachedParameterBytesPerSecond(
395               bandwidth_recorder->BandwidthEstimate());
396       const int32_t max_bw_estimate_bytes_per_second =
397           BandwidthToCachedParameterBytesPerSecond(
398               bandwidth_recorder->MaxBandwidthEstimate());
399       QUIC_BUG_IF(quic_bug_12513_1, max_bw_estimate_bytes_per_second < 0)
400           << max_bw_estimate_bytes_per_second;
401       QUIC_BUG_IF(quic_bug_10393_1, bw_estimate_bytes_per_second < 0)
402           << bw_estimate_bytes_per_second;
403 
404       cached_network_params.set_bandwidth_estimate_bytes_per_second(
405           bw_estimate_bytes_per_second);
406       cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
407           max_bw_estimate_bytes_per_second);
408       cached_network_params.set_max_bandwidth_timestamp_seconds(
409           bandwidth_recorder->MaxBandwidthTimestamp());
410 
411       cached_network_params.set_previous_connection_state(
412           bandwidth_recorder->EstimateRecordedDuringSlowStart()
413               ? CachedNetworkParameters::SLOW_START
414               : CachedNetworkParameters::CONGESTION_AVOIDANCE);
415     }
416   }
417 
418   if (!serving_region_.empty()) {
419     cached_network_params.set_serving_region(serving_region_);
420   }
421 
422   return cached_network_params;
423 }
424 
425 }  // namespace quic
426