blob: 5cdb2c46451a0ce73b98330236e60885f0c8c379 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
6
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
8
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h"
10#include "net/third_party/quiche/src/quic/core/quic_connection.h"
11#include "net/third_party/quiche/src/quic/core/quic_stream.h"
12#include "net/third_party/quiche/src/quic/core/quic_utils.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017
18namespace quic {
19
20QuicServerSessionBase::QuicServerSessionBase(
21 const QuicConfig& config,
22 const ParsedQuicVersionVector& supported_versions,
23 QuicConnection* connection,
24 Visitor* visitor,
25 QuicCryptoServerStream::Helper* helper,
26 const QuicCryptoServerConfig* crypto_config,
27 QuicCompressedCertsCache* compressed_certs_cache)
28 : QuicSpdySession(connection, visitor, config, supported_versions),
29 crypto_config_(crypto_config),
30 compressed_certs_cache_(compressed_certs_cache),
31 helper_(helper),
32 bandwidth_resumption_enabled_(false),
33 bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
34 last_scup_time_(QuicTime::Zero()) {}
35
36QuicServerSessionBase::~QuicServerSessionBase() {}
37
38void QuicServerSessionBase::Initialize() {
39 crypto_stream_.reset(
40 CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_));
41 QuicSpdySession::Initialize();
42}
43
44void QuicServerSessionBase::OnConfigNegotiated() {
45 QuicSpdySession::OnConfigNegotiated();
46
47 if (!config()->HasReceivedConnectionOptions()) {
48 return;
49 }
50
51 // Enable bandwidth resumption if peer sent correct connection options.
52 const bool last_bandwidth_resumption =
53 ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
54 const bool max_bandwidth_resumption =
55 ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWMX);
56 bandwidth_resumption_enabled_ =
57 last_bandwidth_resumption || max_bandwidth_resumption;
58
59 // If the client has provided a bandwidth estimate from the same serving
60 // region as this server, then decide whether to use the data for bandwidth
61 // resumption.
62 const CachedNetworkParameters* cached_network_params =
63 crypto_stream_->PreviousCachedNetworkParams();
64 if (cached_network_params != nullptr &&
65 cached_network_params->serving_region() == serving_region_) {
66 // Log the received connection parameters, regardless of how they
67 // get used for bandwidth resumption.
68 connection()->OnReceiveConnectionState(*cached_network_params);
69
70 if (bandwidth_resumption_enabled_) {
71 // Only do bandwidth resumption if estimate is recent enough.
72 const uint64_t seconds_since_estimate =
73 connection()->clock()->WallNow().ToUNIXSeconds() -
74 cached_network_params->timestamp();
75 if (seconds_since_estimate <= kNumSecondsPerHour) {
76 connection()->ResumeConnectionState(*cached_network_params,
77 max_bandwidth_resumption);
78 }
79 }
80 }
81}
82
83void QuicServerSessionBase::OnConnectionClosed(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -070084 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050085 ConnectionCloseSource source) {
86 QuicSession::OnConnectionClosed(error, error_details, source);
87 // In the unlikely event we get a connection close while doing an asynchronous
88 // crypto event, make sure we cancel the callback.
89 if (crypto_stream_ != nullptr) {
90 crypto_stream_->CancelOutstandingCallbacks();
91 }
92}
93
94void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
95 if (!bandwidth_resumption_enabled_) {
96 return;
97 }
98 // Only send updates when the application has no data to write.
99 if (HasDataToWrite()) {
100 return;
101 }
102
103 // If not enough time has passed since the last time we sent an update to the
104 // client, or not enough packets have been sent, then return early.
105 const QuicSentPacketManager& sent_packet_manager =
106 connection()->sent_packet_manager();
107 int64_t srtt_ms =
108 sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
109 int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
110 int64_t packets_since_last_scup = 0;
111 const QuicPacketNumber largest_sent_packet =
112 connection()->sent_packet_manager().GetLargestSentPacket();
113 if (largest_sent_packet.IsInitialized()) {
114 packets_since_last_scup =
115 last_scup_packet_number_.IsInitialized()
116 ? largest_sent_packet - last_scup_packet_number_
117 : largest_sent_packet.ToUint64();
118 }
119 if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
120 now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
121 packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
122 return;
123 }
124
125 // If the bandwidth recorder does not have a valid estimate, return early.
126 const QuicSustainedBandwidthRecorder* bandwidth_recorder =
127 sent_packet_manager.SustainedBandwidthRecorder();
128 if (bandwidth_recorder == nullptr || !bandwidth_recorder->HasEstimate()) {
129 return;
130 }
131
132 // The bandwidth recorder has recorded at least one sustained bandwidth
133 // estimate. Check that it's substantially different from the last one that
134 // we sent to the client, and if so, send the new one.
135 QuicBandwidth new_bandwidth_estimate =
136 bandwidth_recorder->BandwidthEstimate();
137
138 int64_t bandwidth_delta =
139 std::abs(new_bandwidth_estimate.ToBitsPerSecond() -
140 bandwidth_estimate_sent_to_client_.ToBitsPerSecond());
141
142 // Define "substantial" difference as a 50% increase or decrease from the
143 // last estimate.
144 bool substantial_difference =
145 bandwidth_delta >
146 0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond();
147 if (!substantial_difference) {
148 return;
149 }
150
151 bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
152 QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
153 << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
154
155 // Include max bandwidth in the update.
156 QuicBandwidth max_bandwidth_estimate =
157 bandwidth_recorder->MaxBandwidthEstimate();
158 int32_t max_bandwidth_timestamp = bandwidth_recorder->MaxBandwidthTimestamp();
159
160 // Fill the proto before passing it to the crypto stream to send.
161 const int32_t bw_estimate_bytes_per_second =
162 BandwidthToCachedParameterBytesPerSecond(
163 bandwidth_estimate_sent_to_client_);
164 const int32_t max_bw_estimate_bytes_per_second =
165 BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate);
166 QUIC_BUG_IF(max_bw_estimate_bytes_per_second < 0)
167 << max_bw_estimate_bytes_per_second;
168 QUIC_BUG_IF(bw_estimate_bytes_per_second < 0) << bw_estimate_bytes_per_second;
169
170 CachedNetworkParameters cached_network_params;
171 cached_network_params.set_bandwidth_estimate_bytes_per_second(
172 bw_estimate_bytes_per_second);
173 cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
174 max_bw_estimate_bytes_per_second);
175 cached_network_params.set_max_bandwidth_timestamp_seconds(
176 max_bandwidth_timestamp);
177 cached_network_params.set_min_rtt_ms(
178 sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
179 cached_network_params.set_previous_connection_state(
180 bandwidth_recorder->EstimateRecordedDuringSlowStart()
181 ? CachedNetworkParameters::SLOW_START
182 : CachedNetworkParameters::CONGESTION_AVOIDANCE);
183 cached_network_params.set_timestamp(
184 connection()->clock()->WallNow().ToUNIXSeconds());
185 if (!serving_region_.empty()) {
186 cached_network_params.set_serving_region(serving_region_);
187 }
188
189 crypto_stream_->SendServerConfigUpdate(&cached_network_params);
190
191 connection()->OnSendConnectionState(cached_network_params);
192
193 last_scup_time_ = now;
194 last_scup_packet_number_ =
195 connection()->sent_packet_manager().GetLargestSentPacket();
196}
197
198bool QuicServerSessionBase::ShouldCreateIncomingStream(QuicStreamId id) {
199 if (!connection()->connected()) {
200 QUIC_BUG << "ShouldCreateIncomingStream called when disconnected";
201 return false;
202 }
203
204 if (QuicUtils::IsServerInitiatedStreamId(connection()->transport_version(),
205 id)) {
206 QUIC_DLOG(INFO) << "Invalid incoming even stream_id:" << id;
207 connection()->CloseConnection(
208 QUIC_INVALID_STREAM_ID, "Client created even numbered stream",
209 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
210 return false;
211 }
212 return true;
213}
214
215bool QuicServerSessionBase::ShouldCreateOutgoingBidirectionalStream() {
216 if (!connection()->connected()) {
217 QUIC_BUG
218 << "ShouldCreateOutgoingBidirectionalStream called when disconnected";
219 return false;
220 }
221 if (!crypto_stream_->encryption_established()) {
222 QUIC_BUG << "Encryption not established so no outgoing stream created.";
223 return false;
224 }
225
226 if (!GetQuicReloadableFlag(quic_use_common_stream_check) &&
227 connection()->transport_version() != QUIC_VERSION_99) {
228 if (GetNumOpenOutgoingStreams() >=
229 stream_id_manager().max_open_outgoing_streams()) {
230 VLOG(1) << "No more streams should be created. "
231 << "Already " << GetNumOpenOutgoingStreams() << " open.";
232 return false;
233 }
234 }
235 QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_common_stream_check, 2, 2);
236 return CanOpenNextOutgoingBidirectionalStream();
237}
238
239bool QuicServerSessionBase::ShouldCreateOutgoingUnidirectionalStream() {
240 if (!connection()->connected()) {
241 QUIC_BUG
242 << "ShouldCreateOutgoingUnidirectionalStream called when disconnected";
243 return false;
244 }
245 if (!crypto_stream_->encryption_established()) {
246 QUIC_BUG << "Encryption not established so no outgoing stream created.";
247 return false;
248 }
249
250 if (!GetQuicReloadableFlag(quic_use_common_stream_check) &&
251 connection()->transport_version() != QUIC_VERSION_99) {
252 if (GetNumOpenOutgoingStreams() >=
253 stream_id_manager().max_open_outgoing_streams()) {
254 VLOG(1) << "No more streams should be created. "
255 << "Already " << GetNumOpenOutgoingStreams() << " open.";
256 return false;
257 }
258 }
259
260 return CanOpenNextOutgoingUnidirectionalStream();
261}
262
263QuicCryptoServerStreamBase* QuicServerSessionBase::GetMutableCryptoStream() {
264 return crypto_stream_.get();
265}
266
267const QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream()
268 const {
269 return crypto_stream_.get();
270}
271
272int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
273 const QuicBandwidth& bandwidth) {
274 return static_cast<int32_t>(std::min<int64_t>(
275 bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max()));
276}
277
278} // namespace quic