Implement restrictions at https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1.
This prepares for 0-rtt on the client side.
This change should be no-op for current deployment in gfe because config is currently only set once.
gfe-relnote: unused code. not protected.
PiperOrigin-RevId: 308861599
Change-Id: I0c8182f3d11330f40024dca76de9fed6d383f8d1
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 4862d50..3524242 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1119,6 +1119,18 @@
QUIC_DVLOG(1) << ENDPOINT
<< "Setting Bidirectional outgoing_max_streams_ to "
<< max_streams;
+ if (perspective_ == Perspective::IS_CLIENT &&
+ max_streams <
+ v99_streamid_manager_.max_outgoing_bidirectional_streams()) {
+ connection_->CloseConnection(
+ QUIC_MAX_STREAMS_ERROR,
+ quiche::QuicheStrCat(
+ "new bidirectional limit ", max_streams,
+ " decreases the current limit: ",
+ v99_streamid_manager_.max_outgoing_bidirectional_streams()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
if (v99_streamid_manager_.MaybeAllowNewOutgoingBidirectionalStreams(
max_streams)) {
OnCanCreateNewOutgoingStream(/*unidirectional = */ false);
@@ -1128,6 +1140,8 @@
if (config_.HasReceivedMaxUnidirectionalStreams()) {
max_streams = config_.ReceivedMaxUnidirectionalStreams();
}
+ // TODO(b/153726130): remove this check and
+ // num_expected_unidirectional_static_streams_.
if (max_streams < num_expected_unidirectional_static_streams_) {
QUIC_DLOG(ERROR) << "Received unidirectional stream limit of "
<< max_streams << " < "
@@ -1138,6 +1152,18 @@
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+ if (perspective_ == Perspective::IS_CLIENT &&
+ max_streams <
+ v99_streamid_manager_.max_outgoing_unidirectional_streams()) {
+ connection_->CloseConnection(
+ QUIC_MAX_STREAMS_ERROR,
+ quiche::QuicheStrCat(
+ "new unidirectional limit ", max_streams,
+ " decreases the current limit: ",
+ v99_streamid_manager_.max_outgoing_unidirectional_streams()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
QUIC_DVLOG(1) << ENDPOINT
<< "Setting Unidirectional outgoing_max_streams_ to "
<< max_streams;
@@ -1310,6 +1336,7 @@
}
void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_QUIC_CRYPTO);
QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamFlowControlWindow " << new_window;
if (new_window < kMinimumFlowControlSendWindow &&
!connection_->version().AllowsLowFlowControlLimits()) {
@@ -1326,19 +1353,22 @@
for (auto const& kv : stream_map_) {
QUIC_DVLOG(1) << ENDPOINT << "Informing stream " << kv.first
<< " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
if (!QuicVersionUsesCryptoFrames(transport_version())) {
QUIC_DVLOG(1)
<< ENDPOINT
<< "Informing crypto stream of new stream flow control window "
<< new_window;
- GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
+ GetMutableCryptoStream()->ConfigSendWindowOffset(new_window);
}
}
void QuicSession::OnNewStreamUnidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamUnidirectionalFlowControlWindow "
<< new_window;
// Inform all existing outgoing unidirectional streams about the new window.
@@ -1353,12 +1383,15 @@
}
QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id
<< " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT
<< "OnNewStreamOutgoingBidirectionalFlowControlWindow "
<< new_window;
@@ -1374,12 +1407,15 @@
}
QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream "
<< id << " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT
<< "OnNewStreamIncomingBidirectionalFlowControlWindow "
<< new_window;
@@ -1395,19 +1431,36 @@
}
QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream "
<< id << " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window;
- if (new_window < kMinimumFlowControlSendWindow &&
- !connection_->version().AllowsLowFlowControlLimits()) {
+ bool close_connection = false;
+ if (!connection_->version().AllowsLowFlowControlLimits()) {
+ if (new_window < kMinimumFlowControlSendWindow) {
+ close_connection = true;
+ QUIC_LOG_FIRST_N(ERROR, 1)
+ << "Peer sent us an invalid session flow control send window: "
+ << new_window << ", below default: " << kMinimumFlowControlSendWindow;
+ }
+ } else if (perspective_ == Perspective::IS_CLIENT &&
+ new_window < flow_controller_.send_window_offset()) {
+ // The client receives a lower limit than remembered, violating
+ // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1
QUIC_LOG_FIRST_N(ERROR, 1)
<< "Peer sent us an invalid session flow control send window: "
- << new_window << ", below default: " << kMinimumFlowControlSendWindow;
+ << new_window
+ << ", below current: " << flow_controller_.send_window_offset();
+ close_connection = true;
+ }
+ if (close_connection) {
connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
+ QUIC_FLOW_CONTROL_INVALID_WINDOW,
+ quiche::QuicheStrCat("New connection window too low: ", new_window),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}