blob: ba53d5e03fcbf6acda92498503161b6c6ac4fbf2 [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);
165 }
renjietange76b2da2019-05-13 14:50:23 -0700166}
167
QUICHE teama6ef0a62019-03-07 20:34:33 -0500168void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
169 // TODO(rch) deal with the error case of stream id 0.
170 QuicStreamId stream_id = frame.stream_id;
171 if (stream_id ==
172 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
173 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700174 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500175 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
176 return;
177 }
178
bnc36c47282019-06-21 05:17:59 -0700179 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700180 QuicUtils::GetStreamType(stream_id, perspective(),
181 IsIncomingStream(stream_id)) ==
182 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700183 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700184 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500185 return;
186 }
187
renjietang2c4d7122019-05-20 17:18:14 -0700188 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700189
renjietang2c4d7122019-05-20 17:18:14 -0700190 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500191 // The stream no longer exists, but we may still be interested in the
192 // final stream byte offset sent by the peer. A frame with a FIN can give
193 // us this offset.
194 if (frame.fin) {
195 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
196 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
197 }
198 return;
199 }
renjietangb663b862019-07-08 16:02:39 -0700200 if (frame.fin && stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700201 connection()->CloseConnection(
202 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
203 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
204 return;
205 }
renjietang2c4d7122019-05-20 17:18:14 -0700206 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500207}
208
209void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
210 GetMutableCryptoStream()->OnCryptoFrame(frame);
211}
212
213bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
214 // We are not version 99. In theory, if not in version 99 then the framer
215 // could not call OnStopSending... This is just a check that is good when
216 // both a new protocol and a new implementation of that protocol are both
217 // being developed.
fkastenholz305e1732019-06-18 05:01:22 -0700218 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500219
220 QuicStreamId stream_id = frame.stream_id;
221 // If Stream ID is invalid then close the connection.
222 if (stream_id ==
223 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
224 QUIC_DVLOG(1) << ENDPOINT
225 << "Received STOP_SENDING with invalid stream_id: "
226 << stream_id << " Closing connection";
227 connection()->CloseConnection(
228 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
229 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
230 return false;
231 }
232
233 // Ignore STOP_SENDING for static streams.
234 // TODO(fkastenholz): IETF Quic does not have static streams and does not
235 // make exceptions for them with respect to processing things like
236 // STOP_SENDING.
renjietang0e9980b2019-07-11 12:00:21 -0700237 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -0700238 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500239 QUIC_DVLOG(1) << ENDPOINT
240 << "Received STOP_SENDING for a static stream, id: "
241 << stream_id << " Closing connection";
242 connection()->CloseConnection(
243 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
244 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
245 return false;
246 }
247
248 if (visitor_) {
249 visitor_->OnStopSendingReceived(frame);
250 }
251
252 // If stream is closed, ignore the frame
253 if (IsClosedStream(stream_id)) {
254 QUIC_DVLOG(1)
255 << ENDPOINT
256 << "Received STOP_SENDING for closed or non-existent stream, id: "
257 << stream_id << " Ignoring.";
258 return true; // Continue processing the packet.
259 }
260 // If stream is non-existent, close the connection
renjietang55d182a2019-07-12 10:26:25 -0700261 StreamMap::iterator it = stream_map_.find(stream_id);
262 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500263 QUIC_DVLOG(1) << ENDPOINT
264 << "Received STOP_SENDING for non-existent stream, id: "
265 << stream_id << " Closing connection";
266 connection()->CloseConnection(
267 IETF_QUIC_PROTOCOL_VIOLATION,
268 "Received STOP_SENDING for a non-existent stream",
269 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
270 return false;
271 }
272
273 // Get the QuicStream for this stream. Ignore the STOP_SENDING
274 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700275 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
276 // happen IFF there was an entry in the map, but the pointer is null. sounds
277 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500278 QuicStream* stream = it->second.get();
279 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700280 QUIC_BUG << ENDPOINT
281 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
282 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 return true;
284 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700285
renjietangb663b862019-07-08 16:02:39 -0700286 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700287 QUIC_DVLOG(1) << ENDPOINT
288 << "Received STOP_SENDING for a static stream, id: "
289 << stream_id << " Closing connection";
290 connection()->CloseConnection(
291 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
292 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
293 return false;
294 }
295
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296 stream->OnStopSending(frame.application_error_code);
297
298 stream->set_stream_error(
299 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
300 SendRstStreamInner(
301 stream->id(),
302 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
303 stream->stream_bytes_written(),
304 /*close_write_side_only=*/true);
305
306 return true;
307}
308
renjietange76b2da2019-05-13 14:50:23 -0700309void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700310 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700311 QuicStreamId stream_id = frame.stream_id;
312
313 PendingStream* pending = GetOrCreatePendingStream(stream_id);
314
315 if (!pending) {
316 HandleRstOnValidNonexistentStream(frame);
317 return;
318 }
319
320 pending->OnRstStreamFrame(frame);
321 ClosePendingStream(stream_id);
322}
323
QUICHE teama6ef0a62019-03-07 20:34:33 -0500324void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
325 QuicStreamId stream_id = frame.stream_id;
326 if (stream_id ==
327 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
328 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700329 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500330 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
331 return;
332 }
333
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334 if (visitor_) {
335 visitor_->OnRstStreamReceived(frame);
336 }
337
bnc36c47282019-06-21 05:17:59 -0700338 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700339 QuicUtils::GetStreamType(stream_id, perspective(),
340 IsIncomingStream(stream_id)) ==
341 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700342 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700343 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344 return;
345 }
renjietange76b2da2019-05-13 14:50:23 -0700346
renjietang2c4d7122019-05-20 17:18:14 -0700347 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700348
renjietang2c4d7122019-05-20 17:18:14 -0700349 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 HandleRstOnValidNonexistentStream(frame);
351 return; // Errors are handled by GetOrCreateStream.
352 }
renjietangb663b862019-07-08 16:02:39 -0700353 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700354 connection()->CloseConnection(
355 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
356 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
357 return;
358 }
renjietang2c4d7122019-05-20 17:18:14 -0700359 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500360}
361
dschinazi17d42422019-06-18 16:35:07 -0700362void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500363 goaway_received_ = true;
364}
365
366void QuicSession::OnMessageReceived(QuicStringPiece message) {
367 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
368 << ", " << message;
369}
370
wub2b5942f2019-04-11 13:22:50 -0700371// static
372void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
373 ConnectionCloseSource source) {
374 if (error != QUIC_NO_ERROR) {
375 if (source == ConnectionCloseSource::FROM_SELF) {
376 QUIC_SERVER_HISTOGRAM_ENUM(
377 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
378 "QuicErrorCode for server-closed connections.");
379 } else {
380 QUIC_SERVER_HISTOGRAM_ENUM(
381 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
382 "QuicErrorCode for client-closed connections.");
383 }
384 }
385}
386
fkastenholz5d880a92019-06-21 09:01:56 -0700387void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500388 ConnectionCloseSource source) {
389 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700390 if (perspective() == Perspective::IS_SERVER) {
fkastenholz5d880a92019-06-21 09:01:56 -0700391 RecordConnectionCloseAtServer(frame.quic_error_code, source);
wub2b5942f2019-04-11 13:22:50 -0700392 }
393
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 if (error_ == QUIC_NO_ERROR) {
fkastenholz5d880a92019-06-21 09:01:56 -0700395 error_ = frame.quic_error_code;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500396 }
397
renjietangb663b862019-07-08 16:02:39 -0700398 // Copy all non static streams in a new map for the ease of deleting.
399 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
renjietang55d182a2019-07-12 10:26:25 -0700400 for (const auto& it : stream_map_) {
renjietangb663b862019-07-08 16:02:39 -0700401 if (!it.second->is_static()) {
402 non_static_streams[it.first] = it.second.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700403 }
renjietangb663b862019-07-08 16:02:39 -0700404 }
405 for (const auto& it : non_static_streams) {
406 QuicStreamId id = it.first;
407 it.second->OnConnectionClosed(frame.quic_error_code, source);
renjietang55d182a2019-07-12 10:26:25 -0700408 if (stream_map_.find(id) != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700409 QUIC_BUG << ENDPOINT << "Stream " << id
410 << " failed to close under OnConnectionClosed";
411 CloseStream(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500412 }
413 }
414
415 // Cleanup zombie stream map on connection close.
416 while (!zombie_streams_.empty()) {
417 ZombieStreamMap::iterator it = zombie_streams_.begin();
418 closed_streams_.push_back(std::move(it->second));
419 zombie_streams_.erase(it);
420 }
421
422 closed_streams_clean_up_alarm_->Cancel();
423
424 if (visitor_) {
fkastenholz5d880a92019-06-21 09:01:56 -0700425 visitor_->OnConnectionClosed(connection_->connection_id(),
426 frame.quic_error_code, frame.error_details,
427 source);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500428 }
429}
430
431void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700432 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500433 return;
434 }
435 if (visitor_) {
436 visitor_->OnWriteBlocked(connection_);
437 }
438}
439
440void QuicSession::OnSuccessfulVersionNegotiation(
441 const ParsedQuicVersion& version) {
442 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
443}
444
445void QuicSession::OnConnectivityProbeReceived(
dschinazi17d42422019-06-18 16:35:07 -0700446 const QuicSocketAddress& /*self_address*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500447 const QuicSocketAddress& peer_address) {
448 if (perspective() == Perspective::IS_SERVER) {
449 // Server only sends back a connectivity probe after received a
450 // connectivity probe from a new peer address.
451 connection_->SendConnectivityProbingResponsePacket(peer_address);
452 }
453}
454
455void QuicSession::OnPathDegrading() {}
456
457bool QuicSession::AllowSelfAddressChange() const {
458 return false;
459}
460
461void QuicSession::OnForwardProgressConfirmed() {}
462
463void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
464 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
465 // assume that it still exists.
466 QuicStreamId stream_id = frame.stream_id;
467 if (stream_id ==
468 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
469 // This is a window update that applies to the connection, rather than an
470 // individual stream.
471 QUIC_DLOG(INFO) << ENDPOINT
472 << "Received connection level flow control window "
473 "update with byte offset: "
474 << frame.byte_offset;
475 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
476 return;
477 }
renjietang28c04b72019-07-01 15:08:09 -0700478
479 if (VersionHasIetfQuicFrames(connection_->transport_version()) &&
480 QuicUtils::GetStreamType(stream_id, perspective(),
481 IsIncomingStream(stream_id)) ==
482 READ_UNIDIRECTIONAL) {
483 connection()->CloseConnection(
484 QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM,
485 "WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.",
486 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
487 return;
488 }
489
QUICHE teama6ef0a62019-03-07 20:34:33 -0500490 QuicStream* stream = GetOrCreateStream(stream_id);
491 if (stream != nullptr) {
492 stream->OnWindowUpdateFrame(frame);
493 }
494}
495
496void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
497 // TODO(rjshade): Compare our flow control receive windows for specified
498 // streams: if we have a large window then maybe something
499 // had gone wrong with the flow control accounting.
500 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
501 << frame.stream_id;
502}
503
504bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
505 uint64_t previous_bytes_written,
506 bool previous_fin_sent) {
507 if ( // Stream should not be closed.
508 !stream->write_side_closed() &&
509 // Not connection flow control blocked.
510 !flow_controller_.IsBlocked() &&
511 // Detect lack of forward progress.
512 previous_bytes_written == stream->stream_bytes_written() &&
513 previous_fin_sent == stream->fin_sent()) {
514 stream->set_busy_counter(stream->busy_counter() + 1);
515 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
516 << " stream_bytes_written " << stream->stream_bytes_written()
517 << " fin " << stream->fin_sent() << " count "
518 << stream->busy_counter();
519 // Wait a few iterations before firing, the exact count is
520 // arbitrary, more than a few to cover a few test-only false
521 // positives.
522 if (stream->busy_counter() > 20) {
523 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
524 << " stream_bytes_written "
525 << stream->stream_bytes_written() << " fin "
526 << stream->fin_sent();
527 return false;
528 }
529 } else {
530 stream->set_busy_counter(0);
531 }
532 return true;
533}
534
535bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
536 if (!stream->write_side_closed() && stream->HasBufferedData() &&
537 !stream->flow_controller()->IsBlocked() &&
538 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
539 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
540 << stream->BufferedDataBytes()
541 << " bytes, and is not flow control blocked, "
542 "but it is not in the write block list.";
543 return false;
544 }
545 return true;
546}
547
548void QuicSession::OnCanWrite() {
549 if (!RetransmitLostData()) {
550 // Cannot finish retransmitting lost data, connection is write blocked.
551 QUIC_DVLOG(1) << ENDPOINT
552 << "Cannot finish retransmitting lost data, connection is "
553 "write blocked.";
554 return;
555 }
556 if (session_decides_what_to_write()) {
557 SetTransmissionType(NOT_RETRANSMISSION);
558 }
559 // We limit the number of writes to the number of pending streams. If more
560 // streams become pending, WillingAndAbleToWrite will be true, which will
561 // cause the connection to request resumption before yielding to other
562 // connections.
563 // If we are connection level flow control blocked, then only allow the
564 // crypto and headers streams to try writing as all other streams will be
565 // blocked.
566 size_t num_writes = flow_controller_.IsBlocked()
567 ? write_blocked_streams_.NumBlockedSpecialStreams()
568 : write_blocked_streams_.NumBlockedStreams();
569 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
570 return;
571 }
572
fayanga4b37b22019-06-18 13:37:47 -0700573 QuicConnection::ScopedPacketFlusher flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500574 if (control_frame_manager_.WillingToWrite()) {
575 control_frame_manager_.OnCanWrite();
576 }
577 for (size_t i = 0; i < num_writes; ++i) {
578 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
579 write_blocked_streams_.HasWriteBlockedDataStreams())) {
580 // Writing one stream removed another!? Something's broken.
581 QUIC_BUG << "WriteBlockedStream is missing";
582 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
583 "WriteBlockedStream is missing",
584 ConnectionCloseBehavior::SILENT_CLOSE);
585 return;
586 }
587 if (!connection_->CanWriteStreamData()) {
588 return;
589 }
590 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
591 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
592 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
593 // If the stream can't write all bytes it'll re-add itself to the blocked
594 // list.
595 uint64_t previous_bytes_written = stream->stream_bytes_written();
596 bool previous_fin_sent = stream->fin_sent();
597 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
598 << previous_bytes_written << " fin " << previous_fin_sent;
599 stream->OnCanWrite();
600 DCHECK(CheckStreamWriteBlocked(stream));
601 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
602 previous_fin_sent));
603 }
604 currently_writing_stream_id_ = 0;
605 }
606}
607
QUICHE teamb8343252019-04-29 13:58:01 -0700608bool QuicSession::SendProbingData() {
609 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
610 PROBING_RETRANSMISSION)) {
611 return true;
612 }
613 return false;
614}
615
QUICHE teama6ef0a62019-03-07 20:34:33 -0500616bool QuicSession::WillingAndAbleToWrite() const {
617 // Schedule a write when:
618 // 1) control frame manager has pending or new control frames, or
619 // 2) any stream has pending retransmissions, or
620 // 3) If the crypto or headers streams are blocked, or
621 // 4) connection is not flow control blocked and there are write blocked
622 // streams.
623 return control_frame_manager_.WillingToWrite() ||
624 !streams_with_pending_retransmission_.empty() ||
625 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
626 (!flow_controller_.IsBlocked() &&
627 write_blocked_streams_.HasWriteBlockedDataStreams());
628}
629
630bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700631 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
632 // Writing CRYPTO frames is not subject to flow control, so there can't be
633 // pending data to write, only pending retransmissions.
634 return GetCryptoStream()->HasPendingCryptoRetransmission();
635 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500636 return QuicContainsKey(
637 streams_with_pending_retransmission_,
638 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
639 write_blocked_streams_.IsStreamBlocked(
640 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
641}
642
643uint64_t QuicSession::GetNumOpenDynamicStreams() const {
renjietang55d182a2019-07-12 10:26:25 -0700644 return stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700645 locally_closed_streams_highest_offset_.size() -
646 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500647}
648
649void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
650 const QuicSocketAddress& peer_address,
651 const QuicReceivedPacket& packet) {
652 connection_->ProcessUdpPacket(self_address, peer_address, packet);
653}
654
655QuicConsumedData QuicSession::WritevData(QuicStream* stream,
656 QuicStreamId id,
657 size_t write_length,
658 QuicStreamOffset offset,
659 StreamSendingState state) {
660 // This check is an attempt to deal with potential memory corruption
661 // in which |id| ends up set to 1 (the crypto stream id). If this happen
662 // it might end up resulting in unencrypted stream data being sent.
663 // While this is impossible to avoid given sufficient corruption, this
664 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700665 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500666 stream != GetMutableCryptoStream()) {
667 QUIC_BUG << "Stream id mismatch";
668 connection_->CloseConnection(
669 QUIC_INTERNAL_ERROR,
670 "Non-crypto stream attempted to write data as crypto stream.",
671 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
672 return QuicConsumedData(0, false);
673 }
674 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700675 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500676 // Do not let streams write without encryption. The calling stream will end
677 // up write blocked until OnCanWrite is next called.
678 return QuicConsumedData(0, false);
679 }
680
681 QuicConsumedData data =
682 connection_->SendStreamData(id, write_length, offset, state);
683 if (offset >= stream->stream_bytes_written()) {
684 // This is new stream data.
685 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
686 }
687 return data;
688}
689
690bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
691 return connection_->SendControlFrame(frame);
692}
693
694void QuicSession::SendRstStream(QuicStreamId id,
695 QuicRstStreamErrorCode error,
696 QuicStreamOffset bytes_written) {
697 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
698}
699
700void QuicSession::SendRstStreamInner(QuicStreamId id,
701 QuicRstStreamErrorCode error,
702 QuicStreamOffset bytes_written,
703 bool close_write_side_only) {
704 if (connection()->connected()) {
705 // Only send if still connected.
706 if (close_write_side_only) {
fkastenholz305e1732019-06-18 05:01:22 -0700707 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500708 // Send a RST_STREAM frame.
709 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
710 } else {
711 // Send a RST_STREAM frame plus, if version 99, an IETF
712 // QUIC STOP_SENDING frame. Both sre sent to emulate
713 // the two-way close that Google QUIC's RST_STREAM does.
fkastenholz305e1732019-06-18 05:01:22 -0700714 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fayanga4b37b22019-06-18 13:37:47 -0700715 QuicConnection::ScopedPacketFlusher flusher(connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500716 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
717 control_frame_manager_.WriteOrBufferStopSending(error, id);
718 } else {
719 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
720 }
721 }
722 connection_->OnStreamReset(id, error);
723 }
724 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
725 OnStreamDoneWaitingForAcks(id);
726 return;
727 }
728
729 if (!close_write_side_only) {
730 CloseStreamInner(id, true);
731 return;
732 }
fkastenholz305e1732019-06-18 05:01:22 -0700733 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500734
renjietang55d182a2019-07-12 10:26:25 -0700735 StreamMap::iterator it = stream_map_.find(id);
736 if (it != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700737 if (it->second->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700738 QUIC_DVLOG(1) << ENDPOINT
739 << "Try to send rst for a static stream, id: " << id
740 << " Closing connection";
741 connection()->CloseConnection(
742 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
743 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
744 return;
745 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500746 QuicStream* stream = it->second.get();
747 if (stream) {
748 stream->set_rst_sent(true);
749 stream->CloseWriteSide();
750 }
751 }
752}
753
754void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700755 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500756 // GOAWAY frame is not supported in v99.
fkastenholz305e1732019-06-18 05:01:22 -0700757 DCHECK(!VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500758 if (goaway_sent_) {
759 return;
760 }
761 goaway_sent_ = true;
762 control_frame_manager_.WriteOrBufferGoAway(
763 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
764}
765
766void QuicSession::SendBlocked(QuicStreamId id) {
767 control_frame_manager_.WriteOrBufferBlocked(id);
768}
769
770void QuicSession::SendWindowUpdate(QuicStreamId id,
771 QuicStreamOffset byte_offset) {
772 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
773}
774
fkastenholz3c4eabf2019-04-22 07:49:59 -0700775void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
776 bool unidirectional) {
777 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500778}
779
fkastenholz3c4eabf2019-04-22 07:49:59 -0700780void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
781 bool unidirectional) {
782 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
783 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500784}
785
786void QuicSession::CloseStream(QuicStreamId stream_id) {
787 CloseStreamInner(stream_id, false);
788}
789
790void QuicSession::InsertLocallyClosedStreamsHighestOffset(
791 const QuicStreamId id,
792 QuicStreamOffset offset) {
793 locally_closed_streams_highest_offset_[id] = offset;
794 if (IsIncomingStream(id)) {
795 ++num_locally_closed_incoming_streams_highest_offset_;
796 }
797}
798
799void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
800 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
801
renjietang55d182a2019-07-12 10:26:25 -0700802 StreamMap::iterator it = stream_map_.find(stream_id);
803 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500804 // When CloseStreamInner has been called recursively (via
805 // QuicStream::OnClose), the stream will already have been deleted
806 // from stream_map_, so return immediately.
807 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
808 return;
809 }
810 QuicStream* stream = it->second.get();
renjietangb663b862019-07-08 16:02:39 -0700811 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700812 QUIC_DVLOG(1) << ENDPOINT
813 << "Try to close a static stream, id: " << stream_id
814 << " Closing connection";
815 connection()->CloseConnection(
816 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
817 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
818 return;
819 }
renjietangde12d3d2019-07-19 10:57:42 -0700820 StreamType type = stream->type();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500821
822 // Tell the stream that a RST has been sent.
823 if (locally_reset) {
824 stream->set_rst_sent(true);
825 }
826
827 if (stream->IsWaitingForAcks()) {
828 zombie_streams_[stream->id()] = std::move(it->second);
829 } else {
zhongyi1b2f7832019-06-14 13:31:34 -0700830 // Clean up the stream since it is no longer waiting for acks.
831 if (ignore_tlpr_if_no_pending_stream_data() &&
832 session_decides_what_to_write()) {
833 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data,
834 2, 5);
835 streams_waiting_for_acks_.erase(stream->id());
836 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500837 closed_streams_.push_back(std::move(it->second));
838 // Do not retransmit data of a closed stream.
839 streams_with_pending_retransmission_.erase(stream_id);
840 if (!closed_streams_clean_up_alarm_->IsSet()) {
841 closed_streams_clean_up_alarm_->Set(
842 connection_->clock()->ApproximateNow());
843 }
844 }
845
846 // If we haven't received a FIN or RST for this stream, we need to keep track
847 // of the how many bytes the stream's flow controller believes it has
848 // received, for accurate connection level flow control accounting.
849 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
850 if (!had_fin_or_rst) {
851 InsertLocallyClosedStreamsHighestOffset(
852 stream_id, stream->flow_controller()->highest_received_byte_offset());
853 }
renjietang55d182a2019-07-12 10:26:25 -0700854 stream_map_.erase(it);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500855 if (IsIncomingStream(stream_id)) {
856 --num_dynamic_incoming_streams_;
857 }
858
859 const bool stream_was_draining =
860 draining_streams_.find(stream_id) != draining_streams_.end();
861 if (stream_was_draining) {
862 if (IsIncomingStream(stream_id)) {
863 --num_draining_incoming_streams_;
864 }
865 draining_streams_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700866 } else if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500867 // Stream was not draining, but we did have a fin or rst, so we can now
868 // free the stream ID if version 99.
869 if (had_fin_or_rst) {
870 v99_streamid_manager_.OnStreamClosed(stream_id);
871 }
872 }
873
874 stream->OnClose();
875
876 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
fkastenholz305e1732019-06-18 05:01:22 -0700877 !VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500878 // Streams that first became draining already called OnCanCreate...
879 // This covers the case where the stream went directly to being closed.
renjietangde12d3d2019-07-19 10:57:42 -0700880 OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500881 }
882}
883
884void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
885 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
886
887 if (pending_stream_map_.find(stream_id) == pending_stream_map_.end()) {
888 QUIC_BUG << ENDPOINT << "Stream is already closed: " << stream_id;
889 return;
890 }
891
892 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
893
894 // The pending stream may have been deleted and removed during SendRstStream.
895 // Remove the stream from pending stream map iff it is still in the map.
896 if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
897 pending_stream_map_.erase(stream_id);
898 }
899
fkastenholz305e1732019-06-18 05:01:22 -0700900 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500901 v99_streamid_manager_.OnStreamClosed(stream_id);
902 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500903}
904
905void QuicSession::OnFinalByteOffsetReceived(
906 QuicStreamId stream_id,
907 QuicStreamOffset final_byte_offset) {
908 auto it = locally_closed_streams_highest_offset_.find(stream_id);
909 if (it == locally_closed_streams_highest_offset_.end()) {
910 return;
911 }
912
913 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
914 << final_byte_offset << " for stream " << stream_id;
915 QuicByteCount offset_diff = final_byte_offset - it->second;
916 if (flow_controller_.UpdateHighestReceivedOffset(
917 flow_controller_.highest_received_byte_offset() + offset_diff)) {
918 // If the final offset violates flow control, close the connection now.
919 if (flow_controller_.FlowControlViolation()) {
920 connection_->CloseConnection(
921 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
922 "Connection level flow control violation",
923 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
924 return;
925 }
926 }
927
928 flow_controller_.AddBytesConsumed(offset_diff);
929 locally_closed_streams_highest_offset_.erase(it);
930 if (IsIncomingStream(stream_id)) {
931 --num_locally_closed_incoming_streams_highest_offset_;
fkastenholz305e1732019-06-18 05:01:22 -0700932 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500933 v99_streamid_manager_.OnStreamClosed(stream_id);
934 }
fkastenholz305e1732019-06-18 05:01:22 -0700935 } else if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholz8556dc22019-07-18 12:42:38 -0700936 OnCanCreateNewOutgoingStream(false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500937 }
938}
939
940bool QuicSession::IsEncryptionEstablished() const {
941 // Once the handshake is confirmed, it never becomes un-confirmed.
942 if (is_handshake_confirmed_) {
943 return true;
944 }
945 return GetCryptoStream()->encryption_established();
946}
947
948bool QuicSession::IsCryptoHandshakeConfirmed() const {
949 return GetCryptoStream()->handshake_confirmed();
950}
951
952void QuicSession::OnConfigNegotiated() {
953 connection_->SetFromConfig(config_);
954
fkastenholz305e1732019-06-18 05:01:22 -0700955 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700956 uint32_t max_streams = 0;
957 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
958 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
959 }
960 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
961 << max_streams;
962 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
963 max_streams);
964
965 max_streams = 0;
966 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
967 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
968 }
969 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
970 << max_streams;
971 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
972 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500973 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -0700974 uint32_t max_streams = 0;
975 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
976 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
977 }
978 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500979 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
980 }
fkastenholzd3a1de92019-05-15 07:00:07 -0700981
QUICHE teama6ef0a62019-03-07 20:34:33 -0500982 if (perspective() == Perspective::IS_SERVER) {
983 if (config_.HasReceivedConnectionOptions()) {
984 // The following variations change the initial receive flow control
985 // window sizes.
986 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
987 AdjustInitialFlowControlWindows(64 * 1024);
988 }
989 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
990 AdjustInitialFlowControlWindows(128 * 1024);
991 }
992 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
993 AdjustInitialFlowControlWindows(256 * 1024);
994 }
995 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
996 AdjustInitialFlowControlWindows(512 * 1024);
997 }
998 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
999 AdjustInitialFlowControlWindows(1024 * 1024);
1000 }
fayang944cfbc2019-07-31 09:15:00 -07001001 // Enable HTTP2 (tree-style) priority write scheduler.
1002 if (GetQuicReloadableFlag(quic_use_http2_priority_write_scheduler) &&
1003 ContainsQuicTag(config_.ReceivedConnectionOptions(), kH2PR) &&
1004 !VersionHasIetfQuicFrames(connection_->transport_version())) {
1005 use_http2_priority_write_scheduler_ =
1006 write_blocked_streams_.UseHttp2PriorityScheduler();
1007 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001008 }
1009
1010 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
1011 }
1012
fkastenholz305e1732019-06-18 05:01:22 -07001013 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001014 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1015 config_.GetMaxIncomingBidirectionalStreamsToSend());
1016 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1017 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001018 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001019 // A small number of additional incoming streams beyond the limit should be
1020 // allowed. This helps avoid early connection termination when FIN/RSTs for
1021 // old streams are lost or arrive out of order.
1022 // Use a minimum number of additional streams, or a percentage increase,
1023 // whichever is larger.
1024 uint32_t max_incoming_streams_to_send =
1025 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001026 uint32_t max_incoming_streams =
1027 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1028 static_cast<uint32_t>(max_incoming_streams_to_send *
1029 kMaxStreamsMultiplier));
1030 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1031 }
1032
1033 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1034 // Streams which were created before the SHLO was received (0-RTT
1035 // requests) are now informed of the peer's initial flow control window.
1036 OnNewStreamFlowControlWindow(
1037 config_.ReceivedInitialStreamFlowControlWindowBytes());
1038 }
1039 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1040 OnNewSessionFlowControlWindow(
1041 config_.ReceivedInitialSessionFlowControlWindowBytes());
1042 }
1043}
1044
1045void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1046 const float session_window_multiplier =
1047 config_.GetInitialStreamFlowControlWindowToSend()
1048 ? static_cast<float>(
1049 config_.GetInitialSessionFlowControlWindowToSend()) /
1050 config_.GetInitialStreamFlowControlWindowToSend()
1051 : 1.5;
1052
1053 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1054 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1055
1056 size_t session_window = session_window_multiplier * stream_window;
1057 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1058 << session_window;
1059 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1060 flow_controller_.UpdateReceiveWindowSize(session_window);
1061 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001062 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001063 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1064 }
renjietangb663b862019-07-08 16:02:39 -07001065 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001066 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1067 stream_window);
1068 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001069}
1070
1071void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1072 QuicStreamId stream_id) {
1073 DCHECK(!IsClosedStream(stream_id));
1074 // Received a frame for a locally-created stream that is not currently
1075 // active. This is an error.
1076 connection()->CloseConnection(
1077 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1078 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1079}
1080
1081void QuicSession::HandleRstOnValidNonexistentStream(
1082 const QuicRstStreamFrame& frame) {
1083 // If the stream is neither originally in active streams nor created in
renjietang880d2432019-07-16 13:14:37 -07001084 // GetOrCreateStream(), it could be a closed stream in which case its
QUICHE teama6ef0a62019-03-07 20:34:33 -05001085 // final received byte offset need to be updated.
1086 if (IsClosedStream(frame.stream_id)) {
1087 // The RST frame contains the final byte offset for the stream: we can now
1088 // update the connection level flow controller if needed.
1089 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1090 }
1091}
1092
1093void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001094 if (new_window < kMinimumFlowControlSendWindow &&
1095 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001096 QUIC_LOG_FIRST_N(ERROR, 1)
1097 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001098 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001099 if (connection_->connected()) {
1100 connection_->CloseConnection(
1101 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1102 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1103 }
1104 return;
1105 }
1106
1107 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001108 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001109 kv.second->UpdateSendWindowOffset(new_window);
1110 }
renjietangb663b862019-07-08 16:02:39 -07001111 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001112 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1113 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001114}
1115
1116void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001117 if (new_window < kMinimumFlowControlSendWindow &&
1118 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001119 QUIC_LOG_FIRST_N(ERROR, 1)
1120 << "Peer sent us an invalid session flow control send window: "
1121 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1122 if (connection_->connected()) {
1123 connection_->CloseConnection(
1124 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1125 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1126 }
1127 return;
1128 }
1129
1130 flow_controller_.UpdateSendWindowOffset(new_window);
1131}
1132
1133void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1134 switch (event) {
1135 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
1136 // to QuicSession since it is the glue.
1137 case ENCRYPTION_FIRST_ESTABLISHED:
1138 // Given any streams blocked by encryption a chance to write.
1139 OnCanWrite();
1140 break;
1141
1142 case ENCRYPTION_REESTABLISHED:
1143 // Retransmit originally packets that were sent, since they can't be
1144 // decrypted by the peer.
1145 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1146 // Given any streams blocked by encryption a chance to write.
1147 OnCanWrite();
1148 break;
1149
1150 case HANDSHAKE_CONFIRMED:
1151 QUIC_BUG_IF(!config_.negotiated())
1152 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1153 // Discard originally encrypted packets, since they can't be decrypted by
1154 // the peer.
1155 NeuterUnencryptedData();
1156 is_handshake_confirmed_ = true;
1157 break;
1158
1159 default:
1160 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1161 }
1162}
1163
1164void QuicSession::OnCryptoHandshakeMessageSent(
1165 const CryptoHandshakeMessage& /*message*/) {}
1166
1167void QuicSession::OnCryptoHandshakeMessageReceived(
1168 const CryptoHandshakeMessage& /*message*/) {}
1169
fayang476683a2019-07-25 12:42:16 -07001170void QuicSession::RegisterStreamPriority(
1171 QuicStreamId id,
1172 bool is_static,
1173 const spdy::SpdyStreamPrecedence& precedence) {
1174 write_blocked_streams()->RegisterStream(id, is_static, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001175}
1176
1177void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1178 write_blocked_streams()->UnregisterStream(id, is_static);
1179}
1180
fayang476683a2019-07-25 12:42:16 -07001181void QuicSession::UpdateStreamPriority(
1182 QuicStreamId id,
1183 const spdy::SpdyStreamPrecedence& new_precedence) {
1184 write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001185}
1186
1187QuicConfig* QuicSession::config() {
1188 return &config_;
1189}
1190
1191void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001192 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001193 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -07001194 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001195 << ". activating " << stream_id;
renjietang55d182a2019-07-12 10:26:25 -07001196 DCHECK(!QuicContainsKey(stream_map_, stream_id));
1197 stream_map_[stream_id] = std::move(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001198 if (IsIncomingStream(stream_id)) {
1199 ++num_dynamic_incoming_streams_;
1200 }
1201}
1202
1203QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001204 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001205 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1206 }
1207 return stream_id_manager_.GetNextOutgoingStreamId();
1208}
1209
1210QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001211 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001212 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1213 }
1214 return stream_id_manager_.GetNextOutgoingStreamId();
1215}
1216
1217bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001218 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001219 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1220 }
1221 return stream_id_manager_.CanOpenNextOutgoingStream(
1222 GetNumOpenOutgoingStreams());
1223}
1224
1225bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001226 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001227 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1228 }
1229 return stream_id_manager_.CanOpenNextOutgoingStream(
1230 GetNumOpenOutgoingStreams());
1231}
1232
1233QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang28c04b72019-07-01 15:08:09 -07001234 DCHECK(!QuicContainsKey(pending_stream_map_, stream_id));
renjietangb663b862019-07-08 16:02:39 -07001235 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -07001236 stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001237 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001238 }
renjietang880d2432019-07-16 13:14:37 -07001239
1240 StreamMap::iterator it = stream_map_.find(stream_id);
1241 if (it != stream_map_.end()) {
1242 return it->second.get();
1243 }
1244
1245 if (IsClosedStream(stream_id)) {
1246 return nullptr;
1247 }
1248
1249 if (!IsIncomingStream(stream_id)) {
1250 HandleFrameOnNonexistentOutgoingStream(stream_id);
1251 return nullptr;
1252 }
1253
1254 // TODO(fkastenholz): If we are creating a new stream and we have
1255 // sent a goaway, we should ignore the stream creation. Need to
1256 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1257 // B) reject stream creation ("return nullptr")
1258
1259 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
1260 return nullptr;
1261 }
1262
1263 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
1264 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1265 // CanOpenIncomingStream interface consistent with that of v99.
1266 if (!stream_id_manager_.CanOpenIncomingStream(
1267 GetNumOpenIncomingStreams())) {
1268 // Refuse to open the stream.
1269 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
1270 return nullptr;
1271 }
1272 }
1273
1274 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001275}
1276
1277void QuicSession::StreamDraining(QuicStreamId stream_id) {
renjietang55d182a2019-07-12 10:26:25 -07001278 DCHECK(QuicContainsKey(stream_map_, stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001279 if (!QuicContainsKey(draining_streams_, stream_id)) {
1280 draining_streams_.insert(stream_id);
1281 if (IsIncomingStream(stream_id)) {
1282 ++num_draining_incoming_streams_;
1283 }
fkastenholz305e1732019-06-18 05:01:22 -07001284 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001285 v99_streamid_manager_.OnStreamClosed(stream_id);
1286 }
1287 }
1288 if (!IsIncomingStream(stream_id)) {
1289 // Inform application that a stream is available.
fkastenholz8556dc22019-07-18 12:42:38 -07001290 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietangde12d3d2019-07-19 10:57:42 -07001291 OnCanCreateNewOutgoingStream(
1292 !QuicUtils::IsBidirectionalStreamId(stream_id));
fkastenholz8556dc22019-07-18 12:42:38 -07001293 } else {
renjietangde12d3d2019-07-19 10:57:42 -07001294 QuicStream* stream = GetStream(stream_id);
1295 if (!stream) {
1296 QUIC_BUG << "Stream doesn't exist when draining.";
1297 return;
1298 }
1299 OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL);
fkastenholz8556dc22019-07-18 12:42:38 -07001300 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001301 }
1302}
1303
1304bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1305 const QuicStreamId stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001306 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001307 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1308 }
1309 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1310}
1311
1312bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1313 if (stream_id == currently_writing_stream_id_) {
1314 return false;
1315 }
1316 return write_blocked_streams()->ShouldYield(stream_id);
1317}
1318
renjietange76b2da2019-05-13 14:50:23 -07001319PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1320 auto it = pending_stream_map_.find(stream_id);
1321 if (it != pending_stream_map_.end()) {
1322 return it->second.get();
1323 }
1324
1325 if (IsClosedStream(stream_id) ||
1326 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1327 return nullptr;
1328 }
1329
1330 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1331 PendingStream* unowned_pending = pending.get();
1332 pending_stream_map_[stream_id] = std::move(pending);
1333 return unowned_pending;
1334}
1335
QUICHE teama6ef0a62019-03-07 20:34:33 -05001336QuicStream* QuicSession::GetOrCreateDynamicStream(
1337 const QuicStreamId stream_id) {
renjietang880d2432019-07-16 13:14:37 -07001338 DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream));
renjietang55d182a2019-07-12 10:26:25 -07001339 StreamMap::iterator it = stream_map_.find(stream_id);
1340 if (it != stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001341 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001342 }
1343
1344 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001345 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001346 }
1347
1348 if (!IsIncomingStream(stream_id)) {
1349 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001350 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001351 }
1352
QUICHE teama6ef0a62019-03-07 20:34:33 -05001353 // TODO(fkastenholz): If we are creating a new stream and we have
1354 // sent a goaway, we should ignore the stream creation. Need to
1355 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1356 // B) reject stream creation ("return nullptr")
1357
1358 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001359 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001360 }
1361
fkastenholz305e1732019-06-18 05:01:22 -07001362 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001363 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1364 // CanOpenIncomingStream interface cosistent with that of v99.
1365 if (!stream_id_manager_.CanOpenIncomingStream(
1366 GetNumOpenIncomingStreams())) {
1367 // Refuse to open the stream.
1368 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001369 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001370 }
1371 }
1372
renjietang2c4d7122019-05-20 17:18:14 -07001373 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001374}
1375
1376void QuicSession::set_largest_peer_created_stream_id(
1377 QuicStreamId largest_peer_created_stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001378 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001379 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1380 largest_peer_created_stream_id);
1381 return;
1382 }
1383 stream_id_manager_.set_largest_peer_created_stream_id(
1384 largest_peer_created_stream_id);
1385}
1386
1387bool QuicSession::IsClosedStream(QuicStreamId id) {
1388 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1389 id);
1390 if (IsOpenStream(id)) {
1391 // Stream is active
1392 return false;
1393 }
1394
fkastenholz305e1732019-06-18 05:01:22 -07001395 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001396 return !v99_streamid_manager_.IsAvailableStream(id);
1397 }
1398
1399 return !stream_id_manager_.IsAvailableStream(id);
1400}
1401
1402bool QuicSession::IsOpenStream(QuicStreamId id) {
1403 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1404 id);
renjietang55d182a2019-07-12 10:26:25 -07001405 if (QuicContainsKey(stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001406 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001407 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001408 // Stream is active
1409 return true;
1410 }
1411 return false;
1412}
1413
rchda26cdb2019-05-17 11:57:37 -07001414bool QuicSession::IsStaticStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001415 auto it = stream_map_.find(id);
1416 if (it == stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -07001417 return false;
rchda26cdb2019-05-17 11:57:37 -07001418 }
renjietangb663b862019-07-08 16:02:39 -07001419 return it->second->is_static();
rchda26cdb2019-05-17 11:57:37 -07001420}
1421
QUICHE teama6ef0a62019-03-07 20:34:33 -05001422size_t QuicSession::GetNumOpenIncomingStreams() const {
1423 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1424 num_locally_closed_incoming_streams_highest_offset_;
1425}
1426
1427size_t QuicSession::GetNumOpenOutgoingStreams() const {
1428 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1429 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1430 GetNumDrainingOutgoingStreams());
1431 return GetNumDynamicOutgoingStreams() +
1432 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1433 GetNumDrainingOutgoingStreams();
1434}
1435
1436size_t QuicSession::GetNumActiveStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001437 return stream_map_.size() - draining_streams_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001438 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001439}
1440
1441size_t QuicSession::GetNumDrainingStreams() const {
1442 return draining_streams_.size();
1443}
1444
1445void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1446 if (GetOrCreateStream(id) == nullptr) {
1447 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1448 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1449 }
1450
1451 write_blocked_streams_.AddStream(id);
1452}
1453
1454bool QuicSession::HasDataToWrite() const {
1455 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1456 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1457 connection_->HasQueuedData() ||
1458 !streams_with_pending_retransmission_.empty() ||
1459 control_frame_manager_.WillingToWrite();
1460}
1461
1462void QuicSession::OnAckNeedsRetransmittableFrame() {
1463 flow_controller_.SendWindowUpdate();
1464}
1465
1466void QuicSession::SendPing() {
1467 control_frame_manager_.WritePing();
1468}
1469
1470size_t QuicSession::GetNumDynamicOutgoingStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001471 DCHECK_GE(
1472 static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()),
1473 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1474 num_incoming_static_streams_);
1475 return stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001476 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1477 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001478}
1479
1480size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1481 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1482 return draining_streams_.size() - num_draining_incoming_streams_;
1483}
1484
1485size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1486 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1487 num_locally_closed_incoming_streams_highest_offset_);
1488 return locally_closed_streams_highest_offset_.size() -
1489 num_locally_closed_incoming_streams_highest_offset_;
1490}
1491
1492bool QuicSession::IsConnectionFlowControlBlocked() const {
1493 return flow_controller_.IsBlocked();
1494}
1495
1496bool QuicSession::IsStreamFlowControlBlocked() {
renjietang55d182a2019-07-12 10:26:25 -07001497 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001498 if (kv.second->flow_controller()->IsBlocked()) {
1499 return true;
1500 }
1501 }
renjietangb663b862019-07-08 16:02:39 -07001502 if (!QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001503 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
renjietang08a9cf72019-04-23 17:01:34 -07001504 return true;
1505 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001506 return false;
1507}
1508
1509size_t QuicSession::MaxAvailableBidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001510 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001511 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1512 }
1513 return stream_id_manager_.MaxAvailableStreams();
1514}
1515
1516size_t QuicSession::MaxAvailableUnidirectionalStreams() 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_.GetMaxAllowdIncomingUnidirectionalStreams();
1519 }
1520 return stream_id_manager_.MaxAvailableStreams();
1521}
1522
1523bool QuicSession::IsIncomingStream(QuicStreamId id) 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_.IsIncomingStream(id);
1526 }
1527 return stream_id_manager_.IsIncomingStream(id);
1528}
1529
1530void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
zhongyi1b2f7832019-06-14 13:31:34 -07001531 if (ignore_tlpr_if_no_pending_stream_data() &&
1532 session_decides_what_to_write()) {
1533 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 3,
1534 5);
1535 streams_waiting_for_acks_.erase(id);
1536 }
1537
QUICHE teama6ef0a62019-03-07 20:34:33 -05001538 auto it = zombie_streams_.find(id);
1539 if (it == zombie_streams_.end()) {
1540 return;
1541 }
1542
1543 closed_streams_.push_back(std::move(it->second));
1544 if (!closed_streams_clean_up_alarm_->IsSet()) {
1545 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1546 }
1547 zombie_streams_.erase(it);
1548 // Do not retransmit data of a closed stream.
1549 streams_with_pending_retransmission_.erase(id);
1550}
1551
zhongyi1b2f7832019-06-14 13:31:34 -07001552void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) {
1553 if (!ignore_tlpr_if_no_pending_stream_data() ||
1554 !session_decides_what_to_write())
1555 return;
1556
1557 // Exclude crypto stream's status since it is counted in HasUnackedCryptoData.
1558 if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) {
1559 return;
1560 }
1561
1562 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 4,
1563 5);
1564 streams_waiting_for_acks_.insert(id);
1565
1566 // The number of the streams waiting for acks should not be larger than the
1567 // number of streams.
renjietang55d182a2019-07-12 10:26:25 -07001568 if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) <
zhongyi71e9d9e2019-06-14 14:57:16 -07001569 streams_waiting_for_acks_.size()) {
zhongyi1b2f7832019-06-14 13:31:34 -07001570 QUIC_BUG << "More streams are waiting for acks than the number of streams. "
renjietang55d182a2019-07-12 10:26:25 -07001571 << "Sizes: streams: " << stream_map_.size()
zhongyi1b2f7832019-06-14 13:31:34 -07001572 << ", zombie streams: " << zombie_streams_.size()
1573 << ", vs streams waiting for acks: "
1574 << streams_waiting_for_acks_.size();
1575 }
1576}
1577
QUICHE teama6ef0a62019-03-07 20:34:33 -05001578QuicStream* QuicSession::GetStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001579 auto active_stream = stream_map_.find(id);
1580 if (active_stream != stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001581 return active_stream->second.get();
1582 }
1583 auto zombie_stream = zombie_streams_.find(id);
1584 if (zombie_stream != zombie_streams_.end()) {
1585 return zombie_stream->second.get();
1586 }
renjietang08a9cf72019-04-23 17:01:34 -07001587
renjietangb663b862019-07-08 16:02:39 -07001588 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
renjietang08a9cf72019-04-23 17:01:34 -07001589 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1590 }
1591
QUICHE teama6ef0a62019-03-07 20:34:33 -05001592 return nullptr;
1593}
1594
1595bool QuicSession::OnFrameAcked(const QuicFrame& frame,
QUICHE team9467db02019-05-30 09:38:45 -07001596 QuicTime::Delta ack_delay_time,
1597 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001598 if (frame.type == MESSAGE_FRAME) {
QUICHE team9467db02019-05-30 09:38:45 -07001599 OnMessageAcked(frame.message_frame->message_id, receive_timestamp);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001600 return true;
1601 }
1602 if (frame.type == CRYPTO_FRAME) {
1603 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1604 ack_delay_time);
1605 }
1606 if (frame.type != STREAM_FRAME) {
1607 return control_frame_manager_.OnControlFrameAcked(frame);
1608 }
1609 bool new_stream_data_acked = false;
1610 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1611 // Stream can already be reset when sent frame gets acked.
1612 if (stream != nullptr) {
1613 QuicByteCount newly_acked_length = 0;
1614 new_stream_data_acked = stream->OnStreamFrameAcked(
1615 frame.stream_frame.offset, frame.stream_frame.data_length,
1616 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1617 if (!stream->HasPendingRetransmission()) {
1618 streams_with_pending_retransmission_.erase(stream->id());
1619 }
1620 }
1621 return new_stream_data_acked;
1622}
1623
1624void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1625 QuicStream* stream = GetStream(frame.stream_id);
1626 if (stream == nullptr) {
1627 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1628 << " is retransmitted.";
1629 connection()->CloseConnection(
1630 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1631 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1632 return;
1633 }
1634 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1635 frame.fin);
1636}
1637
1638void QuicSession::OnFrameLost(const QuicFrame& frame) {
1639 if (frame.type == MESSAGE_FRAME) {
1640 OnMessageLost(frame.message_frame->message_id);
1641 return;
1642 }
1643 if (frame.type == CRYPTO_FRAME) {
1644 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1645 return;
1646 }
1647 if (frame.type != STREAM_FRAME) {
1648 control_frame_manager_.OnControlFrameLost(frame);
1649 return;
1650 }
1651 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1652 if (stream == nullptr) {
1653 return;
1654 }
1655 stream->OnStreamFrameLost(frame.stream_frame.offset,
1656 frame.stream_frame.data_length,
1657 frame.stream_frame.fin);
1658 if (stream->HasPendingRetransmission() &&
1659 !QuicContainsKey(streams_with_pending_retransmission_,
1660 frame.stream_frame.stream_id)) {
1661 streams_with_pending_retransmission_.insert(
1662 std::make_pair(frame.stream_frame.stream_id, true));
1663 }
1664}
1665
1666void QuicSession::RetransmitFrames(const QuicFrames& frames,
1667 TransmissionType type) {
fayanga4b37b22019-06-18 13:37:47 -07001668 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001669 SetTransmissionType(type);
1670 for (const QuicFrame& frame : frames) {
1671 if (frame.type == MESSAGE_FRAME) {
1672 // Do not retransmit MESSAGE frames.
1673 continue;
1674 }
1675 if (frame.type == CRYPTO_FRAME) {
1676 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1677 continue;
1678 }
1679 if (frame.type != STREAM_FRAME) {
1680 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1681 break;
1682 }
1683 continue;
1684 }
1685 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1686 if (stream != nullptr &&
1687 !stream->RetransmitStreamData(frame.stream_frame.offset,
1688 frame.stream_frame.data_length,
1689 frame.stream_frame.fin)) {
1690 break;
1691 }
1692 }
1693}
1694
1695bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1696 if (frame.type == MESSAGE_FRAME) {
1697 return false;
1698 }
1699 if (frame.type == CRYPTO_FRAME) {
1700 return GetCryptoStream()->IsFrameOutstanding(
1701 frame.crypto_frame->level, frame.crypto_frame->offset,
1702 frame.crypto_frame->data_length);
1703 }
1704 if (frame.type != STREAM_FRAME) {
1705 return control_frame_manager_.IsControlFrameOutstanding(frame);
1706 }
1707 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1708 return stream != nullptr &&
1709 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1710 frame.stream_frame.data_length,
1711 frame.stream_frame.fin);
1712}
1713
1714bool QuicSession::HasUnackedCryptoData() const {
1715 const QuicCryptoStream* crypto_stream = GetCryptoStream();
fayang44fa92f2019-07-01 07:32:14 -07001716 return crypto_stream->IsWaitingForAcks() || crypto_stream->HasBufferedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001717}
1718
zhongyi1b2f7832019-06-14 13:31:34 -07001719bool QuicSession::HasUnackedStreamData() const {
1720 DCHECK(ignore_tlpr_if_no_pending_stream_data());
1721 if (ignore_tlpr_if_no_pending_stream_data()) {
1722 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 5,
1723 5);
1724 return !streams_waiting_for_acks_.empty();
1725 }
1726
1727 return true;
1728}
1729
QUICHE teama6ef0a62019-03-07 20:34:33 -05001730WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1731 QuicStreamOffset offset,
1732 QuicByteCount data_length,
1733 QuicDataWriter* writer) {
1734 QuicStream* stream = GetStream(id);
1735 if (stream == nullptr) {
1736 // This causes the connection to be closed because of failed to serialize
1737 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001738 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1739 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001740 return STREAM_MISSING;
1741 }
1742 if (stream->WriteStreamData(offset, data_length, writer)) {
1743 return WRITE_SUCCESS;
1744 }
1745 return WRITE_FAILED;
1746}
1747
1748bool QuicSession::WriteCryptoData(EncryptionLevel level,
1749 QuicStreamOffset offset,
1750 QuicByteCount data_length,
1751 QuicDataWriter* writer) {
1752 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1753 writer);
1754}
1755
1756QuicUint128 QuicSession::GetStatelessResetToken() const {
1757 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1758}
1759
1760bool QuicSession::RetransmitLostData() {
fayanga4b37b22019-06-18 13:37:47 -07001761 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001762 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001763 bool uses_crypto_frames =
1764 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001765 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1766 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1767 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1768 crypto_stream->WritePendingCryptoRetransmission();
1769 }
1770 // Retransmit crypto data in stream 1 frames (version < 47).
1771 if (!uses_crypto_frames &&
1772 QuicContainsKey(
1773 streams_with_pending_retransmission_,
1774 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1775 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1776 // Retransmit crypto data first.
1777 QuicStream* crypto_stream = GetStream(
1778 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1779 crypto_stream->OnCanWrite();
1780 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1781 if (crypto_stream->HasPendingRetransmission()) {
1782 // Connection is write blocked.
1783 return false;
1784 } else {
1785 streams_with_pending_retransmission_.erase(
1786 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1787 }
1788 }
1789 if (control_frame_manager_.HasPendingRetransmission()) {
1790 SetTransmissionType(LOSS_RETRANSMISSION);
1791 control_frame_manager_.OnCanWrite();
1792 if (control_frame_manager_.HasPendingRetransmission()) {
1793 return false;
1794 }
1795 }
1796 while (!streams_with_pending_retransmission_.empty()) {
1797 if (!connection_->CanWriteStreamData()) {
1798 break;
1799 }
1800 // Retransmit lost data on headers and data streams.
1801 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1802 QuicStream* stream = GetStream(id);
1803 if (stream != nullptr) {
1804 SetTransmissionType(LOSS_RETRANSMISSION);
1805 stream->OnCanWrite();
1806 DCHECK(CheckStreamWriteBlocked(stream));
1807 if (stream->HasPendingRetransmission()) {
1808 // Connection is write blocked.
1809 break;
1810 } else if (!streams_with_pending_retransmission_.empty() &&
1811 streams_with_pending_retransmission_.begin()->first == id) {
1812 // Retransmit lost data may cause connection close. If this stream
1813 // has not yet sent fin, a RST_STREAM will be sent and it will be
1814 // removed from streams_with_pending_retransmission_.
1815 streams_with_pending_retransmission_.pop_front();
1816 }
1817 } else {
1818 QUIC_BUG << "Try to retransmit data of a closed stream";
1819 streams_with_pending_retransmission_.pop_front();
1820 }
1821 }
1822
1823 return streams_with_pending_retransmission_.empty();
1824}
1825
1826void QuicSession::NeuterUnencryptedData() {
1827 if (connection_->session_decides_what_to_write()) {
1828 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1829 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001830 if (!crypto_stream->HasPendingRetransmission() &&
1831 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001832 streams_with_pending_retransmission_.erase(
1833 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1834 }
1835 }
1836 connection_->NeuterUnencryptedPackets();
1837}
1838
1839void QuicSession::SetTransmissionType(TransmissionType type) {
1840 connection_->SetTransmissionType(type);
1841}
1842
1843MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1844 if (!IsEncryptionEstablished()) {
1845 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1846 }
1847 MessageStatus result =
1848 connection_->SendMessage(last_message_id_ + 1, message);
1849 if (result == MESSAGE_STATUS_SUCCESS) {
1850 return {result, ++last_message_id_};
1851 }
1852 return {result, 0};
1853}
1854
QUICHE team9467db02019-05-30 09:38:45 -07001855void QuicSession::OnMessageAcked(QuicMessageId message_id,
dschinazi17d42422019-06-18 16:35:07 -07001856 QuicTime /*receive_timestamp*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001857 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1858}
1859
1860void QuicSession::OnMessageLost(QuicMessageId message_id) {
1861 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1862 << " is considered lost";
1863}
1864
1865void QuicSession::CleanUpClosedStreams() {
1866 closed_streams_.clear();
1867}
1868
1869bool QuicSession::session_decides_what_to_write() const {
1870 return connection_->session_decides_what_to_write();
1871}
1872
ianswettb239f862019-04-05 09:15:06 -07001873QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1874 return connection_->GetCurrentLargestMessagePayload();
1875}
1876
1877QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1878 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001879}
1880
1881void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1882 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1883}
1884
fkastenholz8556dc22019-07-18 12:42:38 -07001885void QuicSession::OnCanCreateNewOutgoingStream(bool /*unidirectional*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -05001886
1887QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001888 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001889 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1890 }
1891 return stream_id_manager_.next_outgoing_stream_id();
1892}
1893
1894QuicStreamId QuicSession::next_outgoing_unidirectional_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_unidirectional_stream_id();
1897 }
1898 return stream_id_manager_.next_outgoing_stream_id();
1899}
1900
fkastenholz3c4eabf2019-04-22 07:49:59 -07001901bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1902 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001903}
1904
fkastenholz3c4eabf2019-04-22 07:49:59 -07001905bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1906 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001907}
1908
1909size_t QuicSession::max_open_incoming_bidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001910 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001911 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1912 }
1913 return stream_id_manager_.max_open_incoming_streams();
1914}
1915
1916size_t QuicSession::max_open_incoming_unidirectional_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_.GetMaxAllowdIncomingUnidirectionalStreams();
1919 }
1920 return stream_id_manager_.max_open_incoming_streams();
1921}
1922
1923#undef ENDPOINT // undef for jumbo builds
1924} // namespace quic