Add QUIC_BUG_IF to QuicUtils::GetCryptoStreamId
In QUIC versions that use CRYPTO frames (instead of stream 1 frames) for
the crypto handshake, the concept of a "crypto stream ID" makes no
sense, so QuicUtils::GetCryptoStreamId should hit a QUIC_BUG_IF to
prevent its misuse.
gfe-relnote: Add QUIC_BUG_IF protected behind QuicVersionUsesCryptoFrames
PiperOrigin-RevId: 248463613
Change-Id: If6768658e9ffc058778b53a91f95839826602fbf
diff --git a/quic/test_tools/quic_server_session_base_peer.h b/quic/test_tools/quic_server_session_base_peer.h
index 30c9b22..d2a21a6 100644
--- a/quic/test_tools/quic_server_session_base_peer.h
+++ b/quic/test_tools/quic_server_session_base_peer.h
@@ -21,9 +21,11 @@
static void SetCryptoStream(QuicServerSessionBase* s,
QuicCryptoServerStream* crypto_stream) {
s->crypto_stream_.reset(crypto_stream);
- s->RegisterStaticStream(
- QuicUtils::GetCryptoStreamId(s->connection()->transport_version()),
- crypto_stream);
+ if (!QuicVersionUsesCryptoFrames(s->connection()->transport_version())) {
+ s->RegisterStaticStream(
+ QuicUtils::GetCryptoStreamId(s->connection()->transport_version()),
+ crypto_stream);
+ }
}
static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) {
return s->bandwidth_resumption_enabled_;
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc
index 0683fd7..ed7043d 100644
--- a/quic/test_tools/quic_session_peer.cc
+++ b/quic/test_tools/quic_session_peer.cc
@@ -166,6 +166,20 @@
}
// static
+void QuicSessionPeer::RegisterStaticStream(QuicSession* session,
+ QuicStreamId id,
+ QuicStream* stream) {
+ return session->RegisterStaticStream(id, stream);
+}
+
+// static
+void QuicSessionPeer::RegisterStaticStreamNew(
+ QuicSession* session,
+ std::unique_ptr<QuicStream> stream) {
+ return session->RegisterStaticStreamNew(std::move(stream));
+}
+
+// static
bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) {
DCHECK_NE(0u, id);
return session->IsClosedStream(id);
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h
index 994a36c..3828981 100644
--- a/quic/test_tools/quic_session_peer.h
+++ b/quic/test_tools/quic_session_peer.h
@@ -64,6 +64,11 @@
QuicSession* session);
static void ActivateStream(QuicSession* session,
std::unique_ptr<QuicStream> stream);
+ static void RegisterStaticStream(QuicSession* session,
+ QuicStreamId stream_id,
+ QuicStream* stream);
+ static void RegisterStaticStreamNew(QuicSession* session,
+ std::unique_ptr<QuicStream> stream);
// Discern the state of a stream. Exactly one of these should be true at a
// time for any stream id > 0 (other than the special streams 1 and 3).
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc
index 9ae4d22..e72e0e1 100644
--- a/quic/test_tools/simple_session_notifier.cc
+++ b/quic/test_tools/simple_session_notifier.cc
@@ -72,7 +72,7 @@
QuicByteCount data_length,
bool fin) {
StreamState& state = stream_map_.find(id)->second;
- if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) &&
+ if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) &&
data_length > 0) {
crypto_bytes_transferred_[connection_->encryption_level()].Add(
offset, offset + data_length);
@@ -127,8 +127,11 @@
}
void SimpleSessionNotifier::NeuterUnencryptedData() {
+ // TODO(nharper): Handle CRYPTO frame case.
+ if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) {
- // TODO(nharper): Handle CRYPTO frame case.
QuicStreamFrame stream_frame(
QuicUtils::GetCryptoStreamId(connection_->transport_version()), false,
interval.min(), interval.max() - interval.min());
@@ -146,7 +149,6 @@
return;
}
// Write new data.
- // TODO(nharper): Write CRYPTO frames.
for (const auto& pair : stream_map_) {
const auto& state = pair.second;
if (!StreamHasBufferedData(pair.first)) {
@@ -320,8 +322,8 @@
EncryptionLevel retransmission_encryption_level =
connection_->encryption_level();
EncryptionLevel current_encryption_level = connection_->encryption_level();
- if (frame.stream_frame.stream_id ==
- QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+ if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
+ frame.stream_frame.stream_id)) {
for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
if (retransmission.Intersects(crypto_bytes_transferred_[i])) {
retransmission_encryption_level = static_cast<EncryptionLevel>(i);
@@ -339,8 +341,8 @@
const bool can_bundle_fin =
retransmit_fin &&
(retransmission_offset + retransmission_length == state.bytes_sent);
- if (frame.stream_frame.stream_id ==
- QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+ if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
+ frame.stream_frame.stream_id)) {
// Set appropriate encryption level for crypto stream.
connection_->SetDefaultEncryptionLevel(retransmission_encryption_level);
}
@@ -356,8 +358,8 @@
if (can_bundle_fin) {
retransmit_fin = !consumed.fin_consumed;
}
- if (frame.stream_frame.stream_id ==
- QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+ if (QuicUtils::IsCryptoStreamId(connection_->transport_version(),
+ frame.stream_frame.stream_id)) {
// Restore encryption level.
connection_->SetDefaultEncryptionLevel(current_encryption_level);
}
@@ -497,7 +499,36 @@
}
bool SimpleSessionNotifier::RetransmitLostCryptoData() {
- // TODO(nharper): Handle CRYPTO frame case.
+ if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ for (EncryptionLevel level :
+ {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT,
+ ENCRYPTION_FORWARD_SECURE}) {
+ auto& state = crypto_state_[level];
+ while (!state.pending_retransmissions.Empty()) {
+ connection_->SetTransmissionType(HANDSHAKE_RETRANSMISSION);
+ EncryptionLevel current_encryption_level =
+ connection_->encryption_level();
+ connection_->SetDefaultEncryptionLevel(level);
+ QuicIntervalSet<QuicStreamOffset> retransmission(
+ state.pending_retransmissions.begin()->min(),
+ state.pending_retransmissions.begin()->max());
+ retransmission.Intersection(crypto_bytes_transferred_[level]);
+ QuicStreamOffset retransmission_offset = retransmission.begin()->min();
+ QuicByteCount retransmission_length =
+ retransmission.begin()->max() - retransmission.begin()->min();
+ size_t bytes_consumed = connection_->SendCryptoData(
+ level, retransmission_length, retransmission_offset);
+ // Restore encryption level.
+ connection_->SetDefaultEncryptionLevel(current_encryption_level);
+ state.pending_retransmissions.Difference(
+ retransmission_offset, retransmission_offset + bytes_consumed);
+ if (bytes_consumed < retransmission_length) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
connection_->transport_version()))) {
return true;
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc
index 53712fd..e5298eb 100644
--- a/quic/test_tools/simple_session_notifier_test.cc
+++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -4,10 +4,12 @@
#include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h"
using testing::_;
using testing::InSequence;
@@ -126,6 +128,9 @@
}
TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) {
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ return;
+ }
InSequence s;
// Send crypto data [0, 1024) in ENCRYPTION_INITIAL.
connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
@@ -159,6 +164,9 @@
}
TEST_F(SimpleSessionNotifierTest, OnCanWrite) {
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ return;
+ }
InSequence s;
// Send crypto data [0, 1024) in ENCRYPTION_INITIAL.
connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
@@ -221,6 +229,71 @@
EXPECT_FALSE(notifier_.WillingToWrite());
}
+TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) {
+ if (!QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ return;
+ }
+ SimpleDataProducer producer;
+ connection_.SetDataProducer(&producer);
+ InSequence s;
+ // Send crypto data [0, 1024) in ENCRYPTION_INITIAL.
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 1024, 0))
+ .WillOnce(Invoke(&connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ producer.SaveCryptoData(ENCRYPTION_INITIAL, 0, std::string(1024, 'a'));
+ producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, std::string(524, 'a'));
+ notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0);
+ // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<NullEncrypter>(
+ Perspective::IS_CLIENT));
+ EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0))
+ .WillOnce(Invoke(&connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ producer.SaveCryptoData(ENCRYPTION_ZERO_RTT, 0, std::string(1024, 'a'));
+ notifier_.WriteCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0);
+ // Send stream 3 [0, 1024) and connection is blocked.
+ EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, FIN))
+ .WillOnce(Return(QuicConsumedData(512, false)));
+ notifier_.WriteOrBufferData(3, 1024, FIN);
+ // Send stream 5 [0, 1024).
+ EXPECT_CALL(connection_, SendStreamData(5, _, _, _)).Times(0);
+ notifier_.WriteOrBufferData(5, 1024, NO_FIN);
+ // Reset stream 5 with error.
+ EXPECT_CALL(connection_, SendControlFrame(_)).Times(0);
+ notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024);
+
+ // Lost crypto data [500, 1500) and stream 3 [0, 512).
+ QuicCryptoFrame crypto_frame1(ENCRYPTION_INITIAL, 500, 524);
+ QuicCryptoFrame crypto_frame2(ENCRYPTION_ZERO_RTT, 0, 476);
+ QuicStreamFrame stream3_frame(3, false, 0, 512);
+ notifier_.OnFrameLost(QuicFrame(&crypto_frame1));
+ notifier_.OnFrameLost(QuicFrame(&crypto_frame2));
+ notifier_.OnFrameLost(QuicFrame(stream3_frame));
+
+ // Connection becomes writable.
+ // Lost crypto data gets retransmitted as [500, 1024) and [1024, 1500), as
+ // they are in different encryption levels.
+ EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 524, 500))
+ .WillOnce(Invoke(&connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 476, 0))
+ .WillOnce(Invoke(&connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ // Lost stream 3 data gets retransmitted.
+ EXPECT_CALL(connection_, SendStreamData(3, 512, 0, NO_FIN))
+ .WillOnce(Return(QuicConsumedData(512, false)));
+ // Buffered control frames get sent.
+ EXPECT_CALL(connection_, SendControlFrame(_))
+ .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed));
+ // Buffered stream 3 data [512, 1024) gets sent.
+ EXPECT_CALL(connection_, SendStreamData(3, 512, 512, FIN))
+ .WillOnce(Return(QuicConsumedData(512, true)));
+ notifier_.OnCanWrite();
+ EXPECT_FALSE(notifier_.WillingToWrite());
+}
+
TEST_F(SimpleSessionNotifierTest, RetransmitFrames) {
InSequence s;
// Send stream 3 data [0, 10) and fin.