blob: ac4ac9b4533d7966a1b665bf28021009b03066bb [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"
renjietangde12d3d2019-07-19 10:57:42 -070013#include "net/third_party/quiche/src/quic/core/quic_types.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/core/quic_utils.h"
zhongyi1b2f7832019-06-14 13:31:34 -070015#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
wub2b5942f2019-04-11 13:22:50 -070021#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
23#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050024
25using spdy::SpdyPriority;
26
27namespace quic {
28
29namespace {
30
31class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
32 public:
33 explicit ClosedStreamsCleanUpDelegate(QuicSession* session)
34 : session_(session) {}
35 ClosedStreamsCleanUpDelegate(const ClosedStreamsCleanUpDelegate&) = delete;
36 ClosedStreamsCleanUpDelegate& operator=(const ClosedStreamsCleanUpDelegate&) =
37 delete;
38
39 void OnAlarm() override { session_->CleanUpClosedStreams(); }
40
41 private:
42 QuicSession* session_;
43};
44
45} // namespace
46
47#define ENDPOINT \
48 (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
49
50QuicSession::QuicSession(QuicConnection* connection,
51 Visitor* owner,
52 const QuicConfig& config,
53 const ParsedQuicVersionVector& supported_versions)
54 : connection_(connection),
55 visitor_(owner),
nharpercd820e02019-05-16 15:12:07 -070056 write_blocked_streams_(connection->transport_version()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050057 config_(config),
58 stream_id_manager_(this,
59 kDefaultMaxStreamsPerConnection,
fkastenholzd3a1de92019-05-15 07:00:07 -070060 config_.GetMaxIncomingBidirectionalStreamsToSend()),
61 v99_streamid_manager_(
62 this,
63 kDefaultMaxStreamsPerConnection,
64 kDefaultMaxStreamsPerConnection,
65 config_.GetMaxIncomingBidirectionalStreamsToSend(),
66 config_.GetMaxIncomingUnidirectionalStreamsToSend()),
QUICHE teama6ef0a62019-03-07 20:34:33 -050067 num_dynamic_incoming_streams_(0),
68 num_draining_incoming_streams_(0),
renjietangfbeb5bf2019-04-19 15:06:20 -070069 num_outgoing_static_streams_(0),
70 num_incoming_static_streams_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050071 num_locally_closed_incoming_streams_highest_offset_(0),
72 error_(QUIC_NO_ERROR),
73 flow_controller_(
74 this,
75 QuicUtils::GetInvalidStreamId(connection->transport_version()),
76 /*is_connection_flow_controller*/ true,
dschinazic7036122019-04-30 12:46:34 -070077 connection->version().AllowsLowFlowControlLimits()
78 ? 0
79 : kMinimumFlowControlSendWindow,
QUICHE teama6ef0a62019-03-07 20:34:33 -050080 config_.GetInitialSessionFlowControlWindowToSend(),
81 kSessionReceiveWindowLimit,
82 perspective() == Perspective::IS_SERVER,
83 nullptr),
84 currently_writing_stream_id_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050085 is_handshake_confirmed_(false),
86 goaway_sent_(false),
87 goaway_received_(false),
88 control_frame_manager_(this),
89 last_message_id_(0),
90 closed_streams_clean_up_alarm_(nullptr),
fayang944cfbc2019-07-31 09:15:00 -070091 supported_versions_(supported_versions),
92 use_http2_priority_write_scheduler_(false) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050093 closed_streams_clean_up_alarm_ =
94 QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
95 new ClosedStreamsCleanUpDelegate(this)));
dschinazi4e3e6572019-08-02 12:57:17 -070096 if (perspective() == Perspective::IS_SERVER &&
97 connection_->version().handshake_protocol == PROTOCOL_TLS1_3) {
98 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
99 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100}
101
102void QuicSession::Initialize() {
103 connection_->set_visitor(this);
104 connection_->SetSessionNotifier(this);
105 connection_->SetDataProducer(this);
106 connection_->SetFromConfig(config_);
107
nharper46833c32019-05-15 21:33:05 -0700108 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
109 return;
110 }
111
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
113 GetMutableCryptoStream()->id());
renjietangb663b862019-07-08 16:02:39 -0700114
115 QuicStreamId id =
116 QuicUtils::GetCryptoStreamId(connection_->transport_version());
renjietangb663b862019-07-08 16:02:39 -0700117 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
118 v99_streamid_manager_.RegisterStaticStream(id, false);
renjietang08a9cf72019-04-23 17:01:34 -0700119 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120}
121
122QuicSession::~QuicSession() {
123 QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
124}
125
renjietang0e9980b2019-07-11 12:00:21 -0700126void QuicSession::RegisterStaticStream(std::unique_ptr<QuicStream> stream,
127 bool stream_already_counted) {
renjietang9ffbb602019-07-10 14:08:00 -0700128 DCHECK(stream->is_static());
renjietangfbeb5bf2019-04-19 15:06:20 -0700129 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -0700130 stream_map_[stream_id] = std::move(stream);
fkastenholz305e1732019-06-18 05:01:22 -0700131 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietang3a1bb802019-06-11 10:42:41 -0700132 v99_streamid_manager_.RegisterStaticStream(stream_id,
133 stream_already_counted);
renjietangfbeb5bf2019-04-19 15:06:20 -0700134 }
135 if (IsIncomingStream(stream_id)) {
136 ++num_incoming_static_streams_;
137 } else {
138 ++num_outgoing_static_streams_;
139 }
140}
141
renjietange76b2da2019-05-13 14:50:23 -0700142void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700143 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700144 QuicStreamId stream_id = frame.stream_id;
145
146 PendingStream* pending = GetOrCreatePendingStream(stream_id);
147
148 if (!pending) {
149 if (frame.fin) {
150 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
151 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
152 }
153 return;
154 }
155
156 pending->OnStreamFrame(frame);
renjietanga553da02019-06-24 11:57:04 -0700157 if (!connection()->connected()) {
158 return;
159 }
renjietangbb1c4892019-05-24 15:58:44 -0700160 if (ProcessPendingStream(pending)) {
161 // The pending stream should now be in the scope of normal streams.
162 DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
163 << "Stream " << stream_id << " not created";
164 pending_stream_map_.erase(stream_id);
bnc4ff60622019-08-09 18:55:45 -0700165 return;
166 }
167 if (pending->sequencer()->IsClosed()) {
168 ClosePendingStream(stream_id);
renjietangbb1c4892019-05-24 15:58:44 -0700169 }
renjietange76b2da2019-05-13 14:50:23 -0700170}
171
QUICHE teama6ef0a62019-03-07 20:34:33 -0500172void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
173 // TODO(rch) deal with the error case of stream id 0.
174 QuicStreamId stream_id = frame.stream_id;
175 if (stream_id ==
176 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
177 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700178 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500179 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
180 return;
181 }
182
bnc36c47282019-06-21 05:17:59 -0700183 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700184 QuicUtils::GetStreamType(stream_id, perspective(),
185 IsIncomingStream(stream_id)) ==
186 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700187 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700188 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500189 return;
190 }
191
renjietang2c4d7122019-05-20 17:18:14 -0700192 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700193
renjietang2c4d7122019-05-20 17:18:14 -0700194 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500195 // The stream no longer exists, but we may still be interested in the
196 // final stream byte offset sent by the peer. A frame with a FIN can give
197 // us this offset.
198 if (frame.fin) {
199 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
200 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
201 }
202 return;
203 }
renjietangb663b862019-07-08 16:02:39 -0700204 if (frame.fin && stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700205 connection()->CloseConnection(
206 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
207 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
208 return;
209 }
renjietang2c4d7122019-05-20 17:18:14 -0700210 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500211}
212
213void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
214 GetMutableCryptoStream()->OnCryptoFrame(frame);
215}
216
217bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
218 // We are not version 99. In theory, if not in version 99 then the framer
219 // could not call OnStopSending... This is just a check that is good when
220 // both a new protocol and a new implementation of that protocol are both
221 // being developed.
fkastenholz305e1732019-06-18 05:01:22 -0700222 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500223
224 QuicStreamId stream_id = frame.stream_id;
225 // If Stream ID is invalid then close the connection.
226 if (stream_id ==
227 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
228 QUIC_DVLOG(1) << ENDPOINT
229 << "Received STOP_SENDING with invalid stream_id: "
230 << stream_id << " Closing connection";
231 connection()->CloseConnection(
232 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
233 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
234 return false;
235 }
236
237 // Ignore STOP_SENDING for static streams.
238 // TODO(fkastenholz): IETF Quic does not have static streams and does not
239 // make exceptions for them with respect to processing things like
240 // STOP_SENDING.
renjietang0e9980b2019-07-11 12:00:21 -0700241 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -0700242 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500243 QUIC_DVLOG(1) << ENDPOINT
244 << "Received STOP_SENDING for a static stream, id: "
245 << stream_id << " Closing connection";
246 connection()->CloseConnection(
247 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
248 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
249 return false;
250 }
251
252 if (visitor_) {
253 visitor_->OnStopSendingReceived(frame);
254 }
255
256 // If stream is closed, ignore the frame
257 if (IsClosedStream(stream_id)) {
258 QUIC_DVLOG(1)
259 << ENDPOINT
260 << "Received STOP_SENDING for closed or non-existent stream, id: "
261 << stream_id << " Ignoring.";
262 return true; // Continue processing the packet.
263 }
264 // If stream is non-existent, close the connection
renjietang55d182a2019-07-12 10:26:25 -0700265 StreamMap::iterator it = stream_map_.find(stream_id);
266 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500267 QUIC_DVLOG(1) << ENDPOINT
268 << "Received STOP_SENDING for non-existent stream, id: "
269 << stream_id << " Closing connection";
270 connection()->CloseConnection(
271 IETF_QUIC_PROTOCOL_VIOLATION,
272 "Received STOP_SENDING for a non-existent stream",
273 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
274 return false;
275 }
276
277 // Get the QuicStream for this stream. Ignore the STOP_SENDING
278 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700279 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
280 // happen IFF there was an entry in the map, but the pointer is null. sounds
281 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500282 QuicStream* stream = it->second.get();
283 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700284 QUIC_BUG << ENDPOINT
285 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
286 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500287 return true;
288 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700289
renjietangb663b862019-07-08 16:02:39 -0700290 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700291 QUIC_DVLOG(1) << ENDPOINT
292 << "Received STOP_SENDING for a static stream, id: "
293 << stream_id << " Closing connection";
294 connection()->CloseConnection(
295 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
296 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
297 return false;
298 }
299
QUICHE teama6ef0a62019-03-07 20:34:33 -0500300 stream->OnStopSending(frame.application_error_code);
301
302 stream->set_stream_error(
303 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
304 SendRstStreamInner(
305 stream->id(),
306 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
307 stream->stream_bytes_written(),
308 /*close_write_side_only=*/true);
309
310 return true;
311}
312
renjietange76b2da2019-05-13 14:50:23 -0700313void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700314 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700315 QuicStreamId stream_id = frame.stream_id;
316
317 PendingStream* pending = GetOrCreatePendingStream(stream_id);
318
319 if (!pending) {
320 HandleRstOnValidNonexistentStream(frame);
321 return;
322 }
323
324 pending->OnRstStreamFrame(frame);
bnc092d8212019-08-07 11:53:20 -0700325 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
renjietange76b2da2019-05-13 14:50:23 -0700326 ClosePendingStream(stream_id);
327}
328
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
330 QuicStreamId stream_id = frame.stream_id;
331 if (stream_id ==
332 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
333 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700334 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
336 return;
337 }
338
QUICHE teama6ef0a62019-03-07 20:34:33 -0500339 if (visitor_) {
340 visitor_->OnRstStreamReceived(frame);
341 }
342
bnc36c47282019-06-21 05:17:59 -0700343 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700344 QuicUtils::GetStreamType(stream_id, perspective(),
345 IsIncomingStream(stream_id)) ==
346 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700347 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700348 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500349 return;
350 }
renjietange76b2da2019-05-13 14:50:23 -0700351
renjietang2c4d7122019-05-20 17:18:14 -0700352 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700353
renjietang2c4d7122019-05-20 17:18:14 -0700354 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355 HandleRstOnValidNonexistentStream(frame);
356 return; // Errors are handled by GetOrCreateStream.
357 }
renjietangb663b862019-07-08 16:02:39 -0700358 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700359 connection()->CloseConnection(
360 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
361 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
362 return;
363 }
renjietang2c4d7122019-05-20 17:18:14 -0700364 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365}
366
dschinazi17d42422019-06-18 16:35:07 -0700367void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500368 goaway_received_ = true;
369}
370
371void QuicSession::OnMessageReceived(QuicStringPiece message) {
372 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
373 << ", " << message;
374}
375
wub2b5942f2019-04-11 13:22:50 -0700376// static
377void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
378 ConnectionCloseSource source) {
379 if (error != QUIC_NO_ERROR) {
380 if (source == ConnectionCloseSource::FROM_SELF) {
381 QUIC_SERVER_HISTOGRAM_ENUM(
382 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
383 "QuicErrorCode for server-closed connections.");
384 } else {
385 QUIC_SERVER_HISTOGRAM_ENUM(
386 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
387 "QuicErrorCode for client-closed connections.");
388 }
389 }
390}
391
fkastenholz5d880a92019-06-21 09:01:56 -0700392void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500393 ConnectionCloseSource source) {
394 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700395 if (perspective() == Perspective::IS_SERVER) {
fkastenholz5d880a92019-06-21 09:01:56 -0700396 RecordConnectionCloseAtServer(frame.quic_error_code, source);
wub2b5942f2019-04-11 13:22:50 -0700397 }
398
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399 if (error_ == QUIC_NO_ERROR) {
fkastenholz5d880a92019-06-21 09:01:56 -0700400 error_ = frame.quic_error_code;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 }
402
renjietangb663b862019-07-08 16:02:39 -0700403 // Copy all non static streams in a new map for the ease of deleting.
404 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
renjietang55d182a2019-07-12 10:26:25 -0700405 for (const auto& it : stream_map_) {
renjietangb663b862019-07-08 16:02:39 -0700406 if (!it.second->is_static()) {
407 non_static_streams[it.first] = it.second.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700408 }
renjietangb663b862019-07-08 16:02:39 -0700409 }
410 for (const auto& it : non_static_streams) {
411 QuicStreamId id = it.first;
412 it.second->OnConnectionClosed(frame.quic_error_code, source);
renjietang55d182a2019-07-12 10:26:25 -0700413 if (stream_map_.find(id) != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700414 QUIC_BUG << ENDPOINT << "Stream " << id
415 << " failed to close under OnConnectionClosed";
416 CloseStream(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500417 }
418 }
419
420 // Cleanup zombie stream map on connection close.
421 while (!zombie_streams_.empty()) {
422 ZombieStreamMap::iterator it = zombie_streams_.begin();
423 closed_streams_.push_back(std::move(it->second));
424 zombie_streams_.erase(it);
425 }
426
427 closed_streams_clean_up_alarm_->Cancel();
428
429 if (visitor_) {
fkastenholz5d880a92019-06-21 09:01:56 -0700430 visitor_->OnConnectionClosed(connection_->connection_id(),
431 frame.quic_error_code, frame.error_details,
432 source);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500433 }
434}
435
436void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700437 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500438 return;
439 }
440 if (visitor_) {
441 visitor_->OnWriteBlocked(connection_);
442 }
443}
444
445void QuicSession::OnSuccessfulVersionNegotiation(
446 const ParsedQuicVersion& version) {
447 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
448}
449
450void QuicSession::OnConnectivityProbeReceived(
dschinazi17d42422019-06-18 16:35:07 -0700451 const QuicSocketAddress& /*self_address*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500452 const QuicSocketAddress& peer_address) {
453 if (perspective() == Perspective::IS_SERVER) {
454 // Server only sends back a connectivity probe after received a
455 // connectivity probe from a new peer address.
456 connection_->SendConnectivityProbingResponsePacket(peer_address);
457 }
458}
459
460void QuicSession::OnPathDegrading() {}
461
462bool QuicSession::AllowSelfAddressChange() const {
463 return false;
464}
465
466void QuicSession::OnForwardProgressConfirmed() {}
467
468void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
469 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
470 // assume that it still exists.
471 QuicStreamId stream_id = frame.stream_id;
472 if (stream_id ==
473 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
474 // This is a window update that applies to the connection, rather than an
475 // individual stream.
476 QUIC_DLOG(INFO) << ENDPOINT
477 << "Received connection level flow control window "
478 "update with byte offset: "
479 << frame.byte_offset;
480 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
481 return;
482 }
renjietang28c04b72019-07-01 15:08:09 -0700483
484 if (VersionHasIetfQuicFrames(connection_->transport_version()) &&
485 QuicUtils::GetStreamType(stream_id, perspective(),
486 IsIncomingStream(stream_id)) ==
487 READ_UNIDIRECTIONAL) {
488 connection()->CloseConnection(
489 QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM,
490 "WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.",
491 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
492 return;
493 }
494
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 QuicStream* stream = GetOrCreateStream(stream_id);
496 if (stream != nullptr) {
497 stream->OnWindowUpdateFrame(frame);
498 }
499}
500
501void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
502 // TODO(rjshade): Compare our flow control receive windows for specified
503 // streams: if we have a large window then maybe something
504 // had gone wrong with the flow control accounting.
505 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
506 << frame.stream_id;
507}
508
509bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
510 uint64_t previous_bytes_written,
511 bool previous_fin_sent) {
512 if ( // Stream should not be closed.
513 !stream->write_side_closed() &&
514 // Not connection flow control blocked.
515 !flow_controller_.IsBlocked() &&
516 // Detect lack of forward progress.
517 previous_bytes_written == stream->stream_bytes_written() &&
518 previous_fin_sent == stream->fin_sent()) {
519 stream->set_busy_counter(stream->busy_counter() + 1);
520 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
521 << " stream_bytes_written " << stream->stream_bytes_written()
522 << " fin " << stream->fin_sent() << " count "
523 << stream->busy_counter();
524 // Wait a few iterations before firing, the exact count is
525 // arbitrary, more than a few to cover a few test-only false
526 // positives.
527 if (stream->busy_counter() > 20) {
528 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
529 << " stream_bytes_written "
530 << stream->stream_bytes_written() << " fin "
531 << stream->fin_sent();
532 return false;
533 }
534 } else {
535 stream->set_busy_counter(0);
536 }
537 return true;
538}
539
540bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
541 if (!stream->write_side_closed() && stream->HasBufferedData() &&
542 !stream->flow_controller()->IsBlocked() &&
543 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
544 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
545 << stream->BufferedDataBytes()
546 << " bytes, and is not flow control blocked, "
547 "but it is not in the write block list.";
548 return false;
549 }
550 return true;
551}
552
553void QuicSession::OnCanWrite() {
554 if (!RetransmitLostData()) {
555 // Cannot finish retransmitting lost data, connection is write blocked.
556 QUIC_DVLOG(1) << ENDPOINT
557 << "Cannot finish retransmitting lost data, connection is "
558 "write blocked.";
559 return;
560 }
561 if (session_decides_what_to_write()) {
562 SetTransmissionType(NOT_RETRANSMISSION);
563 }
564 // We limit the number of writes to the number of pending streams. If more
565 // streams become pending, WillingAndAbleToWrite will be true, which will
566 // cause the connection to request resumption before yielding to other
567 // connections.
568 // If we are connection level flow control blocked, then only allow the
569 // crypto and headers streams to try writing as all other streams will be
570 // blocked.
571 size_t num_writes = flow_controller_.IsBlocked()
572 ? write_blocked_streams_.NumBlockedSpecialStreams()
573 : write_blocked_streams_.NumBlockedStreams();
574 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
575 return;
576 }
577
fayanga4b37b22019-06-18 13:37:47 -0700578 QuicConnection::ScopedPacketFlusher flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500579 if (control_frame_manager_.WillingToWrite()) {
580 control_frame_manager_.OnCanWrite();
581 }
582 for (size_t i = 0; i < num_writes; ++i) {
583 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
584 write_blocked_streams_.HasWriteBlockedDataStreams())) {
585 // Writing one stream removed another!? Something's broken.
586 QUIC_BUG << "WriteBlockedStream is missing";
587 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
588 "WriteBlockedStream is missing",
589 ConnectionCloseBehavior::SILENT_CLOSE);
590 return;
591 }
592 if (!connection_->CanWriteStreamData()) {
593 return;
594 }
595 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
596 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
597 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
598 // If the stream can't write all bytes it'll re-add itself to the blocked
599 // list.
600 uint64_t previous_bytes_written = stream->stream_bytes_written();
601 bool previous_fin_sent = stream->fin_sent();
602 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
603 << previous_bytes_written << " fin " << previous_fin_sent;
604 stream->OnCanWrite();
605 DCHECK(CheckStreamWriteBlocked(stream));
606 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
607 previous_fin_sent));
608 }
609 currently_writing_stream_id_ = 0;
610 }
611}
612
QUICHE teamb8343252019-04-29 13:58:01 -0700613bool QuicSession::SendProbingData() {
614 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
615 PROBING_RETRANSMISSION)) {
616 return true;
617 }
618 return false;
619}
620
QUICHE teama6ef0a62019-03-07 20:34:33 -0500621bool QuicSession::WillingAndAbleToWrite() const {
622 // Schedule a write when:
623 // 1) control frame manager has pending or new control frames, or
624 // 2) any stream has pending retransmissions, or
625 // 3) If the crypto or headers streams are blocked, or
626 // 4) connection is not flow control blocked and there are write blocked
627 // streams.
628 return control_frame_manager_.WillingToWrite() ||
629 !streams_with_pending_retransmission_.empty() ||
630 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
631 (!flow_controller_.IsBlocked() &&
632 write_blocked_streams_.HasWriteBlockedDataStreams());
633}
634
635bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700636 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
637 // Writing CRYPTO frames is not subject to flow control, so there can't be
638 // pending data to write, only pending retransmissions.
639 return GetCryptoStream()->HasPendingCryptoRetransmission();
640 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500641 return QuicContainsKey(
642 streams_with_pending_retransmission_,
643 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
644 write_blocked_streams_.IsStreamBlocked(
645 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
646}
647
648uint64_t QuicSession::GetNumOpenDynamicStreams() const {
renjietang55d182a2019-07-12 10:26:25 -0700649 return stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700650 locally_closed_streams_highest_offset_.size() -
651 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500652}
653
654void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
655 const QuicSocketAddress& peer_address,
656 const QuicReceivedPacket& packet) {
657 connection_->ProcessUdpPacket(self_address, peer_address, packet);
658}
659
660QuicConsumedData QuicSession::WritevData(QuicStream* stream,
661 QuicStreamId id,
662 size_t write_length,
663 QuicStreamOffset offset,
664 StreamSendingState state) {
665 // This check is an attempt to deal with potential memory corruption
666 // in which |id| ends up set to 1 (the crypto stream id). If this happen
667 // it might end up resulting in unencrypted stream data being sent.
668 // While this is impossible to avoid given sufficient corruption, this
669 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700670 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500671 stream != GetMutableCryptoStream()) {
672 QUIC_BUG << "Stream id mismatch";
673 connection_->CloseConnection(
674 QUIC_INTERNAL_ERROR,
675 "Non-crypto stream attempted to write data as crypto stream.",
676 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
677 return QuicConsumedData(0, false);
678 }
679 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700680 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500681 // Do not let streams write without encryption. The calling stream will end
682 // up write blocked until OnCanWrite is next called.
683 return QuicConsumedData(0, false);
684 }
685
686 QuicConsumedData data =
687 connection_->SendStreamData(id, write_length, offset, state);
688 if (offset >= stream->stream_bytes_written()) {
689 // This is new stream data.
690 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
691 }
692 return data;
693}
694
695bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
696 return connection_->SendControlFrame(frame);
697}
698
699void QuicSession::SendRstStream(QuicStreamId id,
700 QuicRstStreamErrorCode error,
701 QuicStreamOffset bytes_written) {
702 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
703}
704
705void QuicSession::SendRstStreamInner(QuicStreamId id,
706 QuicRstStreamErrorCode error,
707 QuicStreamOffset bytes_written,
708 bool close_write_side_only) {
709 if (connection()->connected()) {
710 // Only send if still connected.
711 if (close_write_side_only) {
fkastenholz305e1732019-06-18 05:01:22 -0700712 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500713 // Send a RST_STREAM frame.
714 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
715 } else {
716 // Send a RST_STREAM frame plus, if version 99, an IETF
717 // QUIC STOP_SENDING frame. Both sre sent to emulate
718 // the two-way close that Google QUIC's RST_STREAM does.
fkastenholz305e1732019-06-18 05:01:22 -0700719 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fayanga4b37b22019-06-18 13:37:47 -0700720 QuicConnection::ScopedPacketFlusher flusher(connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500721 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
722 control_frame_manager_.WriteOrBufferStopSending(error, id);
723 } else {
724 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
725 }
726 }
727 connection_->OnStreamReset(id, error);
728 }
729 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
730 OnStreamDoneWaitingForAcks(id);
731 return;
732 }
733
734 if (!close_write_side_only) {
735 CloseStreamInner(id, true);
736 return;
737 }
fkastenholz305e1732019-06-18 05:01:22 -0700738 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500739
renjietang55d182a2019-07-12 10:26:25 -0700740 StreamMap::iterator it = stream_map_.find(id);
741 if (it != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700742 if (it->second->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700743 QUIC_DVLOG(1) << ENDPOINT
744 << "Try to send rst for a static stream, id: " << id
745 << " Closing connection";
746 connection()->CloseConnection(
747 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
748 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
749 return;
750 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500751 QuicStream* stream = it->second.get();
752 if (stream) {
753 stream->set_rst_sent(true);
754 stream->CloseWriteSide();
755 }
756 }
757}
758
759void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700760 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500761 // GOAWAY frame is not supported in v99.
fkastenholz305e1732019-06-18 05:01:22 -0700762 DCHECK(!VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500763 if (goaway_sent_) {
764 return;
765 }
766 goaway_sent_ = true;
767 control_frame_manager_.WriteOrBufferGoAway(
768 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
769}
770
771void QuicSession::SendBlocked(QuicStreamId id) {
772 control_frame_manager_.WriteOrBufferBlocked(id);
773}
774
775void QuicSession::SendWindowUpdate(QuicStreamId id,
776 QuicStreamOffset byte_offset) {
777 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
778}
779
fkastenholz3c4eabf2019-04-22 07:49:59 -0700780void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
781 bool unidirectional) {
782 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500783}
784
fkastenholz3c4eabf2019-04-22 07:49:59 -0700785void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
786 bool unidirectional) {
787 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
788 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500789}
790
791void QuicSession::CloseStream(QuicStreamId stream_id) {
792 CloseStreamInner(stream_id, false);
793}
794
795void QuicSession::InsertLocallyClosedStreamsHighestOffset(
796 const QuicStreamId id,
797 QuicStreamOffset offset) {
798 locally_closed_streams_highest_offset_[id] = offset;
799 if (IsIncomingStream(id)) {
800 ++num_locally_closed_incoming_streams_highest_offset_;
801 }
802}
803
804void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
805 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
806
renjietang55d182a2019-07-12 10:26:25 -0700807 StreamMap::iterator it = stream_map_.find(stream_id);
808 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500809 // When CloseStreamInner has been called recursively (via
810 // QuicStream::OnClose), the stream will already have been deleted
811 // from stream_map_, so return immediately.
812 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
813 return;
814 }
815 QuicStream* stream = it->second.get();
renjietangb663b862019-07-08 16:02:39 -0700816 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700817 QUIC_DVLOG(1) << ENDPOINT
818 << "Try to close a static stream, id: " << stream_id
819 << " Closing connection";
820 connection()->CloseConnection(
821 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
822 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
823 return;
824 }
renjietangde12d3d2019-07-19 10:57:42 -0700825 StreamType type = stream->type();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500826
827 // Tell the stream that a RST has been sent.
828 if (locally_reset) {
829 stream->set_rst_sent(true);
830 }
831
832 if (stream->IsWaitingForAcks()) {
833 zombie_streams_[stream->id()] = std::move(it->second);
834 } else {
zhongyi1b2f7832019-06-14 13:31:34 -0700835 // Clean up the stream since it is no longer waiting for acks.
836 if (ignore_tlpr_if_no_pending_stream_data() &&
837 session_decides_what_to_write()) {
838 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data,
839 2, 5);
840 streams_waiting_for_acks_.erase(stream->id());
841 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500842 closed_streams_.push_back(std::move(it->second));
843 // Do not retransmit data of a closed stream.
844 streams_with_pending_retransmission_.erase(stream_id);
845 if (!closed_streams_clean_up_alarm_->IsSet()) {
846 closed_streams_clean_up_alarm_->Set(
847 connection_->clock()->ApproximateNow());
848 }
849 }
850
851 // If we haven't received a FIN or RST for this stream, we need to keep track
852 // of the how many bytes the stream's flow controller believes it has
853 // received, for accurate connection level flow control accounting.
854 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
855 if (!had_fin_or_rst) {
856 InsertLocallyClosedStreamsHighestOffset(
857 stream_id, stream->flow_controller()->highest_received_byte_offset());
858 }
renjietang55d182a2019-07-12 10:26:25 -0700859 stream_map_.erase(it);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500860 if (IsIncomingStream(stream_id)) {
861 --num_dynamic_incoming_streams_;
862 }
863
864 const bool stream_was_draining =
865 draining_streams_.find(stream_id) != draining_streams_.end();
866 if (stream_was_draining) {
867 if (IsIncomingStream(stream_id)) {
868 --num_draining_incoming_streams_;
869 }
870 draining_streams_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700871 } else if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500872 // Stream was not draining, but we did have a fin or rst, so we can now
873 // free the stream ID if version 99.
874 if (had_fin_or_rst) {
875 v99_streamid_manager_.OnStreamClosed(stream_id);
876 }
877 }
878
879 stream->OnClose();
880
881 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
fkastenholz305e1732019-06-18 05:01:22 -0700882 !VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500883 // Streams that first became draining already called OnCanCreate...
884 // This covers the case where the stream went directly to being closed.
renjietangde12d3d2019-07-19 10:57:42 -0700885 OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500886 }
887}
888
889void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
890 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
891
bnc092d8212019-08-07 11:53:20 -0700892 pending_stream_map_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700893 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500894 v99_streamid_manager_.OnStreamClosed(stream_id);
895 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500896}
897
898void QuicSession::OnFinalByteOffsetReceived(
899 QuicStreamId stream_id,
900 QuicStreamOffset final_byte_offset) {
901 auto it = locally_closed_streams_highest_offset_.find(stream_id);
902 if (it == locally_closed_streams_highest_offset_.end()) {
903 return;
904 }
905
906 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
907 << final_byte_offset << " for stream " << stream_id;
908 QuicByteCount offset_diff = final_byte_offset - it->second;
909 if (flow_controller_.UpdateHighestReceivedOffset(
910 flow_controller_.highest_received_byte_offset() + offset_diff)) {
911 // If the final offset violates flow control, close the connection now.
912 if (flow_controller_.FlowControlViolation()) {
913 connection_->CloseConnection(
914 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
915 "Connection level flow control violation",
916 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
917 return;
918 }
919 }
920
921 flow_controller_.AddBytesConsumed(offset_diff);
922 locally_closed_streams_highest_offset_.erase(it);
923 if (IsIncomingStream(stream_id)) {
924 --num_locally_closed_incoming_streams_highest_offset_;
fkastenholz305e1732019-06-18 05:01:22 -0700925 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500926 v99_streamid_manager_.OnStreamClosed(stream_id);
927 }
fkastenholz305e1732019-06-18 05:01:22 -0700928 } else if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholz8556dc22019-07-18 12:42:38 -0700929 OnCanCreateNewOutgoingStream(false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500930 }
931}
932
933bool QuicSession::IsEncryptionEstablished() const {
934 // Once the handshake is confirmed, it never becomes un-confirmed.
935 if (is_handshake_confirmed_) {
936 return true;
937 }
938 return GetCryptoStream()->encryption_established();
939}
940
941bool QuicSession::IsCryptoHandshakeConfirmed() const {
942 return GetCryptoStream()->handshake_confirmed();
943}
944
945void QuicSession::OnConfigNegotiated() {
946 connection_->SetFromConfig(config_);
947
fkastenholz305e1732019-06-18 05:01:22 -0700948 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700949 uint32_t max_streams = 0;
950 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
951 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
952 }
953 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
954 << max_streams;
955 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
956 max_streams);
957
958 max_streams = 0;
959 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
960 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
961 }
962 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
963 << max_streams;
964 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
965 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500966 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -0700967 uint32_t max_streams = 0;
968 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
969 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
970 }
971 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500972 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
973 }
fkastenholzd3a1de92019-05-15 07:00:07 -0700974
QUICHE teama6ef0a62019-03-07 20:34:33 -0500975 if (perspective() == Perspective::IS_SERVER) {
976 if (config_.HasReceivedConnectionOptions()) {
977 // The following variations change the initial receive flow control
978 // window sizes.
979 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
980 AdjustInitialFlowControlWindows(64 * 1024);
981 }
982 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
983 AdjustInitialFlowControlWindows(128 * 1024);
984 }
985 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
986 AdjustInitialFlowControlWindows(256 * 1024);
987 }
988 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
989 AdjustInitialFlowControlWindows(512 * 1024);
990 }
991 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
992 AdjustInitialFlowControlWindows(1024 * 1024);
993 }
fayang944cfbc2019-07-31 09:15:00 -0700994 if (GetQuicReloadableFlag(quic_use_http2_priority_write_scheduler) &&
995 ContainsQuicTag(config_.ReceivedConnectionOptions(), kH2PR) &&
996 !VersionHasIetfQuicFrames(connection_->transport_version())) {
fayange606e0c2019-08-05 06:56:05 -0700997 // Enable HTTP2 (tree-style) priority write scheduler.
fayang944cfbc2019-07-31 09:15:00 -0700998 use_http2_priority_write_scheduler_ =
fayange606e0c2019-08-05 06:56:05 -0700999 write_blocked_streams_.SwitchWriteScheduler(
1000 spdy::WriteSchedulerType::HTTP2,
1001 connection_->transport_version());
1002 } else if (GetQuicReloadableFlag(quic_enable_fifo_write_scheduler) &&
1003 ContainsQuicTag(config_.ReceivedConnectionOptions(), kFIFO)) {
1004 // Enable FIFO write scheduler.
1005 if (write_blocked_streams_.SwitchWriteScheduler(
1006 spdy::WriteSchedulerType::FIFO,
1007 connection_->transport_version())) {
1008 QUIC_RELOADABLE_FLAG_COUNT(quic_enable_fifo_write_scheduler);
1009 }
fayangae266342019-08-05 12:19:59 -07001010 } else if (GetQuicReloadableFlag(quic_enable_lifo_write_scheduler) &&
1011 ContainsQuicTag(config_.ReceivedConnectionOptions(), kLIFO)) {
1012 // Enable LIFO write scheduler.
1013 if (write_blocked_streams_.SwitchWriteScheduler(
1014 spdy::WriteSchedulerType::LIFO,
1015 connection_->transport_version())) {
1016 QUIC_RELOADABLE_FLAG_COUNT(quic_enable_lifo_write_scheduler);
1017 }
fayang944cfbc2019-07-31 09:15:00 -07001018 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001019 }
1020
1021 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
1022 }
1023
fkastenholz305e1732019-06-18 05:01:22 -07001024 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001025 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1026 config_.GetMaxIncomingBidirectionalStreamsToSend());
1027 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1028 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001029 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001030 // A small number of additional incoming streams beyond the limit should be
1031 // allowed. This helps avoid early connection termination when FIN/RSTs for
1032 // old streams are lost or arrive out of order.
1033 // Use a minimum number of additional streams, or a percentage increase,
1034 // whichever is larger.
1035 uint32_t max_incoming_streams_to_send =
1036 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001037 uint32_t max_incoming_streams =
1038 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1039 static_cast<uint32_t>(max_incoming_streams_to_send *
1040 kMaxStreamsMultiplier));
1041 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1042 }
1043
1044 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1045 // Streams which were created before the SHLO was received (0-RTT
1046 // requests) are now informed of the peer's initial flow control window.
1047 OnNewStreamFlowControlWindow(
1048 config_.ReceivedInitialStreamFlowControlWindowBytes());
1049 }
1050 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1051 OnNewSessionFlowControlWindow(
1052 config_.ReceivedInitialSessionFlowControlWindowBytes());
1053 }
1054}
1055
1056void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1057 const float session_window_multiplier =
1058 config_.GetInitialStreamFlowControlWindowToSend()
1059 ? static_cast<float>(
1060 config_.GetInitialSessionFlowControlWindowToSend()) /
1061 config_.GetInitialStreamFlowControlWindowToSend()
1062 : 1.5;
1063
1064 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1065 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1066
1067 size_t session_window = session_window_multiplier * stream_window;
1068 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1069 << session_window;
1070 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1071 flow_controller_.UpdateReceiveWindowSize(session_window);
1072 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001073 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001074 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1075 }
renjietangb663b862019-07-08 16:02:39 -07001076 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001077 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1078 stream_window);
1079 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001080}
1081
1082void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1083 QuicStreamId stream_id) {
1084 DCHECK(!IsClosedStream(stream_id));
1085 // Received a frame for a locally-created stream that is not currently
1086 // active. This is an error.
1087 connection()->CloseConnection(
1088 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1089 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1090}
1091
1092void QuicSession::HandleRstOnValidNonexistentStream(
1093 const QuicRstStreamFrame& frame) {
1094 // If the stream is neither originally in active streams nor created in
renjietang880d2432019-07-16 13:14:37 -07001095 // GetOrCreateStream(), it could be a closed stream in which case its
QUICHE teama6ef0a62019-03-07 20:34:33 -05001096 // final received byte offset need to be updated.
1097 if (IsClosedStream(frame.stream_id)) {
1098 // The RST frame contains the final byte offset for the stream: we can now
1099 // update the connection level flow controller if needed.
1100 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1101 }
1102}
1103
1104void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001105 if (new_window < kMinimumFlowControlSendWindow &&
1106 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001107 QUIC_LOG_FIRST_N(ERROR, 1)
1108 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001109 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001110 if (connection_->connected()) {
1111 connection_->CloseConnection(
1112 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1113 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1114 }
1115 return;
1116 }
1117
1118 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001119 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001120 kv.second->UpdateSendWindowOffset(new_window);
1121 }
renjietangb663b862019-07-08 16:02:39 -07001122 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001123 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1124 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001125}
1126
1127void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001128 if (new_window < kMinimumFlowControlSendWindow &&
1129 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001130 QUIC_LOG_FIRST_N(ERROR, 1)
1131 << "Peer sent us an invalid session flow control send window: "
1132 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1133 if (connection_->connected()) {
1134 connection_->CloseConnection(
1135 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1136 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1137 }
1138 return;
1139 }
1140
1141 flow_controller_.UpdateSendWindowOffset(new_window);
1142}
1143
1144void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1145 switch (event) {
1146 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
1147 // to QuicSession since it is the glue.
1148 case ENCRYPTION_FIRST_ESTABLISHED:
1149 // Given any streams blocked by encryption a chance to write.
1150 OnCanWrite();
1151 break;
1152
1153 case ENCRYPTION_REESTABLISHED:
1154 // Retransmit originally packets that were sent, since they can't be
1155 // decrypted by the peer.
1156 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1157 // Given any streams blocked by encryption a chance to write.
1158 OnCanWrite();
1159 break;
1160
1161 case HANDSHAKE_CONFIRMED:
1162 QUIC_BUG_IF(!config_.negotiated())
1163 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1164 // Discard originally encrypted packets, since they can't be decrypted by
1165 // the peer.
1166 NeuterUnencryptedData();
1167 is_handshake_confirmed_ = true;
1168 break;
1169
1170 default:
1171 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1172 }
1173}
1174
1175void QuicSession::OnCryptoHandshakeMessageSent(
1176 const CryptoHandshakeMessage& /*message*/) {}
1177
1178void QuicSession::OnCryptoHandshakeMessageReceived(
1179 const CryptoHandshakeMessage& /*message*/) {}
1180
fayang476683a2019-07-25 12:42:16 -07001181void QuicSession::RegisterStreamPriority(
1182 QuicStreamId id,
1183 bool is_static,
1184 const spdy::SpdyStreamPrecedence& precedence) {
1185 write_blocked_streams()->RegisterStream(id, is_static, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001186}
1187
1188void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1189 write_blocked_streams()->UnregisterStream(id, is_static);
1190}
1191
fayang476683a2019-07-25 12:42:16 -07001192void QuicSession::UpdateStreamPriority(
1193 QuicStreamId id,
1194 const spdy::SpdyStreamPrecedence& new_precedence) {
1195 write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001196}
1197
1198QuicConfig* QuicSession::config() {
1199 return &config_;
1200}
1201
1202void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001203 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001204 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -07001205 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001206 << ". activating " << stream_id;
renjietang55d182a2019-07-12 10:26:25 -07001207 DCHECK(!QuicContainsKey(stream_map_, stream_id));
1208 stream_map_[stream_id] = std::move(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001209 if (IsIncomingStream(stream_id)) {
1210 ++num_dynamic_incoming_streams_;
1211 }
1212}
1213
1214QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001215 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001216 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1217 }
1218 return stream_id_manager_.GetNextOutgoingStreamId();
1219}
1220
1221QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001222 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001223 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1224 }
1225 return stream_id_manager_.GetNextOutgoingStreamId();
1226}
1227
1228bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001229 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001230 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1231 }
1232 return stream_id_manager_.CanOpenNextOutgoingStream(
1233 GetNumOpenOutgoingStreams());
1234}
1235
1236bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001237 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001238 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1239 }
1240 return stream_id_manager_.CanOpenNextOutgoingStream(
1241 GetNumOpenOutgoingStreams());
1242}
1243
1244QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang28c04b72019-07-01 15:08:09 -07001245 DCHECK(!QuicContainsKey(pending_stream_map_, stream_id));
renjietangb663b862019-07-08 16:02:39 -07001246 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -07001247 stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001248 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001249 }
renjietang880d2432019-07-16 13:14:37 -07001250
1251 StreamMap::iterator it = stream_map_.find(stream_id);
1252 if (it != stream_map_.end()) {
1253 return it->second.get();
1254 }
1255
1256 if (IsClosedStream(stream_id)) {
1257 return nullptr;
1258 }
1259
1260 if (!IsIncomingStream(stream_id)) {
1261 HandleFrameOnNonexistentOutgoingStream(stream_id);
1262 return nullptr;
1263 }
1264
1265 // TODO(fkastenholz): If we are creating a new stream and we have
1266 // sent a goaway, we should ignore the stream creation. Need to
1267 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1268 // B) reject stream creation ("return nullptr")
1269
1270 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
1271 return nullptr;
1272 }
1273
1274 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
1275 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1276 // CanOpenIncomingStream interface consistent with that of v99.
1277 if (!stream_id_manager_.CanOpenIncomingStream(
1278 GetNumOpenIncomingStreams())) {
1279 // Refuse to open the stream.
1280 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
1281 return nullptr;
1282 }
1283 }
1284
1285 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001286}
1287
1288void QuicSession::StreamDraining(QuicStreamId stream_id) {
renjietang55d182a2019-07-12 10:26:25 -07001289 DCHECK(QuicContainsKey(stream_map_, stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001290 if (!QuicContainsKey(draining_streams_, stream_id)) {
1291 draining_streams_.insert(stream_id);
1292 if (IsIncomingStream(stream_id)) {
1293 ++num_draining_incoming_streams_;
1294 }
fkastenholz305e1732019-06-18 05:01:22 -07001295 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001296 v99_streamid_manager_.OnStreamClosed(stream_id);
1297 }
1298 }
1299 if (!IsIncomingStream(stream_id)) {
1300 // Inform application that a stream is available.
fkastenholz8556dc22019-07-18 12:42:38 -07001301 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietangde12d3d2019-07-19 10:57:42 -07001302 OnCanCreateNewOutgoingStream(
1303 !QuicUtils::IsBidirectionalStreamId(stream_id));
fkastenholz8556dc22019-07-18 12:42:38 -07001304 } else {
renjietangde12d3d2019-07-19 10:57:42 -07001305 QuicStream* stream = GetStream(stream_id);
1306 if (!stream) {
1307 QUIC_BUG << "Stream doesn't exist when draining.";
1308 return;
1309 }
1310 OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL);
fkastenholz8556dc22019-07-18 12:42:38 -07001311 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001312 }
1313}
1314
1315bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1316 const QuicStreamId stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001317 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001318 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1319 }
1320 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1321}
1322
1323bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1324 if (stream_id == currently_writing_stream_id_) {
1325 return false;
1326 }
1327 return write_blocked_streams()->ShouldYield(stream_id);
1328}
1329
renjietange76b2da2019-05-13 14:50:23 -07001330PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1331 auto it = pending_stream_map_.find(stream_id);
1332 if (it != pending_stream_map_.end()) {
1333 return it->second.get();
1334 }
1335
1336 if (IsClosedStream(stream_id) ||
1337 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1338 return nullptr;
1339 }
1340
1341 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1342 PendingStream* unowned_pending = pending.get();
1343 pending_stream_map_[stream_id] = std::move(pending);
1344 return unowned_pending;
1345}
1346
QUICHE teama6ef0a62019-03-07 20:34:33 -05001347QuicStream* QuicSession::GetOrCreateDynamicStream(
1348 const QuicStreamId stream_id) {
renjietangb035f152019-08-06 11:32:51 -07001349 DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream) ||
1350 !GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream));
renjietang55d182a2019-07-12 10:26:25 -07001351 StreamMap::iterator it = stream_map_.find(stream_id);
1352 if (it != stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001353 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001354 }
1355
1356 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001357 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001358 }
1359
1360 if (!IsIncomingStream(stream_id)) {
1361 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001362 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001363 }
1364
QUICHE teama6ef0a62019-03-07 20:34:33 -05001365 // TODO(fkastenholz): If we are creating a new stream and we have
1366 // sent a goaway, we should ignore the stream creation. Need to
1367 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1368 // B) reject stream creation ("return nullptr")
1369
1370 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001371 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001372 }
1373
fkastenholz305e1732019-06-18 05:01:22 -07001374 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001375 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1376 // CanOpenIncomingStream interface cosistent with that of v99.
1377 if (!stream_id_manager_.CanOpenIncomingStream(
1378 GetNumOpenIncomingStreams())) {
1379 // Refuse to open the stream.
1380 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001381 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001382 }
1383 }
1384
renjietang2c4d7122019-05-20 17:18:14 -07001385 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001386}
1387
1388void QuicSession::set_largest_peer_created_stream_id(
1389 QuicStreamId largest_peer_created_stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001390 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001391 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1392 largest_peer_created_stream_id);
1393 return;
1394 }
1395 stream_id_manager_.set_largest_peer_created_stream_id(
1396 largest_peer_created_stream_id);
1397}
1398
1399bool QuicSession::IsClosedStream(QuicStreamId id) {
1400 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1401 id);
1402 if (IsOpenStream(id)) {
1403 // Stream is active
1404 return false;
1405 }
1406
fkastenholz305e1732019-06-18 05:01:22 -07001407 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001408 return !v99_streamid_manager_.IsAvailableStream(id);
1409 }
1410
1411 return !stream_id_manager_.IsAvailableStream(id);
1412}
1413
1414bool QuicSession::IsOpenStream(QuicStreamId id) {
1415 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1416 id);
renjietang55d182a2019-07-12 10:26:25 -07001417 if (QuicContainsKey(stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001418 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001419 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001420 // Stream is active
1421 return true;
1422 }
1423 return false;
1424}
1425
rchda26cdb2019-05-17 11:57:37 -07001426bool QuicSession::IsStaticStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001427 auto it = stream_map_.find(id);
1428 if (it == stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -07001429 return false;
rchda26cdb2019-05-17 11:57:37 -07001430 }
renjietangb663b862019-07-08 16:02:39 -07001431 return it->second->is_static();
rchda26cdb2019-05-17 11:57:37 -07001432}
1433
QUICHE teama6ef0a62019-03-07 20:34:33 -05001434size_t QuicSession::GetNumOpenIncomingStreams() const {
1435 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1436 num_locally_closed_incoming_streams_highest_offset_;
1437}
1438
1439size_t QuicSession::GetNumOpenOutgoingStreams() const {
1440 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1441 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1442 GetNumDrainingOutgoingStreams());
1443 return GetNumDynamicOutgoingStreams() +
1444 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1445 GetNumDrainingOutgoingStreams();
1446}
1447
1448size_t QuicSession::GetNumActiveStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001449 return stream_map_.size() - draining_streams_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001450 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001451}
1452
1453size_t QuicSession::GetNumDrainingStreams() const {
1454 return draining_streams_.size();
1455}
1456
1457void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1458 if (GetOrCreateStream(id) == nullptr) {
1459 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1460 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1461 }
1462
1463 write_blocked_streams_.AddStream(id);
1464}
1465
1466bool QuicSession::HasDataToWrite() const {
1467 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1468 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1469 connection_->HasQueuedData() ||
1470 !streams_with_pending_retransmission_.empty() ||
1471 control_frame_manager_.WillingToWrite();
1472}
1473
1474void QuicSession::OnAckNeedsRetransmittableFrame() {
1475 flow_controller_.SendWindowUpdate();
1476}
1477
1478void QuicSession::SendPing() {
1479 control_frame_manager_.WritePing();
1480}
1481
1482size_t QuicSession::GetNumDynamicOutgoingStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001483 DCHECK_GE(
1484 static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()),
1485 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1486 num_incoming_static_streams_);
1487 return stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001488 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1489 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001490}
1491
1492size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1493 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1494 return draining_streams_.size() - num_draining_incoming_streams_;
1495}
1496
1497size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1498 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1499 num_locally_closed_incoming_streams_highest_offset_);
1500 return locally_closed_streams_highest_offset_.size() -
1501 num_locally_closed_incoming_streams_highest_offset_;
1502}
1503
1504bool QuicSession::IsConnectionFlowControlBlocked() const {
1505 return flow_controller_.IsBlocked();
1506}
1507
1508bool QuicSession::IsStreamFlowControlBlocked() {
renjietang55d182a2019-07-12 10:26:25 -07001509 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001510 if (kv.second->flow_controller()->IsBlocked()) {
1511 return true;
1512 }
1513 }
renjietangb663b862019-07-08 16:02:39 -07001514 if (!QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001515 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
renjietang08a9cf72019-04-23 17:01:34 -07001516 return true;
1517 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001518 return false;
1519}
1520
1521size_t QuicSession::MaxAvailableBidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001522 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001523 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1524 }
1525 return stream_id_manager_.MaxAvailableStreams();
1526}
1527
1528size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001529 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001530 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1531 }
1532 return stream_id_manager_.MaxAvailableStreams();
1533}
1534
1535bool QuicSession::IsIncomingStream(QuicStreamId id) const {
fkastenholz305e1732019-06-18 05:01:22 -07001536 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001537 return v99_streamid_manager_.IsIncomingStream(id);
1538 }
1539 return stream_id_manager_.IsIncomingStream(id);
1540}
1541
1542void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
zhongyi1b2f7832019-06-14 13:31:34 -07001543 if (ignore_tlpr_if_no_pending_stream_data() &&
1544 session_decides_what_to_write()) {
1545 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 3,
1546 5);
1547 streams_waiting_for_acks_.erase(id);
1548 }
1549
QUICHE teama6ef0a62019-03-07 20:34:33 -05001550 auto it = zombie_streams_.find(id);
1551 if (it == zombie_streams_.end()) {
1552 return;
1553 }
1554
1555 closed_streams_.push_back(std::move(it->second));
1556 if (!closed_streams_clean_up_alarm_->IsSet()) {
1557 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1558 }
1559 zombie_streams_.erase(it);
1560 // Do not retransmit data of a closed stream.
1561 streams_with_pending_retransmission_.erase(id);
1562}
1563
zhongyi1b2f7832019-06-14 13:31:34 -07001564void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) {
1565 if (!ignore_tlpr_if_no_pending_stream_data() ||
1566 !session_decides_what_to_write())
1567 return;
1568
1569 // Exclude crypto stream's status since it is counted in HasUnackedCryptoData.
1570 if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) {
1571 return;
1572 }
1573
1574 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 4,
1575 5);
1576 streams_waiting_for_acks_.insert(id);
1577
1578 // The number of the streams waiting for acks should not be larger than the
1579 // number of streams.
renjietang55d182a2019-07-12 10:26:25 -07001580 if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) <
zhongyi71e9d9e2019-06-14 14:57:16 -07001581 streams_waiting_for_acks_.size()) {
zhongyi1b2f7832019-06-14 13:31:34 -07001582 QUIC_BUG << "More streams are waiting for acks than the number of streams. "
renjietang55d182a2019-07-12 10:26:25 -07001583 << "Sizes: streams: " << stream_map_.size()
zhongyi1b2f7832019-06-14 13:31:34 -07001584 << ", zombie streams: " << zombie_streams_.size()
1585 << ", vs streams waiting for acks: "
1586 << streams_waiting_for_acks_.size();
1587 }
1588}
1589
QUICHE teama6ef0a62019-03-07 20:34:33 -05001590QuicStream* QuicSession::GetStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001591 auto active_stream = stream_map_.find(id);
1592 if (active_stream != stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001593 return active_stream->second.get();
1594 }
1595 auto zombie_stream = zombie_streams_.find(id);
1596 if (zombie_stream != zombie_streams_.end()) {
1597 return zombie_stream->second.get();
1598 }
renjietang08a9cf72019-04-23 17:01:34 -07001599
renjietangb663b862019-07-08 16:02:39 -07001600 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
renjietang08a9cf72019-04-23 17:01:34 -07001601 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1602 }
1603
QUICHE teama6ef0a62019-03-07 20:34:33 -05001604 return nullptr;
1605}
1606
1607bool QuicSession::OnFrameAcked(const QuicFrame& frame,
QUICHE team9467db02019-05-30 09:38:45 -07001608 QuicTime::Delta ack_delay_time,
1609 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001610 if (frame.type == MESSAGE_FRAME) {
QUICHE team9467db02019-05-30 09:38:45 -07001611 OnMessageAcked(frame.message_frame->message_id, receive_timestamp);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001612 return true;
1613 }
1614 if (frame.type == CRYPTO_FRAME) {
1615 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1616 ack_delay_time);
1617 }
1618 if (frame.type != STREAM_FRAME) {
1619 return control_frame_manager_.OnControlFrameAcked(frame);
1620 }
1621 bool new_stream_data_acked = false;
1622 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1623 // Stream can already be reset when sent frame gets acked.
1624 if (stream != nullptr) {
1625 QuicByteCount newly_acked_length = 0;
1626 new_stream_data_acked = stream->OnStreamFrameAcked(
1627 frame.stream_frame.offset, frame.stream_frame.data_length,
1628 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1629 if (!stream->HasPendingRetransmission()) {
1630 streams_with_pending_retransmission_.erase(stream->id());
1631 }
1632 }
1633 return new_stream_data_acked;
1634}
1635
1636void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1637 QuicStream* stream = GetStream(frame.stream_id);
1638 if (stream == nullptr) {
1639 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1640 << " is retransmitted.";
1641 connection()->CloseConnection(
1642 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1643 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1644 return;
1645 }
1646 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1647 frame.fin);
1648}
1649
1650void QuicSession::OnFrameLost(const QuicFrame& frame) {
1651 if (frame.type == MESSAGE_FRAME) {
1652 OnMessageLost(frame.message_frame->message_id);
1653 return;
1654 }
1655 if (frame.type == CRYPTO_FRAME) {
1656 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1657 return;
1658 }
1659 if (frame.type != STREAM_FRAME) {
1660 control_frame_manager_.OnControlFrameLost(frame);
1661 return;
1662 }
1663 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1664 if (stream == nullptr) {
1665 return;
1666 }
1667 stream->OnStreamFrameLost(frame.stream_frame.offset,
1668 frame.stream_frame.data_length,
1669 frame.stream_frame.fin);
1670 if (stream->HasPendingRetransmission() &&
1671 !QuicContainsKey(streams_with_pending_retransmission_,
1672 frame.stream_frame.stream_id)) {
1673 streams_with_pending_retransmission_.insert(
1674 std::make_pair(frame.stream_frame.stream_id, true));
1675 }
1676}
1677
1678void QuicSession::RetransmitFrames(const QuicFrames& frames,
1679 TransmissionType type) {
fayanga4b37b22019-06-18 13:37:47 -07001680 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001681 SetTransmissionType(type);
1682 for (const QuicFrame& frame : frames) {
1683 if (frame.type == MESSAGE_FRAME) {
1684 // Do not retransmit MESSAGE frames.
1685 continue;
1686 }
1687 if (frame.type == CRYPTO_FRAME) {
1688 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1689 continue;
1690 }
1691 if (frame.type != STREAM_FRAME) {
1692 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1693 break;
1694 }
1695 continue;
1696 }
1697 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1698 if (stream != nullptr &&
1699 !stream->RetransmitStreamData(frame.stream_frame.offset,
1700 frame.stream_frame.data_length,
1701 frame.stream_frame.fin)) {
1702 break;
1703 }
1704 }
1705}
1706
1707bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1708 if (frame.type == MESSAGE_FRAME) {
1709 return false;
1710 }
1711 if (frame.type == CRYPTO_FRAME) {
1712 return GetCryptoStream()->IsFrameOutstanding(
1713 frame.crypto_frame->level, frame.crypto_frame->offset,
1714 frame.crypto_frame->data_length);
1715 }
1716 if (frame.type != STREAM_FRAME) {
1717 return control_frame_manager_.IsControlFrameOutstanding(frame);
1718 }
1719 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1720 return stream != nullptr &&
1721 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1722 frame.stream_frame.data_length,
1723 frame.stream_frame.fin);
1724}
1725
1726bool QuicSession::HasUnackedCryptoData() const {
1727 const QuicCryptoStream* crypto_stream = GetCryptoStream();
fayang44fa92f2019-07-01 07:32:14 -07001728 return crypto_stream->IsWaitingForAcks() || crypto_stream->HasBufferedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001729}
1730
zhongyi1b2f7832019-06-14 13:31:34 -07001731bool QuicSession::HasUnackedStreamData() const {
1732 DCHECK(ignore_tlpr_if_no_pending_stream_data());
1733 if (ignore_tlpr_if_no_pending_stream_data()) {
1734 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 5,
1735 5);
1736 return !streams_waiting_for_acks_.empty();
1737 }
1738
1739 return true;
1740}
1741
QUICHE teama6ef0a62019-03-07 20:34:33 -05001742WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1743 QuicStreamOffset offset,
1744 QuicByteCount data_length,
1745 QuicDataWriter* writer) {
1746 QuicStream* stream = GetStream(id);
1747 if (stream == nullptr) {
1748 // This causes the connection to be closed because of failed to serialize
1749 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001750 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1751 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001752 return STREAM_MISSING;
1753 }
1754 if (stream->WriteStreamData(offset, data_length, writer)) {
1755 return WRITE_SUCCESS;
1756 }
1757 return WRITE_FAILED;
1758}
1759
1760bool QuicSession::WriteCryptoData(EncryptionLevel level,
1761 QuicStreamOffset offset,
1762 QuicByteCount data_length,
1763 QuicDataWriter* writer) {
1764 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1765 writer);
1766}
1767
1768QuicUint128 QuicSession::GetStatelessResetToken() const {
1769 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1770}
1771
1772bool QuicSession::RetransmitLostData() {
fayanga4b37b22019-06-18 13:37:47 -07001773 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001774 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001775 bool uses_crypto_frames =
1776 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001777 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1778 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1779 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1780 crypto_stream->WritePendingCryptoRetransmission();
1781 }
1782 // Retransmit crypto data in stream 1 frames (version < 47).
1783 if (!uses_crypto_frames &&
1784 QuicContainsKey(
1785 streams_with_pending_retransmission_,
1786 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1787 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1788 // Retransmit crypto data first.
1789 QuicStream* crypto_stream = GetStream(
1790 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1791 crypto_stream->OnCanWrite();
1792 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1793 if (crypto_stream->HasPendingRetransmission()) {
1794 // Connection is write blocked.
1795 return false;
1796 } else {
1797 streams_with_pending_retransmission_.erase(
1798 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1799 }
1800 }
1801 if (control_frame_manager_.HasPendingRetransmission()) {
1802 SetTransmissionType(LOSS_RETRANSMISSION);
1803 control_frame_manager_.OnCanWrite();
1804 if (control_frame_manager_.HasPendingRetransmission()) {
1805 return false;
1806 }
1807 }
1808 while (!streams_with_pending_retransmission_.empty()) {
1809 if (!connection_->CanWriteStreamData()) {
1810 break;
1811 }
1812 // Retransmit lost data on headers and data streams.
1813 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1814 QuicStream* stream = GetStream(id);
1815 if (stream != nullptr) {
1816 SetTransmissionType(LOSS_RETRANSMISSION);
1817 stream->OnCanWrite();
1818 DCHECK(CheckStreamWriteBlocked(stream));
1819 if (stream->HasPendingRetransmission()) {
1820 // Connection is write blocked.
1821 break;
1822 } else if (!streams_with_pending_retransmission_.empty() &&
1823 streams_with_pending_retransmission_.begin()->first == id) {
1824 // Retransmit lost data may cause connection close. If this stream
1825 // has not yet sent fin, a RST_STREAM will be sent and it will be
1826 // removed from streams_with_pending_retransmission_.
1827 streams_with_pending_retransmission_.pop_front();
1828 }
1829 } else {
1830 QUIC_BUG << "Try to retransmit data of a closed stream";
1831 streams_with_pending_retransmission_.pop_front();
1832 }
1833 }
1834
1835 return streams_with_pending_retransmission_.empty();
1836}
1837
1838void QuicSession::NeuterUnencryptedData() {
1839 if (connection_->session_decides_what_to_write()) {
1840 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1841 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001842 if (!crypto_stream->HasPendingRetransmission() &&
1843 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001844 streams_with_pending_retransmission_.erase(
1845 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1846 }
1847 }
1848 connection_->NeuterUnencryptedPackets();
1849}
1850
1851void QuicSession::SetTransmissionType(TransmissionType type) {
1852 connection_->SetTransmissionType(type);
1853}
1854
1855MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1856 if (!IsEncryptionEstablished()) {
1857 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1858 }
1859 MessageStatus result =
1860 connection_->SendMessage(last_message_id_ + 1, message);
1861 if (result == MESSAGE_STATUS_SUCCESS) {
1862 return {result, ++last_message_id_};
1863 }
1864 return {result, 0};
1865}
1866
QUICHE team9467db02019-05-30 09:38:45 -07001867void QuicSession::OnMessageAcked(QuicMessageId message_id,
dschinazi17d42422019-06-18 16:35:07 -07001868 QuicTime /*receive_timestamp*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001869 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1870}
1871
1872void QuicSession::OnMessageLost(QuicMessageId message_id) {
1873 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1874 << " is considered lost";
1875}
1876
1877void QuicSession::CleanUpClosedStreams() {
1878 closed_streams_.clear();
1879}
1880
1881bool QuicSession::session_decides_what_to_write() const {
1882 return connection_->session_decides_what_to_write();
1883}
1884
ianswettb239f862019-04-05 09:15:06 -07001885QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1886 return connection_->GetCurrentLargestMessagePayload();
1887}
1888
1889QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1890 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001891}
1892
1893void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1894 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1895}
1896
fkastenholz8556dc22019-07-18 12:42:38 -07001897void QuicSession::OnCanCreateNewOutgoingStream(bool /*unidirectional*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -05001898
1899QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001900 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001901 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1902 }
1903 return stream_id_manager_.next_outgoing_stream_id();
1904}
1905
1906QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001907 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001908 return v99_streamid_manager_.next_outgoing_unidirectional_stream_id();
1909 }
1910 return stream_id_manager_.next_outgoing_stream_id();
1911}
1912
fkastenholz3c4eabf2019-04-22 07:49:59 -07001913bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1914 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001915}
1916
fkastenholz3c4eabf2019-04-22 07:49:59 -07001917bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1918 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001919}
1920
1921size_t QuicSession::max_open_incoming_bidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001922 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001923 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1924 }
1925 return stream_id_manager_.max_open_incoming_streams();
1926}
1927
1928size_t QuicSession::max_open_incoming_unidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001929 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001930 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1931 }
1932 return stream_id_manager_.max_open_incoming_streams();
1933}
1934
1935#undef ENDPOINT // undef for jumbo builds
1936} // namespace quic