blob: fd3d48913139d3f9644afe69f4fe84d5df6440b0 [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),
fkastenholz9b4b0ad2019-08-20 05:10:40 -070092 use_http2_priority_write_scheduler_(false),
93 is_configured_(false) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050094 closed_streams_clean_up_alarm_ =
95 QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
96 new ClosedStreamsCleanUpDelegate(this)));
dschinazi4e3e6572019-08-02 12:57:17 -070097 if (perspective() == Perspective::IS_SERVER &&
98 connection_->version().handshake_protocol == PROTOCOL_TLS1_3) {
99 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
100 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500101}
102
103void QuicSession::Initialize() {
104 connection_->set_visitor(this);
105 connection_->SetSessionNotifier(this);
106 connection_->SetDataProducer(this);
107 connection_->SetFromConfig(config_);
108
nharper46833c32019-05-15 21:33:05 -0700109 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
110 return;
111 }
112
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
114 GetMutableCryptoStream()->id());
renjietangb663b862019-07-08 16:02:39 -0700115
116 QuicStreamId id =
117 QuicUtils::GetCryptoStreamId(connection_->transport_version());
renjietangb663b862019-07-08 16:02:39 -0700118 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
119 v99_streamid_manager_.RegisterStaticStream(id, false);
renjietang08a9cf72019-04-23 17:01:34 -0700120 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121}
122
123QuicSession::~QuicSession() {
124 QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
125}
126
renjietang0e9980b2019-07-11 12:00:21 -0700127void QuicSession::RegisterStaticStream(std::unique_ptr<QuicStream> stream,
128 bool stream_already_counted) {
renjietang9ffbb602019-07-10 14:08:00 -0700129 DCHECK(stream->is_static());
renjietangfbeb5bf2019-04-19 15:06:20 -0700130 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -0700131 stream_map_[stream_id] = std::move(stream);
fkastenholz305e1732019-06-18 05:01:22 -0700132 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietang3a1bb802019-06-11 10:42:41 -0700133 v99_streamid_manager_.RegisterStaticStream(stream_id,
134 stream_already_counted);
renjietangfbeb5bf2019-04-19 15:06:20 -0700135 }
136 if (IsIncomingStream(stream_id)) {
137 ++num_incoming_static_streams_;
138 } else {
139 ++num_outgoing_static_streams_;
140 }
141}
142
renjietange76b2da2019-05-13 14:50:23 -0700143void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700144 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700145 QuicStreamId stream_id = frame.stream_id;
146
147 PendingStream* pending = GetOrCreatePendingStream(stream_id);
148
149 if (!pending) {
150 if (frame.fin) {
151 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
152 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
153 }
154 return;
155 }
156
157 pending->OnStreamFrame(frame);
renjietanga553da02019-06-24 11:57:04 -0700158 if (!connection()->connected()) {
159 return;
160 }
renjietangbb1c4892019-05-24 15:58:44 -0700161 if (ProcessPendingStream(pending)) {
162 // The pending stream should now be in the scope of normal streams.
163 DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
164 << "Stream " << stream_id << " not created";
165 pending_stream_map_.erase(stream_id);
bnc4ff60622019-08-09 18:55:45 -0700166 return;
167 }
168 if (pending->sequencer()->IsClosed()) {
169 ClosePendingStream(stream_id);
renjietangbb1c4892019-05-24 15:58:44 -0700170 }
renjietange76b2da2019-05-13 14:50:23 -0700171}
172
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
174 // TODO(rch) deal with the error case of stream id 0.
175 QuicStreamId stream_id = frame.stream_id;
176 if (stream_id ==
177 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
178 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700179 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
181 return;
182 }
183
bnc36c47282019-06-21 05:17:59 -0700184 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700185 QuicUtils::GetStreamType(stream_id, perspective(),
186 IsIncomingStream(stream_id)) ==
187 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700188 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700189 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500190 return;
191 }
192
renjietang2c4d7122019-05-20 17:18:14 -0700193 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700194
renjietang2c4d7122019-05-20 17:18:14 -0700195 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500196 // The stream no longer exists, but we may still be interested in the
197 // final stream byte offset sent by the peer. A frame with a FIN can give
198 // us this offset.
199 if (frame.fin) {
200 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
201 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
202 }
203 return;
204 }
renjietangb663b862019-07-08 16:02:39 -0700205 if (frame.fin && stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700206 connection()->CloseConnection(
207 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
208 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
209 return;
210 }
renjietang2c4d7122019-05-20 17:18:14 -0700211 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500212}
213
214void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
215 GetMutableCryptoStream()->OnCryptoFrame(frame);
216}
217
218bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
219 // We are not version 99. In theory, if not in version 99 then the framer
220 // could not call OnStopSending... This is just a check that is good when
221 // both a new protocol and a new implementation of that protocol are both
222 // being developed.
fkastenholz305e1732019-06-18 05:01:22 -0700223 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500224
225 QuicStreamId stream_id = frame.stream_id;
226 // If Stream ID is invalid then close the connection.
227 if (stream_id ==
228 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
229 QUIC_DVLOG(1) << ENDPOINT
230 << "Received STOP_SENDING with invalid stream_id: "
231 << stream_id << " Closing connection";
232 connection()->CloseConnection(
233 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
234 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
235 return false;
236 }
237
238 // Ignore STOP_SENDING for static streams.
239 // TODO(fkastenholz): IETF Quic does not have static streams and does not
240 // make exceptions for them with respect to processing things like
241 // STOP_SENDING.
renjietang0e9980b2019-07-11 12:00:21 -0700242 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -0700243 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 QUIC_DVLOG(1) << ENDPOINT
245 << "Received STOP_SENDING for a static stream, id: "
246 << stream_id << " Closing connection";
247 connection()->CloseConnection(
248 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
249 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
250 return false;
251 }
252
253 if (visitor_) {
254 visitor_->OnStopSendingReceived(frame);
255 }
256
257 // If stream is closed, ignore the frame
258 if (IsClosedStream(stream_id)) {
259 QUIC_DVLOG(1)
260 << ENDPOINT
261 << "Received STOP_SENDING for closed or non-existent stream, id: "
262 << stream_id << " Ignoring.";
263 return true; // Continue processing the packet.
264 }
265 // If stream is non-existent, close the connection
renjietang55d182a2019-07-12 10:26:25 -0700266 StreamMap::iterator it = stream_map_.find(stream_id);
267 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268 QUIC_DVLOG(1) << ENDPOINT
269 << "Received STOP_SENDING for non-existent stream, id: "
270 << stream_id << " Closing connection";
271 connection()->CloseConnection(
272 IETF_QUIC_PROTOCOL_VIOLATION,
273 "Received STOP_SENDING for a non-existent stream",
274 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
275 return false;
276 }
277
278 // Get the QuicStream for this stream. Ignore the STOP_SENDING
279 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700280 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
281 // happen IFF there was an entry in the map, but the pointer is null. sounds
282 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 QuicStream* stream = it->second.get();
284 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700285 QUIC_BUG << ENDPOINT
286 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
287 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500288 return true;
289 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700290
renjietangb663b862019-07-08 16:02:39 -0700291 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700292 QUIC_DVLOG(1) << ENDPOINT
293 << "Received STOP_SENDING for a static stream, id: "
294 << stream_id << " Closing connection";
295 connection()->CloseConnection(
296 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
297 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
298 return false;
299 }
300
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301 stream->OnStopSending(frame.application_error_code);
302
303 stream->set_stream_error(
304 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
305 SendRstStreamInner(
306 stream->id(),
307 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
308 stream->stream_bytes_written(),
309 /*close_write_side_only=*/true);
310
311 return true;
312}
313
renjietange76b2da2019-05-13 14:50:23 -0700314void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700315 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700316 QuicStreamId stream_id = frame.stream_id;
317
318 PendingStream* pending = GetOrCreatePendingStream(stream_id);
319
320 if (!pending) {
321 HandleRstOnValidNonexistentStream(frame);
322 return;
323 }
324
325 pending->OnRstStreamFrame(frame);
bnc092d8212019-08-07 11:53:20 -0700326 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
renjietange76b2da2019-05-13 14:50:23 -0700327 ClosePendingStream(stream_id);
328}
329
QUICHE teama6ef0a62019-03-07 20:34:33 -0500330void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
331 QuicStreamId stream_id = frame.stream_id;
332 if (stream_id ==
333 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
334 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700335 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500336 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
337 return;
338 }
339
QUICHE teama6ef0a62019-03-07 20:34:33 -0500340 if (visitor_) {
341 visitor_->OnRstStreamReceived(frame);
342 }
343
bnc36c47282019-06-21 05:17:59 -0700344 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700345 QuicUtils::GetStreamType(stream_id, perspective(),
346 IsIncomingStream(stream_id)) ==
347 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700348 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700349 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 return;
351 }
renjietange76b2da2019-05-13 14:50:23 -0700352
renjietang2c4d7122019-05-20 17:18:14 -0700353 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700354
renjietang2c4d7122019-05-20 17:18:14 -0700355 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500356 HandleRstOnValidNonexistentStream(frame);
357 return; // Errors are handled by GetOrCreateStream.
358 }
renjietangb663b862019-07-08 16:02:39 -0700359 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700360 connection()->CloseConnection(
361 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
362 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
363 return;
364 }
renjietang2c4d7122019-05-20 17:18:14 -0700365 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366}
367
dschinazi17d42422019-06-18 16:35:07 -0700368void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500369 goaway_received_ = true;
370}
371
372void QuicSession::OnMessageReceived(QuicStringPiece message) {
373 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
374 << ", " << message;
375}
376
wub2b5942f2019-04-11 13:22:50 -0700377// static
378void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
379 ConnectionCloseSource source) {
380 if (error != QUIC_NO_ERROR) {
381 if (source == ConnectionCloseSource::FROM_SELF) {
382 QUIC_SERVER_HISTOGRAM_ENUM(
383 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
384 "QuicErrorCode for server-closed connections.");
385 } else {
386 QUIC_SERVER_HISTOGRAM_ENUM(
387 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
388 "QuicErrorCode for client-closed connections.");
389 }
390 }
391}
392
fkastenholz5d880a92019-06-21 09:01:56 -0700393void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 ConnectionCloseSource source) {
395 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700396 if (perspective() == Perspective::IS_SERVER) {
fkastenholz5d880a92019-06-21 09:01:56 -0700397 RecordConnectionCloseAtServer(frame.quic_error_code, source);
wub2b5942f2019-04-11 13:22:50 -0700398 }
399
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400 if (error_ == QUIC_NO_ERROR) {
fkastenholz5d880a92019-06-21 09:01:56 -0700401 error_ = frame.quic_error_code;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500402 }
403
renjietangb663b862019-07-08 16:02:39 -0700404 // Copy all non static streams in a new map for the ease of deleting.
405 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
renjietang55d182a2019-07-12 10:26:25 -0700406 for (const auto& it : stream_map_) {
renjietangb663b862019-07-08 16:02:39 -0700407 if (!it.second->is_static()) {
408 non_static_streams[it.first] = it.second.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700409 }
renjietangb663b862019-07-08 16:02:39 -0700410 }
411 for (const auto& it : non_static_streams) {
412 QuicStreamId id = it.first;
413 it.second->OnConnectionClosed(frame.quic_error_code, source);
renjietang55d182a2019-07-12 10:26:25 -0700414 if (stream_map_.find(id) != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700415 QUIC_BUG << ENDPOINT << "Stream " << id
416 << " failed to close under OnConnectionClosed";
417 CloseStream(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500418 }
419 }
420
421 // Cleanup zombie stream map on connection close.
422 while (!zombie_streams_.empty()) {
423 ZombieStreamMap::iterator it = zombie_streams_.begin();
424 closed_streams_.push_back(std::move(it->second));
425 zombie_streams_.erase(it);
426 }
427
428 closed_streams_clean_up_alarm_->Cancel();
429
430 if (visitor_) {
fkastenholz5d880a92019-06-21 09:01:56 -0700431 visitor_->OnConnectionClosed(connection_->connection_id(),
432 frame.quic_error_code, frame.error_details,
433 source);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500434 }
435}
436
437void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700438 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500439 return;
440 }
441 if (visitor_) {
442 visitor_->OnWriteBlocked(connection_);
443 }
444}
445
446void QuicSession::OnSuccessfulVersionNegotiation(
447 const ParsedQuicVersion& version) {
448 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
449}
450
zhongyi83161e42019-08-19 09:06:25 -0700451void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/,
452 const QuicSocketAddress& peer_address,
453 bool is_connectivity_probe) {
454 if (is_connectivity_probe && perspective() == Perspective::IS_SERVER) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500455 // Server only sends back a connectivity probe after received a
456 // connectivity probe from a new peer address.
457 connection_->SendConnectivityProbingResponsePacket(peer_address);
458 }
459}
460
461void QuicSession::OnPathDegrading() {}
462
463bool QuicSession::AllowSelfAddressChange() const {
464 return false;
465}
466
467void QuicSession::OnForwardProgressConfirmed() {}
468
469void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
470 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
471 // assume that it still exists.
472 QuicStreamId stream_id = frame.stream_id;
473 if (stream_id ==
474 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
475 // This is a window update that applies to the connection, rather than an
476 // individual stream.
477 QUIC_DLOG(INFO) << ENDPOINT
478 << "Received connection level flow control window "
479 "update with byte offset: "
480 << frame.byte_offset;
481 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
482 return;
483 }
renjietang28c04b72019-07-01 15:08:09 -0700484
485 if (VersionHasIetfQuicFrames(connection_->transport_version()) &&
486 QuicUtils::GetStreamType(stream_id, perspective(),
487 IsIncomingStream(stream_id)) ==
488 READ_UNIDIRECTIONAL) {
489 connection()->CloseConnection(
490 QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM,
491 "WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.",
492 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
493 return;
494 }
495
QUICHE teama6ef0a62019-03-07 20:34:33 -0500496 QuicStream* stream = GetOrCreateStream(stream_id);
497 if (stream != nullptr) {
498 stream->OnWindowUpdateFrame(frame);
499 }
500}
501
502void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
503 // TODO(rjshade): Compare our flow control receive windows for specified
504 // streams: if we have a large window then maybe something
505 // had gone wrong with the flow control accounting.
506 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
507 << frame.stream_id;
508}
509
510bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
511 uint64_t previous_bytes_written,
512 bool previous_fin_sent) {
513 if ( // Stream should not be closed.
514 !stream->write_side_closed() &&
515 // Not connection flow control blocked.
516 !flow_controller_.IsBlocked() &&
517 // Detect lack of forward progress.
518 previous_bytes_written == stream->stream_bytes_written() &&
519 previous_fin_sent == stream->fin_sent()) {
520 stream->set_busy_counter(stream->busy_counter() + 1);
521 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
522 << " stream_bytes_written " << stream->stream_bytes_written()
523 << " fin " << stream->fin_sent() << " count "
524 << stream->busy_counter();
525 // Wait a few iterations before firing, the exact count is
526 // arbitrary, more than a few to cover a few test-only false
527 // positives.
528 if (stream->busy_counter() > 20) {
529 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
530 << " stream_bytes_written "
531 << stream->stream_bytes_written() << " fin "
532 << stream->fin_sent();
533 return false;
534 }
535 } else {
536 stream->set_busy_counter(0);
537 }
538 return true;
539}
540
541bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
542 if (!stream->write_side_closed() && stream->HasBufferedData() &&
543 !stream->flow_controller()->IsBlocked() &&
544 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
545 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
546 << stream->BufferedDataBytes()
547 << " bytes, and is not flow control blocked, "
548 "but it is not in the write block list.";
549 return false;
550 }
551 return true;
552}
553
554void QuicSession::OnCanWrite() {
555 if (!RetransmitLostData()) {
556 // Cannot finish retransmitting lost data, connection is write blocked.
557 QUIC_DVLOG(1) << ENDPOINT
558 << "Cannot finish retransmitting lost data, connection is "
559 "write blocked.";
560 return;
561 }
562 if (session_decides_what_to_write()) {
563 SetTransmissionType(NOT_RETRANSMISSION);
564 }
565 // We limit the number of writes to the number of pending streams. If more
566 // streams become pending, WillingAndAbleToWrite will be true, which will
567 // cause the connection to request resumption before yielding to other
568 // connections.
569 // If we are connection level flow control blocked, then only allow the
570 // crypto and headers streams to try writing as all other streams will be
571 // blocked.
572 size_t num_writes = flow_controller_.IsBlocked()
573 ? write_blocked_streams_.NumBlockedSpecialStreams()
574 : write_blocked_streams_.NumBlockedStreams();
575 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
576 return;
577 }
578
fayanga4b37b22019-06-18 13:37:47 -0700579 QuicConnection::ScopedPacketFlusher flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500580 if (control_frame_manager_.WillingToWrite()) {
581 control_frame_manager_.OnCanWrite();
582 }
583 for (size_t i = 0; i < num_writes; ++i) {
584 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
585 write_blocked_streams_.HasWriteBlockedDataStreams())) {
586 // Writing one stream removed another!? Something's broken.
587 QUIC_BUG << "WriteBlockedStream is missing";
588 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
589 "WriteBlockedStream is missing",
590 ConnectionCloseBehavior::SILENT_CLOSE);
591 return;
592 }
593 if (!connection_->CanWriteStreamData()) {
594 return;
595 }
596 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
597 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
598 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
599 // If the stream can't write all bytes it'll re-add itself to the blocked
600 // list.
601 uint64_t previous_bytes_written = stream->stream_bytes_written();
602 bool previous_fin_sent = stream->fin_sent();
603 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
604 << previous_bytes_written << " fin " << previous_fin_sent;
605 stream->OnCanWrite();
606 DCHECK(CheckStreamWriteBlocked(stream));
607 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
608 previous_fin_sent));
609 }
610 currently_writing_stream_id_ = 0;
611 }
612}
613
QUICHE teamb8343252019-04-29 13:58:01 -0700614bool QuicSession::SendProbingData() {
615 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
616 PROBING_RETRANSMISSION)) {
617 return true;
618 }
619 return false;
620}
621
QUICHE teama6ef0a62019-03-07 20:34:33 -0500622bool QuicSession::WillingAndAbleToWrite() const {
623 // Schedule a write when:
624 // 1) control frame manager has pending or new control frames, or
625 // 2) any stream has pending retransmissions, or
626 // 3) If the crypto or headers streams are blocked, or
627 // 4) connection is not flow control blocked and there are write blocked
628 // streams.
629 return control_frame_manager_.WillingToWrite() ||
630 !streams_with_pending_retransmission_.empty() ||
631 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
632 (!flow_controller_.IsBlocked() &&
633 write_blocked_streams_.HasWriteBlockedDataStreams());
634}
635
636bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700637 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
638 // Writing CRYPTO frames is not subject to flow control, so there can't be
639 // pending data to write, only pending retransmissions.
640 return GetCryptoStream()->HasPendingCryptoRetransmission();
641 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642 return QuicContainsKey(
643 streams_with_pending_retransmission_,
644 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
645 write_blocked_streams_.IsStreamBlocked(
646 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
647}
648
649uint64_t QuicSession::GetNumOpenDynamicStreams() const {
renjietang55d182a2019-07-12 10:26:25 -0700650 return stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700651 locally_closed_streams_highest_offset_.size() -
652 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500653}
654
655void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
656 const QuicSocketAddress& peer_address,
657 const QuicReceivedPacket& packet) {
658 connection_->ProcessUdpPacket(self_address, peer_address, packet);
659}
660
661QuicConsumedData QuicSession::WritevData(QuicStream* stream,
662 QuicStreamId id,
663 size_t write_length,
664 QuicStreamOffset offset,
665 StreamSendingState state) {
666 // This check is an attempt to deal with potential memory corruption
667 // in which |id| ends up set to 1 (the crypto stream id). If this happen
668 // it might end up resulting in unencrypted stream data being sent.
669 // While this is impossible to avoid given sufficient corruption, this
670 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700671 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500672 stream != GetMutableCryptoStream()) {
673 QUIC_BUG << "Stream id mismatch";
674 connection_->CloseConnection(
675 QUIC_INTERNAL_ERROR,
676 "Non-crypto stream attempted to write data as crypto stream.",
677 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
678 return QuicConsumedData(0, false);
679 }
680 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700681 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500682 // Do not let streams write without encryption. The calling stream will end
683 // up write blocked until OnCanWrite is next called.
684 return QuicConsumedData(0, false);
685 }
686
687 QuicConsumedData data =
688 connection_->SendStreamData(id, write_length, offset, state);
689 if (offset >= stream->stream_bytes_written()) {
690 // This is new stream data.
691 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
692 }
693 return data;
694}
695
696bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
697 return connection_->SendControlFrame(frame);
698}
699
700void QuicSession::SendRstStream(QuicStreamId id,
701 QuicRstStreamErrorCode error,
702 QuicStreamOffset bytes_written) {
703 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
704}
705
706void QuicSession::SendRstStreamInner(QuicStreamId id,
707 QuicRstStreamErrorCode error,
708 QuicStreamOffset bytes_written,
709 bool close_write_side_only) {
710 if (connection()->connected()) {
711 // Only send if still connected.
712 if (close_write_side_only) {
fkastenholz305e1732019-06-18 05:01:22 -0700713 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500714 // Send a RST_STREAM frame.
715 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
716 } else {
717 // Send a RST_STREAM frame plus, if version 99, an IETF
718 // QUIC STOP_SENDING frame. Both sre sent to emulate
719 // the two-way close that Google QUIC's RST_STREAM does.
fkastenholz305e1732019-06-18 05:01:22 -0700720 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fayanga4b37b22019-06-18 13:37:47 -0700721 QuicConnection::ScopedPacketFlusher flusher(connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500722 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
723 control_frame_manager_.WriteOrBufferStopSending(error, id);
724 } else {
725 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
726 }
727 }
728 connection_->OnStreamReset(id, error);
729 }
730 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
731 OnStreamDoneWaitingForAcks(id);
732 return;
733 }
734
735 if (!close_write_side_only) {
736 CloseStreamInner(id, true);
737 return;
738 }
fkastenholz305e1732019-06-18 05:01:22 -0700739 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740
renjietang55d182a2019-07-12 10:26:25 -0700741 StreamMap::iterator it = stream_map_.find(id);
742 if (it != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700743 if (it->second->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700744 QUIC_DVLOG(1) << ENDPOINT
745 << "Try to send rst for a static stream, id: " << id
746 << " Closing connection";
747 connection()->CloseConnection(
748 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
749 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
750 return;
751 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500752 QuicStream* stream = it->second.get();
753 if (stream) {
754 stream->set_rst_sent(true);
755 stream->CloseWriteSide();
756 }
757 }
758}
759
760void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700761 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500762 // GOAWAY frame is not supported in v99.
fkastenholz305e1732019-06-18 05:01:22 -0700763 DCHECK(!VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500764 if (goaway_sent_) {
765 return;
766 }
767 goaway_sent_ = true;
768 control_frame_manager_.WriteOrBufferGoAway(
769 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
770}
771
772void QuicSession::SendBlocked(QuicStreamId id) {
773 control_frame_manager_.WriteOrBufferBlocked(id);
774}
775
776void QuicSession::SendWindowUpdate(QuicStreamId id,
777 QuicStreamOffset byte_offset) {
778 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
779}
780
fkastenholz3c4eabf2019-04-22 07:49:59 -0700781void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
782 bool unidirectional) {
783 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500784}
785
fkastenholz3c4eabf2019-04-22 07:49:59 -0700786void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
787 bool unidirectional) {
788 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
789 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500790}
791
792void QuicSession::CloseStream(QuicStreamId stream_id) {
793 CloseStreamInner(stream_id, false);
794}
795
796void QuicSession::InsertLocallyClosedStreamsHighestOffset(
797 const QuicStreamId id,
798 QuicStreamOffset offset) {
799 locally_closed_streams_highest_offset_[id] = offset;
800 if (IsIncomingStream(id)) {
801 ++num_locally_closed_incoming_streams_highest_offset_;
802 }
803}
804
805void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
806 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
807
renjietang55d182a2019-07-12 10:26:25 -0700808 StreamMap::iterator it = stream_map_.find(stream_id);
809 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500810 // When CloseStreamInner has been called recursively (via
811 // QuicStream::OnClose), the stream will already have been deleted
812 // from stream_map_, so return immediately.
813 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
814 return;
815 }
816 QuicStream* stream = it->second.get();
renjietangb663b862019-07-08 16:02:39 -0700817 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700818 QUIC_DVLOG(1) << ENDPOINT
819 << "Try to close a static stream, id: " << stream_id
820 << " Closing connection";
821 connection()->CloseConnection(
822 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
823 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
824 return;
825 }
renjietangde12d3d2019-07-19 10:57:42 -0700826 StreamType type = stream->type();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500827
828 // Tell the stream that a RST has been sent.
829 if (locally_reset) {
830 stream->set_rst_sent(true);
831 }
832
833 if (stream->IsWaitingForAcks()) {
834 zombie_streams_[stream->id()] = std::move(it->second);
835 } else {
zhongyi1b2f7832019-06-14 13:31:34 -0700836 // Clean up the stream since it is no longer waiting for acks.
837 if (ignore_tlpr_if_no_pending_stream_data() &&
838 session_decides_what_to_write()) {
839 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data,
840 2, 5);
841 streams_waiting_for_acks_.erase(stream->id());
842 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500843 closed_streams_.push_back(std::move(it->second));
844 // Do not retransmit data of a closed stream.
845 streams_with_pending_retransmission_.erase(stream_id);
846 if (!closed_streams_clean_up_alarm_->IsSet()) {
847 closed_streams_clean_up_alarm_->Set(
848 connection_->clock()->ApproximateNow());
849 }
850 }
851
852 // If we haven't received a FIN or RST for this stream, we need to keep track
853 // of the how many bytes the stream's flow controller believes it has
854 // received, for accurate connection level flow control accounting.
855 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
856 if (!had_fin_or_rst) {
857 InsertLocallyClosedStreamsHighestOffset(
858 stream_id, stream->flow_controller()->highest_received_byte_offset());
859 }
renjietang55d182a2019-07-12 10:26:25 -0700860 stream_map_.erase(it);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500861 if (IsIncomingStream(stream_id)) {
862 --num_dynamic_incoming_streams_;
863 }
864
865 const bool stream_was_draining =
866 draining_streams_.find(stream_id) != draining_streams_.end();
867 if (stream_was_draining) {
868 if (IsIncomingStream(stream_id)) {
869 --num_draining_incoming_streams_;
870 }
871 draining_streams_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700872 } else if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500873 // Stream was not draining, but we did have a fin or rst, so we can now
874 // free the stream ID if version 99.
875 if (had_fin_or_rst) {
876 v99_streamid_manager_.OnStreamClosed(stream_id);
877 }
878 }
879
880 stream->OnClose();
881
882 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
fkastenholz305e1732019-06-18 05:01:22 -0700883 !VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500884 // Streams that first became draining already called OnCanCreate...
885 // This covers the case where the stream went directly to being closed.
renjietangde12d3d2019-07-19 10:57:42 -0700886 OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500887 }
888}
889
890void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
891 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
892
bnc092d8212019-08-07 11:53:20 -0700893 pending_stream_map_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700894 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500895 v99_streamid_manager_.OnStreamClosed(stream_id);
896 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500897}
898
899void QuicSession::OnFinalByteOffsetReceived(
900 QuicStreamId stream_id,
901 QuicStreamOffset final_byte_offset) {
902 auto it = locally_closed_streams_highest_offset_.find(stream_id);
903 if (it == locally_closed_streams_highest_offset_.end()) {
904 return;
905 }
906
907 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
908 << final_byte_offset << " for stream " << stream_id;
909 QuicByteCount offset_diff = final_byte_offset - it->second;
910 if (flow_controller_.UpdateHighestReceivedOffset(
911 flow_controller_.highest_received_byte_offset() + offset_diff)) {
912 // If the final offset violates flow control, close the connection now.
913 if (flow_controller_.FlowControlViolation()) {
914 connection_->CloseConnection(
915 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
916 "Connection level flow control violation",
917 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
918 return;
919 }
920 }
921
922 flow_controller_.AddBytesConsumed(offset_diff);
923 locally_closed_streams_highest_offset_.erase(it);
924 if (IsIncomingStream(stream_id)) {
925 --num_locally_closed_incoming_streams_highest_offset_;
fkastenholz305e1732019-06-18 05:01:22 -0700926 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500927 v99_streamid_manager_.OnStreamClosed(stream_id);
928 }
fkastenholz305e1732019-06-18 05:01:22 -0700929 } else if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholz8556dc22019-07-18 12:42:38 -0700930 OnCanCreateNewOutgoingStream(false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500931 }
932}
933
934bool QuicSession::IsEncryptionEstablished() const {
935 // Once the handshake is confirmed, it never becomes un-confirmed.
936 if (is_handshake_confirmed_) {
937 return true;
938 }
939 return GetCryptoStream()->encryption_established();
940}
941
942bool QuicSession::IsCryptoHandshakeConfirmed() const {
943 return GetCryptoStream()->handshake_confirmed();
944}
945
946void QuicSession::OnConfigNegotiated() {
947 connection_->SetFromConfig(config_);
948
fkastenholz305e1732019-06-18 05:01:22 -0700949 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700950 uint32_t max_streams = 0;
951 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
952 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
953 }
954 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
955 << max_streams;
956 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
957 max_streams);
958
959 max_streams = 0;
960 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
961 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
962 }
963 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
964 << max_streams;
965 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
966 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500967 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -0700968 uint32_t max_streams = 0;
969 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
970 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
971 }
972 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500973 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
974 }
fkastenholzd3a1de92019-05-15 07:00:07 -0700975
QUICHE teama6ef0a62019-03-07 20:34:33 -0500976 if (perspective() == Perspective::IS_SERVER) {
977 if (config_.HasReceivedConnectionOptions()) {
978 // The following variations change the initial receive flow control
979 // window sizes.
980 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
981 AdjustInitialFlowControlWindows(64 * 1024);
982 }
983 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
984 AdjustInitialFlowControlWindows(128 * 1024);
985 }
986 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
987 AdjustInitialFlowControlWindows(256 * 1024);
988 }
989 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
990 AdjustInitialFlowControlWindows(512 * 1024);
991 }
992 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
993 AdjustInitialFlowControlWindows(1024 * 1024);
994 }
fayang944cfbc2019-07-31 09:15:00 -0700995 if (GetQuicReloadableFlag(quic_use_http2_priority_write_scheduler) &&
996 ContainsQuicTag(config_.ReceivedConnectionOptions(), kH2PR) &&
997 !VersionHasIetfQuicFrames(connection_->transport_version())) {
fayange606e0c2019-08-05 06:56:05 -0700998 // Enable HTTP2 (tree-style) priority write scheduler.
fayang944cfbc2019-07-31 09:15:00 -0700999 use_http2_priority_write_scheduler_ =
fayange606e0c2019-08-05 06:56:05 -07001000 write_blocked_streams_.SwitchWriteScheduler(
1001 spdy::WriteSchedulerType::HTTP2,
1002 connection_->transport_version());
1003 } else if (GetQuicReloadableFlag(quic_enable_fifo_write_scheduler) &&
1004 ContainsQuicTag(config_.ReceivedConnectionOptions(), kFIFO)) {
1005 // Enable FIFO write scheduler.
1006 if (write_blocked_streams_.SwitchWriteScheduler(
1007 spdy::WriteSchedulerType::FIFO,
1008 connection_->transport_version())) {
1009 QUIC_RELOADABLE_FLAG_COUNT(quic_enable_fifo_write_scheduler);
1010 }
fayangae266342019-08-05 12:19:59 -07001011 } else if (GetQuicReloadableFlag(quic_enable_lifo_write_scheduler) &&
1012 ContainsQuicTag(config_.ReceivedConnectionOptions(), kLIFO)) {
1013 // Enable LIFO write scheduler.
1014 if (write_blocked_streams_.SwitchWriteScheduler(
1015 spdy::WriteSchedulerType::LIFO,
1016 connection_->transport_version())) {
1017 QUIC_RELOADABLE_FLAG_COUNT(quic_enable_lifo_write_scheduler);
1018 }
fayang944cfbc2019-07-31 09:15:00 -07001019 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001020 }
1021
1022 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
1023 }
1024
fkastenholz305e1732019-06-18 05:01:22 -07001025 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001026 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1027 config_.GetMaxIncomingBidirectionalStreamsToSend());
1028 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1029 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001030 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001031 // A small number of additional incoming streams beyond the limit should be
1032 // allowed. This helps avoid early connection termination when FIN/RSTs for
1033 // old streams are lost or arrive out of order.
1034 // Use a minimum number of additional streams, or a percentage increase,
1035 // whichever is larger.
1036 uint32_t max_incoming_streams_to_send =
1037 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001038 uint32_t max_incoming_streams =
1039 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1040 static_cast<uint32_t>(max_incoming_streams_to_send *
1041 kMaxStreamsMultiplier));
1042 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1043 }
1044
1045 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1046 // Streams which were created before the SHLO was received (0-RTT
1047 // requests) are now informed of the peer's initial flow control window.
1048 OnNewStreamFlowControlWindow(
1049 config_.ReceivedInitialStreamFlowControlWindowBytes());
1050 }
1051 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1052 OnNewSessionFlowControlWindow(
1053 config_.ReceivedInitialSessionFlowControlWindowBytes());
1054 }
fkastenholz9b4b0ad2019-08-20 05:10:40 -07001055 is_configured_ = true;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001056}
1057
1058void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1059 const float session_window_multiplier =
1060 config_.GetInitialStreamFlowControlWindowToSend()
1061 ? static_cast<float>(
1062 config_.GetInitialSessionFlowControlWindowToSend()) /
1063 config_.GetInitialStreamFlowControlWindowToSend()
1064 : 1.5;
1065
1066 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1067 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1068
1069 size_t session_window = session_window_multiplier * stream_window;
1070 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1071 << session_window;
1072 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1073 flow_controller_.UpdateReceiveWindowSize(session_window);
1074 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001075 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001076 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1077 }
renjietangb663b862019-07-08 16:02:39 -07001078 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001079 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1080 stream_window);
1081 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001082}
1083
1084void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1085 QuicStreamId stream_id) {
1086 DCHECK(!IsClosedStream(stream_id));
1087 // Received a frame for a locally-created stream that is not currently
1088 // active. This is an error.
1089 connection()->CloseConnection(
1090 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1091 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1092}
1093
1094void QuicSession::HandleRstOnValidNonexistentStream(
1095 const QuicRstStreamFrame& frame) {
1096 // If the stream is neither originally in active streams nor created in
renjietang880d2432019-07-16 13:14:37 -07001097 // GetOrCreateStream(), it could be a closed stream in which case its
QUICHE teama6ef0a62019-03-07 20:34:33 -05001098 // final received byte offset need to be updated.
1099 if (IsClosedStream(frame.stream_id)) {
1100 // The RST frame contains the final byte offset for the stream: we can now
1101 // update the connection level flow controller if needed.
1102 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1103 }
1104}
1105
1106void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001107 if (new_window < kMinimumFlowControlSendWindow &&
1108 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001109 QUIC_LOG_FIRST_N(ERROR, 1)
1110 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001111 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001112 if (connection_->connected()) {
1113 connection_->CloseConnection(
1114 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1115 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1116 }
1117 return;
1118 }
1119
1120 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001121 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001122 kv.second->UpdateSendWindowOffset(new_window);
1123 }
renjietangb663b862019-07-08 16:02:39 -07001124 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001125 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1126 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001127}
1128
1129void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001130 if (new_window < kMinimumFlowControlSendWindow &&
1131 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001132 QUIC_LOG_FIRST_N(ERROR, 1)
1133 << "Peer sent us an invalid session flow control send window: "
1134 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1135 if (connection_->connected()) {
1136 connection_->CloseConnection(
1137 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1138 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1139 }
1140 return;
1141 }
1142
1143 flow_controller_.UpdateSendWindowOffset(new_window);
1144}
1145
1146void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1147 switch (event) {
renjietangea71d6f2019-08-19 12:22:28 -07001148 case ENCRYPTION_ESTABLISHED:
QUICHE teama6ef0a62019-03-07 20:34:33 -05001149 // Retransmit originally packets that were sent, since they can't be
1150 // decrypted by the peer.
1151 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1152 // Given any streams blocked by encryption a chance to write.
1153 OnCanWrite();
1154 break;
1155
1156 case HANDSHAKE_CONFIRMED:
1157 QUIC_BUG_IF(!config_.negotiated())
1158 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1159 // Discard originally encrypted packets, since they can't be decrypted by
1160 // the peer.
1161 NeuterUnencryptedData();
1162 is_handshake_confirmed_ = true;
1163 break;
1164
1165 default:
1166 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1167 }
1168}
1169
1170void QuicSession::OnCryptoHandshakeMessageSent(
1171 const CryptoHandshakeMessage& /*message*/) {}
1172
1173void QuicSession::OnCryptoHandshakeMessageReceived(
1174 const CryptoHandshakeMessage& /*message*/) {}
1175
fayang476683a2019-07-25 12:42:16 -07001176void QuicSession::RegisterStreamPriority(
1177 QuicStreamId id,
1178 bool is_static,
1179 const spdy::SpdyStreamPrecedence& precedence) {
1180 write_blocked_streams()->RegisterStream(id, is_static, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001181}
1182
1183void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1184 write_blocked_streams()->UnregisterStream(id, is_static);
1185}
1186
fayang476683a2019-07-25 12:42:16 -07001187void QuicSession::UpdateStreamPriority(
1188 QuicStreamId id,
1189 const spdy::SpdyStreamPrecedence& new_precedence) {
1190 write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001191}
1192
1193QuicConfig* QuicSession::config() {
1194 return &config_;
1195}
1196
1197void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001198 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001199 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -07001200 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001201 << ". activating " << stream_id;
renjietang55d182a2019-07-12 10:26:25 -07001202 DCHECK(!QuicContainsKey(stream_map_, stream_id));
1203 stream_map_[stream_id] = std::move(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001204 if (IsIncomingStream(stream_id)) {
1205 ++num_dynamic_incoming_streams_;
1206 }
1207}
1208
1209QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001210 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001211 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1212 }
1213 return stream_id_manager_.GetNextOutgoingStreamId();
1214}
1215
1216QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001217 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001218 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1219 }
1220 return stream_id_manager_.GetNextOutgoingStreamId();
1221}
1222
1223bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001224 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001225 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1226 }
1227 return stream_id_manager_.CanOpenNextOutgoingStream(
1228 GetNumOpenOutgoingStreams());
1229}
1230
1231bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001232 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001233 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1234 }
1235 return stream_id_manager_.CanOpenNextOutgoingStream(
1236 GetNumOpenOutgoingStreams());
1237}
1238
1239QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang28c04b72019-07-01 15:08:09 -07001240 DCHECK(!QuicContainsKey(pending_stream_map_, stream_id));
renjietangb663b862019-07-08 16:02:39 -07001241 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -07001242 stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001243 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001244 }
renjietang880d2432019-07-16 13:14:37 -07001245
1246 StreamMap::iterator it = stream_map_.find(stream_id);
1247 if (it != stream_map_.end()) {
1248 return it->second.get();
1249 }
1250
1251 if (IsClosedStream(stream_id)) {
1252 return nullptr;
1253 }
1254
1255 if (!IsIncomingStream(stream_id)) {
1256 HandleFrameOnNonexistentOutgoingStream(stream_id);
1257 return nullptr;
1258 }
1259
1260 // TODO(fkastenholz): If we are creating a new stream and we have
1261 // sent a goaway, we should ignore the stream creation. Need to
1262 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1263 // B) reject stream creation ("return nullptr")
1264
1265 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
1266 return nullptr;
1267 }
1268
1269 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
1270 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1271 // CanOpenIncomingStream interface consistent with that of v99.
1272 if (!stream_id_manager_.CanOpenIncomingStream(
1273 GetNumOpenIncomingStreams())) {
1274 // Refuse to open the stream.
1275 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
1276 return nullptr;
1277 }
1278 }
1279
1280 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001281}
1282
1283void QuicSession::StreamDraining(QuicStreamId stream_id) {
renjietang55d182a2019-07-12 10:26:25 -07001284 DCHECK(QuicContainsKey(stream_map_, stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001285 if (!QuicContainsKey(draining_streams_, stream_id)) {
1286 draining_streams_.insert(stream_id);
1287 if (IsIncomingStream(stream_id)) {
1288 ++num_draining_incoming_streams_;
1289 }
fkastenholz305e1732019-06-18 05:01:22 -07001290 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001291 v99_streamid_manager_.OnStreamClosed(stream_id);
1292 }
1293 }
1294 if (!IsIncomingStream(stream_id)) {
1295 // Inform application that a stream is available.
fkastenholz8556dc22019-07-18 12:42:38 -07001296 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietangde12d3d2019-07-19 10:57:42 -07001297 OnCanCreateNewOutgoingStream(
1298 !QuicUtils::IsBidirectionalStreamId(stream_id));
fkastenholz8556dc22019-07-18 12:42:38 -07001299 } else {
renjietangde12d3d2019-07-19 10:57:42 -07001300 QuicStream* stream = GetStream(stream_id);
1301 if (!stream) {
1302 QUIC_BUG << "Stream doesn't exist when draining.";
1303 return;
1304 }
1305 OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL);
fkastenholz8556dc22019-07-18 12:42:38 -07001306 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001307 }
1308}
1309
1310bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1311 const QuicStreamId stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001312 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001313 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1314 }
1315 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1316}
1317
1318bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1319 if (stream_id == currently_writing_stream_id_) {
1320 return false;
1321 }
1322 return write_blocked_streams()->ShouldYield(stream_id);
1323}
1324
renjietange76b2da2019-05-13 14:50:23 -07001325PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1326 auto it = pending_stream_map_.find(stream_id);
1327 if (it != pending_stream_map_.end()) {
1328 return it->second.get();
1329 }
1330
1331 if (IsClosedStream(stream_id) ||
1332 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1333 return nullptr;
1334 }
1335
1336 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1337 PendingStream* unowned_pending = pending.get();
1338 pending_stream_map_[stream_id] = std::move(pending);
1339 return unowned_pending;
1340}
1341
QUICHE teama6ef0a62019-03-07 20:34:33 -05001342QuicStream* QuicSession::GetOrCreateDynamicStream(
1343 const QuicStreamId stream_id) {
renjietangb035f152019-08-06 11:32:51 -07001344 DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream) ||
1345 !GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream));
renjietang55d182a2019-07-12 10:26:25 -07001346 StreamMap::iterator it = stream_map_.find(stream_id);
1347 if (it != stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001348 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001349 }
1350
1351 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001352 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001353 }
1354
1355 if (!IsIncomingStream(stream_id)) {
1356 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001357 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001358 }
1359
QUICHE teama6ef0a62019-03-07 20:34:33 -05001360 // TODO(fkastenholz): If we are creating a new stream and we have
1361 // sent a goaway, we should ignore the stream creation. Need to
1362 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1363 // B) reject stream creation ("return nullptr")
1364
1365 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001366 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001367 }
1368
fkastenholz305e1732019-06-18 05:01:22 -07001369 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001370 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1371 // CanOpenIncomingStream interface cosistent with that of v99.
1372 if (!stream_id_manager_.CanOpenIncomingStream(
1373 GetNumOpenIncomingStreams())) {
1374 // Refuse to open the stream.
1375 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001376 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001377 }
1378 }
1379
renjietang2c4d7122019-05-20 17:18:14 -07001380 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001381}
1382
1383void QuicSession::set_largest_peer_created_stream_id(
1384 QuicStreamId largest_peer_created_stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001385 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001386 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1387 largest_peer_created_stream_id);
1388 return;
1389 }
1390 stream_id_manager_.set_largest_peer_created_stream_id(
1391 largest_peer_created_stream_id);
1392}
1393
1394bool QuicSession::IsClosedStream(QuicStreamId id) {
1395 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1396 id);
1397 if (IsOpenStream(id)) {
1398 // Stream is active
1399 return false;
1400 }
1401
fkastenholz305e1732019-06-18 05:01:22 -07001402 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001403 return !v99_streamid_manager_.IsAvailableStream(id);
1404 }
1405
1406 return !stream_id_manager_.IsAvailableStream(id);
1407}
1408
1409bool QuicSession::IsOpenStream(QuicStreamId id) {
1410 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1411 id);
renjietang55d182a2019-07-12 10:26:25 -07001412 if (QuicContainsKey(stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001413 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001414 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001415 // Stream is active
1416 return true;
1417 }
1418 return false;
1419}
1420
rchda26cdb2019-05-17 11:57:37 -07001421bool QuicSession::IsStaticStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001422 auto it = stream_map_.find(id);
1423 if (it == stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -07001424 return false;
rchda26cdb2019-05-17 11:57:37 -07001425 }
renjietangb663b862019-07-08 16:02:39 -07001426 return it->second->is_static();
rchda26cdb2019-05-17 11:57:37 -07001427}
1428
QUICHE teama6ef0a62019-03-07 20:34:33 -05001429size_t QuicSession::GetNumOpenIncomingStreams() const {
1430 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1431 num_locally_closed_incoming_streams_highest_offset_;
1432}
1433
1434size_t QuicSession::GetNumOpenOutgoingStreams() const {
1435 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1436 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1437 GetNumDrainingOutgoingStreams());
1438 return GetNumDynamicOutgoingStreams() +
1439 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1440 GetNumDrainingOutgoingStreams();
1441}
1442
1443size_t QuicSession::GetNumActiveStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001444 return stream_map_.size() - draining_streams_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001445 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001446}
1447
1448size_t QuicSession::GetNumDrainingStreams() const {
1449 return draining_streams_.size();
1450}
1451
1452void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1453 if (GetOrCreateStream(id) == nullptr) {
1454 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1455 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1456 }
1457
1458 write_blocked_streams_.AddStream(id);
1459}
1460
1461bool QuicSession::HasDataToWrite() const {
1462 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1463 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1464 connection_->HasQueuedData() ||
1465 !streams_with_pending_retransmission_.empty() ||
1466 control_frame_manager_.WillingToWrite();
1467}
1468
1469void QuicSession::OnAckNeedsRetransmittableFrame() {
1470 flow_controller_.SendWindowUpdate();
1471}
1472
1473void QuicSession::SendPing() {
1474 control_frame_manager_.WritePing();
1475}
1476
1477size_t QuicSession::GetNumDynamicOutgoingStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001478 DCHECK_GE(
1479 static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()),
1480 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1481 num_incoming_static_streams_);
1482 return stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001483 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1484 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001485}
1486
1487size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1488 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1489 return draining_streams_.size() - num_draining_incoming_streams_;
1490}
1491
1492size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1493 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1494 num_locally_closed_incoming_streams_highest_offset_);
1495 return locally_closed_streams_highest_offset_.size() -
1496 num_locally_closed_incoming_streams_highest_offset_;
1497}
1498
1499bool QuicSession::IsConnectionFlowControlBlocked() const {
1500 return flow_controller_.IsBlocked();
1501}
1502
1503bool QuicSession::IsStreamFlowControlBlocked() {
renjietang55d182a2019-07-12 10:26:25 -07001504 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001505 if (kv.second->flow_controller()->IsBlocked()) {
1506 return true;
1507 }
1508 }
renjietangb663b862019-07-08 16:02:39 -07001509 if (!QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001510 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
renjietang08a9cf72019-04-23 17:01:34 -07001511 return true;
1512 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001513 return false;
1514}
1515
1516size_t QuicSession::MaxAvailableBidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001517 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001518 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1519 }
1520 return stream_id_manager_.MaxAvailableStreams();
1521}
1522
1523size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001524 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001525 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1526 }
1527 return stream_id_manager_.MaxAvailableStreams();
1528}
1529
1530bool QuicSession::IsIncomingStream(QuicStreamId id) const {
fkastenholz305e1732019-06-18 05:01:22 -07001531 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001532 return v99_streamid_manager_.IsIncomingStream(id);
1533 }
1534 return stream_id_manager_.IsIncomingStream(id);
1535}
1536
1537void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
zhongyi1b2f7832019-06-14 13:31:34 -07001538 if (ignore_tlpr_if_no_pending_stream_data() &&
1539 session_decides_what_to_write()) {
1540 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 3,
1541 5);
1542 streams_waiting_for_acks_.erase(id);
1543 }
1544
QUICHE teama6ef0a62019-03-07 20:34:33 -05001545 auto it = zombie_streams_.find(id);
1546 if (it == zombie_streams_.end()) {
1547 return;
1548 }
1549
1550 closed_streams_.push_back(std::move(it->second));
1551 if (!closed_streams_clean_up_alarm_->IsSet()) {
1552 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1553 }
1554 zombie_streams_.erase(it);
1555 // Do not retransmit data of a closed stream.
1556 streams_with_pending_retransmission_.erase(id);
1557}
1558
zhongyi1b2f7832019-06-14 13:31:34 -07001559void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) {
1560 if (!ignore_tlpr_if_no_pending_stream_data() ||
1561 !session_decides_what_to_write())
1562 return;
1563
1564 // Exclude crypto stream's status since it is counted in HasUnackedCryptoData.
1565 if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) {
1566 return;
1567 }
1568
1569 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 4,
1570 5);
1571 streams_waiting_for_acks_.insert(id);
1572
1573 // The number of the streams waiting for acks should not be larger than the
1574 // number of streams.
renjietang55d182a2019-07-12 10:26:25 -07001575 if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) <
zhongyi71e9d9e2019-06-14 14:57:16 -07001576 streams_waiting_for_acks_.size()) {
zhongyi1b2f7832019-06-14 13:31:34 -07001577 QUIC_BUG << "More streams are waiting for acks than the number of streams. "
renjietang55d182a2019-07-12 10:26:25 -07001578 << "Sizes: streams: " << stream_map_.size()
zhongyi1b2f7832019-06-14 13:31:34 -07001579 << ", zombie streams: " << zombie_streams_.size()
1580 << ", vs streams waiting for acks: "
1581 << streams_waiting_for_acks_.size();
1582 }
1583}
1584
QUICHE teama6ef0a62019-03-07 20:34:33 -05001585QuicStream* QuicSession::GetStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001586 auto active_stream = stream_map_.find(id);
1587 if (active_stream != stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001588 return active_stream->second.get();
1589 }
1590 auto zombie_stream = zombie_streams_.find(id);
1591 if (zombie_stream != zombie_streams_.end()) {
1592 return zombie_stream->second.get();
1593 }
renjietang08a9cf72019-04-23 17:01:34 -07001594
renjietangb663b862019-07-08 16:02:39 -07001595 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
renjietang08a9cf72019-04-23 17:01:34 -07001596 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1597 }
1598
QUICHE teama6ef0a62019-03-07 20:34:33 -05001599 return nullptr;
1600}
1601
1602bool QuicSession::OnFrameAcked(const QuicFrame& frame,
QUICHE team9467db02019-05-30 09:38:45 -07001603 QuicTime::Delta ack_delay_time,
1604 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001605 if (frame.type == MESSAGE_FRAME) {
QUICHE team9467db02019-05-30 09:38:45 -07001606 OnMessageAcked(frame.message_frame->message_id, receive_timestamp);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001607 return true;
1608 }
1609 if (frame.type == CRYPTO_FRAME) {
1610 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1611 ack_delay_time);
1612 }
1613 if (frame.type != STREAM_FRAME) {
1614 return control_frame_manager_.OnControlFrameAcked(frame);
1615 }
1616 bool new_stream_data_acked = false;
1617 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1618 // Stream can already be reset when sent frame gets acked.
1619 if (stream != nullptr) {
1620 QuicByteCount newly_acked_length = 0;
1621 new_stream_data_acked = stream->OnStreamFrameAcked(
1622 frame.stream_frame.offset, frame.stream_frame.data_length,
1623 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1624 if (!stream->HasPendingRetransmission()) {
1625 streams_with_pending_retransmission_.erase(stream->id());
1626 }
1627 }
1628 return new_stream_data_acked;
1629}
1630
1631void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1632 QuicStream* stream = GetStream(frame.stream_id);
1633 if (stream == nullptr) {
1634 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1635 << " is retransmitted.";
1636 connection()->CloseConnection(
1637 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1638 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1639 return;
1640 }
1641 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1642 frame.fin);
1643}
1644
1645void QuicSession::OnFrameLost(const QuicFrame& frame) {
1646 if (frame.type == MESSAGE_FRAME) {
1647 OnMessageLost(frame.message_frame->message_id);
1648 return;
1649 }
1650 if (frame.type == CRYPTO_FRAME) {
1651 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1652 return;
1653 }
1654 if (frame.type != STREAM_FRAME) {
1655 control_frame_manager_.OnControlFrameLost(frame);
1656 return;
1657 }
1658 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1659 if (stream == nullptr) {
1660 return;
1661 }
1662 stream->OnStreamFrameLost(frame.stream_frame.offset,
1663 frame.stream_frame.data_length,
1664 frame.stream_frame.fin);
1665 if (stream->HasPendingRetransmission() &&
1666 !QuicContainsKey(streams_with_pending_retransmission_,
1667 frame.stream_frame.stream_id)) {
1668 streams_with_pending_retransmission_.insert(
1669 std::make_pair(frame.stream_frame.stream_id, true));
1670 }
1671}
1672
1673void QuicSession::RetransmitFrames(const QuicFrames& frames,
1674 TransmissionType type) {
fayanga4b37b22019-06-18 13:37:47 -07001675 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001676 SetTransmissionType(type);
1677 for (const QuicFrame& frame : frames) {
1678 if (frame.type == MESSAGE_FRAME) {
1679 // Do not retransmit MESSAGE frames.
1680 continue;
1681 }
1682 if (frame.type == CRYPTO_FRAME) {
1683 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1684 continue;
1685 }
1686 if (frame.type != STREAM_FRAME) {
1687 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1688 break;
1689 }
1690 continue;
1691 }
1692 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1693 if (stream != nullptr &&
1694 !stream->RetransmitStreamData(frame.stream_frame.offset,
1695 frame.stream_frame.data_length,
1696 frame.stream_frame.fin)) {
1697 break;
1698 }
1699 }
1700}
1701
1702bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1703 if (frame.type == MESSAGE_FRAME) {
1704 return false;
1705 }
1706 if (frame.type == CRYPTO_FRAME) {
1707 return GetCryptoStream()->IsFrameOutstanding(
1708 frame.crypto_frame->level, frame.crypto_frame->offset,
1709 frame.crypto_frame->data_length);
1710 }
1711 if (frame.type != STREAM_FRAME) {
1712 return control_frame_manager_.IsControlFrameOutstanding(frame);
1713 }
1714 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1715 return stream != nullptr &&
1716 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1717 frame.stream_frame.data_length,
1718 frame.stream_frame.fin);
1719}
1720
1721bool QuicSession::HasUnackedCryptoData() const {
1722 const QuicCryptoStream* crypto_stream = GetCryptoStream();
fayang44fa92f2019-07-01 07:32:14 -07001723 return crypto_stream->IsWaitingForAcks() || crypto_stream->HasBufferedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001724}
1725
zhongyi1b2f7832019-06-14 13:31:34 -07001726bool QuicSession::HasUnackedStreamData() const {
1727 DCHECK(ignore_tlpr_if_no_pending_stream_data());
1728 if (ignore_tlpr_if_no_pending_stream_data()) {
1729 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 5,
1730 5);
1731 return !streams_waiting_for_acks_.empty();
1732 }
1733
1734 return true;
1735}
1736
QUICHE teama6ef0a62019-03-07 20:34:33 -05001737WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1738 QuicStreamOffset offset,
1739 QuicByteCount data_length,
1740 QuicDataWriter* writer) {
1741 QuicStream* stream = GetStream(id);
1742 if (stream == nullptr) {
1743 // This causes the connection to be closed because of failed to serialize
1744 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001745 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1746 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001747 return STREAM_MISSING;
1748 }
1749 if (stream->WriteStreamData(offset, data_length, writer)) {
1750 return WRITE_SUCCESS;
1751 }
1752 return WRITE_FAILED;
1753}
1754
1755bool QuicSession::WriteCryptoData(EncryptionLevel level,
1756 QuicStreamOffset offset,
1757 QuicByteCount data_length,
1758 QuicDataWriter* writer) {
1759 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1760 writer);
1761}
1762
1763QuicUint128 QuicSession::GetStatelessResetToken() const {
1764 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1765}
1766
1767bool QuicSession::RetransmitLostData() {
fayanga4b37b22019-06-18 13:37:47 -07001768 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001769 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001770 bool uses_crypto_frames =
1771 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001772 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1773 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1774 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1775 crypto_stream->WritePendingCryptoRetransmission();
1776 }
1777 // Retransmit crypto data in stream 1 frames (version < 47).
1778 if (!uses_crypto_frames &&
1779 QuicContainsKey(
1780 streams_with_pending_retransmission_,
1781 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1782 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1783 // Retransmit crypto data first.
1784 QuicStream* crypto_stream = GetStream(
1785 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1786 crypto_stream->OnCanWrite();
1787 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1788 if (crypto_stream->HasPendingRetransmission()) {
1789 // Connection is write blocked.
1790 return false;
1791 } else {
1792 streams_with_pending_retransmission_.erase(
1793 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1794 }
1795 }
1796 if (control_frame_manager_.HasPendingRetransmission()) {
1797 SetTransmissionType(LOSS_RETRANSMISSION);
1798 control_frame_manager_.OnCanWrite();
1799 if (control_frame_manager_.HasPendingRetransmission()) {
1800 return false;
1801 }
1802 }
1803 while (!streams_with_pending_retransmission_.empty()) {
1804 if (!connection_->CanWriteStreamData()) {
1805 break;
1806 }
1807 // Retransmit lost data on headers and data streams.
1808 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1809 QuicStream* stream = GetStream(id);
1810 if (stream != nullptr) {
1811 SetTransmissionType(LOSS_RETRANSMISSION);
1812 stream->OnCanWrite();
1813 DCHECK(CheckStreamWriteBlocked(stream));
1814 if (stream->HasPendingRetransmission()) {
1815 // Connection is write blocked.
1816 break;
1817 } else if (!streams_with_pending_retransmission_.empty() &&
1818 streams_with_pending_retransmission_.begin()->first == id) {
1819 // Retransmit lost data may cause connection close. If this stream
1820 // has not yet sent fin, a RST_STREAM will be sent and it will be
1821 // removed from streams_with_pending_retransmission_.
1822 streams_with_pending_retransmission_.pop_front();
1823 }
1824 } else {
1825 QUIC_BUG << "Try to retransmit data of a closed stream";
1826 streams_with_pending_retransmission_.pop_front();
1827 }
1828 }
1829
1830 return streams_with_pending_retransmission_.empty();
1831}
1832
1833void QuicSession::NeuterUnencryptedData() {
1834 if (connection_->session_decides_what_to_write()) {
1835 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1836 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001837 if (!crypto_stream->HasPendingRetransmission() &&
1838 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001839 streams_with_pending_retransmission_.erase(
1840 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1841 }
1842 }
1843 connection_->NeuterUnencryptedPackets();
1844}
1845
1846void QuicSession::SetTransmissionType(TransmissionType type) {
1847 connection_->SetTransmissionType(type);
1848}
1849
1850MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1851 if (!IsEncryptionEstablished()) {
1852 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1853 }
1854 MessageStatus result =
1855 connection_->SendMessage(last_message_id_ + 1, message);
1856 if (result == MESSAGE_STATUS_SUCCESS) {
1857 return {result, ++last_message_id_};
1858 }
1859 return {result, 0};
1860}
1861
QUICHE team9467db02019-05-30 09:38:45 -07001862void QuicSession::OnMessageAcked(QuicMessageId message_id,
dschinazi17d42422019-06-18 16:35:07 -07001863 QuicTime /*receive_timestamp*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001864 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1865}
1866
1867void QuicSession::OnMessageLost(QuicMessageId message_id) {
1868 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1869 << " is considered lost";
1870}
1871
1872void QuicSession::CleanUpClosedStreams() {
1873 closed_streams_.clear();
1874}
1875
1876bool QuicSession::session_decides_what_to_write() const {
1877 return connection_->session_decides_what_to_write();
1878}
1879
ianswettb239f862019-04-05 09:15:06 -07001880QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1881 return connection_->GetCurrentLargestMessagePayload();
1882}
1883
1884QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1885 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001886}
1887
1888void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1889 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1890}
1891
fkastenholz8556dc22019-07-18 12:42:38 -07001892void QuicSession::OnCanCreateNewOutgoingStream(bool /*unidirectional*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -05001893
1894QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001895 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001896 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1897 }
1898 return stream_id_manager_.next_outgoing_stream_id();
1899}
1900
1901QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001902 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001903 return v99_streamid_manager_.next_outgoing_unidirectional_stream_id();
1904 }
1905 return stream_id_manager_.next_outgoing_stream_id();
1906}
1907
fkastenholz3c4eabf2019-04-22 07:49:59 -07001908bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1909 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001910}
1911
fkastenholz3c4eabf2019-04-22 07:49:59 -07001912bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1913 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001914}
1915
1916size_t QuicSession::max_open_incoming_bidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001917 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001918 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1919 }
1920 return stream_id_manager_.max_open_incoming_streams();
1921}
1922
1923size_t QuicSession::max_open_incoming_unidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001924 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001925 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1926 }
1927 return stream_id_manager_.max_open_incoming_streams();
1928}
1929
1930#undef ENDPOINT // undef for jumbo builds
1931} // namespace quic