blob: 33b9ddbe2525fad3b4bff5c8993a148ff00c89df [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) {
renjietang3a1bb802019-06-11 10:42:41 -0700121 v99_streamid_manager_.RegisterStaticStream(id, false);
renjietang08a9cf72019-04-23 17:01:34 -0700122 }
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) {
renjietang3a1bb802019-06-11 10:42:41 -0700141 v99_streamid_manager_.RegisterStaticStream(id, false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500142 }
143}
144
renjietang3a1bb802019-06-11 10:42:41 -0700145void QuicSession::RegisterStaticStreamNew(std::unique_ptr<QuicStream> stream,
146 bool stream_already_counted) {
renjietang615f13b2019-05-06 17:08:02 -0700147 DCHECK(eliminate_static_stream_map_);
renjietangfbeb5bf2019-04-19 15:06:20 -0700148 QuicStreamId stream_id = stream->id();
149 dynamic_stream_map_[stream_id] = std::move(stream);
150 if (connection_->transport_version() == QUIC_VERSION_99) {
renjietang3a1bb802019-06-11 10:42:41 -0700151 v99_streamid_manager_.RegisterStaticStream(stream_id,
152 stream_already_counted);
renjietangfbeb5bf2019-04-19 15:06:20 -0700153 }
154 if (IsIncomingStream(stream_id)) {
155 ++num_incoming_static_streams_;
156 } else {
157 ++num_outgoing_static_streams_;
158 }
159}
160
renjietange76b2da2019-05-13 14:50:23 -0700161void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700162 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700163 QuicStreamId stream_id = frame.stream_id;
164
165 PendingStream* pending = GetOrCreatePendingStream(stream_id);
166
167 if (!pending) {
168 if (frame.fin) {
169 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
170 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
171 }
172 return;
173 }
174
175 pending->OnStreamFrame(frame);
renjietangbb1c4892019-05-24 15:58:44 -0700176 if (ProcessPendingStream(pending)) {
177 // The pending stream should now be in the scope of normal streams.
178 DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
179 << "Stream " << stream_id << " not created";
180 pending_stream_map_.erase(stream_id);
181 }
renjietange76b2da2019-05-13 14:50:23 -0700182}
183
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
185 // TODO(rch) deal with the error case of stream id 0.
186 QuicStreamId stream_id = frame.stream_id;
187 if (stream_id ==
188 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
189 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700190 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500191 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
192 return;
193 }
194
195 if (frame.fin && QuicContainsKey(static_stream_map_, stream_id)) {
196 connection()->CloseConnection(
197 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
198 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
199 return;
200 }
201
renjietangbb1c4892019-05-24 15:58:44 -0700202 if (VersionHasStreamType(connection()->transport_version()) &&
renjietange76b2da2019-05-13 14:50:23 -0700203 UsesPendingStreams() &&
204 QuicUtils::GetStreamType(stream_id, perspective(),
205 IsIncomingStream(stream_id)) ==
206 READ_UNIDIRECTIONAL &&
207 dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) {
208 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500209 return;
210 }
211
renjietang2c4d7122019-05-20 17:18:14 -0700212 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700213
renjietang2c4d7122019-05-20 17:18:14 -0700214 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500215 // The stream no longer exists, but we may still be interested in the
216 // final stream byte offset sent by the peer. A frame with a FIN can give
217 // us this offset.
218 if (frame.fin) {
219 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
220 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
221 }
222 return;
223 }
renjietang2c4d7122019-05-20 17:18:14 -0700224 if (eliminate_static_stream_map_ && frame.fin && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700225 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 1, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700226 connection()->CloseConnection(
227 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
228 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
229 return;
230 }
renjietang2c4d7122019-05-20 17:18:14 -0700231 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232}
233
234void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
235 GetMutableCryptoStream()->OnCryptoFrame(frame);
236}
237
238bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
239 // We are not version 99. In theory, if not in version 99 then the framer
240 // could not call OnStopSending... This is just a check that is good when
241 // both a new protocol and a new implementation of that protocol are both
242 // being developed.
243 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
244
245 QuicStreamId stream_id = frame.stream_id;
246 // If Stream ID is invalid then close the connection.
247 if (stream_id ==
248 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
249 QUIC_DVLOG(1) << ENDPOINT
250 << "Received STOP_SENDING with invalid stream_id: "
251 << stream_id << " Closing connection";
252 connection()->CloseConnection(
253 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
254 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
255 return false;
256 }
257
258 // Ignore STOP_SENDING for static streams.
259 // TODO(fkastenholz): IETF Quic does not have static streams and does not
260 // make exceptions for them with respect to processing things like
261 // STOP_SENDING.
renjietang08a9cf72019-04-23 17:01:34 -0700262 if (QuicContainsKey(static_stream_map_, stream_id) ||
nharper46833c32019-05-15 21:33:05 -0700263 QuicUtils::IsCryptoStreamId(connection_->transport_version(),
264 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265 QUIC_DVLOG(1) << ENDPOINT
266 << "Received STOP_SENDING for a static stream, id: "
267 << stream_id << " Closing connection";
268 connection()->CloseConnection(
269 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
270 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
271 return false;
272 }
273
274 if (visitor_) {
275 visitor_->OnStopSendingReceived(frame);
276 }
277
278 // If stream is closed, ignore the frame
279 if (IsClosedStream(stream_id)) {
280 QUIC_DVLOG(1)
281 << ENDPOINT
282 << "Received STOP_SENDING for closed or non-existent stream, id: "
283 << stream_id << " Ignoring.";
284 return true; // Continue processing the packet.
285 }
286 // If stream is non-existent, close the connection
287 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
288 if (it == dynamic_stream_map_.end()) {
289 QUIC_DVLOG(1) << ENDPOINT
290 << "Received STOP_SENDING for non-existent stream, id: "
291 << stream_id << " Closing connection";
292 connection()->CloseConnection(
293 IETF_QUIC_PROTOCOL_VIOLATION,
294 "Received STOP_SENDING for a non-existent stream",
295 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
296 return false;
297 }
298
299 // Get the QuicStream for this stream. Ignore the STOP_SENDING
300 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700301 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
302 // happen IFF there was an entry in the map, but the pointer is null. sounds
303 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500304 QuicStream* stream = it->second.get();
305 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700306 QUIC_BUG << ENDPOINT
307 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
308 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500309 return true;
310 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700311
renjietang615f13b2019-05-06 17:08:02 -0700312 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700313 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 2, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700314 QUIC_DVLOG(1) << ENDPOINT
315 << "Received STOP_SENDING for a static stream, id: "
316 << stream_id << " Closing connection";
317 connection()->CloseConnection(
318 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
319 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
320 return false;
321 }
322
QUICHE teama6ef0a62019-03-07 20:34:33 -0500323 stream->OnStopSending(frame.application_error_code);
324
325 stream->set_stream_error(
326 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
327 SendRstStreamInner(
328 stream->id(),
329 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
330 stream->stream_bytes_written(),
331 /*close_write_side_only=*/true);
332
333 return true;
334}
335
renjietange76b2da2019-05-13 14:50:23 -0700336void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700337 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700338 QuicStreamId stream_id = frame.stream_id;
339
340 PendingStream* pending = GetOrCreatePendingStream(stream_id);
341
342 if (!pending) {
343 HandleRstOnValidNonexistentStream(frame);
344 return;
345 }
346
347 pending->OnRstStreamFrame(frame);
348 ClosePendingStream(stream_id);
349}
350
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
352 QuicStreamId stream_id = frame.stream_id;
353 if (stream_id ==
354 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
355 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700356 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500357 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
358 return;
359 }
360
361 if (QuicContainsKey(static_stream_map_, stream_id)) {
362 connection()->CloseConnection(
363 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
364 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
365 return;
366 }
367
368 if (visitor_) {
369 visitor_->OnRstStreamReceived(frame);
370 }
371
renjietangbb1c4892019-05-24 15:58:44 -0700372 if (VersionHasStreamType(connection()->transport_version()) &&
renjietange76b2da2019-05-13 14:50:23 -0700373 UsesPendingStreams() &&
374 QuicUtils::GetStreamType(stream_id, perspective(),
375 IsIncomingStream(stream_id)) ==
376 READ_UNIDIRECTIONAL &&
377 dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) {
378 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500379 return;
380 }
renjietange76b2da2019-05-13 14:50:23 -0700381
renjietang2c4d7122019-05-20 17:18:14 -0700382 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700383
renjietang2c4d7122019-05-20 17:18:14 -0700384 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500385 HandleRstOnValidNonexistentStream(frame);
386 return; // Errors are handled by GetOrCreateStream.
387 }
renjietang2c4d7122019-05-20 17:18:14 -0700388 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700389 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 3, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700390 connection()->CloseConnection(
391 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
392 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
393 return;
394 }
renjietang2c4d7122019-05-20 17:18:14 -0700395 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500396}
397
398void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
399 goaway_received_ = true;
400}
401
402void QuicSession::OnMessageReceived(QuicStringPiece message) {
403 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
404 << ", " << message;
405}
406
wub2b5942f2019-04-11 13:22:50 -0700407// static
408void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
409 ConnectionCloseSource source) {
410 if (error != QUIC_NO_ERROR) {
411 if (source == ConnectionCloseSource::FROM_SELF) {
412 QUIC_SERVER_HISTOGRAM_ENUM(
413 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
414 "QuicErrorCode for server-closed connections.");
415 } else {
416 QUIC_SERVER_HISTOGRAM_ENUM(
417 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
418 "QuicErrorCode for client-closed connections.");
419 }
420 }
421}
422
QUICHE teama6ef0a62019-03-07 20:34:33 -0500423void QuicSession::OnConnectionClosed(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700424 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500425 ConnectionCloseSource source) {
426 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700427 if (perspective() == Perspective::IS_SERVER) {
428 RecordConnectionCloseAtServer(error, source);
429 }
430
QUICHE teama6ef0a62019-03-07 20:34:33 -0500431 if (error_ == QUIC_NO_ERROR) {
432 error_ = error;
433 }
434
renjietang615f13b2019-05-06 17:08:02 -0700435 if (!eliminate_static_stream_map_) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700436 while (!dynamic_stream_map_.empty()) {
437 DynamicStreamMap::iterator it = dynamic_stream_map_.begin();
438 QuicStreamId id = it->first;
439 it->second->OnConnectionClosed(error, source);
440 // The stream should call CloseStream as part of OnConnectionClosed.
441 if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
442 QUIC_BUG << ENDPOINT << "Stream " << id
443 << " failed to close under OnConnectionClosed";
444 CloseStream(id);
445 }
446 }
447 } else {
rchda26cdb2019-05-17 11:57:37 -0700448 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 4, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700449 // Copy all non static streams in a new map for the ease of deleting.
450 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
451 for (const auto& it : dynamic_stream_map_) {
452 if (!it.second->is_static()) {
453 non_static_streams[it.first] = it.second.get();
454 }
455 }
456 for (const auto& it : non_static_streams) {
457 QuicStreamId id = it.first;
458 it.second->OnConnectionClosed(error, source);
459 if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
460 QUIC_BUG << ENDPOINT << "Stream " << id
461 << " failed to close under OnConnectionClosed";
462 CloseStream(id);
463 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500464 }
465 }
466
467 // Cleanup zombie stream map on connection close.
468 while (!zombie_streams_.empty()) {
469 ZombieStreamMap::iterator it = zombie_streams_.begin();
470 closed_streams_.push_back(std::move(it->second));
471 zombie_streams_.erase(it);
472 }
473
474 closed_streams_clean_up_alarm_->Cancel();
475
476 if (visitor_) {
477 visitor_->OnConnectionClosed(connection_->connection_id(), error,
478 error_details, source);
479 }
480}
481
482void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700483 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500484 return;
485 }
486 if (visitor_) {
487 visitor_->OnWriteBlocked(connection_);
488 }
489}
490
491void QuicSession::OnSuccessfulVersionNegotiation(
492 const ParsedQuicVersion& version) {
493 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
494}
495
496void QuicSession::OnConnectivityProbeReceived(
497 const QuicSocketAddress& self_address,
498 const QuicSocketAddress& peer_address) {
499 if (perspective() == Perspective::IS_SERVER) {
500 // Server only sends back a connectivity probe after received a
501 // connectivity probe from a new peer address.
502 connection_->SendConnectivityProbingResponsePacket(peer_address);
503 }
504}
505
506void QuicSession::OnPathDegrading() {}
507
508bool QuicSession::AllowSelfAddressChange() const {
509 return false;
510}
511
512void QuicSession::OnForwardProgressConfirmed() {}
513
514void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
515 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
516 // assume that it still exists.
517 QuicStreamId stream_id = frame.stream_id;
518 if (stream_id ==
519 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
520 // This is a window update that applies to the connection, rather than an
521 // individual stream.
522 QUIC_DLOG(INFO) << ENDPOINT
523 << "Received connection level flow control window "
524 "update with byte offset: "
525 << frame.byte_offset;
526 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
527 return;
528 }
529 QuicStream* stream = GetOrCreateStream(stream_id);
530 if (stream != nullptr) {
531 stream->OnWindowUpdateFrame(frame);
532 }
533}
534
535void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
536 // TODO(rjshade): Compare our flow control receive windows for specified
537 // streams: if we have a large window then maybe something
538 // had gone wrong with the flow control accounting.
539 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
540 << frame.stream_id;
541}
542
543bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
544 uint64_t previous_bytes_written,
545 bool previous_fin_sent) {
546 if ( // Stream should not be closed.
547 !stream->write_side_closed() &&
548 // Not connection flow control blocked.
549 !flow_controller_.IsBlocked() &&
550 // Detect lack of forward progress.
551 previous_bytes_written == stream->stream_bytes_written() &&
552 previous_fin_sent == stream->fin_sent()) {
553 stream->set_busy_counter(stream->busy_counter() + 1);
554 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
555 << " stream_bytes_written " << stream->stream_bytes_written()
556 << " fin " << stream->fin_sent() << " count "
557 << stream->busy_counter();
558 // Wait a few iterations before firing, the exact count is
559 // arbitrary, more than a few to cover a few test-only false
560 // positives.
561 if (stream->busy_counter() > 20) {
562 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
563 << " stream_bytes_written "
564 << stream->stream_bytes_written() << " fin "
565 << stream->fin_sent();
566 return false;
567 }
568 } else {
569 stream->set_busy_counter(0);
570 }
571 return true;
572}
573
574bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
575 if (!stream->write_side_closed() && stream->HasBufferedData() &&
576 !stream->flow_controller()->IsBlocked() &&
577 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
578 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
579 << stream->BufferedDataBytes()
580 << " bytes, and is not flow control blocked, "
581 "but it is not in the write block list.";
582 return false;
583 }
584 return true;
585}
586
587void QuicSession::OnCanWrite() {
588 if (!RetransmitLostData()) {
589 // Cannot finish retransmitting lost data, connection is write blocked.
590 QUIC_DVLOG(1) << ENDPOINT
591 << "Cannot finish retransmitting lost data, connection is "
592 "write blocked.";
593 return;
594 }
595 if (session_decides_what_to_write()) {
596 SetTransmissionType(NOT_RETRANSMISSION);
597 }
598 // We limit the number of writes to the number of pending streams. If more
599 // streams become pending, WillingAndAbleToWrite will be true, which will
600 // cause the connection to request resumption before yielding to other
601 // connections.
602 // If we are connection level flow control blocked, then only allow the
603 // crypto and headers streams to try writing as all other streams will be
604 // blocked.
605 size_t num_writes = flow_controller_.IsBlocked()
606 ? write_blocked_streams_.NumBlockedSpecialStreams()
607 : write_blocked_streams_.NumBlockedStreams();
608 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
609 return;
610 }
611
612 QuicConnection::ScopedPacketFlusher flusher(
613 connection_, QuicConnection::SEND_ACK_IF_QUEUED);
614 if (control_frame_manager_.WillingToWrite()) {
615 control_frame_manager_.OnCanWrite();
616 }
617 for (size_t i = 0; i < num_writes; ++i) {
618 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
619 write_blocked_streams_.HasWriteBlockedDataStreams())) {
620 // Writing one stream removed another!? Something's broken.
621 QUIC_BUG << "WriteBlockedStream is missing";
622 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
623 "WriteBlockedStream is missing",
624 ConnectionCloseBehavior::SILENT_CLOSE);
625 return;
626 }
627 if (!connection_->CanWriteStreamData()) {
628 return;
629 }
630 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
631 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
632 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
633 // If the stream can't write all bytes it'll re-add itself to the blocked
634 // list.
635 uint64_t previous_bytes_written = stream->stream_bytes_written();
636 bool previous_fin_sent = stream->fin_sent();
637 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
638 << previous_bytes_written << " fin " << previous_fin_sent;
639 stream->OnCanWrite();
640 DCHECK(CheckStreamWriteBlocked(stream));
641 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
642 previous_fin_sent));
643 }
644 currently_writing_stream_id_ = 0;
645 }
646}
647
QUICHE teamb8343252019-04-29 13:58:01 -0700648bool QuicSession::SendProbingData() {
649 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
650 PROBING_RETRANSMISSION)) {
651 return true;
652 }
653 return false;
654}
655
QUICHE teama6ef0a62019-03-07 20:34:33 -0500656bool QuicSession::WillingAndAbleToWrite() const {
657 // Schedule a write when:
658 // 1) control frame manager has pending or new control frames, or
659 // 2) any stream has pending retransmissions, or
660 // 3) If the crypto or headers streams are blocked, or
661 // 4) connection is not flow control blocked and there are write blocked
662 // streams.
663 return control_frame_manager_.WillingToWrite() ||
664 !streams_with_pending_retransmission_.empty() ||
665 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
666 (!flow_controller_.IsBlocked() &&
667 write_blocked_streams_.HasWriteBlockedDataStreams());
668}
669
670bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700671 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
672 // Writing CRYPTO frames is not subject to flow control, so there can't be
673 // pending data to write, only pending retransmissions.
674 return GetCryptoStream()->HasPendingCryptoRetransmission();
675 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500676 return QuicContainsKey(
677 streams_with_pending_retransmission_,
678 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
679 write_blocked_streams_.IsStreamBlocked(
680 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
681}
682
683uint64_t QuicSession::GetNumOpenDynamicStreams() const {
684 return dynamic_stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700685 locally_closed_streams_highest_offset_.size() -
686 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500687}
688
689void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
690 const QuicSocketAddress& peer_address,
691 const QuicReceivedPacket& packet) {
692 connection_->ProcessUdpPacket(self_address, peer_address, packet);
693}
694
695QuicConsumedData QuicSession::WritevData(QuicStream* stream,
696 QuicStreamId id,
697 size_t write_length,
698 QuicStreamOffset offset,
699 StreamSendingState state) {
700 // This check is an attempt to deal with potential memory corruption
701 // in which |id| ends up set to 1 (the crypto stream id). If this happen
702 // it might end up resulting in unencrypted stream data being sent.
703 // While this is impossible to avoid given sufficient corruption, this
704 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700705 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500706 stream != GetMutableCryptoStream()) {
707 QUIC_BUG << "Stream id mismatch";
708 connection_->CloseConnection(
709 QUIC_INTERNAL_ERROR,
710 "Non-crypto stream attempted to write data as crypto stream.",
711 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
712 return QuicConsumedData(0, false);
713 }
714 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700715 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500716 // Do not let streams write without encryption. The calling stream will end
717 // up write blocked until OnCanWrite is next called.
718 return QuicConsumedData(0, false);
719 }
720
721 QuicConsumedData data =
722 connection_->SendStreamData(id, write_length, offset, state);
723 if (offset >= stream->stream_bytes_written()) {
724 // This is new stream data.
725 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
726 }
727 return data;
728}
729
730bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
731 return connection_->SendControlFrame(frame);
732}
733
734void QuicSession::SendRstStream(QuicStreamId id,
735 QuicRstStreamErrorCode error,
736 QuicStreamOffset bytes_written) {
737 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
738}
739
740void QuicSession::SendRstStreamInner(QuicStreamId id,
741 QuicRstStreamErrorCode error,
742 QuicStreamOffset bytes_written,
743 bool close_write_side_only) {
744 if (connection()->connected()) {
745 // Only send if still connected.
746 if (close_write_side_only) {
747 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
748 // Send a RST_STREAM frame.
749 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
750 } else {
751 // Send a RST_STREAM frame plus, if version 99, an IETF
752 // QUIC STOP_SENDING frame. Both sre sent to emulate
753 // the two-way close that Google QUIC's RST_STREAM does.
754 if (connection_->transport_version() == QUIC_VERSION_99) {
755 QuicConnection::ScopedPacketFlusher flusher(
756 connection(), QuicConnection::SEND_ACK_IF_QUEUED);
757 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
758 control_frame_manager_.WriteOrBufferStopSending(error, id);
759 } else {
760 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
761 }
762 }
763 connection_->OnStreamReset(id, error);
764 }
765 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
766 OnStreamDoneWaitingForAcks(id);
767 return;
768 }
769
770 if (!close_write_side_only) {
771 CloseStreamInner(id, true);
772 return;
773 }
774 DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
775
776 DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
777 if (it != dynamic_stream_map_.end()) {
renjietang615f13b2019-05-06 17:08:02 -0700778 if (eliminate_static_stream_map_ && it->second->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700779 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 5, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700780 QUIC_DVLOG(1) << ENDPOINT
781 << "Try to send rst for a static stream, id: " << id
782 << " Closing connection";
783 connection()->CloseConnection(
784 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
785 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
786 return;
787 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500788 QuicStream* stream = it->second.get();
789 if (stream) {
790 stream->set_rst_sent(true);
791 stream->CloseWriteSide();
792 }
793 }
794}
795
796void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700797 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500798 // GOAWAY frame is not supported in v99.
799 DCHECK_NE(QUIC_VERSION_99, connection_->transport_version());
800 if (goaway_sent_) {
801 return;
802 }
803 goaway_sent_ = true;
804 control_frame_manager_.WriteOrBufferGoAway(
805 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
806}
807
808void QuicSession::SendBlocked(QuicStreamId id) {
809 control_frame_manager_.WriteOrBufferBlocked(id);
810}
811
812void QuicSession::SendWindowUpdate(QuicStreamId id,
813 QuicStreamOffset byte_offset) {
814 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
815}
816
fkastenholz3c4eabf2019-04-22 07:49:59 -0700817void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
818 bool unidirectional) {
819 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500820}
821
fkastenholz3c4eabf2019-04-22 07:49:59 -0700822void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
823 bool unidirectional) {
824 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
825 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500826}
827
828void QuicSession::CloseStream(QuicStreamId stream_id) {
829 CloseStreamInner(stream_id, false);
830}
831
832void QuicSession::InsertLocallyClosedStreamsHighestOffset(
833 const QuicStreamId id,
834 QuicStreamOffset offset) {
835 locally_closed_streams_highest_offset_[id] = offset;
836 if (IsIncomingStream(id)) {
837 ++num_locally_closed_incoming_streams_highest_offset_;
838 }
839}
840
841void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
842 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
843
844 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
845 if (it == dynamic_stream_map_.end()) {
846 // When CloseStreamInner has been called recursively (via
847 // QuicStream::OnClose), the stream will already have been deleted
848 // from stream_map_, so return immediately.
849 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
850 return;
851 }
852 QuicStream* stream = it->second.get();
renjietang615f13b2019-05-06 17:08:02 -0700853 if (eliminate_static_stream_map_ && stream->is_static()) {
rchda26cdb2019-05-17 11:57:37 -0700854 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 6, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700855 QUIC_DVLOG(1) << ENDPOINT
856 << "Try to close a static stream, id: " << stream_id
857 << " Closing connection";
858 connection()->CloseConnection(
859 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
860 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
861 return;
862 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500863
864 // Tell the stream that a RST has been sent.
865 if (locally_reset) {
866 stream->set_rst_sent(true);
867 }
868
869 if (stream->IsWaitingForAcks()) {
870 zombie_streams_[stream->id()] = std::move(it->second);
871 } else {
872 closed_streams_.push_back(std::move(it->second));
873 // Do not retransmit data of a closed stream.
874 streams_with_pending_retransmission_.erase(stream_id);
875 if (!closed_streams_clean_up_alarm_->IsSet()) {
876 closed_streams_clean_up_alarm_->Set(
877 connection_->clock()->ApproximateNow());
878 }
879 }
880
881 // If we haven't received a FIN or RST for this stream, we need to keep track
882 // of the how many bytes the stream's flow controller believes it has
883 // received, for accurate connection level flow control accounting.
884 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
885 if (!had_fin_or_rst) {
886 InsertLocallyClosedStreamsHighestOffset(
887 stream_id, stream->flow_controller()->highest_received_byte_offset());
888 }
889 dynamic_stream_map_.erase(it);
890 if (IsIncomingStream(stream_id)) {
891 --num_dynamic_incoming_streams_;
892 }
893
894 const bool stream_was_draining =
895 draining_streams_.find(stream_id) != draining_streams_.end();
896 if (stream_was_draining) {
897 if (IsIncomingStream(stream_id)) {
898 --num_draining_incoming_streams_;
899 }
900 draining_streams_.erase(stream_id);
901 } else if (connection_->transport_version() == QUIC_VERSION_99) {
902 // Stream was not draining, but we did have a fin or rst, so we can now
903 // free the stream ID if version 99.
904 if (had_fin_or_rst) {
905 v99_streamid_manager_.OnStreamClosed(stream_id);
906 }
907 }
908
909 stream->OnClose();
910
911 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
912 connection_->transport_version() != QUIC_VERSION_99) {
913 // Streams that first became draining already called OnCanCreate...
914 // This covers the case where the stream went directly to being closed.
915 OnCanCreateNewOutgoingStream();
916 }
917}
918
919void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
920 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
921
922 if (pending_stream_map_.find(stream_id) == pending_stream_map_.end()) {
923 QUIC_BUG << ENDPOINT << "Stream is already closed: " << stream_id;
924 return;
925 }
926
927 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
928
929 // The pending stream may have been deleted and removed during SendRstStream.
930 // Remove the stream from pending stream map iff it is still in the map.
931 if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
932 pending_stream_map_.erase(stream_id);
933 }
934
935 --num_dynamic_incoming_streams_;
936
937 if (connection_->transport_version() == QUIC_VERSION_99) {
938 v99_streamid_manager_.OnStreamClosed(stream_id);
939 }
940
941 OnCanCreateNewOutgoingStream();
942}
943
944void QuicSession::OnFinalByteOffsetReceived(
945 QuicStreamId stream_id,
946 QuicStreamOffset final_byte_offset) {
947 auto it = locally_closed_streams_highest_offset_.find(stream_id);
948 if (it == locally_closed_streams_highest_offset_.end()) {
949 return;
950 }
951
952 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
953 << final_byte_offset << " for stream " << stream_id;
954 QuicByteCount offset_diff = final_byte_offset - it->second;
955 if (flow_controller_.UpdateHighestReceivedOffset(
956 flow_controller_.highest_received_byte_offset() + offset_diff)) {
957 // If the final offset violates flow control, close the connection now.
958 if (flow_controller_.FlowControlViolation()) {
959 connection_->CloseConnection(
960 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
961 "Connection level flow control violation",
962 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
963 return;
964 }
965 }
966
967 flow_controller_.AddBytesConsumed(offset_diff);
968 locally_closed_streams_highest_offset_.erase(it);
969 if (IsIncomingStream(stream_id)) {
970 --num_locally_closed_incoming_streams_highest_offset_;
971 if (connection_->transport_version() == QUIC_VERSION_99) {
972 v99_streamid_manager_.OnStreamClosed(stream_id);
973 }
974 } else if (connection_->transport_version() != QUIC_VERSION_99) {
975 OnCanCreateNewOutgoingStream();
976 }
977}
978
979bool QuicSession::IsEncryptionEstablished() const {
980 // Once the handshake is confirmed, it never becomes un-confirmed.
981 if (is_handshake_confirmed_) {
982 return true;
983 }
984 return GetCryptoStream()->encryption_established();
985}
986
987bool QuicSession::IsCryptoHandshakeConfirmed() const {
988 return GetCryptoStream()->handshake_confirmed();
989}
990
991void QuicSession::OnConfigNegotiated() {
992 connection_->SetFromConfig(config_);
993
QUICHE teama6ef0a62019-03-07 20:34:33 -0500994 if (connection_->transport_version() == QUIC_VERSION_99) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700995 uint32_t max_streams = 0;
996 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
997 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
998 }
999 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
1000 << max_streams;
1001 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
1002 max_streams);
1003
1004 max_streams = 0;
1005 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
1006 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
1007 }
1008 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
1009 << max_streams;
1010 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
1011 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001012 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001013 uint32_t max_streams = 0;
1014 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
1015 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
1016 }
1017 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001018 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
1019 }
fkastenholzd3a1de92019-05-15 07:00:07 -07001020
QUICHE teama6ef0a62019-03-07 20:34:33 -05001021 if (perspective() == Perspective::IS_SERVER) {
1022 if (config_.HasReceivedConnectionOptions()) {
1023 // The following variations change the initial receive flow control
1024 // window sizes.
1025 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
1026 AdjustInitialFlowControlWindows(64 * 1024);
1027 }
1028 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
1029 AdjustInitialFlowControlWindows(128 * 1024);
1030 }
1031 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
1032 AdjustInitialFlowControlWindows(256 * 1024);
1033 }
1034 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
1035 AdjustInitialFlowControlWindows(512 * 1024);
1036 }
1037 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
1038 AdjustInitialFlowControlWindows(1024 * 1024);
1039 }
1040 }
1041
1042 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
1043 }
1044
QUICHE teama6ef0a62019-03-07 20:34:33 -05001045 if (connection_->transport_version() == QUIC_VERSION_99) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001046 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1047 config_.GetMaxIncomingBidirectionalStreamsToSend());
1048 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1049 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001050 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001051 // A small number of additional incoming streams beyond the limit should be
1052 // allowed. This helps avoid early connection termination when FIN/RSTs for
1053 // old streams are lost or arrive out of order.
1054 // Use a minimum number of additional streams, or a percentage increase,
1055 // whichever is larger.
1056 uint32_t max_incoming_streams_to_send =
1057 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001058 uint32_t max_incoming_streams =
1059 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1060 static_cast<uint32_t>(max_incoming_streams_to_send *
1061 kMaxStreamsMultiplier));
1062 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1063 }
1064
1065 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1066 // Streams which were created before the SHLO was received (0-RTT
1067 // requests) are now informed of the peer's initial flow control window.
1068 OnNewStreamFlowControlWindow(
1069 config_.ReceivedInitialStreamFlowControlWindowBytes());
1070 }
1071 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1072 OnNewSessionFlowControlWindow(
1073 config_.ReceivedInitialSessionFlowControlWindowBytes());
1074 }
1075}
1076
1077void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1078 const float session_window_multiplier =
1079 config_.GetInitialStreamFlowControlWindowToSend()
1080 ? static_cast<float>(
1081 config_.GetInitialSessionFlowControlWindowToSend()) /
1082 config_.GetInitialStreamFlowControlWindowToSend()
1083 : 1.5;
1084
1085 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1086 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1087
1088 size_t session_window = session_window_multiplier * stream_window;
1089 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1090 << session_window;
1091 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1092 flow_controller_.UpdateReceiveWindowSize(session_window);
1093 // Inform all existing streams about the new window.
1094 for (auto const& kv : static_stream_map_) {
1095 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1096 }
1097 for (auto const& kv : dynamic_stream_map_) {
1098 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1099 }
nharperd5c4a932019-05-13 13:58:49 -07001100 if (eliminate_static_stream_map_ &&
1101 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
rchda26cdb2019-05-17 11:57:37 -07001102 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 11, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001103 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1104 stream_window);
1105 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001106}
1107
1108void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1109 QuicStreamId stream_id) {
1110 DCHECK(!IsClosedStream(stream_id));
1111 // Received a frame for a locally-created stream that is not currently
1112 // active. This is an error.
1113 connection()->CloseConnection(
1114 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1115 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1116}
1117
1118void QuicSession::HandleRstOnValidNonexistentStream(
1119 const QuicRstStreamFrame& frame) {
1120 // If the stream is neither originally in active streams nor created in
1121 // GetOrCreateDynamicStream(), it could be a closed stream in which case its
1122 // final received byte offset need to be updated.
1123 if (IsClosedStream(frame.stream_id)) {
1124 // The RST frame contains the final byte offset for the stream: we can now
1125 // update the connection level flow controller if needed.
1126 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1127 }
1128}
1129
1130void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001131 if (new_window < kMinimumFlowControlSendWindow &&
1132 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001133 QUIC_LOG_FIRST_N(ERROR, 1)
1134 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001135 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001136 if (connection_->connected()) {
1137 connection_->CloseConnection(
1138 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1139 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1140 }
1141 return;
1142 }
1143
1144 // Inform all existing streams about the new window.
1145 for (auto const& kv : static_stream_map_) {
1146 kv.second->UpdateSendWindowOffset(new_window);
1147 }
1148 for (auto const& kv : dynamic_stream_map_) {
1149 kv.second->UpdateSendWindowOffset(new_window);
1150 }
nharperd5c4a932019-05-13 13:58:49 -07001151 if (eliminate_static_stream_map_ &&
1152 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
rchda26cdb2019-05-17 11:57:37 -07001153 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 12, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001154 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1155 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001156}
1157
1158void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001159 if (new_window < kMinimumFlowControlSendWindow &&
1160 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001161 QUIC_LOG_FIRST_N(ERROR, 1)
1162 << "Peer sent us an invalid session flow control send window: "
1163 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1164 if (connection_->connected()) {
1165 connection_->CloseConnection(
1166 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1167 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1168 }
1169 return;
1170 }
1171
1172 flow_controller_.UpdateSendWindowOffset(new_window);
1173}
1174
1175void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1176 switch (event) {
1177 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
1178 // to QuicSession since it is the glue.
1179 case ENCRYPTION_FIRST_ESTABLISHED:
1180 // Given any streams blocked by encryption a chance to write.
1181 OnCanWrite();
1182 break;
1183
1184 case ENCRYPTION_REESTABLISHED:
1185 // Retransmit originally packets that were sent, since they can't be
1186 // decrypted by the peer.
1187 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1188 // Given any streams blocked by encryption a chance to write.
1189 OnCanWrite();
1190 break;
1191
1192 case HANDSHAKE_CONFIRMED:
1193 QUIC_BUG_IF(!config_.negotiated())
1194 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1195 // Discard originally encrypted packets, since they can't be decrypted by
1196 // the peer.
1197 NeuterUnencryptedData();
1198 is_handshake_confirmed_ = true;
1199 break;
1200
1201 default:
1202 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1203 }
1204}
1205
1206void QuicSession::OnCryptoHandshakeMessageSent(
1207 const CryptoHandshakeMessage& /*message*/) {}
1208
1209void QuicSession::OnCryptoHandshakeMessageReceived(
1210 const CryptoHandshakeMessage& /*message*/) {}
1211
1212void QuicSession::RegisterStreamPriority(QuicStreamId id,
1213 bool is_static,
1214 SpdyPriority priority) {
1215 write_blocked_streams()->RegisterStream(id, is_static, priority);
1216}
1217
1218void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1219 write_blocked_streams()->UnregisterStream(id, is_static);
1220}
1221
1222void QuicSession::UpdateStreamPriority(QuicStreamId id,
1223 SpdyPriority new_priority) {
1224 write_blocked_streams()->UpdateStreamPriority(id, new_priority);
1225}
1226
1227QuicConfig* QuicSession::config() {
1228 return &config_;
1229}
1230
1231void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001232 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001233 QuicStreamId stream_id = stream->id();
1234 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
1235 << ". activating " << stream_id;
1236 DCHECK(!QuicContainsKey(dynamic_stream_map_, stream_id));
1237 DCHECK(!QuicContainsKey(static_stream_map_, stream_id));
1238 dynamic_stream_map_[stream_id] = std::move(stream);
1239 if (IsIncomingStream(stream_id)) {
1240 ++num_dynamic_incoming_streams_;
1241 }
1242}
1243
1244QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
1245 if (connection_->transport_version() == QUIC_VERSION_99) {
1246 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1247 }
1248 return stream_id_manager_.GetNextOutgoingStreamId();
1249}
1250
1251QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
1252 if (connection_->transport_version() == QUIC_VERSION_99) {
1253 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1254 }
1255 return stream_id_manager_.GetNextOutgoingStreamId();
1256}
1257
1258bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
1259 if (connection_->transport_version() == QUIC_VERSION_99) {
1260 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1261 }
1262 return stream_id_manager_.CanOpenNextOutgoingStream(
1263 GetNumOpenOutgoingStreams());
1264}
1265
1266bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
1267 if (connection_->transport_version() == QUIC_VERSION_99) {
1268 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1269 }
1270 return stream_id_manager_.CanOpenNextOutgoingStream(
1271 GetNumOpenOutgoingStreams());
1272}
1273
1274QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang615f13b2019-05-06 17:08:02 -07001275 if (eliminate_static_stream_map_ &&
nharper46833c32019-05-15 21:33:05 -07001276 QuicUtils::IsCryptoStreamId(connection_->transport_version(),
1277 stream_id)) {
rchda26cdb2019-05-17 11:57:37 -07001278 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 13, 17);
renjietang2c4d7122019-05-20 17:18:14 -07001279 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001280 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001281 StaticStreamMap::iterator it = static_stream_map_.find(stream_id);
1282 if (it != static_stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001283 return it->second;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001284 }
renjietang2c4d7122019-05-20 17:18:14 -07001285 return GetOrCreateDynamicStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001286}
1287
1288void QuicSession::StreamDraining(QuicStreamId stream_id) {
1289 DCHECK(QuicContainsKey(dynamic_stream_map_, stream_id));
1290 if (!QuicContainsKey(draining_streams_, stream_id)) {
1291 draining_streams_.insert(stream_id);
1292 if (IsIncomingStream(stream_id)) {
1293 ++num_draining_incoming_streams_;
1294 }
1295 if (connection_->transport_version() == QUIC_VERSION_99) {
1296 v99_streamid_manager_.OnStreamClosed(stream_id);
1297 }
1298 }
1299 if (!IsIncomingStream(stream_id)) {
1300 // Inform application that a stream is available.
1301 OnCanCreateNewOutgoingStream();
1302 }
1303}
1304
1305bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1306 const QuicStreamId stream_id) {
1307 if (connection_->transport_version() == QUIC_VERSION_99) {
1308 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1309 }
1310 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1311}
1312
1313bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1314 if (stream_id == currently_writing_stream_id_) {
1315 return false;
1316 }
1317 return write_blocked_streams()->ShouldYield(stream_id);
1318}
1319
renjietange76b2da2019-05-13 14:50:23 -07001320PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1321 auto it = pending_stream_map_.find(stream_id);
1322 if (it != pending_stream_map_.end()) {
1323 return it->second.get();
1324 }
1325
1326 if (IsClosedStream(stream_id) ||
1327 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1328 return nullptr;
1329 }
1330
1331 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1332 PendingStream* unowned_pending = pending.get();
1333 pending_stream_map_[stream_id] = std::move(pending);
1334 return unowned_pending;
1335}
1336
QUICHE teama6ef0a62019-03-07 20:34:33 -05001337QuicStream* QuicSession::GetOrCreateDynamicStream(
1338 const QuicStreamId stream_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001339 DCHECK(!QuicContainsKey(static_stream_map_, stream_id))
1340 << "Attempt to call GetOrCreateDynamicStream for a static stream";
1341
1342 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
1343 if (it != dynamic_stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001344 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001345 }
1346
1347 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001348 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001349 }
1350
1351 if (!IsIncomingStream(stream_id)) {
1352 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001353 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001354 }
1355
QUICHE teama6ef0a62019-03-07 20:34:33 -05001356 // TODO(fkastenholz): If we are creating a new stream and we have
1357 // sent a goaway, we should ignore the stream creation. Need to
1358 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1359 // B) reject stream creation ("return nullptr")
1360
1361 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001362 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001363 }
1364
1365 if (connection_->transport_version() != QUIC_VERSION_99) {
1366 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1367 // CanOpenIncomingStream interface cosistent with that of v99.
1368 if (!stream_id_manager_.CanOpenIncomingStream(
1369 GetNumOpenIncomingStreams())) {
1370 // Refuse to open the stream.
1371 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001372 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001373 }
1374 }
1375
renjietang2c4d7122019-05-20 17:18:14 -07001376 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001377}
1378
1379void QuicSession::set_largest_peer_created_stream_id(
1380 QuicStreamId largest_peer_created_stream_id) {
1381 if (connection_->transport_version() == QUIC_VERSION_99) {
1382 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1383 largest_peer_created_stream_id);
1384 return;
1385 }
1386 stream_id_manager_.set_largest_peer_created_stream_id(
1387 largest_peer_created_stream_id);
1388}
1389
1390bool QuicSession::IsClosedStream(QuicStreamId id) {
1391 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1392 id);
1393 if (IsOpenStream(id)) {
1394 // Stream is active
1395 return false;
1396 }
1397
1398 if (connection_->transport_version() == QUIC_VERSION_99) {
1399 return !v99_streamid_manager_.IsAvailableStream(id);
1400 }
1401
1402 return !stream_id_manager_.IsAvailableStream(id);
1403}
1404
1405bool QuicSession::IsOpenStream(QuicStreamId id) {
1406 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1407 id);
1408 if (QuicContainsKey(static_stream_map_, id) ||
1409 QuicContainsKey(dynamic_stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001410 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001411 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001412 // Stream is active
1413 return true;
1414 }
1415 return false;
1416}
1417
rchda26cdb2019-05-17 11:57:37 -07001418bool QuicSession::IsStaticStream(QuicStreamId id) const {
1419 if (eliminate_static_stream_map()) {
1420 auto it = dynamic_stream_map_.find(id);
1421 if (it == dynamic_stream_map_.end()) {
1422 return false;
1423 }
1424 return it->second->is_static();
1425 }
1426
1427 return QuicContainsKey(static_streams(), id);
1428}
1429
QUICHE teama6ef0a62019-03-07 20:34:33 -05001430size_t QuicSession::GetNumOpenIncomingStreams() const {
1431 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1432 num_locally_closed_incoming_streams_highest_offset_;
1433}
1434
1435size_t QuicSession::GetNumOpenOutgoingStreams() const {
1436 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1437 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1438 GetNumDrainingOutgoingStreams());
1439 return GetNumDynamicOutgoingStreams() +
1440 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1441 GetNumDrainingOutgoingStreams();
1442}
1443
1444size_t QuicSession::GetNumActiveStreams() const {
renjietangfbeb5bf2019-04-19 15:06:20 -07001445 return dynamic_stream_map_.size() - draining_streams_.size() -
1446 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001447}
1448
1449size_t QuicSession::GetNumDrainingStreams() const {
1450 return draining_streams_.size();
1451}
1452
1453void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1454 if (GetOrCreateStream(id) == nullptr) {
1455 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1456 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1457 }
1458
1459 write_blocked_streams_.AddStream(id);
1460}
1461
1462bool QuicSession::HasDataToWrite() const {
1463 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1464 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1465 connection_->HasQueuedData() ||
1466 !streams_with_pending_retransmission_.empty() ||
1467 control_frame_manager_.WillingToWrite();
1468}
1469
1470void QuicSession::OnAckNeedsRetransmittableFrame() {
1471 flow_controller_.SendWindowUpdate();
1472}
1473
1474void QuicSession::SendPing() {
1475 control_frame_manager_.WritePing();
1476}
1477
1478size_t QuicSession::GetNumDynamicOutgoingStreams() const {
QUICHE team1243d142019-03-21 13:02:02 -07001479 DCHECK_GE(static_cast<size_t>(dynamic_stream_map_.size() +
1480 pending_stream_map_.size()),
renjietangfbeb5bf2019-04-19 15:06:20 -07001481 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1482 num_incoming_static_streams_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001483 return dynamic_stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001484 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1485 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001486}
1487
1488size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1489 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1490 return draining_streams_.size() - num_draining_incoming_streams_;
1491}
1492
1493size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1494 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1495 num_locally_closed_incoming_streams_highest_offset_);
1496 return locally_closed_streams_highest_offset_.size() -
1497 num_locally_closed_incoming_streams_highest_offset_;
1498}
1499
1500bool QuicSession::IsConnectionFlowControlBlocked() const {
1501 return flow_controller_.IsBlocked();
1502}
1503
1504bool QuicSession::IsStreamFlowControlBlocked() {
1505 for (auto const& kv : static_stream_map_) {
1506 if (kv.second->flow_controller()->IsBlocked()) {
1507 return true;
1508 }
1509 }
1510 for (auto const& kv : dynamic_stream_map_) {
1511 if (kv.second->flow_controller()->IsBlocked()) {
1512 return true;
1513 }
1514 }
renjietang615f13b2019-05-06 17:08:02 -07001515 if (eliminate_static_stream_map_ &&
nharperd5c4a932019-05-13 13:58:49 -07001516 !QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001517 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
rchda26cdb2019-05-17 11:57:37 -07001518 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 14, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001519 return true;
1520 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001521 return false;
1522}
1523
1524size_t QuicSession::MaxAvailableBidirectionalStreams() const {
1525 if (connection()->transport_version() == QUIC_VERSION_99) {
1526 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1527 }
1528 return stream_id_manager_.MaxAvailableStreams();
1529}
1530
1531size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
1532 if (connection()->transport_version() == QUIC_VERSION_99) {
1533 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1534 }
1535 return stream_id_manager_.MaxAvailableStreams();
1536}
1537
1538bool QuicSession::IsIncomingStream(QuicStreamId id) const {
1539 if (connection()->transport_version() == QUIC_VERSION_99) {
1540 return v99_streamid_manager_.IsIncomingStream(id);
1541 }
1542 return stream_id_manager_.IsIncomingStream(id);
1543}
1544
1545void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
1546 auto it = zombie_streams_.find(id);
1547 if (it == zombie_streams_.end()) {
1548 return;
1549 }
1550
1551 closed_streams_.push_back(std::move(it->second));
1552 if (!closed_streams_clean_up_alarm_->IsSet()) {
1553 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1554 }
1555 zombie_streams_.erase(it);
1556 // Do not retransmit data of a closed stream.
1557 streams_with_pending_retransmission_.erase(id);
1558}
1559
1560QuicStream* QuicSession::GetStream(QuicStreamId id) const {
1561 if (id <= largest_static_stream_id_) {
1562 auto static_stream = static_stream_map_.find(id);
1563 if (static_stream != static_stream_map_.end()) {
1564 return static_stream->second;
1565 }
1566 }
1567
1568 auto active_stream = dynamic_stream_map_.find(id);
1569 if (active_stream != dynamic_stream_map_.end()) {
1570 return active_stream->second.get();
1571 }
1572 auto zombie_stream = zombie_streams_.find(id);
1573 if (zombie_stream != zombie_streams_.end()) {
1574 return zombie_stream->second.get();
1575 }
renjietang08a9cf72019-04-23 17:01:34 -07001576
renjietang615f13b2019-05-06 17:08:02 -07001577 if (eliminate_static_stream_map_ &&
nharper46833c32019-05-15 21:33:05 -07001578 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
rchda26cdb2019-05-17 11:57:37 -07001579 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 15, 17);
renjietang08a9cf72019-04-23 17:01:34 -07001580 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1581 }
1582
QUICHE teama6ef0a62019-03-07 20:34:33 -05001583 return nullptr;
1584}
1585
1586bool QuicSession::OnFrameAcked(const QuicFrame& frame,
QUICHE team9467db02019-05-30 09:38:45 -07001587 QuicTime::Delta ack_delay_time,
1588 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001589 if (frame.type == MESSAGE_FRAME) {
QUICHE team9467db02019-05-30 09:38:45 -07001590 OnMessageAcked(frame.message_frame->message_id, receive_timestamp);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001591 return true;
1592 }
1593 if (frame.type == CRYPTO_FRAME) {
1594 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1595 ack_delay_time);
1596 }
1597 if (frame.type != STREAM_FRAME) {
1598 return control_frame_manager_.OnControlFrameAcked(frame);
1599 }
1600 bool new_stream_data_acked = false;
1601 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1602 // Stream can already be reset when sent frame gets acked.
1603 if (stream != nullptr) {
1604 QuicByteCount newly_acked_length = 0;
1605 new_stream_data_acked = stream->OnStreamFrameAcked(
1606 frame.stream_frame.offset, frame.stream_frame.data_length,
1607 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1608 if (!stream->HasPendingRetransmission()) {
1609 streams_with_pending_retransmission_.erase(stream->id());
1610 }
1611 }
1612 return new_stream_data_acked;
1613}
1614
1615void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1616 QuicStream* stream = GetStream(frame.stream_id);
1617 if (stream == nullptr) {
1618 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1619 << " is retransmitted.";
1620 connection()->CloseConnection(
1621 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1622 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1623 return;
1624 }
1625 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1626 frame.fin);
1627}
1628
1629void QuicSession::OnFrameLost(const QuicFrame& frame) {
1630 if (frame.type == MESSAGE_FRAME) {
1631 OnMessageLost(frame.message_frame->message_id);
1632 return;
1633 }
1634 if (frame.type == CRYPTO_FRAME) {
1635 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1636 return;
1637 }
1638 if (frame.type != STREAM_FRAME) {
1639 control_frame_manager_.OnControlFrameLost(frame);
1640 return;
1641 }
1642 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1643 if (stream == nullptr) {
1644 return;
1645 }
1646 stream->OnStreamFrameLost(frame.stream_frame.offset,
1647 frame.stream_frame.data_length,
1648 frame.stream_frame.fin);
1649 if (stream->HasPendingRetransmission() &&
1650 !QuicContainsKey(streams_with_pending_retransmission_,
1651 frame.stream_frame.stream_id)) {
1652 streams_with_pending_retransmission_.insert(
1653 std::make_pair(frame.stream_frame.stream_id, true));
1654 }
1655}
1656
1657void QuicSession::RetransmitFrames(const QuicFrames& frames,
1658 TransmissionType type) {
1659 QuicConnection::ScopedPacketFlusher retransmission_flusher(
1660 connection_, QuicConnection::NO_ACK);
1661 SetTransmissionType(type);
1662 for (const QuicFrame& frame : frames) {
1663 if (frame.type == MESSAGE_FRAME) {
1664 // Do not retransmit MESSAGE frames.
1665 continue;
1666 }
1667 if (frame.type == CRYPTO_FRAME) {
1668 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1669 continue;
1670 }
1671 if (frame.type != STREAM_FRAME) {
1672 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1673 break;
1674 }
1675 continue;
1676 }
1677 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1678 if (stream != nullptr &&
1679 !stream->RetransmitStreamData(frame.stream_frame.offset,
1680 frame.stream_frame.data_length,
1681 frame.stream_frame.fin)) {
1682 break;
1683 }
1684 }
1685}
1686
1687bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1688 if (frame.type == MESSAGE_FRAME) {
1689 return false;
1690 }
1691 if (frame.type == CRYPTO_FRAME) {
1692 return GetCryptoStream()->IsFrameOutstanding(
1693 frame.crypto_frame->level, frame.crypto_frame->offset,
1694 frame.crypto_frame->data_length);
1695 }
1696 if (frame.type != STREAM_FRAME) {
1697 return control_frame_manager_.IsControlFrameOutstanding(frame);
1698 }
1699 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1700 return stream != nullptr &&
1701 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1702 frame.stream_frame.data_length,
1703 frame.stream_frame.fin);
1704}
1705
1706bool QuicSession::HasUnackedCryptoData() const {
1707 const QuicCryptoStream* crypto_stream = GetCryptoStream();
1708 if (crypto_stream->IsWaitingForAcks()) {
1709 return true;
1710 }
1711 if (GetQuicReloadableFlag(quic_fix_has_pending_crypto_data) &&
1712 crypto_stream->HasBufferedData()) {
1713 QUIC_RELOADABLE_FLAG_COUNT(quic_fix_has_pending_crypto_data);
1714 return true;
1715 }
1716 return false;
1717}
1718
1719WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1720 QuicStreamOffset offset,
1721 QuicByteCount data_length,
1722 QuicDataWriter* writer) {
1723 QuicStream* stream = GetStream(id);
1724 if (stream == nullptr) {
1725 // This causes the connection to be closed because of failed to serialize
1726 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001727 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1728 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001729 return STREAM_MISSING;
1730 }
1731 if (stream->WriteStreamData(offset, data_length, writer)) {
1732 return WRITE_SUCCESS;
1733 }
1734 return WRITE_FAILED;
1735}
1736
1737bool QuicSession::WriteCryptoData(EncryptionLevel level,
1738 QuicStreamOffset offset,
1739 QuicByteCount data_length,
1740 QuicDataWriter* writer) {
1741 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1742 writer);
1743}
1744
1745QuicUint128 QuicSession::GetStatelessResetToken() const {
1746 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1747}
1748
1749bool QuicSession::RetransmitLostData() {
1750 QuicConnection::ScopedPacketFlusher retransmission_flusher(
1751 connection_, QuicConnection::SEND_ACK_IF_QUEUED);
1752 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001753 bool uses_crypto_frames =
1754 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001755 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1756 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1757 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1758 crypto_stream->WritePendingCryptoRetransmission();
1759 }
1760 // Retransmit crypto data in stream 1 frames (version < 47).
1761 if (!uses_crypto_frames &&
1762 QuicContainsKey(
1763 streams_with_pending_retransmission_,
1764 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1765 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1766 // Retransmit crypto data first.
1767 QuicStream* crypto_stream = GetStream(
1768 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1769 crypto_stream->OnCanWrite();
1770 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1771 if (crypto_stream->HasPendingRetransmission()) {
1772 // Connection is write blocked.
1773 return false;
1774 } else {
1775 streams_with_pending_retransmission_.erase(
1776 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1777 }
1778 }
1779 if (control_frame_manager_.HasPendingRetransmission()) {
1780 SetTransmissionType(LOSS_RETRANSMISSION);
1781 control_frame_manager_.OnCanWrite();
1782 if (control_frame_manager_.HasPendingRetransmission()) {
1783 return false;
1784 }
1785 }
1786 while (!streams_with_pending_retransmission_.empty()) {
1787 if (!connection_->CanWriteStreamData()) {
1788 break;
1789 }
1790 // Retransmit lost data on headers and data streams.
1791 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1792 QuicStream* stream = GetStream(id);
1793 if (stream != nullptr) {
1794 SetTransmissionType(LOSS_RETRANSMISSION);
1795 stream->OnCanWrite();
1796 DCHECK(CheckStreamWriteBlocked(stream));
1797 if (stream->HasPendingRetransmission()) {
1798 // Connection is write blocked.
1799 break;
1800 } else if (!streams_with_pending_retransmission_.empty() &&
1801 streams_with_pending_retransmission_.begin()->first == id) {
1802 // Retransmit lost data may cause connection close. If this stream
1803 // has not yet sent fin, a RST_STREAM will be sent and it will be
1804 // removed from streams_with_pending_retransmission_.
1805 streams_with_pending_retransmission_.pop_front();
1806 }
1807 } else {
1808 QUIC_BUG << "Try to retransmit data of a closed stream";
1809 streams_with_pending_retransmission_.pop_front();
1810 }
1811 }
1812
1813 return streams_with_pending_retransmission_.empty();
1814}
1815
1816void QuicSession::NeuterUnencryptedData() {
1817 if (connection_->session_decides_what_to_write()) {
1818 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1819 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001820 if (!crypto_stream->HasPendingRetransmission() &&
1821 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001822 streams_with_pending_retransmission_.erase(
1823 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1824 }
1825 }
1826 connection_->NeuterUnencryptedPackets();
1827}
1828
1829void QuicSession::SetTransmissionType(TransmissionType type) {
1830 connection_->SetTransmissionType(type);
1831}
1832
1833MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1834 if (!IsEncryptionEstablished()) {
1835 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1836 }
1837 MessageStatus result =
1838 connection_->SendMessage(last_message_id_ + 1, message);
1839 if (result == MESSAGE_STATUS_SUCCESS) {
1840 return {result, ++last_message_id_};
1841 }
1842 return {result, 0};
1843}
1844
QUICHE team9467db02019-05-30 09:38:45 -07001845void QuicSession::OnMessageAcked(QuicMessageId message_id,
1846 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001847 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1848}
1849
1850void QuicSession::OnMessageLost(QuicMessageId message_id) {
1851 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1852 << " is considered lost";
1853}
1854
1855void QuicSession::CleanUpClosedStreams() {
1856 closed_streams_.clear();
1857}
1858
1859bool QuicSession::session_decides_what_to_write() const {
1860 return connection_->session_decides_what_to_write();
1861}
1862
ianswettb239f862019-04-05 09:15:06 -07001863QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1864 return connection_->GetCurrentLargestMessagePayload();
1865}
1866
1867QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1868 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001869}
1870
1871void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1872 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1873}
1874
1875void QuicSession::OnCanCreateNewOutgoingStream() {}
1876
1877QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
1878 if (connection_->transport_version() == QUIC_VERSION_99) {
1879 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1880 }
1881 return stream_id_manager_.next_outgoing_stream_id();
1882}
1883
1884QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const {
1885 if (connection_->transport_version() == QUIC_VERSION_99) {
1886 return v99_streamid_manager_.next_outgoing_unidirectional_stream_id();
1887 }
1888 return stream_id_manager_.next_outgoing_stream_id();
1889}
1890
fkastenholz3c4eabf2019-04-22 07:49:59 -07001891bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1892 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001893}
1894
fkastenholz3c4eabf2019-04-22 07:49:59 -07001895bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1896 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001897}
1898
1899size_t QuicSession::max_open_incoming_bidirectional_streams() const {
1900 if (connection_->transport_version() == QUIC_VERSION_99) {
1901 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1902 }
1903 return stream_id_manager_.max_open_incoming_streams();
1904}
1905
1906size_t QuicSession::max_open_incoming_unidirectional_streams() const {
1907 if (connection_->transport_version() == QUIC_VERSION_99) {
1908 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1909 }
1910 return stream_id_manager_.max_open_incoming_streams();
1911}
1912
1913#undef ENDPOINT // undef for jumbo builds
1914} // namespace quic