blob: f605e56c88f1976487d66b2db034dc087045ef99 [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/quic_session.h"
6
7#include <cstdint>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include <utility>
10
11#include "net/third_party/quiche/src/quic/core/quic_connection.h"
12#include "net/third_party/quiche/src/quic/core/quic_flow_controller.h"
13#include "net/third_party/quiche/src/quic/core/quic_utils.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
wub2b5942f2019-04-11 13:22:50 -070019#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022
23using spdy::SpdyPriority;
24
25namespace quic {
26
27namespace {
28
29class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
30 public:
31 explicit ClosedStreamsCleanUpDelegate(QuicSession* session)
32 : session_(session) {}
33 ClosedStreamsCleanUpDelegate(const ClosedStreamsCleanUpDelegate&) = delete;
34 ClosedStreamsCleanUpDelegate& operator=(const ClosedStreamsCleanUpDelegate&) =
35 delete;
36
37 void OnAlarm() override { session_->CleanUpClosedStreams(); }
38
39 private:
40 QuicSession* session_;
41};
42
43} // namespace
44
45#define ENDPOINT \
46 (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
47
48QuicSession::QuicSession(QuicConnection* connection,
49 Visitor* owner,
50 const QuicConfig& config,
51 const ParsedQuicVersionVector& supported_versions)
52 : connection_(connection),
53 visitor_(owner),
nharpercd820e02019-05-16 15:12:07 -070054 write_blocked_streams_(connection->transport_version()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050055 config_(config),
56 stream_id_manager_(this,
57 kDefaultMaxStreamsPerConnection,
fkastenholzd3a1de92019-05-15 07:00:07 -070058 config_.GetMaxIncomingBidirectionalStreamsToSend()),
59 v99_streamid_manager_(
60 this,
61 kDefaultMaxStreamsPerConnection,
62 kDefaultMaxStreamsPerConnection,
63 config_.GetMaxIncomingBidirectionalStreamsToSend(),
64 config_.GetMaxIncomingUnidirectionalStreamsToSend()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050065 num_dynamic_incoming_streams_(0),
66 num_draining_incoming_streams_(0),
renjietangfbeb5bf2019-04-19 15:06:20 -070067 num_outgoing_static_streams_(0),
68 num_incoming_static_streams_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 num_locally_closed_incoming_streams_highest_offset_(0),
70 error_(QUIC_NO_ERROR),
71 flow_controller_(
72 this,
73 QuicUtils::GetInvalidStreamId(connection->transport_version()),
74 /*is_connection_flow_controller*/ true,
dschinazic7036122019-04-30 12:46:34 -070075 connection->version().AllowsLowFlowControlLimits()
76 ? 0
77 : kMinimumFlowControlSendWindow,
QUICHE teama6ef0a62019-03-07 20:34:33 -050078 config_.GetInitialSessionFlowControlWindowToSend(),
79 kSessionReceiveWindowLimit,
80 perspective() == Perspective::IS_SERVER,
81 nullptr),
82 currently_writing_stream_id_(0),
83 largest_static_stream_id_(0),
84 is_handshake_confirmed_(false),
85 goaway_sent_(false),
86 goaway_received_(false),
87 control_frame_manager_(this),
88 last_message_id_(0),
89 closed_streams_clean_up_alarm_(nullptr),
renjietang615f13b2019-05-06 17:08:02 -070090 supported_versions_(supported_versions),
91 eliminate_static_stream_map_(
rchda26cdb2019-05-17 11:57:37 -070092 GetQuicReloadableFlag(quic_eliminate_static_stream_map_3) ||
nharperd5c4a932019-05-13 13:58:49 -070093 QuicVersionUsesCryptoFrames(connection->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050094 closed_streams_clean_up_alarm_ =
95 QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
96 new ClosedStreamsCleanUpDelegate(this)));
97}
98
99void QuicSession::Initialize() {
100 connection_->set_visitor(this);
101 connection_->SetSessionNotifier(this);
102 connection_->SetDataProducer(this);
103 connection_->SetFromConfig(config_);
104
nharper46833c32019-05-15 21:33:05 -0700105 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
106 return;
107 }
108
QUICHE teama6ef0a62019-03-07 20:34:33 -0500109 DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
110 GetMutableCryptoStream()->id());
renjietang615f13b2019-05-06 17:08:02 -0700111 if (!eliminate_static_stream_map_) {
renjietang08a9cf72019-04-23 17:01:34 -0700112 RegisterStaticStream(
113 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
114 GetMutableCryptoStream());
115 } else {
rchda26cdb2019-05-17 11:57:37 -0700116 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 10, 17);
renjietang08a9cf72019-04-23 17:01:34 -0700117 QuicStreamId id =
118 QuicUtils::GetCryptoStreamId(connection_->transport_version());
119 largest_static_stream_id_ = std::max(id, largest_static_stream_id_);
120 if (connection_->transport_version() == QUIC_VERSION_99) {
121 v99_streamid_manager_.RegisterStaticStream(id);
122 }
123 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500124}
125
126QuicSession::~QuicSession() {
127 QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
128}
129
130void QuicSession::RegisterStaticStream(QuicStreamId id, QuicStream* stream) {
131 static_stream_map_[id] = stream;
132
133 QUIC_BUG_IF(id >
134 largest_static_stream_id_ +
135 QuicUtils::StreamIdDelta(connection_->transport_version()))
136 << ENDPOINT << "Static stream registered out of order: " << id
137 << " vs: " << largest_static_stream_id_;
138 largest_static_stream_id_ = std::max(id, largest_static_stream_id_);
139
140 if (connection_->transport_version() == QUIC_VERSION_99) {
141 v99_streamid_manager_.RegisterStaticStream(id);
142 }
143}
144
renjietangfbeb5bf2019-04-19 15:06:20 -0700145void QuicSession::RegisterStaticStreamNew(std::unique_ptr<QuicStream> stream) {
renjietang615f13b2019-05-06 17:08:02 -0700146 DCHECK(eliminate_static_stream_map_);
renjietangfbeb5bf2019-04-19 15:06:20 -0700147 QuicStreamId stream_id = stream->id();
148 dynamic_stream_map_[stream_id] = std::move(stream);
149 if (connection_->transport_version() == QUIC_VERSION_99) {
150 v99_streamid_manager_.RegisterStaticStream(stream_id);
151 }
152 if (IsIncomingStream(stream_id)) {
153 ++num_incoming_static_streams_;
154 } else {
155 ++num_outgoing_static_streams_;
156 }
157}
158
renjietange76b2da2019-05-13 14:50:23 -0700159void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
160 DCHECK(VersionHasControlStreams(connection()->transport_version()));
161 QuicStreamId stream_id = frame.stream_id;
162
163 PendingStream* pending = GetOrCreatePendingStream(stream_id);
164
165 if (!pending) {
166 if (frame.fin) {
167 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
168 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
169 }
170 return;
171 }
172
173 pending->OnStreamFrame(frame);
174 ProcessPendingStream(pending);
175}
176
QUICHE teama6ef0a62019-03-07 20:34:33 -0500177void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
178 // TODO(rch) deal with the error case of stream id 0.
179 QuicStreamId stream_id = frame.stream_id;
180 if (stream_id ==
181 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
182 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700183 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
185 return;
186 }
187
188 if (frame.fin && QuicContainsKey(static_stream_map_, stream_id)) {
189 connection()->CloseConnection(
190 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
191 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
192 return;
193 }
194
renjietange76b2da2019-05-13 14:50:23 -0700195 if (VersionHasControlStreams(connection()->transport_version()) &&
196 UsesPendingStreams() &&
197 QuicUtils::GetStreamType(stream_id, perspective(),
198 IsIncomingStream(stream_id)) ==
199 READ_UNIDIRECTIONAL &&
200 dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) {
201 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202 return;
203 }
204
renjietang2c4d7122019-05-20 17:18:14 -0700205 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700206
renjietang2c4d7122019-05-20 17:18:14 -0700207 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500208 // The stream no longer exists, but we may still be interested in the
209 // final stream byte offset sent by the peer. A frame with a FIN can give
210 // us this offset.
211 if (frame.fin) {
212 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
213 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
214 }
215 return;
216 }
renjietang2c4d7122019-05-20 17:18:14 -0700217 if (eliminate_static_stream_map_ && frame.fin && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700218 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 1, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700219 connection()->CloseConnection(
220 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
221 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
222 return;
223 }
renjietang2c4d7122019-05-20 17:18:14 -0700224 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500225}
226
227void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
228 GetMutableCryptoStream()->OnCryptoFrame(frame);
229}
230
231bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
232 // We are not version 99. In theory, if not in version 99 then the framer
233 // could not call OnStopSending... This is just a check that is good when
234 // both a new protocol and a new implementation of that protocol are both
235 // being developed.
236 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
237
238 QuicStreamId stream_id = frame.stream_id;
239 // If Stream ID is invalid then close the connection.
240 if (stream_id ==
241 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
242 QUIC_DVLOG(1) << ENDPOINT
243 << "Received STOP_SENDING with invalid stream_id: "
244 << stream_id << " Closing connection";
245 connection()->CloseConnection(
246 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
247 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
248 return false;
249 }
250
251 // Ignore STOP_SENDING for static streams.
252 // TODO(fkastenholz): IETF Quic does not have static streams and does not
253 // make exceptions for them with respect to processing things like
254 // STOP_SENDING.
renjietang08a9cf72019-04-23 17:01:34 -0700255 if (QuicContainsKey(static_stream_map_, stream_id) ||
nharper46833c32019-05-15 21:33:05 -0700256 QuicUtils::IsCryptoStreamId(connection_->transport_version(),
257 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500258 QUIC_DVLOG(1) << ENDPOINT
259 << "Received STOP_SENDING for a static stream, id: "
260 << stream_id << " Closing connection";
261 connection()->CloseConnection(
262 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
263 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
264 return false;
265 }
266
267 if (visitor_) {
268 visitor_->OnStopSendingReceived(frame);
269 }
270
271 // If stream is closed, ignore the frame
272 if (IsClosedStream(stream_id)) {
273 QUIC_DVLOG(1)
274 << ENDPOINT
275 << "Received STOP_SENDING for closed or non-existent stream, id: "
276 << stream_id << " Ignoring.";
277 return true; // Continue processing the packet.
278 }
279 // If stream is non-existent, close the connection
280 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
281 if (it == dynamic_stream_map_.end()) {
282 QUIC_DVLOG(1) << ENDPOINT
283 << "Received STOP_SENDING for non-existent stream, id: "
284 << stream_id << " Closing connection";
285 connection()->CloseConnection(
286 IETF_QUIC_PROTOCOL_VIOLATION,
287 "Received STOP_SENDING for a non-existent stream",
288 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
289 return false;
290 }
291
292 // Get the QuicStream for this stream. Ignore the STOP_SENDING
293 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700294 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
295 // happen IFF there was an entry in the map, but the pointer is null. sounds
296 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500297 QuicStream* stream = it->second.get();
298 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700299 QUIC_BUG << ENDPOINT
300 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
301 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500302 return true;
303 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700304
renjietang615f13b2019-05-06 17:08:02 -0700305 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700306 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 2, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700307 QUIC_DVLOG(1) << ENDPOINT
308 << "Received STOP_SENDING for a static stream, id: "
309 << stream_id << " Closing connection";
310 connection()->CloseConnection(
311 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
312 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
313 return false;
314 }
315
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316 stream->OnStopSending(frame.application_error_code);
317
318 stream->set_stream_error(
319 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
320 SendRstStreamInner(
321 stream->id(),
322 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
323 stream->stream_bytes_written(),
324 /*close_write_side_only=*/true);
325
326 return true;
327}
328
renjietange76b2da2019-05-13 14:50:23 -0700329void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
330 DCHECK(VersionHasControlStreams(connection()->transport_version()));
331 QuicStreamId stream_id = frame.stream_id;
332
333 PendingStream* pending = GetOrCreatePendingStream(stream_id);
334
335 if (!pending) {
336 HandleRstOnValidNonexistentStream(frame);
337 return;
338 }
339
340 pending->OnRstStreamFrame(frame);
341 ClosePendingStream(stream_id);
342}
343
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
345 QuicStreamId stream_id = frame.stream_id;
346 if (stream_id ==
347 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
348 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700349 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
351 return;
352 }
353
354 if (QuicContainsKey(static_stream_map_, stream_id)) {
355 connection()->CloseConnection(
356 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
357 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
358 return;
359 }
360
361 if (visitor_) {
362 visitor_->OnRstStreamReceived(frame);
363 }
364
renjietange76b2da2019-05-13 14:50:23 -0700365 if (VersionHasControlStreams(connection()->transport_version()) &&
366 UsesPendingStreams() &&
367 QuicUtils::GetStreamType(stream_id, perspective(),
368 IsIncomingStream(stream_id)) ==
369 READ_UNIDIRECTIONAL &&
370 dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) {
371 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500372 return;
373 }
renjietange76b2da2019-05-13 14:50:23 -0700374
renjietang2c4d7122019-05-20 17:18:14 -0700375 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700376
renjietang2c4d7122019-05-20 17:18:14 -0700377 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500378 HandleRstOnValidNonexistentStream(frame);
379 return; // Errors are handled by GetOrCreateStream.
380 }
renjietang2c4d7122019-05-20 17:18:14 -0700381 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700382 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 3, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700383 connection()->CloseConnection(
384 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
385 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
386 return;
387 }
renjietang2c4d7122019-05-20 17:18:14 -0700388 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389}
390
391void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
392 goaway_received_ = true;
393}
394
395void QuicSession::OnMessageReceived(QuicStringPiece message) {
396 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
397 << ", " << message;
398}
399
wub2b5942f2019-04-11 13:22:50 -0700400// static
401void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
402 ConnectionCloseSource source) {
403 if (error != QUIC_NO_ERROR) {
404 if (source == ConnectionCloseSource::FROM_SELF) {
405 QUIC_SERVER_HISTOGRAM_ENUM(
406 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
407 "QuicErrorCode for server-closed connections.");
408 } else {
409 QUIC_SERVER_HISTOGRAM_ENUM(
410 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
411 "QuicErrorCode for client-closed connections.");
412 }
413 }
414}
415
QUICHE teama6ef0a62019-03-07 20:34:33 -0500416void QuicSession::OnConnectionClosed(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700417 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500418 ConnectionCloseSource source) {
419 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700420 if (perspective() == Perspective::IS_SERVER) {
421 RecordConnectionCloseAtServer(error, source);
422 }
423
QUICHE teama6ef0a62019-03-07 20:34:33 -0500424 if (error_ == QUIC_NO_ERROR) {
425 error_ = error;
426 }
427
renjietang615f13b2019-05-06 17:08:02 -0700428 if (!eliminate_static_stream_map_) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700429 while (!dynamic_stream_map_.empty()) {
430 DynamicStreamMap::iterator it = dynamic_stream_map_.begin();
431 QuicStreamId id = it->first;
432 it->second->OnConnectionClosed(error, source);
433 // The stream should call CloseStream as part of OnConnectionClosed.
434 if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
435 QUIC_BUG << ENDPOINT << "Stream " << id
436 << " failed to close under OnConnectionClosed";
437 CloseStream(id);
438 }
439 }
440 } else {
rchda26cdb2019-05-17 11:57:37 -0700441 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 4, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700442 // Copy all non static streams in a new map for the ease of deleting.
443 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
444 for (const auto& it : dynamic_stream_map_) {
445 if (!it.second->is_static()) {
446 non_static_streams[it.first] = it.second.get();
447 }
448 }
449 for (const auto& it : non_static_streams) {
450 QuicStreamId id = it.first;
451 it.second->OnConnectionClosed(error, source);
452 if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
453 QUIC_BUG << ENDPOINT << "Stream " << id
454 << " failed to close under OnConnectionClosed";
455 CloseStream(id);
456 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500457 }
458 }
459
460 // Cleanup zombie stream map on connection close.
461 while (!zombie_streams_.empty()) {
462 ZombieStreamMap::iterator it = zombie_streams_.begin();
463 closed_streams_.push_back(std::move(it->second));
464 zombie_streams_.erase(it);
465 }
466
467 closed_streams_clean_up_alarm_->Cancel();
468
469 if (visitor_) {
470 visitor_->OnConnectionClosed(connection_->connection_id(), error,
471 error_details, source);
472 }
473}
474
475void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700476 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500477 return;
478 }
479 if (visitor_) {
480 visitor_->OnWriteBlocked(connection_);
481 }
482}
483
484void QuicSession::OnSuccessfulVersionNegotiation(
485 const ParsedQuicVersion& version) {
486 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
487}
488
489void QuicSession::OnConnectivityProbeReceived(
490 const QuicSocketAddress& self_address,
491 const QuicSocketAddress& peer_address) {
492 if (perspective() == Perspective::IS_SERVER) {
493 // Server only sends back a connectivity probe after received a
494 // connectivity probe from a new peer address.
495 connection_->SendConnectivityProbingResponsePacket(peer_address);
496 }
497}
498
499void QuicSession::OnPathDegrading() {}
500
501bool QuicSession::AllowSelfAddressChange() const {
502 return false;
503}
504
505void QuicSession::OnForwardProgressConfirmed() {}
506
507void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
508 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
509 // assume that it still exists.
510 QuicStreamId stream_id = frame.stream_id;
511 if (stream_id ==
512 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
513 // This is a window update that applies to the connection, rather than an
514 // individual stream.
515 QUIC_DLOG(INFO) << ENDPOINT
516 << "Received connection level flow control window "
517 "update with byte offset: "
518 << frame.byte_offset;
519 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
520 return;
521 }
522 QuicStream* stream = GetOrCreateStream(stream_id);
523 if (stream != nullptr) {
524 stream->OnWindowUpdateFrame(frame);
525 }
526}
527
528void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
529 // TODO(rjshade): Compare our flow control receive windows for specified
530 // streams: if we have a large window then maybe something
531 // had gone wrong with the flow control accounting.
532 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
533 << frame.stream_id;
534}
535
536bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
537 uint64_t previous_bytes_written,
538 bool previous_fin_sent) {
539 if ( // Stream should not be closed.
540 !stream->write_side_closed() &&
541 // Not connection flow control blocked.
542 !flow_controller_.IsBlocked() &&
543 // Detect lack of forward progress.
544 previous_bytes_written == stream->stream_bytes_written() &&
545 previous_fin_sent == stream->fin_sent()) {
546 stream->set_busy_counter(stream->busy_counter() + 1);
547 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
548 << " stream_bytes_written " << stream->stream_bytes_written()
549 << " fin " << stream->fin_sent() << " count "
550 << stream->busy_counter();
551 // Wait a few iterations before firing, the exact count is
552 // arbitrary, more than a few to cover a few test-only false
553 // positives.
554 if (stream->busy_counter() > 20) {
555 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
556 << " stream_bytes_written "
557 << stream->stream_bytes_written() << " fin "
558 << stream->fin_sent();
559 return false;
560 }
561 } else {
562 stream->set_busy_counter(0);
563 }
564 return true;
565}
566
567bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
568 if (!stream->write_side_closed() && stream->HasBufferedData() &&
569 !stream->flow_controller()->IsBlocked() &&
570 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
571 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
572 << stream->BufferedDataBytes()
573 << " bytes, and is not flow control blocked, "
574 "but it is not in the write block list.";
575 return false;
576 }
577 return true;
578}
579
580void QuicSession::OnCanWrite() {
581 if (!RetransmitLostData()) {
582 // Cannot finish retransmitting lost data, connection is write blocked.
583 QUIC_DVLOG(1) << ENDPOINT
584 << "Cannot finish retransmitting lost data, connection is "
585 "write blocked.";
586 return;
587 }
588 if (session_decides_what_to_write()) {
589 SetTransmissionType(NOT_RETRANSMISSION);
590 }
591 // We limit the number of writes to the number of pending streams. If more
592 // streams become pending, WillingAndAbleToWrite will be true, which will
593 // cause the connection to request resumption before yielding to other
594 // connections.
595 // If we are connection level flow control blocked, then only allow the
596 // crypto and headers streams to try writing as all other streams will be
597 // blocked.
598 size_t num_writes = flow_controller_.IsBlocked()
599 ? write_blocked_streams_.NumBlockedSpecialStreams()
600 : write_blocked_streams_.NumBlockedStreams();
601 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
602 return;
603 }
604
605 QuicConnection::ScopedPacketFlusher flusher(
606 connection_, QuicConnection::SEND_ACK_IF_QUEUED);
607 if (control_frame_manager_.WillingToWrite()) {
608 control_frame_manager_.OnCanWrite();
609 }
610 for (size_t i = 0; i < num_writes; ++i) {
611 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
612 write_blocked_streams_.HasWriteBlockedDataStreams())) {
613 // Writing one stream removed another!? Something's broken.
614 QUIC_BUG << "WriteBlockedStream is missing";
615 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
616 "WriteBlockedStream is missing",
617 ConnectionCloseBehavior::SILENT_CLOSE);
618 return;
619 }
620 if (!connection_->CanWriteStreamData()) {
621 return;
622 }
623 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
624 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
625 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
626 // If the stream can't write all bytes it'll re-add itself to the blocked
627 // list.
628 uint64_t previous_bytes_written = stream->stream_bytes_written();
629 bool previous_fin_sent = stream->fin_sent();
630 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
631 << previous_bytes_written << " fin " << previous_fin_sent;
632 stream->OnCanWrite();
633 DCHECK(CheckStreamWriteBlocked(stream));
634 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
635 previous_fin_sent));
636 }
637 currently_writing_stream_id_ = 0;
638 }
639}
640
QUICHE teamb8343252019-04-29 13:58:01 -0700641bool QuicSession::SendProbingData() {
642 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
643 PROBING_RETRANSMISSION)) {
644 return true;
645 }
646 return false;
647}
648
QUICHE teama6ef0a62019-03-07 20:34:33 -0500649bool QuicSession::WillingAndAbleToWrite() const {
650 // Schedule a write when:
651 // 1) control frame manager has pending or new control frames, or
652 // 2) any stream has pending retransmissions, or
653 // 3) If the crypto or headers streams are blocked, or
654 // 4) connection is not flow control blocked and there are write blocked
655 // streams.
656 return control_frame_manager_.WillingToWrite() ||
657 !streams_with_pending_retransmission_.empty() ||
658 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
659 (!flow_controller_.IsBlocked() &&
660 write_blocked_streams_.HasWriteBlockedDataStreams());
661}
662
663bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700664 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
665 // Writing CRYPTO frames is not subject to flow control, so there can't be
666 // pending data to write, only pending retransmissions.
667 return GetCryptoStream()->HasPendingCryptoRetransmission();
668 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500669 return QuicContainsKey(
670 streams_with_pending_retransmission_,
671 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
672 write_blocked_streams_.IsStreamBlocked(
673 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
674}
675
676uint64_t QuicSession::GetNumOpenDynamicStreams() const {
677 return dynamic_stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700678 locally_closed_streams_highest_offset_.size() -
679 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500680}
681
682void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
683 const QuicSocketAddress& peer_address,
684 const QuicReceivedPacket& packet) {
685 connection_->ProcessUdpPacket(self_address, peer_address, packet);
686}
687
688QuicConsumedData QuicSession::WritevData(QuicStream* stream,
689 QuicStreamId id,
690 size_t write_length,
691 QuicStreamOffset offset,
692 StreamSendingState state) {
693 // This check is an attempt to deal with potential memory corruption
694 // in which |id| ends up set to 1 (the crypto stream id). If this happen
695 // it might end up resulting in unencrypted stream data being sent.
696 // While this is impossible to avoid given sufficient corruption, this
697 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700698 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500699 stream != GetMutableCryptoStream()) {
700 QUIC_BUG << "Stream id mismatch";
701 connection_->CloseConnection(
702 QUIC_INTERNAL_ERROR,
703 "Non-crypto stream attempted to write data as crypto stream.",
704 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
705 return QuicConsumedData(0, false);
706 }
707 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700708 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500709 // Do not let streams write without encryption. The calling stream will end
710 // up write blocked until OnCanWrite is next called.
711 return QuicConsumedData(0, false);
712 }
713
714 QuicConsumedData data =
715 connection_->SendStreamData(id, write_length, offset, state);
716 if (offset >= stream->stream_bytes_written()) {
717 // This is new stream data.
718 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
719 }
720 return data;
721}
722
723bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
724 return connection_->SendControlFrame(frame);
725}
726
727void QuicSession::SendRstStream(QuicStreamId id,
728 QuicRstStreamErrorCode error,
729 QuicStreamOffset bytes_written) {
730 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
731}
732
733void QuicSession::SendRstStreamInner(QuicStreamId id,
734 QuicRstStreamErrorCode error,
735 QuicStreamOffset bytes_written,
736 bool close_write_side_only) {
737 if (connection()->connected()) {
738 // Only send if still connected.
739 if (close_write_side_only) {
740 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
741 // Send a RST_STREAM frame.
742 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
743 } else {
744 // Send a RST_STREAM frame plus, if version 99, an IETF
745 // QUIC STOP_SENDING frame. Both sre sent to emulate
746 // the two-way close that Google QUIC's RST_STREAM does.
747 if (connection_->transport_version() == QUIC_VERSION_99) {
748 QuicConnection::ScopedPacketFlusher flusher(
749 connection(), QuicConnection::SEND_ACK_IF_QUEUED);
750 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
751 control_frame_manager_.WriteOrBufferStopSending(error, id);
752 } else {
753 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
754 }
755 }
756 connection_->OnStreamReset(id, error);
757 }
758 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
759 OnStreamDoneWaitingForAcks(id);
760 return;
761 }
762
763 if (!close_write_side_only) {
764 CloseStreamInner(id, true);
765 return;
766 }
767 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
768
769 DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
770 if (it != dynamic_stream_map_.end()) {
renjietang615f13b2019-05-06 17:08:02 -0700771 if (eliminate_static_stream_map_ && it->second->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700772 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 5, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700773 QUIC_DVLOG(1) << ENDPOINT
774 << "Try to send rst for a static stream, id: " << id
775 << " Closing connection";
776 connection()->CloseConnection(
777 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
778 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
779 return;
780 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500781 QuicStream* stream = it->second.get();
782 if (stream) {
783 stream->set_rst_sent(true);
784 stream->CloseWriteSide();
785 }
786 }
787}
788
789void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700790 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500791 // GOAWAY frame is not supported in v99.
792 DCHECK_NE(QUIC_VERSION_99, connection_->transport_version());
793 if (goaway_sent_) {
794 return;
795 }
796 goaway_sent_ = true;
797 control_frame_manager_.WriteOrBufferGoAway(
798 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
799}
800
801void QuicSession::SendBlocked(QuicStreamId id) {
802 control_frame_manager_.WriteOrBufferBlocked(id);
803}
804
805void QuicSession::SendWindowUpdate(QuicStreamId id,
806 QuicStreamOffset byte_offset) {
807 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
808}
809
fkastenholz3c4eabf2019-04-22 07:49:59 -0700810void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
811 bool unidirectional) {
812 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500813}
814
fkastenholz3c4eabf2019-04-22 07:49:59 -0700815void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
816 bool unidirectional) {
817 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
818 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500819}
820
821void QuicSession::CloseStream(QuicStreamId stream_id) {
822 CloseStreamInner(stream_id, false);
823}
824
825void QuicSession::InsertLocallyClosedStreamsHighestOffset(
826 const QuicStreamId id,
827 QuicStreamOffset offset) {
828 locally_closed_streams_highest_offset_[id] = offset;
829 if (IsIncomingStream(id)) {
830 ++num_locally_closed_incoming_streams_highest_offset_;
831 }
832}
833
834void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
835 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
836
837 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
838 if (it == dynamic_stream_map_.end()) {
839 // When CloseStreamInner has been called recursively (via
840 // QuicStream::OnClose), the stream will already have been deleted
841 // from stream_map_, so return immediately.
842 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
843 return;
844 }
845 QuicStream* stream = it->second.get();
renjietang615f13b2019-05-06 17:08:02 -0700846 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700847 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 6, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700848 QUIC_DVLOG(1) << ENDPOINT
849 << "Try to close a static stream, id: " << stream_id
850 << " Closing connection";
851 connection()->CloseConnection(
852 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
853 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
854 return;
855 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500856
857 // Tell the stream that a RST has been sent.
858 if (locally_reset) {
859 stream->set_rst_sent(true);
860 }
861
862 if (stream->IsWaitingForAcks()) {
863 zombie_streams_[stream->id()] = std::move(it->second);
864 } else {
865 closed_streams_.push_back(std::move(it->second));
866 // Do not retransmit data of a closed stream.
867 streams_with_pending_retransmission_.erase(stream_id);
868 if (!closed_streams_clean_up_alarm_->IsSet()) {
869 closed_streams_clean_up_alarm_->Set(
870 connection_->clock()->ApproximateNow());
871 }
872 }
873
874 // If we haven't received a FIN or RST for this stream, we need to keep track
875 // of the how many bytes the stream's flow controller believes it has
876 // received, for accurate connection level flow control accounting.
877 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
878 if (!had_fin_or_rst) {
879 InsertLocallyClosedStreamsHighestOffset(
880 stream_id, stream->flow_controller()->highest_received_byte_offset());
881 }
882 dynamic_stream_map_.erase(it);
883 if (IsIncomingStream(stream_id)) {
884 --num_dynamic_incoming_streams_;
885 }
886
887 const bool stream_was_draining =
888 draining_streams_.find(stream_id) != draining_streams_.end();
889 if (stream_was_draining) {
890 if (IsIncomingStream(stream_id)) {
891 --num_draining_incoming_streams_;
892 }
893 draining_streams_.erase(stream_id);
894 } else if (connection_->transport_version() == QUIC_VERSION_99) {
895 // Stream was not draining, but we did have a fin or rst, so we can now
896 // free the stream ID if version 99.
897 if (had_fin_or_rst) {
898 v99_streamid_manager_.OnStreamClosed(stream_id);
899 }
900 }
901
902 stream->OnClose();
903
904 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
905 connection_->transport_version() != QUIC_VERSION_99) {
906 // Streams that first became draining already called OnCanCreate...
907 // This covers the case where the stream went directly to being closed.
908 OnCanCreateNewOutgoingStream();
909 }
910}
911
912void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
913 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
914
915 if (pending_stream_map_.find(stream_id) == pending_stream_map_.end()) {
916 QUIC_BUG << ENDPOINT << "Stream is already closed: " << stream_id;
917 return;
918 }
919
920 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
921
922 // The pending stream may have been deleted and removed during SendRstStream.
923 // Remove the stream from pending stream map iff it is still in the map.
924 if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
925 pending_stream_map_.erase(stream_id);
926 }
927
928 --num_dynamic_incoming_streams_;
929
930 if (connection_->transport_version() == QUIC_VERSION_99) {
931 v99_streamid_manager_.OnStreamClosed(stream_id);
932 }
933
934 OnCanCreateNewOutgoingStream();
935}
936
937void QuicSession::OnFinalByteOffsetReceived(
938 QuicStreamId stream_id,
939 QuicStreamOffset final_byte_offset) {
940 auto it = locally_closed_streams_highest_offset_.find(stream_id);
941 if (it == locally_closed_streams_highest_offset_.end()) {
942 return;
943 }
944
945 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
946 << final_byte_offset << " for stream " << stream_id;
947 QuicByteCount offset_diff = final_byte_offset - it->second;
948 if (flow_controller_.UpdateHighestReceivedOffset(
949 flow_controller_.highest_received_byte_offset() + offset_diff)) {
950 // If the final offset violates flow control, close the connection now.
951 if (flow_controller_.FlowControlViolation()) {
952 connection_->CloseConnection(
953 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
954 "Connection level flow control violation",
955 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
956 return;
957 }
958 }
959
960 flow_controller_.AddBytesConsumed(offset_diff);
961 locally_closed_streams_highest_offset_.erase(it);
962 if (IsIncomingStream(stream_id)) {
963 --num_locally_closed_incoming_streams_highest_offset_;
964 if (connection_->transport_version() == QUIC_VERSION_99) {
965 v99_streamid_manager_.OnStreamClosed(stream_id);
966 }
967 } else if (connection_->transport_version() != QUIC_VERSION_99) {
968 OnCanCreateNewOutgoingStream();
969 }
970}
971
972bool QuicSession::IsEncryptionEstablished() const {
973 // Once the handshake is confirmed, it never becomes un-confirmed.
974 if (is_handshake_confirmed_) {
975 return true;
976 }
977 return GetCryptoStream()->encryption_established();
978}
979
980bool QuicSession::IsCryptoHandshakeConfirmed() const {
981 return GetCryptoStream()->handshake_confirmed();
982}
983
984void QuicSession::OnConfigNegotiated() {
985 connection_->SetFromConfig(config_);
986
QUICHE teama6ef0a62019-03-07 20:34:33 -0500987 if (connection_->transport_version() == QUIC_VERSION_99) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700988 uint32_t max_streams = 0;
989 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
990 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
991 }
992 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
993 << max_streams;
994 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
995 max_streams);
996
997 max_streams = 0;
998 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
999 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
1000 }
1001 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
1002 << max_streams;
1003 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
1004 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001005 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001006 uint32_t max_streams = 0;
1007 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
1008 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
1009 }
1010 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001011 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
1012 }
fkastenholzd3a1de92019-05-15 07:00:07 -07001013
QUICHE teama6ef0a62019-03-07 20:34:33 -05001014 if (perspective() == Perspective::IS_SERVER) {
1015 if (config_.HasReceivedConnectionOptions()) {
1016 // The following variations change the initial receive flow control
1017 // window sizes.
1018 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
1019 AdjustInitialFlowControlWindows(64 * 1024);
1020 }
1021 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
1022 AdjustInitialFlowControlWindows(128 * 1024);
1023 }
1024 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
1025 AdjustInitialFlowControlWindows(256 * 1024);
1026 }
1027 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
1028 AdjustInitialFlowControlWindows(512 * 1024);
1029 }
1030 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
1031 AdjustInitialFlowControlWindows(1024 * 1024);
1032 }
1033 }
1034
1035 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
1036 }
1037
QUICHE teama6ef0a62019-03-07 20:34:33 -05001038 if (connection_->transport_version() == QUIC_VERSION_99) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001039 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1040 config_.GetMaxIncomingBidirectionalStreamsToSend());
1041 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1042 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001043 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001044 // A small number of additional incoming streams beyond the limit should be
1045 // allowed. This helps avoid early connection termination when FIN/RSTs for
1046 // old streams are lost or arrive out of order.
1047 // Use a minimum number of additional streams, or a percentage increase,
1048 // whichever is larger.
1049 uint32_t max_incoming_streams_to_send =
1050 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001051 uint32_t max_incoming_streams =
1052 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1053 static_cast<uint32_t>(max_incoming_streams_to_send *
1054 kMaxStreamsMultiplier));
1055 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1056 }
1057
1058 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1059 // Streams which were created before the SHLO was received (0-RTT
1060 // requests) are now informed of the peer's initial flow control window.
1061 OnNewStreamFlowControlWindow(
1062 config_.ReceivedInitialStreamFlowControlWindowBytes());
1063 }
1064 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1065 OnNewSessionFlowControlWindow(
1066 config_.ReceivedInitialSessionFlowControlWindowBytes());
1067 }
1068}
1069
1070void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1071 const float session_window_multiplier =
1072 config_.GetInitialStreamFlowControlWindowToSend()
1073 ? static_cast<float>(
1074 config_.GetInitialSessionFlowControlWindowToSend()) /
1075 config_.GetInitialStreamFlowControlWindowToSend()
1076 : 1.5;
1077
1078 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1079 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1080
1081 size_t session_window = session_window_multiplier * stream_window;
1082 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1083 << session_window;
1084 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1085 flow_controller_.UpdateReceiveWindowSize(session_window);
1086 // Inform all existing streams about the new window.
1087 for (auto const& kv : static_stream_map_) {
1088 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1089 }
1090 for (auto const& kv : dynamic_stream_map_) {
1091 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1092 }
nharperd5c4a932019-05-13 13:58:49 -07001093 if (eliminate_static_stream_map_ &&
1094 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
rchda26cdb2019-05-17 11:57:37 -07001095 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 11, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001096 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1097 stream_window);
1098 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001099}
1100
1101void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1102 QuicStreamId stream_id) {
1103 DCHECK(!IsClosedStream(stream_id));
1104 // Received a frame for a locally-created stream that is not currently
1105 // active. This is an error.
1106 connection()->CloseConnection(
1107 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1108 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1109}
1110
1111void QuicSession::HandleRstOnValidNonexistentStream(
1112 const QuicRstStreamFrame& frame) {
1113 // If the stream is neither originally in active streams nor created in
1114 // GetOrCreateDynamicStream(), it could be a closed stream in which case its
1115 // final received byte offset need to be updated.
1116 if (IsClosedStream(frame.stream_id)) {
1117 // The RST frame contains the final byte offset for the stream: we can now
1118 // update the connection level flow controller if needed.
1119 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1120 }
1121}
1122
1123void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001124 if (new_window < kMinimumFlowControlSendWindow &&
1125 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001126 QUIC_LOG_FIRST_N(ERROR, 1)
1127 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001128 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001129 if (connection_->connected()) {
1130 connection_->CloseConnection(
1131 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1132 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1133 }
1134 return;
1135 }
1136
1137 // Inform all existing streams about the new window.
1138 for (auto const& kv : static_stream_map_) {
1139 kv.second->UpdateSendWindowOffset(new_window);
1140 }
1141 for (auto const& kv : dynamic_stream_map_) {
1142 kv.second->UpdateSendWindowOffset(new_window);
1143 }
nharperd5c4a932019-05-13 13:58:49 -07001144 if (eliminate_static_stream_map_ &&
1145 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
rchda26cdb2019-05-17 11:57:37 -07001146 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 12, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001147 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1148 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001149}
1150
1151void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001152 if (new_window < kMinimumFlowControlSendWindow &&
1153 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001154 QUIC_LOG_FIRST_N(ERROR, 1)
1155 << "Peer sent us an invalid session flow control send window: "
1156 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1157 if (connection_->connected()) {
1158 connection_->CloseConnection(
1159 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1160 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1161 }
1162 return;
1163 }
1164
1165 flow_controller_.UpdateSendWindowOffset(new_window);
1166}
1167
1168void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1169 switch (event) {
1170 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
1171 // to QuicSession since it is the glue.
1172 case ENCRYPTION_FIRST_ESTABLISHED:
1173 // Given any streams blocked by encryption a chance to write.
1174 OnCanWrite();
1175 break;
1176
1177 case ENCRYPTION_REESTABLISHED:
1178 // Retransmit originally packets that were sent, since they can't be
1179 // decrypted by the peer.
1180 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1181 // Given any streams blocked by encryption a chance to write.
1182 OnCanWrite();
1183 break;
1184
1185 case HANDSHAKE_CONFIRMED:
1186 QUIC_BUG_IF(!config_.negotiated())
1187 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1188 // Discard originally encrypted packets, since they can't be decrypted by
1189 // the peer.
1190 NeuterUnencryptedData();
1191 is_handshake_confirmed_ = true;
1192 break;
1193
1194 default:
1195 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1196 }
1197}
1198
1199void QuicSession::OnCryptoHandshakeMessageSent(
1200 const CryptoHandshakeMessage& /*message*/) {}
1201
1202void QuicSession::OnCryptoHandshakeMessageReceived(
1203 const CryptoHandshakeMessage& /*message*/) {}
1204
1205void QuicSession::RegisterStreamPriority(QuicStreamId id,
1206 bool is_static,
1207 SpdyPriority priority) {
1208 write_blocked_streams()->RegisterStream(id, is_static, priority);
1209}
1210
1211void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1212 write_blocked_streams()->UnregisterStream(id, is_static);
1213}
1214
1215void QuicSession::UpdateStreamPriority(QuicStreamId id,
1216 SpdyPriority new_priority) {
1217 write_blocked_streams()->UpdateStreamPriority(id, new_priority);
1218}
1219
1220QuicConfig* QuicSession::config() {
1221 return &config_;
1222}
1223
1224void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001225 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001226 QuicStreamId stream_id = stream->id();
1227 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
1228 << ". activating " << stream_id;
1229 DCHECK(!QuicContainsKey(dynamic_stream_map_, stream_id));
1230 DCHECK(!QuicContainsKey(static_stream_map_, stream_id));
1231 dynamic_stream_map_[stream_id] = std::move(stream);
1232 if (IsIncomingStream(stream_id)) {
1233 ++num_dynamic_incoming_streams_;
1234 }
1235}
1236
1237QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
1238 if (connection_->transport_version() == QUIC_VERSION_99) {
1239 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1240 }
1241 return stream_id_manager_.GetNextOutgoingStreamId();
1242}
1243
1244QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
1245 if (connection_->transport_version() == QUIC_VERSION_99) {
1246 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1247 }
1248 return stream_id_manager_.GetNextOutgoingStreamId();
1249}
1250
1251bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
1252 if (connection_->transport_version() == QUIC_VERSION_99) {
1253 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1254 }
1255 return stream_id_manager_.CanOpenNextOutgoingStream(
1256 GetNumOpenOutgoingStreams());
1257}
1258
1259bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
1260 if (connection_->transport_version() == QUIC_VERSION_99) {
1261 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1262 }
1263 return stream_id_manager_.CanOpenNextOutgoingStream(
1264 GetNumOpenOutgoingStreams());
1265}
1266
1267QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang615f13b2019-05-06 17:08:02 -07001268 if (eliminate_static_stream_map_ &&
nharper46833c32019-05-15 21:33:05 -07001269 QuicUtils::IsCryptoStreamId(connection_->transport_version(),
1270 stream_id)) {
rchda26cdb2019-05-17 11:57:37 -07001271 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 13, 17);
renjietang2c4d7122019-05-20 17:18:14 -07001272 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001273 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001274 StaticStreamMap::iterator it = static_stream_map_.find(stream_id);
1275 if (it != static_stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001276 return it->second;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001277 }
renjietang2c4d7122019-05-20 17:18:14 -07001278 return GetOrCreateDynamicStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001279}
1280
1281void QuicSession::StreamDraining(QuicStreamId stream_id) {
1282 DCHECK(QuicContainsKey(dynamic_stream_map_, stream_id));
1283 if (!QuicContainsKey(draining_streams_, stream_id)) {
1284 draining_streams_.insert(stream_id);
1285 if (IsIncomingStream(stream_id)) {
1286 ++num_draining_incoming_streams_;
1287 }
1288 if (connection_->transport_version() == QUIC_VERSION_99) {
1289 v99_streamid_manager_.OnStreamClosed(stream_id);
1290 }
1291 }
1292 if (!IsIncomingStream(stream_id)) {
1293 // Inform application that a stream is available.
1294 OnCanCreateNewOutgoingStream();
1295 }
1296}
1297
1298bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1299 const QuicStreamId stream_id) {
1300 if (connection_->transport_version() == QUIC_VERSION_99) {
1301 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1302 }
1303 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1304}
1305
1306bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1307 if (stream_id == currently_writing_stream_id_) {
1308 return false;
1309 }
1310 return write_blocked_streams()->ShouldYield(stream_id);
1311}
1312
renjietange76b2da2019-05-13 14:50:23 -07001313PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1314 auto it = pending_stream_map_.find(stream_id);
1315 if (it != pending_stream_map_.end()) {
1316 return it->second.get();
1317 }
1318
1319 if (IsClosedStream(stream_id) ||
1320 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1321 return nullptr;
1322 }
1323
1324 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1325 PendingStream* unowned_pending = pending.get();
1326 pending_stream_map_[stream_id] = std::move(pending);
1327 return unowned_pending;
1328}
1329
QUICHE teama6ef0a62019-03-07 20:34:33 -05001330QuicStream* QuicSession::GetOrCreateDynamicStream(
1331 const QuicStreamId stream_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001332 DCHECK(!QuicContainsKey(static_stream_map_, stream_id))
1333 << "Attempt to call GetOrCreateDynamicStream for a static stream";
1334
1335 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
1336 if (it != dynamic_stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001337 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001338 }
1339
1340 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001341 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001342 }
1343
1344 if (!IsIncomingStream(stream_id)) {
1345 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001346 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001347 }
1348
QUICHE teama6ef0a62019-03-07 20:34:33 -05001349 // TODO(fkastenholz): If we are creating a new stream and we have
1350 // sent a goaway, we should ignore the stream creation. Need to
1351 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1352 // B) reject stream creation ("return nullptr")
1353
1354 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001355 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001356 }
1357
1358 if (connection_->transport_version() != QUIC_VERSION_99) {
1359 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1360 // CanOpenIncomingStream interface cosistent with that of v99.
1361 if (!stream_id_manager_.CanOpenIncomingStream(
1362 GetNumOpenIncomingStreams())) {
1363 // Refuse to open the stream.
1364 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001365 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001366 }
1367 }
1368
renjietang2c4d7122019-05-20 17:18:14 -07001369 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001370}
1371
1372void QuicSession::set_largest_peer_created_stream_id(
1373 QuicStreamId largest_peer_created_stream_id) {
1374 if (connection_->transport_version() == QUIC_VERSION_99) {
1375 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1376 largest_peer_created_stream_id);
1377 return;
1378 }
1379 stream_id_manager_.set_largest_peer_created_stream_id(
1380 largest_peer_created_stream_id);
1381}
1382
1383bool QuicSession::IsClosedStream(QuicStreamId id) {
1384 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1385 id);
1386 if (IsOpenStream(id)) {
1387 // Stream is active
1388 return false;
1389 }
1390
1391 if (connection_->transport_version() == QUIC_VERSION_99) {
1392 return !v99_streamid_manager_.IsAvailableStream(id);
1393 }
1394
1395 return !stream_id_manager_.IsAvailableStream(id);
1396}
1397
1398bool QuicSession::IsOpenStream(QuicStreamId id) {
1399 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1400 id);
1401 if (QuicContainsKey(static_stream_map_, id) ||
1402 QuicContainsKey(dynamic_stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001403 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001404 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001405 // Stream is active
1406 return true;
1407 }
1408 return false;
1409}
1410
rchda26cdb2019-05-17 11:57:37 -07001411bool QuicSession::IsStaticStream(QuicStreamId id) const {
1412 if (eliminate_static_stream_map()) {
1413 auto it = dynamic_stream_map_.find(id);
1414 if (it == dynamic_stream_map_.end()) {
1415 return false;
1416 }
1417 return it->second->is_static();
1418 }
1419
1420 return QuicContainsKey(static_streams(), id);
1421}
1422
QUICHE teama6ef0a62019-03-07 20:34:33 -05001423size_t QuicSession::GetNumOpenIncomingStreams() const {
1424 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1425 num_locally_closed_incoming_streams_highest_offset_;
1426}
1427
1428size_t QuicSession::GetNumOpenOutgoingStreams() const {
1429 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1430 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1431 GetNumDrainingOutgoingStreams());
1432 return GetNumDynamicOutgoingStreams() +
1433 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1434 GetNumDrainingOutgoingStreams();
1435}
1436
1437size_t QuicSession::GetNumActiveStreams() const {
renjietangfbeb5bf2019-04-19 15:06:20 -07001438 return dynamic_stream_map_.size() - draining_streams_.size() -
1439 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001440}
1441
1442size_t QuicSession::GetNumDrainingStreams() const {
1443 return draining_streams_.size();
1444}
1445
1446void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1447 if (GetOrCreateStream(id) == nullptr) {
1448 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1449 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1450 }
1451
1452 write_blocked_streams_.AddStream(id);
1453}
1454
1455bool QuicSession::HasDataToWrite() const {
1456 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1457 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1458 connection_->HasQueuedData() ||
1459 !streams_with_pending_retransmission_.empty() ||
1460 control_frame_manager_.WillingToWrite();
1461}
1462
1463void QuicSession::OnAckNeedsRetransmittableFrame() {
1464 flow_controller_.SendWindowUpdate();
1465}
1466
1467void QuicSession::SendPing() {
1468 control_frame_manager_.WritePing();
1469}
1470
1471size_t QuicSession::GetNumDynamicOutgoingStreams() const {
QUICHE team1243d142019-03-21 13:02:02 -07001472 DCHECK_GE(static_cast<size_t>(dynamic_stream_map_.size() +
1473 pending_stream_map_.size()),
renjietangfbeb5bf2019-04-19 15:06:20 -07001474 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1475 num_incoming_static_streams_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001476 return dynamic_stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001477 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1478 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001479}
1480
1481size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1482 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1483 return draining_streams_.size() - num_draining_incoming_streams_;
1484}
1485
1486size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1487 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1488 num_locally_closed_incoming_streams_highest_offset_);
1489 return locally_closed_streams_highest_offset_.size() -
1490 num_locally_closed_incoming_streams_highest_offset_;
1491}
1492
1493bool QuicSession::IsConnectionFlowControlBlocked() const {
1494 return flow_controller_.IsBlocked();
1495}
1496
1497bool QuicSession::IsStreamFlowControlBlocked() {
1498 for (auto const& kv : static_stream_map_) {
1499 if (kv.second->flow_controller()->IsBlocked()) {
1500 return true;
1501 }
1502 }
1503 for (auto const& kv : dynamic_stream_map_) {
1504 if (kv.second->flow_controller()->IsBlocked()) {
1505 return true;
1506 }
1507 }
renjietang615f13b2019-05-06 17:08:02 -07001508 if (eliminate_static_stream_map_ &&
nharperd5c4a932019-05-13 13:58:49 -07001509 !QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001510 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
rchda26cdb2019-05-17 11:57:37 -07001511 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 14, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001512 return true;
1513 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001514 return false;
1515}
1516
1517size_t QuicSession::MaxAvailableBidirectionalStreams() const {
1518 if (connection()->transport_version() == QUIC_VERSION_99) {
1519 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1520 }
1521 return stream_id_manager_.MaxAvailableStreams();
1522}
1523
1524size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
1525 if (connection()->transport_version() == QUIC_VERSION_99) {
1526 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1527 }
1528 return stream_id_manager_.MaxAvailableStreams();
1529}
1530
1531bool QuicSession::IsIncomingStream(QuicStreamId id) const {
1532 if (connection()->transport_version() == QUIC_VERSION_99) {
1533 return v99_streamid_manager_.IsIncomingStream(id);
1534 }
1535 return stream_id_manager_.IsIncomingStream(id);
1536}
1537
1538void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
1539 auto it = zombie_streams_.find(id);
1540 if (it == zombie_streams_.end()) {
1541 return;
1542 }
1543
1544 closed_streams_.push_back(std::move(it->second));
1545 if (!closed_streams_clean_up_alarm_->IsSet()) {
1546 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1547 }
1548 zombie_streams_.erase(it);
1549 // Do not retransmit data of a closed stream.
1550 streams_with_pending_retransmission_.erase(id);
1551}
1552
1553QuicStream* QuicSession::GetStream(QuicStreamId id) const {
1554 if (id <= largest_static_stream_id_) {
1555 auto static_stream = static_stream_map_.find(id);
1556 if (static_stream != static_stream_map_.end()) {
1557 return static_stream->second;
1558 }
1559 }
1560
1561 auto active_stream = dynamic_stream_map_.find(id);
1562 if (active_stream != dynamic_stream_map_.end()) {
1563 return active_stream->second.get();
1564 }
1565 auto zombie_stream = zombie_streams_.find(id);
1566 if (zombie_stream != zombie_streams_.end()) {
1567 return zombie_stream->second.get();
1568 }
renjietang08a9cf72019-04-23 17:01:34 -07001569
renjietang615f13b2019-05-06 17:08:02 -07001570 if (eliminate_static_stream_map_ &&
nharper46833c32019-05-15 21:33:05 -07001571 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
rchda26cdb2019-05-17 11:57:37 -07001572 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 15, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001573 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1574 }
1575
QUICHE teama6ef0a62019-03-07 20:34:33 -05001576 return nullptr;
1577}
1578
1579bool QuicSession::OnFrameAcked(const QuicFrame& frame,
1580 QuicTime::Delta ack_delay_time) {
1581 if (frame.type == MESSAGE_FRAME) {
1582 OnMessageAcked(frame.message_frame->message_id);
1583 return true;
1584 }
1585 if (frame.type == CRYPTO_FRAME) {
1586 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1587 ack_delay_time);
1588 }
1589 if (frame.type != STREAM_FRAME) {
1590 return control_frame_manager_.OnControlFrameAcked(frame);
1591 }
1592 bool new_stream_data_acked = false;
1593 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1594 // Stream can already be reset when sent frame gets acked.
1595 if (stream != nullptr) {
1596 QuicByteCount newly_acked_length = 0;
1597 new_stream_data_acked = stream->OnStreamFrameAcked(
1598 frame.stream_frame.offset, frame.stream_frame.data_length,
1599 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1600 if (!stream->HasPendingRetransmission()) {
1601 streams_with_pending_retransmission_.erase(stream->id());
1602 }
1603 }
1604 return new_stream_data_acked;
1605}
1606
1607void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1608 QuicStream* stream = GetStream(frame.stream_id);
1609 if (stream == nullptr) {
1610 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1611 << " is retransmitted.";
1612 connection()->CloseConnection(
1613 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1614 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1615 return;
1616 }
1617 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1618 frame.fin);
1619}
1620
1621void QuicSession::OnFrameLost(const QuicFrame& frame) {
1622 if (frame.type == MESSAGE_FRAME) {
1623 OnMessageLost(frame.message_frame->message_id);
1624 return;
1625 }
1626 if (frame.type == CRYPTO_FRAME) {
1627 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1628 return;
1629 }
1630 if (frame.type != STREAM_FRAME) {
1631 control_frame_manager_.OnControlFrameLost(frame);
1632 return;
1633 }
1634 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1635 if (stream == nullptr) {
1636 return;
1637 }
1638 stream->OnStreamFrameLost(frame.stream_frame.offset,
1639 frame.stream_frame.data_length,
1640 frame.stream_frame.fin);
1641 if (stream->HasPendingRetransmission() &&
1642 !QuicContainsKey(streams_with_pending_retransmission_,
1643 frame.stream_frame.stream_id)) {
1644 streams_with_pending_retransmission_.insert(
1645 std::make_pair(frame.stream_frame.stream_id, true));
1646 }
1647}
1648
1649void QuicSession::RetransmitFrames(const QuicFrames& frames,
1650 TransmissionType type) {
1651 QuicConnection::ScopedPacketFlusher retransmission_flusher(
1652 connection_, QuicConnection::NO_ACK);
1653 SetTransmissionType(type);
1654 for (const QuicFrame& frame : frames) {
1655 if (frame.type == MESSAGE_FRAME) {
1656 // Do not retransmit MESSAGE frames.
1657 continue;
1658 }
1659 if (frame.type == CRYPTO_FRAME) {
1660 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1661 continue;
1662 }
1663 if (frame.type != STREAM_FRAME) {
1664 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1665 break;
1666 }
1667 continue;
1668 }
1669 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1670 if (stream != nullptr &&
1671 !stream->RetransmitStreamData(frame.stream_frame.offset,
1672 frame.stream_frame.data_length,
1673 frame.stream_frame.fin)) {
1674 break;
1675 }
1676 }
1677}
1678
1679bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1680 if (frame.type == MESSAGE_FRAME) {
1681 return false;
1682 }
1683 if (frame.type == CRYPTO_FRAME) {
1684 return GetCryptoStream()->IsFrameOutstanding(
1685 frame.crypto_frame->level, frame.crypto_frame->offset,
1686 frame.crypto_frame->data_length);
1687 }
1688 if (frame.type != STREAM_FRAME) {
1689 return control_frame_manager_.IsControlFrameOutstanding(frame);
1690 }
1691 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1692 return stream != nullptr &&
1693 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1694 frame.stream_frame.data_length,
1695 frame.stream_frame.fin);
1696}
1697
1698bool QuicSession::HasUnackedCryptoData() const {
1699 const QuicCryptoStream* crypto_stream = GetCryptoStream();
1700 if (crypto_stream->IsWaitingForAcks()) {
1701 return true;
1702 }
1703 if (GetQuicReloadableFlag(quic_fix_has_pending_crypto_data) &&
1704 crypto_stream->HasBufferedData()) {
1705 QUIC_RELOADABLE_FLAG_COUNT(quic_fix_has_pending_crypto_data);
1706 return true;
1707 }
1708 return false;
1709}
1710
1711WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1712 QuicStreamOffset offset,
1713 QuicByteCount data_length,
1714 QuicDataWriter* writer) {
1715 QuicStream* stream = GetStream(id);
1716 if (stream == nullptr) {
1717 // This causes the connection to be closed because of failed to serialize
1718 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001719 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1720 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001721 return STREAM_MISSING;
1722 }
1723 if (stream->WriteStreamData(offset, data_length, writer)) {
1724 return WRITE_SUCCESS;
1725 }
1726 return WRITE_FAILED;
1727}
1728
1729bool QuicSession::WriteCryptoData(EncryptionLevel level,
1730 QuicStreamOffset offset,
1731 QuicByteCount data_length,
1732 QuicDataWriter* writer) {
1733 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1734 writer);
1735}
1736
1737QuicUint128 QuicSession::GetStatelessResetToken() const {
1738 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1739}
1740
1741bool QuicSession::RetransmitLostData() {
1742 QuicConnection::ScopedPacketFlusher retransmission_flusher(
1743 connection_, QuicConnection::SEND_ACK_IF_QUEUED);
1744 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001745 bool uses_crypto_frames =
1746 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001747 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1748 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1749 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1750 crypto_stream->WritePendingCryptoRetransmission();
1751 }
1752 // Retransmit crypto data in stream 1 frames (version < 47).
1753 if (!uses_crypto_frames &&
1754 QuicContainsKey(
1755 streams_with_pending_retransmission_,
1756 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1757 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1758 // Retransmit crypto data first.
1759 QuicStream* crypto_stream = GetStream(
1760 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1761 crypto_stream->OnCanWrite();
1762 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1763 if (crypto_stream->HasPendingRetransmission()) {
1764 // Connection is write blocked.
1765 return false;
1766 } else {
1767 streams_with_pending_retransmission_.erase(
1768 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1769 }
1770 }
1771 if (control_frame_manager_.HasPendingRetransmission()) {
1772 SetTransmissionType(LOSS_RETRANSMISSION);
1773 control_frame_manager_.OnCanWrite();
1774 if (control_frame_manager_.HasPendingRetransmission()) {
1775 return false;
1776 }
1777 }
1778 while (!streams_with_pending_retransmission_.empty()) {
1779 if (!connection_->CanWriteStreamData()) {
1780 break;
1781 }
1782 // Retransmit lost data on headers and data streams.
1783 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1784 QuicStream* stream = GetStream(id);
1785 if (stream != nullptr) {
1786 SetTransmissionType(LOSS_RETRANSMISSION);
1787 stream->OnCanWrite();
1788 DCHECK(CheckStreamWriteBlocked(stream));
1789 if (stream->HasPendingRetransmission()) {
1790 // Connection is write blocked.
1791 break;
1792 } else if (!streams_with_pending_retransmission_.empty() &&
1793 streams_with_pending_retransmission_.begin()->first == id) {
1794 // Retransmit lost data may cause connection close. If this stream
1795 // has not yet sent fin, a RST_STREAM will be sent and it will be
1796 // removed from streams_with_pending_retransmission_.
1797 streams_with_pending_retransmission_.pop_front();
1798 }
1799 } else {
1800 QUIC_BUG << "Try to retransmit data of a closed stream";
1801 streams_with_pending_retransmission_.pop_front();
1802 }
1803 }
1804
1805 return streams_with_pending_retransmission_.empty();
1806}
1807
1808void QuicSession::NeuterUnencryptedData() {
1809 if (connection_->session_decides_what_to_write()) {
1810 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1811 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001812 if (!crypto_stream->HasPendingRetransmission() &&
1813 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001814 streams_with_pending_retransmission_.erase(
1815 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1816 }
1817 }
1818 connection_->NeuterUnencryptedPackets();
1819}
1820
1821void QuicSession::SetTransmissionType(TransmissionType type) {
1822 connection_->SetTransmissionType(type);
1823}
1824
1825MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1826 if (!IsEncryptionEstablished()) {
1827 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1828 }
1829 MessageStatus result =
1830 connection_->SendMessage(last_message_id_ + 1, message);
1831 if (result == MESSAGE_STATUS_SUCCESS) {
1832 return {result, ++last_message_id_};
1833 }
1834 return {result, 0};
1835}
1836
1837void QuicSession::OnMessageAcked(QuicMessageId message_id) {
1838 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1839}
1840
1841void QuicSession::OnMessageLost(QuicMessageId message_id) {
1842 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1843 << " is considered lost";
1844}
1845
1846void QuicSession::CleanUpClosedStreams() {
1847 closed_streams_.clear();
1848}
1849
1850bool QuicSession::session_decides_what_to_write() const {
1851 return connection_->session_decides_what_to_write();
1852}
1853
ianswettb239f862019-04-05 09:15:06 -07001854QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1855 return connection_->GetCurrentLargestMessagePayload();
1856}
1857
1858QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1859 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001860}
1861
1862void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1863 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1864}
1865
1866void QuicSession::OnCanCreateNewOutgoingStream() {}
1867
1868QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
1869 if (connection_->transport_version() == QUIC_VERSION_99) {
1870 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1871 }
1872 return stream_id_manager_.next_outgoing_stream_id();
1873}
1874
1875QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const {
1876 if (connection_->transport_version() == QUIC_VERSION_99) {
1877 return v99_streamid_manager_.next_outgoing_unidirectional_stream_id();
1878 }
1879 return stream_id_manager_.next_outgoing_stream_id();
1880}
1881
fkastenholz3c4eabf2019-04-22 07:49:59 -07001882bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1883 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001884}
1885
fkastenholz3c4eabf2019-04-22 07:49:59 -07001886bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1887 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001888}
1889
1890size_t QuicSession::max_open_incoming_bidirectional_streams() const {
1891 if (connection_->transport_version() == QUIC_VERSION_99) {
1892 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1893 }
1894 return stream_id_manager_.max_open_incoming_streams();
1895}
1896
1897size_t QuicSession::max_open_incoming_unidirectional_streams() const {
1898 if (connection_->transport_version() == QUIC_VERSION_99) {
1899 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1900 }
1901 return stream_id_manager_.max_open_incoming_streams();
1902}
1903
1904#undef ENDPOINT // undef for jumbo builds
1905} // namespace quic