blob: 964ddc1aea72fe0475a26cb474c7ba04a8e985bb [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),
renjietangb663b862019-07-08 16:02:39 -070091 supported_versions_(supported_versions) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050092 closed_streams_clean_up_alarm_ =
93 QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
94 new ClosedStreamsCleanUpDelegate(this)));
95}
96
97void QuicSession::Initialize() {
98 connection_->set_visitor(this);
99 connection_->SetSessionNotifier(this);
100 connection_->SetDataProducer(this);
101 connection_->SetFromConfig(config_);
102
nharper46833c32019-05-15 21:33:05 -0700103 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
104 return;
105 }
106
QUICHE teama6ef0a62019-03-07 20:34:33 -0500107 DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
108 GetMutableCryptoStream()->id());
renjietangb663b862019-07-08 16:02:39 -0700109
110 QuicStreamId id =
111 QuicUtils::GetCryptoStreamId(connection_->transport_version());
renjietangb663b862019-07-08 16:02:39 -0700112 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
113 v99_streamid_manager_.RegisterStaticStream(id, false);
renjietang08a9cf72019-04-23 17:01:34 -0700114 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115}
116
117QuicSession::~QuicSession() {
118 QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
119}
120
renjietang0e9980b2019-07-11 12:00:21 -0700121void QuicSession::RegisterStaticStream(std::unique_ptr<QuicStream> stream,
122 bool stream_already_counted) {
renjietang9ffbb602019-07-10 14:08:00 -0700123 DCHECK(stream->is_static());
renjietangfbeb5bf2019-04-19 15:06:20 -0700124 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -0700125 stream_map_[stream_id] = std::move(stream);
fkastenholz305e1732019-06-18 05:01:22 -0700126 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietang3a1bb802019-06-11 10:42:41 -0700127 v99_streamid_manager_.RegisterStaticStream(stream_id,
128 stream_already_counted);
renjietangfbeb5bf2019-04-19 15:06:20 -0700129 }
130 if (IsIncomingStream(stream_id)) {
131 ++num_incoming_static_streams_;
132 } else {
133 ++num_outgoing_static_streams_;
134 }
135}
136
renjietange76b2da2019-05-13 14:50:23 -0700137void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700138 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700139 QuicStreamId stream_id = frame.stream_id;
140
141 PendingStream* pending = GetOrCreatePendingStream(stream_id);
142
143 if (!pending) {
144 if (frame.fin) {
145 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
146 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
147 }
148 return;
149 }
150
151 pending->OnStreamFrame(frame);
renjietanga553da02019-06-24 11:57:04 -0700152 if (!connection()->connected()) {
153 return;
154 }
renjietangbb1c4892019-05-24 15:58:44 -0700155 if (ProcessPendingStream(pending)) {
156 // The pending stream should now be in the scope of normal streams.
157 DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
158 << "Stream " << stream_id << " not created";
159 pending_stream_map_.erase(stream_id);
160 }
renjietange76b2da2019-05-13 14:50:23 -0700161}
162
QUICHE teama6ef0a62019-03-07 20:34:33 -0500163void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
164 // TODO(rch) deal with the error case of stream id 0.
165 QuicStreamId stream_id = frame.stream_id;
166 if (stream_id ==
167 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
168 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700169 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500170 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
171 return;
172 }
173
bnc36c47282019-06-21 05:17:59 -0700174 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700175 QuicUtils::GetStreamType(stream_id, perspective(),
176 IsIncomingStream(stream_id)) ==
177 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700178 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700179 PendingStreamOnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180 return;
181 }
182
renjietang2c4d7122019-05-20 17:18:14 -0700183 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700184
renjietang2c4d7122019-05-20 17:18:14 -0700185 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500186 // The stream no longer exists, but we may still be interested in the
187 // final stream byte offset sent by the peer. A frame with a FIN can give
188 // us this offset.
189 if (frame.fin) {
190 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
191 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
192 }
193 return;
194 }
renjietangb663b862019-07-08 16:02:39 -0700195 if (frame.fin && stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700196 connection()->CloseConnection(
197 QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
198 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
199 return;
200 }
renjietang2c4d7122019-05-20 17:18:14 -0700201 stream->OnStreamFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202}
203
204void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
205 GetMutableCryptoStream()->OnCryptoFrame(frame);
206}
207
208bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
209 // We are not version 99. In theory, if not in version 99 then the framer
210 // could not call OnStopSending... This is just a check that is good when
211 // both a new protocol and a new implementation of that protocol are both
212 // being developed.
fkastenholz305e1732019-06-18 05:01:22 -0700213 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500214
215 QuicStreamId stream_id = frame.stream_id;
216 // If Stream ID is invalid then close the connection.
217 if (stream_id ==
218 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
219 QUIC_DVLOG(1) << ENDPOINT
220 << "Received STOP_SENDING with invalid stream_id: "
221 << stream_id << " Closing connection";
222 connection()->CloseConnection(
223 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for an invalid stream",
224 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
225 return false;
226 }
227
228 // Ignore STOP_SENDING for static streams.
229 // TODO(fkastenholz): IETF Quic does not have static streams and does not
230 // make exceptions for them with respect to processing things like
231 // STOP_SENDING.
renjietang0e9980b2019-07-11 12:00:21 -0700232 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -0700233 stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500234 QUIC_DVLOG(1) << ENDPOINT
235 << "Received STOP_SENDING for a static stream, id: "
236 << stream_id << " Closing connection";
237 connection()->CloseConnection(
238 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
239 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
240 return false;
241 }
242
243 if (visitor_) {
244 visitor_->OnStopSendingReceived(frame);
245 }
246
247 // If stream is closed, ignore the frame
248 if (IsClosedStream(stream_id)) {
249 QUIC_DVLOG(1)
250 << ENDPOINT
251 << "Received STOP_SENDING for closed or non-existent stream, id: "
252 << stream_id << " Ignoring.";
253 return true; // Continue processing the packet.
254 }
255 // If stream is non-existent, close the connection
renjietang55d182a2019-07-12 10:26:25 -0700256 StreamMap::iterator it = stream_map_.find(stream_id);
257 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500258 QUIC_DVLOG(1) << ENDPOINT
259 << "Received STOP_SENDING for non-existent stream, id: "
260 << stream_id << " Closing connection";
261 connection()->CloseConnection(
262 IETF_QUIC_PROTOCOL_VIOLATION,
263 "Received STOP_SENDING for a non-existent stream",
264 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
265 return false;
266 }
267
268 // Get the QuicStream for this stream. Ignore the STOP_SENDING
269 // if the QuicStream pointer is NULL
fkastenholz3c4eabf2019-04-22 07:49:59 -0700270 // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would
271 // happen IFF there was an entry in the map, but the pointer is null. sounds
272 // more like a deep programming error rather than a simple protocol problem).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 QuicStream* stream = it->second.get();
274 if (stream == nullptr) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700275 QUIC_BUG << ENDPOINT
276 << "Received STOP_SENDING for NULL QuicStream, stream_id: "
277 << stream_id << ". Ignoring.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500278 return true;
279 }
renjietangfbeb5bf2019-04-19 15:06:20 -0700280
renjietangb663b862019-07-08 16:02:39 -0700281 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700282 QUIC_DVLOG(1) << ENDPOINT
283 << "Received STOP_SENDING for a static stream, id: "
284 << stream_id << " Closing connection";
285 connection()->CloseConnection(
286 QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream",
287 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
288 return false;
289 }
290
QUICHE teama6ef0a62019-03-07 20:34:33 -0500291 stream->OnStopSending(frame.application_error_code);
292
293 stream->set_stream_error(
294 static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
295 SendRstStreamInner(
296 stream->id(),
297 static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
298 stream->stream_bytes_written(),
299 /*close_write_side_only=*/true);
300
301 return true;
302}
303
renjietange76b2da2019-05-13 14:50:23 -0700304void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
renjietangbb1c4892019-05-24 15:58:44 -0700305 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietange76b2da2019-05-13 14:50:23 -0700306 QuicStreamId stream_id = frame.stream_id;
307
308 PendingStream* pending = GetOrCreatePendingStream(stream_id);
309
310 if (!pending) {
311 HandleRstOnValidNonexistentStream(frame);
312 return;
313 }
314
315 pending->OnRstStreamFrame(frame);
316 ClosePendingStream(stream_id);
317}
318
QUICHE teama6ef0a62019-03-07 20:34:33 -0500319void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
320 QuicStreamId stream_id = frame.stream_id;
321 if (stream_id ==
322 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
323 connection()->CloseConnection(
bnce433f532019-04-16 13:05:27 -0700324 QUIC_INVALID_STREAM_ID, "Received data for an invalid stream",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500325 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
326 return;
327 }
328
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 if (visitor_) {
330 visitor_->OnRstStreamReceived(frame);
331 }
332
bnc36c47282019-06-21 05:17:59 -0700333 if (UsesPendingStreams() &&
renjietange76b2da2019-05-13 14:50:23 -0700334 QuicUtils::GetStreamType(stream_id, perspective(),
335 IsIncomingStream(stream_id)) ==
336 READ_UNIDIRECTIONAL &&
renjietang55d182a2019-07-12 10:26:25 -0700337 stream_map_.find(stream_id) == stream_map_.end()) {
renjietange76b2da2019-05-13 14:50:23 -0700338 PendingStreamOnRstStream(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500339 return;
340 }
renjietange76b2da2019-05-13 14:50:23 -0700341
renjietang2c4d7122019-05-20 17:18:14 -0700342 QuicStream* stream = GetOrCreateStream(stream_id);
renjietange76b2da2019-05-13 14:50:23 -0700343
renjietang2c4d7122019-05-20 17:18:14 -0700344 if (!stream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500345 HandleRstOnValidNonexistentStream(frame);
346 return; // Errors are handled by GetOrCreateStream.
347 }
renjietangb663b862019-07-08 16:02:39 -0700348 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700349 connection()->CloseConnection(
350 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
351 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
352 return;
353 }
renjietang2c4d7122019-05-20 17:18:14 -0700354 stream->OnStreamReset(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355}
356
dschinazi17d42422019-06-18 16:35:07 -0700357void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500358 goaway_received_ = true;
359}
360
361void QuicSession::OnMessageReceived(QuicStringPiece message) {
362 QUIC_DVLOG(1) << ENDPOINT << "Received message, length: " << message.length()
363 << ", " << message;
364}
365
wub2b5942f2019-04-11 13:22:50 -0700366// static
367void QuicSession::RecordConnectionCloseAtServer(QuicErrorCode error,
368 ConnectionCloseSource source) {
369 if (error != QUIC_NO_ERROR) {
370 if (source == ConnectionCloseSource::FROM_SELF) {
371 QUIC_SERVER_HISTOGRAM_ENUM(
372 "quic_server_connection_close_errors", error, QUIC_LAST_ERROR,
373 "QuicErrorCode for server-closed connections.");
374 } else {
375 QUIC_SERVER_HISTOGRAM_ENUM(
376 "quic_client_connection_close_errors", error, QUIC_LAST_ERROR,
377 "QuicErrorCode for client-closed connections.");
378 }
379 }
380}
381
fkastenholz5d880a92019-06-21 09:01:56 -0700382void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500383 ConnectionCloseSource source) {
384 DCHECK(!connection_->connected());
wub2b5942f2019-04-11 13:22:50 -0700385 if (perspective() == Perspective::IS_SERVER) {
fkastenholz5d880a92019-06-21 09:01:56 -0700386 RecordConnectionCloseAtServer(frame.quic_error_code, source);
wub2b5942f2019-04-11 13:22:50 -0700387 }
388
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389 if (error_ == QUIC_NO_ERROR) {
fkastenholz5d880a92019-06-21 09:01:56 -0700390 error_ = frame.quic_error_code;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391 }
392
renjietangb663b862019-07-08 16:02:39 -0700393 // Copy all non static streams in a new map for the ease of deleting.
394 QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
renjietang55d182a2019-07-12 10:26:25 -0700395 for (const auto& it : stream_map_) {
renjietangb663b862019-07-08 16:02:39 -0700396 if (!it.second->is_static()) {
397 non_static_streams[it.first] = it.second.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700398 }
renjietangb663b862019-07-08 16:02:39 -0700399 }
400 for (const auto& it : non_static_streams) {
401 QuicStreamId id = it.first;
402 it.second->OnConnectionClosed(frame.quic_error_code, source);
renjietang55d182a2019-07-12 10:26:25 -0700403 if (stream_map_.find(id) != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700404 QUIC_BUG << ENDPOINT << "Stream " << id
405 << " failed to close under OnConnectionClosed";
406 CloseStream(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407 }
408 }
409
410 // Cleanup zombie stream map on connection close.
411 while (!zombie_streams_.empty()) {
412 ZombieStreamMap::iterator it = zombie_streams_.begin();
413 closed_streams_.push_back(std::move(it->second));
414 zombie_streams_.erase(it);
415 }
416
417 closed_streams_clean_up_alarm_->Cancel();
418
419 if (visitor_) {
fkastenholz5d880a92019-06-21 09:01:56 -0700420 visitor_->OnConnectionClosed(connection_->connection_id(),
421 frame.quic_error_code, frame.error_details,
422 source);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500423 }
424}
425
426void QuicSession::OnWriteBlocked() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700427 if (!connection_->connected()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500428 return;
429 }
430 if (visitor_) {
431 visitor_->OnWriteBlocked(connection_);
432 }
433}
434
435void QuicSession::OnSuccessfulVersionNegotiation(
436 const ParsedQuicVersion& version) {
437 GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
438}
439
440void QuicSession::OnConnectivityProbeReceived(
dschinazi17d42422019-06-18 16:35:07 -0700441 const QuicSocketAddress& /*self_address*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500442 const QuicSocketAddress& peer_address) {
443 if (perspective() == Perspective::IS_SERVER) {
444 // Server only sends back a connectivity probe after received a
445 // connectivity probe from a new peer address.
446 connection_->SendConnectivityProbingResponsePacket(peer_address);
447 }
448}
449
450void QuicSession::OnPathDegrading() {}
451
452bool QuicSession::AllowSelfAddressChange() const {
453 return false;
454}
455
456void QuicSession::OnForwardProgressConfirmed() {}
457
458void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
459 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
460 // assume that it still exists.
461 QuicStreamId stream_id = frame.stream_id;
462 if (stream_id ==
463 QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
464 // This is a window update that applies to the connection, rather than an
465 // individual stream.
466 QUIC_DLOG(INFO) << ENDPOINT
467 << "Received connection level flow control window "
468 "update with byte offset: "
469 << frame.byte_offset;
470 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
471 return;
472 }
renjietang28c04b72019-07-01 15:08:09 -0700473
474 if (VersionHasIetfQuicFrames(connection_->transport_version()) &&
475 QuicUtils::GetStreamType(stream_id, perspective(),
476 IsIncomingStream(stream_id)) ==
477 READ_UNIDIRECTIONAL) {
478 connection()->CloseConnection(
479 QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM,
480 "WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.",
481 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
482 return;
483 }
484
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485 QuicStream* stream = GetOrCreateStream(stream_id);
486 if (stream != nullptr) {
487 stream->OnWindowUpdateFrame(frame);
488 }
489}
490
491void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
492 // TODO(rjshade): Compare our flow control receive windows for specified
493 // streams: if we have a large window then maybe something
494 // had gone wrong with the flow control accounting.
495 QUIC_DLOG(INFO) << ENDPOINT << "Received BLOCKED frame with stream id: "
496 << frame.stream_id;
497}
498
499bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream,
500 uint64_t previous_bytes_written,
501 bool previous_fin_sent) {
502 if ( // Stream should not be closed.
503 !stream->write_side_closed() &&
504 // Not connection flow control blocked.
505 !flow_controller_.IsBlocked() &&
506 // Detect lack of forward progress.
507 previous_bytes_written == stream->stream_bytes_written() &&
508 previous_fin_sent == stream->fin_sent()) {
509 stream->set_busy_counter(stream->busy_counter() + 1);
510 QUIC_DVLOG(1) << "Suspected busy loop on stream id " << stream->id()
511 << " stream_bytes_written " << stream->stream_bytes_written()
512 << " fin " << stream->fin_sent() << " count "
513 << stream->busy_counter();
514 // Wait a few iterations before firing, the exact count is
515 // arbitrary, more than a few to cover a few test-only false
516 // positives.
517 if (stream->busy_counter() > 20) {
518 QUIC_LOG(ERROR) << "Detected busy loop on stream id " << stream->id()
519 << " stream_bytes_written "
520 << stream->stream_bytes_written() << " fin "
521 << stream->fin_sent();
522 return false;
523 }
524 } else {
525 stream->set_busy_counter(0);
526 }
527 return true;
528}
529
530bool QuicSession::CheckStreamWriteBlocked(QuicStream* stream) const {
531 if (!stream->write_side_closed() && stream->HasBufferedData() &&
532 !stream->flow_controller()->IsBlocked() &&
533 !write_blocked_streams_.IsStreamBlocked(stream->id())) {
534 QUIC_DLOG(ERROR) << "stream " << stream->id() << " has buffered "
535 << stream->BufferedDataBytes()
536 << " bytes, and is not flow control blocked, "
537 "but it is not in the write block list.";
538 return false;
539 }
540 return true;
541}
542
543void QuicSession::OnCanWrite() {
544 if (!RetransmitLostData()) {
545 // Cannot finish retransmitting lost data, connection is write blocked.
546 QUIC_DVLOG(1) << ENDPOINT
547 << "Cannot finish retransmitting lost data, connection is "
548 "write blocked.";
549 return;
550 }
551 if (session_decides_what_to_write()) {
552 SetTransmissionType(NOT_RETRANSMISSION);
553 }
554 // We limit the number of writes to the number of pending streams. If more
555 // streams become pending, WillingAndAbleToWrite will be true, which will
556 // cause the connection to request resumption before yielding to other
557 // connections.
558 // If we are connection level flow control blocked, then only allow the
559 // crypto and headers streams to try writing as all other streams will be
560 // blocked.
561 size_t num_writes = flow_controller_.IsBlocked()
562 ? write_blocked_streams_.NumBlockedSpecialStreams()
563 : write_blocked_streams_.NumBlockedStreams();
564 if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
565 return;
566 }
567
fayanga4b37b22019-06-18 13:37:47 -0700568 QuicConnection::ScopedPacketFlusher flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500569 if (control_frame_manager_.WillingToWrite()) {
570 control_frame_manager_.OnCanWrite();
571 }
572 for (size_t i = 0; i < num_writes; ++i) {
573 if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() ||
574 write_blocked_streams_.HasWriteBlockedDataStreams())) {
575 // Writing one stream removed another!? Something's broken.
576 QUIC_BUG << "WriteBlockedStream is missing";
577 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
578 "WriteBlockedStream is missing",
579 ConnectionCloseBehavior::SILENT_CLOSE);
580 return;
581 }
582 if (!connection_->CanWriteStreamData()) {
583 return;
584 }
585 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
586 QuicStream* stream = GetOrCreateStream(currently_writing_stream_id_);
587 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
588 // If the stream can't write all bytes it'll re-add itself to the blocked
589 // list.
590 uint64_t previous_bytes_written = stream->stream_bytes_written();
591 bool previous_fin_sent = stream->fin_sent();
592 QUIC_DVLOG(1) << "stream " << stream->id() << " bytes_written "
593 << previous_bytes_written << " fin " << previous_fin_sent;
594 stream->OnCanWrite();
595 DCHECK(CheckStreamWriteBlocked(stream));
596 DCHECK(CheckStreamNotBusyLooping(stream, previous_bytes_written,
597 previous_fin_sent));
598 }
599 currently_writing_stream_id_ = 0;
600 }
601}
602
QUICHE teamb8343252019-04-29 13:58:01 -0700603bool QuicSession::SendProbingData() {
604 if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket(
605 PROBING_RETRANSMISSION)) {
606 return true;
607 }
608 return false;
609}
610
QUICHE teama6ef0a62019-03-07 20:34:33 -0500611bool QuicSession::WillingAndAbleToWrite() const {
612 // Schedule a write when:
613 // 1) control frame manager has pending or new control frames, or
614 // 2) any stream has pending retransmissions, or
615 // 3) If the crypto or headers streams are blocked, or
616 // 4) connection is not flow control blocked and there are write blocked
617 // streams.
618 return control_frame_manager_.WillingToWrite() ||
619 !streams_with_pending_retransmission_.empty() ||
620 write_blocked_streams_.HasWriteBlockedSpecialStream() ||
621 (!flow_controller_.IsBlocked() &&
622 write_blocked_streams_.HasWriteBlockedDataStreams());
623}
624
625bool QuicSession::HasPendingHandshake() const {
nharper46833c32019-05-15 21:33:05 -0700626 if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
627 // Writing CRYPTO frames is not subject to flow control, so there can't be
628 // pending data to write, only pending retransmissions.
629 return GetCryptoStream()->HasPendingCryptoRetransmission();
630 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500631 return QuicContainsKey(
632 streams_with_pending_retransmission_,
633 QuicUtils::GetCryptoStreamId(connection_->transport_version())) ||
634 write_blocked_streams_.IsStreamBlocked(
635 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
636}
637
638uint64_t QuicSession::GetNumOpenDynamicStreams() const {
renjietang55d182a2019-07-12 10:26:25 -0700639 return stream_map_.size() - draining_streams_.size() +
renjietangfbeb5bf2019-04-19 15:06:20 -0700640 locally_closed_streams_highest_offset_.size() -
641 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642}
643
644void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address,
645 const QuicSocketAddress& peer_address,
646 const QuicReceivedPacket& packet) {
647 connection_->ProcessUdpPacket(self_address, peer_address, packet);
648}
649
650QuicConsumedData QuicSession::WritevData(QuicStream* stream,
651 QuicStreamId id,
652 size_t write_length,
653 QuicStreamOffset offset,
654 StreamSendingState state) {
655 // This check is an attempt to deal with potential memory corruption
656 // in which |id| ends up set to 1 (the crypto stream id). If this happen
657 // it might end up resulting in unencrypted stream data being sent.
658 // While this is impossible to avoid given sufficient corruption, this
659 // seems like a reasonable mitigation.
nharper46833c32019-05-15 21:33:05 -0700660 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500661 stream != GetMutableCryptoStream()) {
662 QUIC_BUG << "Stream id mismatch";
663 connection_->CloseConnection(
664 QUIC_INTERNAL_ERROR,
665 "Non-crypto stream attempted to write data as crypto stream.",
666 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
667 return QuicConsumedData(0, false);
668 }
669 if (!IsEncryptionEstablished() &&
nharper46833c32019-05-15 21:33:05 -0700670 !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500671 // Do not let streams write without encryption. The calling stream will end
672 // up write blocked until OnCanWrite is next called.
673 return QuicConsumedData(0, false);
674 }
675
676 QuicConsumedData data =
677 connection_->SendStreamData(id, write_length, offset, state);
678 if (offset >= stream->stream_bytes_written()) {
679 // This is new stream data.
680 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
681 }
682 return data;
683}
684
685bool QuicSession::WriteControlFrame(const QuicFrame& frame) {
686 return connection_->SendControlFrame(frame);
687}
688
689void QuicSession::SendRstStream(QuicStreamId id,
690 QuicRstStreamErrorCode error,
691 QuicStreamOffset bytes_written) {
692 SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
693}
694
695void QuicSession::SendRstStreamInner(QuicStreamId id,
696 QuicRstStreamErrorCode error,
697 QuicStreamOffset bytes_written,
698 bool close_write_side_only) {
699 if (connection()->connected()) {
700 // Only send if still connected.
701 if (close_write_side_only) {
fkastenholz305e1732019-06-18 05:01:22 -0700702 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500703 // Send a RST_STREAM frame.
704 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
705 } else {
706 // Send a RST_STREAM frame plus, if version 99, an IETF
707 // QUIC STOP_SENDING frame. Both sre sent to emulate
708 // the two-way close that Google QUIC's RST_STREAM does.
fkastenholz305e1732019-06-18 05:01:22 -0700709 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fayanga4b37b22019-06-18 13:37:47 -0700710 QuicConnection::ScopedPacketFlusher flusher(connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500711 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
712 control_frame_manager_.WriteOrBufferStopSending(error, id);
713 } else {
714 control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
715 }
716 }
717 connection_->OnStreamReset(id, error);
718 }
719 if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
720 OnStreamDoneWaitingForAcks(id);
721 return;
722 }
723
724 if (!close_write_side_only) {
725 CloseStreamInner(id, true);
726 return;
727 }
fkastenholz305e1732019-06-18 05:01:22 -0700728 DCHECK(VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500729
renjietang55d182a2019-07-12 10:26:25 -0700730 StreamMap::iterator it = stream_map_.find(id);
731 if (it != stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -0700732 if (it->second->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700733 QUIC_DVLOG(1) << ENDPOINT
734 << "Try to send rst for a static stream, id: " << id
735 << " Closing connection";
736 connection()->CloseConnection(
737 QUIC_INVALID_STREAM_ID, "Sending rst for a static stream",
738 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
739 return;
740 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500741 QuicStream* stream = it->second.get();
742 if (stream) {
743 stream->set_rst_sent(true);
744 stream->CloseWriteSide();
745 }
746 }
747}
748
749void QuicSession::SendGoAway(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700750 const std::string& reason) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500751 // GOAWAY frame is not supported in v99.
fkastenholz305e1732019-06-18 05:01:22 -0700752 DCHECK(!VersionHasIetfQuicFrames(connection_->transport_version()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500753 if (goaway_sent_) {
754 return;
755 }
756 goaway_sent_ = true;
757 control_frame_manager_.WriteOrBufferGoAway(
758 error_code, stream_id_manager_.largest_peer_created_stream_id(), reason);
759}
760
761void QuicSession::SendBlocked(QuicStreamId id) {
762 control_frame_manager_.WriteOrBufferBlocked(id);
763}
764
765void QuicSession::SendWindowUpdate(QuicStreamId id,
766 QuicStreamOffset byte_offset) {
767 control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
768}
769
fkastenholz3c4eabf2019-04-22 07:49:59 -0700770void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
771 bool unidirectional) {
772 control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500773}
774
fkastenholz3c4eabf2019-04-22 07:49:59 -0700775void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count,
776 bool unidirectional) {
777 control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count,
778 unidirectional);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500779}
780
781void QuicSession::CloseStream(QuicStreamId stream_id) {
782 CloseStreamInner(stream_id, false);
783}
784
785void QuicSession::InsertLocallyClosedStreamsHighestOffset(
786 const QuicStreamId id,
787 QuicStreamOffset offset) {
788 locally_closed_streams_highest_offset_[id] = offset;
789 if (IsIncomingStream(id)) {
790 ++num_locally_closed_incoming_streams_highest_offset_;
791 }
792}
793
794void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
795 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
796
renjietang55d182a2019-07-12 10:26:25 -0700797 StreamMap::iterator it = stream_map_.find(stream_id);
798 if (it == stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500799 // When CloseStreamInner has been called recursively (via
800 // QuicStream::OnClose), the stream will already have been deleted
801 // from stream_map_, so return immediately.
802 QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
803 return;
804 }
805 QuicStream* stream = it->second.get();
renjietangb663b862019-07-08 16:02:39 -0700806 if (stream->is_static()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700807 QUIC_DVLOG(1) << ENDPOINT
808 << "Try to close a static stream, id: " << stream_id
809 << " Closing connection";
810 connection()->CloseConnection(
811 QUIC_INVALID_STREAM_ID, "Try to close a static stream",
812 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
813 return;
814 }
renjietangde12d3d2019-07-19 10:57:42 -0700815 StreamType type = stream->type();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500816
817 // Tell the stream that a RST has been sent.
818 if (locally_reset) {
819 stream->set_rst_sent(true);
820 }
821
822 if (stream->IsWaitingForAcks()) {
823 zombie_streams_[stream->id()] = std::move(it->second);
824 } else {
zhongyi1b2f7832019-06-14 13:31:34 -0700825 // Clean up the stream since it is no longer waiting for acks.
826 if (ignore_tlpr_if_no_pending_stream_data() &&
827 session_decides_what_to_write()) {
828 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data,
829 2, 5);
830 streams_waiting_for_acks_.erase(stream->id());
831 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500832 closed_streams_.push_back(std::move(it->second));
833 // Do not retransmit data of a closed stream.
834 streams_with_pending_retransmission_.erase(stream_id);
835 if (!closed_streams_clean_up_alarm_->IsSet()) {
836 closed_streams_clean_up_alarm_->Set(
837 connection_->clock()->ApproximateNow());
838 }
839 }
840
841 // If we haven't received a FIN or RST for this stream, we need to keep track
842 // of the how many bytes the stream's flow controller believes it has
843 // received, for accurate connection level flow control accounting.
844 const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
845 if (!had_fin_or_rst) {
846 InsertLocallyClosedStreamsHighestOffset(
847 stream_id, stream->flow_controller()->highest_received_byte_offset());
848 }
renjietang55d182a2019-07-12 10:26:25 -0700849 stream_map_.erase(it);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500850 if (IsIncomingStream(stream_id)) {
851 --num_dynamic_incoming_streams_;
852 }
853
854 const bool stream_was_draining =
855 draining_streams_.find(stream_id) != draining_streams_.end();
856 if (stream_was_draining) {
857 if (IsIncomingStream(stream_id)) {
858 --num_draining_incoming_streams_;
859 }
860 draining_streams_.erase(stream_id);
fkastenholz305e1732019-06-18 05:01:22 -0700861 } else if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500862 // Stream was not draining, but we did have a fin or rst, so we can now
863 // free the stream ID if version 99.
864 if (had_fin_or_rst) {
865 v99_streamid_manager_.OnStreamClosed(stream_id);
866 }
867 }
868
869 stream->OnClose();
870
871 if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst &&
fkastenholz305e1732019-06-18 05:01:22 -0700872 !VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500873 // Streams that first became draining already called OnCanCreate...
874 // This covers the case where the stream went directly to being closed.
renjietangde12d3d2019-07-19 10:57:42 -0700875 OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500876 }
877}
878
879void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
880 QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
881
882 if (pending_stream_map_.find(stream_id) == pending_stream_map_.end()) {
883 QUIC_BUG << ENDPOINT << "Stream is already closed: " << stream_id;
884 return;
885 }
886
887 SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
888
889 // The pending stream may have been deleted and removed during SendRstStream.
890 // Remove the stream from pending stream map iff it is still in the map.
891 if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
892 pending_stream_map_.erase(stream_id);
893 }
894
fkastenholz305e1732019-06-18 05:01:22 -0700895 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500896 v99_streamid_manager_.OnStreamClosed(stream_id);
897 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500898}
899
900void QuicSession::OnFinalByteOffsetReceived(
901 QuicStreamId stream_id,
902 QuicStreamOffset final_byte_offset) {
903 auto it = locally_closed_streams_highest_offset_.find(stream_id);
904 if (it == locally_closed_streams_highest_offset_.end()) {
905 return;
906 }
907
908 QUIC_DVLOG(1) << ENDPOINT << "Received final byte offset "
909 << final_byte_offset << " for stream " << stream_id;
910 QuicByteCount offset_diff = final_byte_offset - it->second;
911 if (flow_controller_.UpdateHighestReceivedOffset(
912 flow_controller_.highest_received_byte_offset() + offset_diff)) {
913 // If the final offset violates flow control, close the connection now.
914 if (flow_controller_.FlowControlViolation()) {
915 connection_->CloseConnection(
916 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
917 "Connection level flow control violation",
918 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
919 return;
920 }
921 }
922
923 flow_controller_.AddBytesConsumed(offset_diff);
924 locally_closed_streams_highest_offset_.erase(it);
925 if (IsIncomingStream(stream_id)) {
926 --num_locally_closed_incoming_streams_highest_offset_;
fkastenholz305e1732019-06-18 05:01:22 -0700927 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500928 v99_streamid_manager_.OnStreamClosed(stream_id);
929 }
fkastenholz305e1732019-06-18 05:01:22 -0700930 } else if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholz8556dc22019-07-18 12:42:38 -0700931 OnCanCreateNewOutgoingStream(false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500932 }
933}
934
935bool QuicSession::IsEncryptionEstablished() const {
936 // Once the handshake is confirmed, it never becomes un-confirmed.
937 if (is_handshake_confirmed_) {
938 return true;
939 }
940 return GetCryptoStream()->encryption_established();
941}
942
943bool QuicSession::IsCryptoHandshakeConfirmed() const {
944 return GetCryptoStream()->handshake_confirmed();
945}
946
947void QuicSession::OnConfigNegotiated() {
948 connection_->SetFromConfig(config_);
949
fkastenholz305e1732019-06-18 05:01:22 -0700950 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700951 uint32_t max_streams = 0;
952 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
953 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
954 }
955 QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
956 << max_streams;
957 v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
958 max_streams);
959
960 max_streams = 0;
961 if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
962 max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams();
963 }
964 QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
965 << max_streams;
966 v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
967 max_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500968 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -0700969 uint32_t max_streams = 0;
970 if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
971 max_streams = config_.ReceivedMaxIncomingBidirectionalStreams();
972 }
973 QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500974 stream_id_manager_.set_max_open_outgoing_streams(max_streams);
975 }
fkastenholzd3a1de92019-05-15 07:00:07 -0700976
QUICHE teama6ef0a62019-03-07 20:34:33 -0500977 if (perspective() == Perspective::IS_SERVER) {
978 if (config_.HasReceivedConnectionOptions()) {
979 // The following variations change the initial receive flow control
980 // window sizes.
981 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
982 AdjustInitialFlowControlWindows(64 * 1024);
983 }
984 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
985 AdjustInitialFlowControlWindows(128 * 1024);
986 }
987 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
988 AdjustInitialFlowControlWindows(256 * 1024);
989 }
990 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
991 AdjustInitialFlowControlWindows(512 * 1024);
992 }
993 if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
994 AdjustInitialFlowControlWindows(1024 * 1024);
995 }
996 }
997
998 config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
999 }
1000
fkastenholz305e1732019-06-18 05:01:22 -07001001 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -07001002 v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
1003 config_.GetMaxIncomingBidirectionalStreamsToSend());
1004 v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
1005 config_.GetMaxIncomingUnidirectionalStreamsToSend());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001006 } else {
fkastenholzd3a1de92019-05-15 07:00:07 -07001007 // A small number of additional incoming streams beyond the limit should be
1008 // allowed. This helps avoid early connection termination when FIN/RSTs for
1009 // old streams are lost or arrive out of order.
1010 // Use a minimum number of additional streams, or a percentage increase,
1011 // whichever is larger.
1012 uint32_t max_incoming_streams_to_send =
1013 config_.GetMaxIncomingBidirectionalStreamsToSend();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001014 uint32_t max_incoming_streams =
1015 std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
1016 static_cast<uint32_t>(max_incoming_streams_to_send *
1017 kMaxStreamsMultiplier));
1018 stream_id_manager_.set_max_open_incoming_streams(max_incoming_streams);
1019 }
1020
1021 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
1022 // Streams which were created before the SHLO was received (0-RTT
1023 // requests) are now informed of the peer's initial flow control window.
1024 OnNewStreamFlowControlWindow(
1025 config_.ReceivedInitialStreamFlowControlWindowBytes());
1026 }
1027 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
1028 OnNewSessionFlowControlWindow(
1029 config_.ReceivedInitialSessionFlowControlWindowBytes());
1030 }
1031}
1032
1033void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
1034 const float session_window_multiplier =
1035 config_.GetInitialStreamFlowControlWindowToSend()
1036 ? static_cast<float>(
1037 config_.GetInitialSessionFlowControlWindowToSend()) /
1038 config_.GetInitialStreamFlowControlWindowToSend()
1039 : 1.5;
1040
1041 QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
1042 config_.SetInitialStreamFlowControlWindowToSend(stream_window);
1043
1044 size_t session_window = session_window_multiplier * stream_window;
1045 QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
1046 << session_window;
1047 config_.SetInitialSessionFlowControlWindowToSend(session_window);
1048 flow_controller_.UpdateReceiveWindowSize(session_window);
1049 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001050 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001051 kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
1052 }
renjietangb663b862019-07-08 16:02:39 -07001053 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001054 GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize(
1055 stream_window);
1056 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001057}
1058
1059void QuicSession::HandleFrameOnNonexistentOutgoingStream(
1060 QuicStreamId stream_id) {
1061 DCHECK(!IsClosedStream(stream_id));
1062 // Received a frame for a locally-created stream that is not currently
1063 // active. This is an error.
1064 connection()->CloseConnection(
1065 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
1066 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1067}
1068
1069void QuicSession::HandleRstOnValidNonexistentStream(
1070 const QuicRstStreamFrame& frame) {
1071 // If the stream is neither originally in active streams nor created in
renjietang880d2432019-07-16 13:14:37 -07001072 // GetOrCreateStream(), it could be a closed stream in which case its
QUICHE teama6ef0a62019-03-07 20:34:33 -05001073 // final received byte offset need to be updated.
1074 if (IsClosedStream(frame.stream_id)) {
1075 // The RST frame contains the final byte offset for the stream: we can now
1076 // update the connection level flow controller if needed.
1077 OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset);
1078 }
1079}
1080
1081void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001082 if (new_window < kMinimumFlowControlSendWindow &&
1083 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001084 QUIC_LOG_FIRST_N(ERROR, 1)
1085 << "Peer sent us an invalid stream flow control send window: "
dschinazic7036122019-04-30 12:46:34 -07001086 << new_window << ", below minimum: " << kMinimumFlowControlSendWindow;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001087 if (connection_->connected()) {
1088 connection_->CloseConnection(
1089 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
1090 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1091 }
1092 return;
1093 }
1094
1095 // Inform all existing streams about the new window.
renjietang55d182a2019-07-12 10:26:25 -07001096 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001097 kv.second->UpdateSendWindowOffset(new_window);
1098 }
renjietangb663b862019-07-08 16:02:39 -07001099 if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
renjietang08a9cf72019-04-23 17:01:34 -07001100 GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
1101 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001102}
1103
1104void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
dschinazic7036122019-04-30 12:46:34 -07001105 if (new_window < kMinimumFlowControlSendWindow &&
1106 !connection_->version().AllowsLowFlowControlLimits()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001107 QUIC_LOG_FIRST_N(ERROR, 1)
1108 << "Peer sent us an invalid session flow control send window: "
1109 << new_window << ", below default: " << kMinimumFlowControlSendWindow;
1110 if (connection_->connected()) {
1111 connection_->CloseConnection(
1112 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
1113 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1114 }
1115 return;
1116 }
1117
1118 flow_controller_.UpdateSendWindowOffset(new_window);
1119}
1120
1121void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
1122 switch (event) {
1123 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
1124 // to QuicSession since it is the glue.
1125 case ENCRYPTION_FIRST_ESTABLISHED:
1126 // Given any streams blocked by encryption a chance to write.
1127 OnCanWrite();
1128 break;
1129
1130 case ENCRYPTION_REESTABLISHED:
1131 // Retransmit originally packets that were sent, since they can't be
1132 // decrypted by the peer.
1133 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
1134 // Given any streams blocked by encryption a chance to write.
1135 OnCanWrite();
1136 break;
1137
1138 case HANDSHAKE_CONFIRMED:
1139 QUIC_BUG_IF(!config_.negotiated())
1140 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
1141 // Discard originally encrypted packets, since they can't be decrypted by
1142 // the peer.
1143 NeuterUnencryptedData();
1144 is_handshake_confirmed_ = true;
1145 break;
1146
1147 default:
1148 QUIC_LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
1149 }
1150}
1151
1152void QuicSession::OnCryptoHandshakeMessageSent(
1153 const CryptoHandshakeMessage& /*message*/) {}
1154
1155void QuicSession::OnCryptoHandshakeMessageReceived(
1156 const CryptoHandshakeMessage& /*message*/) {}
1157
fayang476683a2019-07-25 12:42:16 -07001158void QuicSession::RegisterStreamPriority(
1159 QuicStreamId id,
1160 bool is_static,
1161 const spdy::SpdyStreamPrecedence& precedence) {
1162 write_blocked_streams()->RegisterStream(id, is_static, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001163}
1164
1165void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
1166 write_blocked_streams()->UnregisterStream(id, is_static);
1167}
1168
fayang476683a2019-07-25 12:42:16 -07001169void QuicSession::UpdateStreamPriority(
1170 QuicStreamId id,
1171 const spdy::SpdyStreamPrecedence& new_precedence) {
1172 write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001173}
1174
1175QuicConfig* QuicSession::config() {
1176 return &config_;
1177}
1178
1179void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
renjietangfbeb5bf2019-04-19 15:06:20 -07001180 DCHECK(!stream->is_static());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001181 QuicStreamId stream_id = stream->id();
renjietang55d182a2019-07-12 10:26:25 -07001182 QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
QUICHE teama6ef0a62019-03-07 20:34:33 -05001183 << ". activating " << stream_id;
renjietang55d182a2019-07-12 10:26:25 -07001184 DCHECK(!QuicContainsKey(stream_map_, stream_id));
1185 stream_map_[stream_id] = std::move(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001186 if (IsIncomingStream(stream_id)) {
1187 ++num_dynamic_incoming_streams_;
1188 }
1189}
1190
1191QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001192 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001193 return v99_streamid_manager_.GetNextOutgoingBidirectionalStreamId();
1194 }
1195 return stream_id_manager_.GetNextOutgoingStreamId();
1196}
1197
1198QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() {
fkastenholz305e1732019-06-18 05:01:22 -07001199 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001200 return v99_streamid_manager_.GetNextOutgoingUnidirectionalStreamId();
1201 }
1202 return stream_id_manager_.GetNextOutgoingStreamId();
1203}
1204
1205bool QuicSession::CanOpenNextOutgoingBidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001206 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001207 return v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream();
1208 }
1209 return stream_id_manager_.CanOpenNextOutgoingStream(
1210 GetNumOpenOutgoingStreams());
1211}
1212
1213bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() {
fkastenholz305e1732019-06-18 05:01:22 -07001214 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001215 return v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream();
1216 }
1217 return stream_id_manager_.CanOpenNextOutgoingStream(
1218 GetNumOpenOutgoingStreams());
1219}
1220
1221QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
renjietang28c04b72019-07-01 15:08:09 -07001222 DCHECK(!QuicContainsKey(pending_stream_map_, stream_id));
renjietangb663b862019-07-08 16:02:39 -07001223 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
nharper46833c32019-05-15 21:33:05 -07001224 stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001225 return GetMutableCryptoStream();
renjietang08a9cf72019-04-23 17:01:34 -07001226 }
renjietang880d2432019-07-16 13:14:37 -07001227
1228 StreamMap::iterator it = stream_map_.find(stream_id);
1229 if (it != stream_map_.end()) {
1230 return it->second.get();
1231 }
1232
1233 if (IsClosedStream(stream_id)) {
1234 return nullptr;
1235 }
1236
1237 if (!IsIncomingStream(stream_id)) {
1238 HandleFrameOnNonexistentOutgoingStream(stream_id);
1239 return nullptr;
1240 }
1241
1242 // TODO(fkastenholz): If we are creating a new stream and we have
1243 // sent a goaway, we should ignore the stream creation. Need to
1244 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1245 // B) reject stream creation ("return nullptr")
1246
1247 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
1248 return nullptr;
1249 }
1250
1251 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
1252 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1253 // CanOpenIncomingStream interface consistent with that of v99.
1254 if (!stream_id_manager_.CanOpenIncomingStream(
1255 GetNumOpenIncomingStreams())) {
1256 // Refuse to open the stream.
1257 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
1258 return nullptr;
1259 }
1260 }
1261
1262 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001263}
1264
1265void QuicSession::StreamDraining(QuicStreamId stream_id) {
renjietang55d182a2019-07-12 10:26:25 -07001266 DCHECK(QuicContainsKey(stream_map_, stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -05001267 if (!QuicContainsKey(draining_streams_, stream_id)) {
1268 draining_streams_.insert(stream_id);
1269 if (IsIncomingStream(stream_id)) {
1270 ++num_draining_incoming_streams_;
1271 }
fkastenholz305e1732019-06-18 05:01:22 -07001272 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001273 v99_streamid_manager_.OnStreamClosed(stream_id);
1274 }
1275 }
1276 if (!IsIncomingStream(stream_id)) {
1277 // Inform application that a stream is available.
fkastenholz8556dc22019-07-18 12:42:38 -07001278 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
renjietangde12d3d2019-07-19 10:57:42 -07001279 OnCanCreateNewOutgoingStream(
1280 !QuicUtils::IsBidirectionalStreamId(stream_id));
fkastenholz8556dc22019-07-18 12:42:38 -07001281 } else {
renjietangde12d3d2019-07-19 10:57:42 -07001282 QuicStream* stream = GetStream(stream_id);
1283 if (!stream) {
1284 QUIC_BUG << "Stream doesn't exist when draining.";
1285 return;
1286 }
1287 OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL);
fkastenholz8556dc22019-07-18 12:42:38 -07001288 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001289 }
1290}
1291
1292bool QuicSession::MaybeIncreaseLargestPeerStreamId(
1293 const QuicStreamId stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001294 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001295 return v99_streamid_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1296 }
1297 return stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id);
1298}
1299
1300bool QuicSession::ShouldYield(QuicStreamId stream_id) {
1301 if (stream_id == currently_writing_stream_id_) {
1302 return false;
1303 }
1304 return write_blocked_streams()->ShouldYield(stream_id);
1305}
1306
renjietange76b2da2019-05-13 14:50:23 -07001307PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
1308 auto it = pending_stream_map_.find(stream_id);
1309 if (it != pending_stream_map_.end()) {
1310 return it->second.get();
1311 }
1312
1313 if (IsClosedStream(stream_id) ||
1314 !MaybeIncreaseLargestPeerStreamId(stream_id)) {
1315 return nullptr;
1316 }
1317
1318 auto pending = QuicMakeUnique<PendingStream>(stream_id, this);
1319 PendingStream* unowned_pending = pending.get();
1320 pending_stream_map_[stream_id] = std::move(pending);
1321 return unowned_pending;
1322}
1323
QUICHE teama6ef0a62019-03-07 20:34:33 -05001324QuicStream* QuicSession::GetOrCreateDynamicStream(
1325 const QuicStreamId stream_id) {
renjietang880d2432019-07-16 13:14:37 -07001326 DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream));
renjietang55d182a2019-07-12 10:26:25 -07001327 StreamMap::iterator it = stream_map_.find(stream_id);
1328 if (it != stream_map_.end()) {
renjietang2c4d7122019-05-20 17:18:14 -07001329 return it->second.get();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001330 }
1331
1332 if (IsClosedStream(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001333 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001334 }
1335
1336 if (!IsIncomingStream(stream_id)) {
1337 HandleFrameOnNonexistentOutgoingStream(stream_id);
renjietang2c4d7122019-05-20 17:18:14 -07001338 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001339 }
1340
QUICHE teama6ef0a62019-03-07 20:34:33 -05001341 // TODO(fkastenholz): If we are creating a new stream and we have
1342 // sent a goaway, we should ignore the stream creation. Need to
1343 // add code to A) test if goaway was sent ("if (goaway_sent_)") and
1344 // B) reject stream creation ("return nullptr")
1345
1346 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
renjietang2c4d7122019-05-20 17:18:14 -07001347 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001348 }
1349
fkastenholz305e1732019-06-18 05:01:22 -07001350 if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001351 // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
1352 // CanOpenIncomingStream interface cosistent with that of v99.
1353 if (!stream_id_manager_.CanOpenIncomingStream(
1354 GetNumOpenIncomingStreams())) {
1355 // Refuse to open the stream.
1356 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
renjietang2c4d7122019-05-20 17:18:14 -07001357 return nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001358 }
1359 }
1360
renjietang2c4d7122019-05-20 17:18:14 -07001361 return CreateIncomingStream(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001362}
1363
1364void QuicSession::set_largest_peer_created_stream_id(
1365 QuicStreamId largest_peer_created_stream_id) {
fkastenholz305e1732019-06-18 05:01:22 -07001366 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001367 v99_streamid_manager_.SetLargestPeerCreatedStreamId(
1368 largest_peer_created_stream_id);
1369 return;
1370 }
1371 stream_id_manager_.set_largest_peer_created_stream_id(
1372 largest_peer_created_stream_id);
1373}
1374
1375bool QuicSession::IsClosedStream(QuicStreamId id) {
1376 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1377 id);
1378 if (IsOpenStream(id)) {
1379 // Stream is active
1380 return false;
1381 }
1382
fkastenholz305e1732019-06-18 05:01:22 -07001383 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001384 return !v99_streamid_manager_.IsAvailableStream(id);
1385 }
1386
1387 return !stream_id_manager_.IsAvailableStream(id);
1388}
1389
1390bool QuicSession::IsOpenStream(QuicStreamId id) {
1391 DCHECK_NE(QuicUtils::GetInvalidStreamId(connection_->transport_version()),
1392 id);
renjietang55d182a2019-07-12 10:26:25 -07001393 if (QuicContainsKey(stream_map_, id) ||
renjietang08a9cf72019-04-23 17:01:34 -07001394 QuicContainsKey(pending_stream_map_, id) ||
nharper46833c32019-05-15 21:33:05 -07001395 QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001396 // Stream is active
1397 return true;
1398 }
1399 return false;
1400}
1401
rchda26cdb2019-05-17 11:57:37 -07001402bool QuicSession::IsStaticStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001403 auto it = stream_map_.find(id);
1404 if (it == stream_map_.end()) {
renjietangb663b862019-07-08 16:02:39 -07001405 return false;
rchda26cdb2019-05-17 11:57:37 -07001406 }
renjietangb663b862019-07-08 16:02:39 -07001407 return it->second->is_static();
rchda26cdb2019-05-17 11:57:37 -07001408}
1409
QUICHE teama6ef0a62019-03-07 20:34:33 -05001410size_t QuicSession::GetNumOpenIncomingStreams() const {
1411 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
1412 num_locally_closed_incoming_streams_highest_offset_;
1413}
1414
1415size_t QuicSession::GetNumOpenOutgoingStreams() const {
1416 DCHECK_GE(GetNumDynamicOutgoingStreams() +
1417 GetNumLocallyClosedOutgoingStreamsHighestOffset(),
1418 GetNumDrainingOutgoingStreams());
1419 return GetNumDynamicOutgoingStreams() +
1420 GetNumLocallyClosedOutgoingStreamsHighestOffset() -
1421 GetNumDrainingOutgoingStreams();
1422}
1423
1424size_t QuicSession::GetNumActiveStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001425 return stream_map_.size() - draining_streams_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001426 num_incoming_static_streams_ - num_outgoing_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001427}
1428
1429size_t QuicSession::GetNumDrainingStreams() const {
1430 return draining_streams_.size();
1431}
1432
1433void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
1434 if (GetOrCreateStream(id) == nullptr) {
1435 QUIC_BUG << "Marking unknown stream " << id << " blocked.";
1436 QUIC_LOG_FIRST_N(ERROR, 2) << QuicStackTrace();
1437 }
1438
1439 write_blocked_streams_.AddStream(id);
1440}
1441
1442bool QuicSession::HasDataToWrite() const {
1443 return write_blocked_streams_.HasWriteBlockedSpecialStream() ||
1444 write_blocked_streams_.HasWriteBlockedDataStreams() ||
1445 connection_->HasQueuedData() ||
1446 !streams_with_pending_retransmission_.empty() ||
1447 control_frame_manager_.WillingToWrite();
1448}
1449
1450void QuicSession::OnAckNeedsRetransmittableFrame() {
1451 flow_controller_.SendWindowUpdate();
1452}
1453
1454void QuicSession::SendPing() {
1455 control_frame_manager_.WritePing();
1456}
1457
1458size_t QuicSession::GetNumDynamicOutgoingStreams() const {
renjietang55d182a2019-07-12 10:26:25 -07001459 DCHECK_GE(
1460 static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()),
1461 num_dynamic_incoming_streams_ + num_outgoing_static_streams_ +
1462 num_incoming_static_streams_);
1463 return stream_map_.size() + pending_stream_map_.size() -
renjietangfbeb5bf2019-04-19 15:06:20 -07001464 num_dynamic_incoming_streams_ - num_outgoing_static_streams_ -
1465 num_incoming_static_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001466}
1467
1468size_t QuicSession::GetNumDrainingOutgoingStreams() const {
1469 DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
1470 return draining_streams_.size() - num_draining_incoming_streams_;
1471}
1472
1473size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
1474 DCHECK_GE(locally_closed_streams_highest_offset_.size(),
1475 num_locally_closed_incoming_streams_highest_offset_);
1476 return locally_closed_streams_highest_offset_.size() -
1477 num_locally_closed_incoming_streams_highest_offset_;
1478}
1479
1480bool QuicSession::IsConnectionFlowControlBlocked() const {
1481 return flow_controller_.IsBlocked();
1482}
1483
1484bool QuicSession::IsStreamFlowControlBlocked() {
renjietang55d182a2019-07-12 10:26:25 -07001485 for (auto const& kv : stream_map_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001486 if (kv.second->flow_controller()->IsBlocked()) {
1487 return true;
1488 }
1489 }
renjietangb663b862019-07-08 16:02:39 -07001490 if (!QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
renjietang08a9cf72019-04-23 17:01:34 -07001491 GetMutableCryptoStream()->flow_controller()->IsBlocked()) {
renjietang08a9cf72019-04-23 17:01:34 -07001492 return true;
1493 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001494 return false;
1495}
1496
1497size_t QuicSession::MaxAvailableBidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001498 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001499 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1500 }
1501 return stream_id_manager_.MaxAvailableStreams();
1502}
1503
1504size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001505 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001506 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1507 }
1508 return stream_id_manager_.MaxAvailableStreams();
1509}
1510
1511bool QuicSession::IsIncomingStream(QuicStreamId id) const {
fkastenholz305e1732019-06-18 05:01:22 -07001512 if (VersionHasIetfQuicFrames(connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001513 return v99_streamid_manager_.IsIncomingStream(id);
1514 }
1515 return stream_id_manager_.IsIncomingStream(id);
1516}
1517
1518void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
zhongyi1b2f7832019-06-14 13:31:34 -07001519 if (ignore_tlpr_if_no_pending_stream_data() &&
1520 session_decides_what_to_write()) {
1521 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 3,
1522 5);
1523 streams_waiting_for_acks_.erase(id);
1524 }
1525
QUICHE teama6ef0a62019-03-07 20:34:33 -05001526 auto it = zombie_streams_.find(id);
1527 if (it == zombie_streams_.end()) {
1528 return;
1529 }
1530
1531 closed_streams_.push_back(std::move(it->second));
1532 if (!closed_streams_clean_up_alarm_->IsSet()) {
1533 closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow());
1534 }
1535 zombie_streams_.erase(it);
1536 // Do not retransmit data of a closed stream.
1537 streams_with_pending_retransmission_.erase(id);
1538}
1539
zhongyi1b2f7832019-06-14 13:31:34 -07001540void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) {
1541 if (!ignore_tlpr_if_no_pending_stream_data() ||
1542 !session_decides_what_to_write())
1543 return;
1544
1545 // Exclude crypto stream's status since it is counted in HasUnackedCryptoData.
1546 if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) {
1547 return;
1548 }
1549
1550 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 4,
1551 5);
1552 streams_waiting_for_acks_.insert(id);
1553
1554 // The number of the streams waiting for acks should not be larger than the
1555 // number of streams.
renjietang55d182a2019-07-12 10:26:25 -07001556 if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) <
zhongyi71e9d9e2019-06-14 14:57:16 -07001557 streams_waiting_for_acks_.size()) {
zhongyi1b2f7832019-06-14 13:31:34 -07001558 QUIC_BUG << "More streams are waiting for acks than the number of streams. "
renjietang55d182a2019-07-12 10:26:25 -07001559 << "Sizes: streams: " << stream_map_.size()
zhongyi1b2f7832019-06-14 13:31:34 -07001560 << ", zombie streams: " << zombie_streams_.size()
1561 << ", vs streams waiting for acks: "
1562 << streams_waiting_for_acks_.size();
1563 }
1564}
1565
QUICHE teama6ef0a62019-03-07 20:34:33 -05001566QuicStream* QuicSession::GetStream(QuicStreamId id) const {
renjietang55d182a2019-07-12 10:26:25 -07001567 auto active_stream = stream_map_.find(id);
1568 if (active_stream != stream_map_.end()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001569 return active_stream->second.get();
1570 }
1571 auto zombie_stream = zombie_streams_.find(id);
1572 if (zombie_stream != zombie_streams_.end()) {
1573 return zombie_stream->second.get();
1574 }
renjietang08a9cf72019-04-23 17:01:34 -07001575
renjietangb663b862019-07-08 16:02:39 -07001576 if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) {
renjietang08a9cf72019-04-23 17:01:34 -07001577 return const_cast<QuicCryptoStream*>(GetCryptoStream());
1578 }
1579
QUICHE teama6ef0a62019-03-07 20:34:33 -05001580 return nullptr;
1581}
1582
1583bool QuicSession::OnFrameAcked(const QuicFrame& frame,
QUICHE team9467db02019-05-30 09:38:45 -07001584 QuicTime::Delta ack_delay_time,
1585 QuicTime receive_timestamp) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001586 if (frame.type == MESSAGE_FRAME) {
QUICHE team9467db02019-05-30 09:38:45 -07001587 OnMessageAcked(frame.message_frame->message_id, receive_timestamp);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001588 return true;
1589 }
1590 if (frame.type == CRYPTO_FRAME) {
1591 return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
1592 ack_delay_time);
1593 }
1594 if (frame.type != STREAM_FRAME) {
1595 return control_frame_manager_.OnControlFrameAcked(frame);
1596 }
1597 bool new_stream_data_acked = false;
1598 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1599 // Stream can already be reset when sent frame gets acked.
1600 if (stream != nullptr) {
1601 QuicByteCount newly_acked_length = 0;
1602 new_stream_data_acked = stream->OnStreamFrameAcked(
1603 frame.stream_frame.offset, frame.stream_frame.data_length,
1604 frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
1605 if (!stream->HasPendingRetransmission()) {
1606 streams_with_pending_retransmission_.erase(stream->id());
1607 }
1608 }
1609 return new_stream_data_acked;
1610}
1611
1612void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
1613 QuicStream* stream = GetStream(frame.stream_id);
1614 if (stream == nullptr) {
1615 QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame
1616 << " is retransmitted.";
1617 connection()->CloseConnection(
1618 QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream",
1619 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1620 return;
1621 }
1622 stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length,
1623 frame.fin);
1624}
1625
1626void QuicSession::OnFrameLost(const QuicFrame& frame) {
1627 if (frame.type == MESSAGE_FRAME) {
1628 OnMessageLost(frame.message_frame->message_id);
1629 return;
1630 }
1631 if (frame.type == CRYPTO_FRAME) {
1632 GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
1633 return;
1634 }
1635 if (frame.type != STREAM_FRAME) {
1636 control_frame_manager_.OnControlFrameLost(frame);
1637 return;
1638 }
1639 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1640 if (stream == nullptr) {
1641 return;
1642 }
1643 stream->OnStreamFrameLost(frame.stream_frame.offset,
1644 frame.stream_frame.data_length,
1645 frame.stream_frame.fin);
1646 if (stream->HasPendingRetransmission() &&
1647 !QuicContainsKey(streams_with_pending_retransmission_,
1648 frame.stream_frame.stream_id)) {
1649 streams_with_pending_retransmission_.insert(
1650 std::make_pair(frame.stream_frame.stream_id, true));
1651 }
1652}
1653
1654void QuicSession::RetransmitFrames(const QuicFrames& frames,
1655 TransmissionType type) {
fayanga4b37b22019-06-18 13:37:47 -07001656 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001657 SetTransmissionType(type);
1658 for (const QuicFrame& frame : frames) {
1659 if (frame.type == MESSAGE_FRAME) {
1660 // Do not retransmit MESSAGE frames.
1661 continue;
1662 }
1663 if (frame.type == CRYPTO_FRAME) {
1664 GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
1665 continue;
1666 }
1667 if (frame.type != STREAM_FRAME) {
1668 if (!control_frame_manager_.RetransmitControlFrame(frame)) {
1669 break;
1670 }
1671 continue;
1672 }
1673 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1674 if (stream != nullptr &&
1675 !stream->RetransmitStreamData(frame.stream_frame.offset,
1676 frame.stream_frame.data_length,
1677 frame.stream_frame.fin)) {
1678 break;
1679 }
1680 }
1681}
1682
1683bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const {
1684 if (frame.type == MESSAGE_FRAME) {
1685 return false;
1686 }
1687 if (frame.type == CRYPTO_FRAME) {
1688 return GetCryptoStream()->IsFrameOutstanding(
1689 frame.crypto_frame->level, frame.crypto_frame->offset,
1690 frame.crypto_frame->data_length);
1691 }
1692 if (frame.type != STREAM_FRAME) {
1693 return control_frame_manager_.IsControlFrameOutstanding(frame);
1694 }
1695 QuicStream* stream = GetStream(frame.stream_frame.stream_id);
1696 return stream != nullptr &&
1697 stream->IsStreamFrameOutstanding(frame.stream_frame.offset,
1698 frame.stream_frame.data_length,
1699 frame.stream_frame.fin);
1700}
1701
1702bool QuicSession::HasUnackedCryptoData() const {
1703 const QuicCryptoStream* crypto_stream = GetCryptoStream();
fayang44fa92f2019-07-01 07:32:14 -07001704 return crypto_stream->IsWaitingForAcks() || crypto_stream->HasBufferedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001705}
1706
zhongyi1b2f7832019-06-14 13:31:34 -07001707bool QuicSession::HasUnackedStreamData() const {
1708 DCHECK(ignore_tlpr_if_no_pending_stream_data());
1709 if (ignore_tlpr_if_no_pending_stream_data()) {
1710 QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_no_pending_stream_data, 5,
1711 5);
1712 return !streams_waiting_for_acks_.empty();
1713 }
1714
1715 return true;
1716}
1717
QUICHE teama6ef0a62019-03-07 20:34:33 -05001718WriteStreamDataResult QuicSession::WriteStreamData(QuicStreamId id,
1719 QuicStreamOffset offset,
1720 QuicByteCount data_length,
1721 QuicDataWriter* writer) {
1722 QuicStream* stream = GetStream(id);
1723 if (stream == nullptr) {
1724 // This causes the connection to be closed because of failed to serialize
1725 // packet.
ianswetteb101f82019-04-04 09:13:24 -07001726 QUIC_BUG << "Stream " << id << " does not exist when trying to write data."
1727 << " version:" << connection_->transport_version();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001728 return STREAM_MISSING;
1729 }
1730 if (stream->WriteStreamData(offset, data_length, writer)) {
1731 return WRITE_SUCCESS;
1732 }
1733 return WRITE_FAILED;
1734}
1735
1736bool QuicSession::WriteCryptoData(EncryptionLevel level,
1737 QuicStreamOffset offset,
1738 QuicByteCount data_length,
1739 QuicDataWriter* writer) {
1740 return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
1741 writer);
1742}
1743
1744QuicUint128 QuicSession::GetStatelessResetToken() const {
1745 return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
1746}
1747
1748bool QuicSession::RetransmitLostData() {
fayanga4b37b22019-06-18 13:37:47 -07001749 QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001750 // Retransmit crypto data first.
QUICHE teamea740082019-03-11 17:58:43 -07001751 bool uses_crypto_frames =
1752 QuicVersionUsesCryptoFrames(connection_->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -05001753 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1754 if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
1755 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1756 crypto_stream->WritePendingCryptoRetransmission();
1757 }
1758 // Retransmit crypto data in stream 1 frames (version < 47).
1759 if (!uses_crypto_frames &&
1760 QuicContainsKey(
1761 streams_with_pending_retransmission_,
1762 QuicUtils::GetCryptoStreamId(connection_->transport_version()))) {
1763 SetTransmissionType(HANDSHAKE_RETRANSMISSION);
1764 // Retransmit crypto data first.
1765 QuicStream* crypto_stream = GetStream(
1766 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1767 crypto_stream->OnCanWrite();
1768 DCHECK(CheckStreamWriteBlocked(crypto_stream));
1769 if (crypto_stream->HasPendingRetransmission()) {
1770 // Connection is write blocked.
1771 return false;
1772 } else {
1773 streams_with_pending_retransmission_.erase(
1774 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1775 }
1776 }
1777 if (control_frame_manager_.HasPendingRetransmission()) {
1778 SetTransmissionType(LOSS_RETRANSMISSION);
1779 control_frame_manager_.OnCanWrite();
1780 if (control_frame_manager_.HasPendingRetransmission()) {
1781 return false;
1782 }
1783 }
1784 while (!streams_with_pending_retransmission_.empty()) {
1785 if (!connection_->CanWriteStreamData()) {
1786 break;
1787 }
1788 // Retransmit lost data on headers and data streams.
1789 const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
1790 QuicStream* stream = GetStream(id);
1791 if (stream != nullptr) {
1792 SetTransmissionType(LOSS_RETRANSMISSION);
1793 stream->OnCanWrite();
1794 DCHECK(CheckStreamWriteBlocked(stream));
1795 if (stream->HasPendingRetransmission()) {
1796 // Connection is write blocked.
1797 break;
1798 } else if (!streams_with_pending_retransmission_.empty() &&
1799 streams_with_pending_retransmission_.begin()->first == id) {
1800 // Retransmit lost data may cause connection close. If this stream
1801 // has not yet sent fin, a RST_STREAM will be sent and it will be
1802 // removed from streams_with_pending_retransmission_.
1803 streams_with_pending_retransmission_.pop_front();
1804 }
1805 } else {
1806 QUIC_BUG << "Try to retransmit data of a closed stream";
1807 streams_with_pending_retransmission_.pop_front();
1808 }
1809 }
1810
1811 return streams_with_pending_retransmission_.empty();
1812}
1813
1814void QuicSession::NeuterUnencryptedData() {
1815 if (connection_->session_decides_what_to_write()) {
1816 QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
1817 crypto_stream->NeuterUnencryptedStreamData();
nharper46833c32019-05-15 21:33:05 -07001818 if (!crypto_stream->HasPendingRetransmission() &&
1819 !QuicVersionUsesCryptoFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001820 streams_with_pending_retransmission_.erase(
1821 QuicUtils::GetCryptoStreamId(connection_->transport_version()));
1822 }
1823 }
1824 connection_->NeuterUnencryptedPackets();
1825}
1826
1827void QuicSession::SetTransmissionType(TransmissionType type) {
1828 connection_->SetTransmissionType(type);
1829}
1830
1831MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
1832 if (!IsEncryptionEstablished()) {
1833 return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
1834 }
1835 MessageStatus result =
1836 connection_->SendMessage(last_message_id_ + 1, message);
1837 if (result == MESSAGE_STATUS_SUCCESS) {
1838 return {result, ++last_message_id_};
1839 }
1840 return {result, 0};
1841}
1842
QUICHE team9467db02019-05-30 09:38:45 -07001843void QuicSession::OnMessageAcked(QuicMessageId message_id,
dschinazi17d42422019-06-18 16:35:07 -07001844 QuicTime /*receive_timestamp*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001845 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id << " gets acked.";
1846}
1847
1848void QuicSession::OnMessageLost(QuicMessageId message_id) {
1849 QUIC_DVLOG(1) << ENDPOINT << "message " << message_id
1850 << " is considered lost";
1851}
1852
1853void QuicSession::CleanUpClosedStreams() {
1854 closed_streams_.clear();
1855}
1856
1857bool QuicSession::session_decides_what_to_write() const {
1858 return connection_->session_decides_what_to_write();
1859}
1860
ianswettb239f862019-04-05 09:15:06 -07001861QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
1862 return connection_->GetCurrentLargestMessagePayload();
1863}
1864
1865QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
1866 return connection_->GetGuaranteedLargestMessagePayload();
QUICHE teama6ef0a62019-03-07 20:34:33 -05001867}
1868
1869void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
1870 control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
1871}
1872
fkastenholz8556dc22019-07-18 12:42:38 -07001873void QuicSession::OnCanCreateNewOutgoingStream(bool /*unidirectional*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -05001874
1875QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001876 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001877 return v99_streamid_manager_.next_outgoing_bidirectional_stream_id();
1878 }
1879 return stream_id_manager_.next_outgoing_stream_id();
1880}
1881
1882QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const {
fkastenholz305e1732019-06-18 05:01:22 -07001883 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001884 return v99_streamid_manager_.next_outgoing_unidirectional_stream_id();
1885 }
1886 return stream_id_manager_.next_outgoing_stream_id();
1887}
1888
fkastenholz3c4eabf2019-04-22 07:49:59 -07001889bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
1890 return v99_streamid_manager_.OnMaxStreamsFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001891}
1892
fkastenholz3c4eabf2019-04-22 07:49:59 -07001893bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) {
1894 return v99_streamid_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -05001895}
1896
1897size_t QuicSession::max_open_incoming_bidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001898 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001899 return v99_streamid_manager_.GetMaxAllowdIncomingBidirectionalStreams();
1900 }
1901 return stream_id_manager_.max_open_incoming_streams();
1902}
1903
1904size_t QuicSession::max_open_incoming_unidirectional_streams() const {
fkastenholz305e1732019-06-18 05:01:22 -07001905 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -05001906 return v99_streamid_manager_.GetMaxAllowdIncomingUnidirectionalStreams();
1907 }
1908 return stream_id_manager_.max_open_incoming_streams();
1909}
1910
1911#undef ENDPOINT // undef for jumbo builds
1912} // namespace quic