Change QuicCryptoStream to track crypto-substreams by packet number space instead of encryption level such that ZERO_RTT and FORWARD_SECURE crypto data are sent/received/re-transmitted on the same stream.
PiperOrigin-RevId: 447566612
diff --git a/quiche/quic/core/frames/quic_crypto_frame.h b/quiche/quic/core/frames/quic_crypto_frame.h
index bc76da1..19fb579 100644
--- a/quiche/quic/core/frames/quic_crypto_frame.h
+++ b/quiche/quic/core/frames/quic_crypto_frame.h
@@ -25,6 +25,8 @@
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const QuicCryptoFrame& s);
+ // TODO(haoyuewang) Consider replace the EncryptionLevel here with
+ // PacketNumberSpace.
// When writing a crypto frame to a packet, the packet must be encrypted at
// |level|. When a crypto frame is read, the encryption level of the packet it
// was received in is put in |level|.
diff --git a/quiche/quic/core/http/quic_spdy_session_test.cc b/quiche/quic/core/http/quic_spdy_session_test.cc
index a8fb322..accd1b0 100644
--- a/quiche/quic/core/http/quic_spdy_session_test.cc
+++ b/quiche/quic/core/http/quic_spdy_session_test.cc
@@ -199,11 +199,25 @@
EncryptionLevel level) const override {
return level != ENCRYPTION_ZERO_RTT;
}
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+ }
bool ExportKeyingMaterial(absl::string_view /*label*/,
absl::string_view /*context*/,
- size_t /*result_len*/,
- std::string* /*result*/) override {
+ size_t /*result_len*/, std::string*
+ /*result*/) override {
return false;
}
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index 281f359..de8a5be 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -192,6 +192,21 @@
return level != ENCRYPTION_ZERO_RTT;
}
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+ }
+
private:
using QuicCryptoStream::session;
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 73f5763..3913635 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -4120,6 +4120,21 @@
visitor_->OnAckNeedsRetransmittableFrame();
}
+EncryptionLevel QuicConnection::GetEncryptionLevelToSendPingForSpace(
+ PacketNumberSpace space) const {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return framer_.GetEncryptionLevelToSendApplicationData();
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+}
+
void QuicConnection::OnRetransmissionTimeout() {
ScopedRetransmissionTimeoutIndicator indicator(this);
#ifndef NDEBUG
@@ -4182,7 +4197,8 @@
if (sent_packet_manager_
.GetEarliestPacketSentTimeForPto(&packet_number_space)
.IsInitialized()) {
- SendPingAtLevel(QuicUtils::GetEncryptionLevel(packet_number_space));
+ SendPingAtLevel(
+ GetEncryptionLevelToSendPingForSpace(packet_number_space));
} else {
// The client must PTO when there is nothing in flight if the server
// could be blocked from sending by the amplification limit
@@ -5911,7 +5927,8 @@
<< PacketNumberSpaceToString(
static_cast<PacketNumberSpace>(i));
ScopedEncryptionLevelContext context(
- this, QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)));
+ this, QuicUtils::GetEncryptionLevelToSendAckofSpace(
+ static_cast<PacketNumberSpace>(i)));
QuicFrames frames;
frames.push_back(uber_received_packet_manager_.GetUpdatedAckFrame(
static_cast<PacketNumberSpace>(i), clock_->ApproximateNow()));
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 28d5747..b214361 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -1863,6 +1863,10 @@
bool ShouldSetRetransmissionAlarmOnPacketSent(bool in_flight,
EncryptionLevel level) const;
+ // Determines encryption level to send ping in `packet_number_space`.
+ EncryptionLevel GetEncryptionLevelToSendPingForSpace(
+ PacketNumberSpace space) const;
+
QuicConnectionContext context_;
QuicFramer framer_;
diff --git a/quiche/quic/core/quic_crypto_client_handshaker.cc b/quiche/quic/core/quic_crypto_client_handshaker.cc
index 6a9fa6c..4ec9b48 100644
--- a/quiche/quic/core/quic_crypto_client_handshaker.cc
+++ b/quiche/quic/core/quic_crypto_client_handshaker.cc
@@ -11,9 +11,11 @@
#include "quiche/quic/core/crypto/crypto_protocol.h"
#include "quiche/quic/core/crypto/crypto_utils.h"
#include "quiche/quic/core/quic_session.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_client_stats.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_logging.h"
+#include "quiche/common/platform/api/quiche_logging.h"
namespace quic {
@@ -149,6 +151,16 @@
return true;
}
+EncryptionLevel
+QuicCryptoClientHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const {
+ if (space == INITIAL_DATA) {
+ return ENCRYPTION_INITIAL;
+ }
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+}
+
bool QuicCryptoClientHandshaker::one_rtt_keys_available() const {
return one_rtt_keys_available_;
}
diff --git a/quiche/quic/core/quic_crypto_client_handshaker.h b/quiche/quic/core/quic_crypto_client_handshaker.h
index 9c19f89..dbbd942 100644
--- a/quiche/quic/core/quic_crypto_client_handshaker.h
+++ b/quiche/quic/core/quic_crypto_client_handshaker.h
@@ -11,6 +11,7 @@
#include "quiche/quic/core/crypto/quic_crypto_client_config.h"
#include "quiche/quic/core/quic_crypto_client_stream.h"
#include "quiche/quic/core/quic_server_id.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/common/platform/api/quiche_logging.h"
@@ -45,6 +46,8 @@
bool encryption_established() const override;
bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const override;
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
diff --git a/quiche/quic/core/quic_crypto_client_stream.cc b/quiche/quic/core/quic_crypto_client_stream.cc
index a241ecb..3c6dbe7 100644
--- a/quiche/quic/core/quic_crypto_client_stream.cc
+++ b/quiche/quic/core/quic_crypto_client_stream.cc
@@ -169,4 +169,10 @@
return handshaker_->IsCryptoFrameExpectedForEncryptionLevel(level);
}
+EncryptionLevel
+QuicCryptoClientStream::GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const {
+ return handshaker_->GetEncryptionLevelToSendCryptoDataOfSpace(space);
+}
+
} // namespace quic
diff --git a/quiche/quic/core/quic_crypto_client_stream.h b/quiche/quic/core/quic_crypto_client_stream.h
index d3da4db..0a3e5e4 100644
--- a/quiche/quic/core/quic_crypto_client_stream.h
+++ b/quiche/quic/core/quic_crypto_client_stream.h
@@ -17,6 +17,7 @@
#include "quiche/quic/core/quic_crypto_stream.h"
#include "quiche/quic/core/quic_server_id.h"
#include "quiche/quic/core/quic_session.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_versions.h"
#include "quiche/quic/platform/api/quic_export.h"
@@ -173,6 +174,10 @@
virtual bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const = 0;
+ // Returns the encryption level to send CRYPTO_FRAME for `space`.
+ virtual EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const = 0;
+
// Returns true once 1RTT keys are available.
virtual bool one_rtt_keys_available() const = 0;
@@ -289,6 +294,9 @@
SSL* GetSsl() const override;
bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const override;
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override;
+
bool ExportKeyingMaterial(absl::string_view label, absl::string_view context,
size_t result_len, std::string* result) override;
std::string chlo_hash() const;
diff --git a/quiche/quic/core/quic_crypto_server_stream.cc b/quiche/quic/core/quic_crypto_server_stream.cc
index 11a5728..5d41e47 100644
--- a/quiche/quic/core/quic_crypto_server_stream.cc
+++ b/quiche/quic/core/quic_crypto_server_stream.cc
@@ -10,6 +10,7 @@
#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "openssl/sha.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_flag_utils.h"
#include "quiche/quic/platform/api/quic_testvalue.h"
#include "quiche/common/platform/api/quiche_logging.h"
@@ -532,4 +533,17 @@
return true;
}
+EncryptionLevel
+QuicCryptoServerStream::GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const {
+ if (space == INITIAL_DATA) {
+ return ENCRYPTION_INITIAL;
+ }
+ if (space == APPLICATION_DATA) {
+ return ENCRYPTION_ZERO_RTT;
+ }
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+}
+
} // namespace quic
diff --git a/quiche/quic/core/quic_crypto_server_stream.h b/quiche/quic/core/quic_crypto_server_stream.h
index 5bdfb54..f91ceba 100644
--- a/quiche/quic/core/quic_crypto_server_stream.h
+++ b/quiche/quic/core/quic_crypto_server_stream.h
@@ -12,6 +12,7 @@
#include "quiche/quic/core/quic_crypto_handshaker.h"
#include "quiche/quic/core/quic_crypto_server_stream_base.h"
#include "quiche/quic/core/quic_session.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_export.h"
namespace quic {
@@ -74,6 +75,8 @@
SSL* GetSsl() const override;
bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const override;
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override;
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/quiche/quic/core/quic_crypto_stream.cc b/quiche/quic/core/quic_crypto_stream.cc
index 33eb543..3839db3 100644
--- a/quiche/quic/core/quic_crypto_stream.cc
+++ b/quiche/quic/core/quic_crypto_stream.cc
@@ -37,10 +37,7 @@
QuicVersionUsesCryptoFrames(session->transport_version())
? CRYPTO
: BIDIRECTIONAL),
- substreams_{{{this, ENCRYPTION_INITIAL},
- {this, ENCRYPTION_HANDSHAKE},
- {this, ENCRYPTION_ZERO_RTT},
- {this, ENCRYPTION_FORWARD_SECURE}}} {
+ substreams_{{{this}, {this}, {this}}} {
// The crypto stream is exempt from connection level flow control.
DisableConnectionFlowControlForThisStream();
}
@@ -82,9 +79,11 @@
absl::StrCat("CRYPTO_FRAME is unexpectedly received at level ", level));
return;
}
- substreams_[level].sequencer.OnCryptoFrame(frame);
+ CryptoSubstream& substream =
+ substreams_[QuicUtils::GetPacketNumberSpace(level)];
+ substream.sequencer.OnCryptoFrame(frame);
EncryptionLevel frame_level = level;
- if (substreams_[level].sequencer.NumBytesBuffered() >
+ if (substream.sequencer.NumBytesBuffered() >
BufferSizeLimitForLevel(frame_level)) {
OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
"Too much crypto data received");
@@ -109,7 +108,8 @@
OnDataAvailableInSequencer(sequencer(), level);
return;
}
- OnDataAvailableInSequencer(&substreams_[level].sequencer, level);
+ OnDataAvailableInSequencer(
+ &substreams_[QuicUtils::GetPacketNumberSpace(level)].sequencer, level);
}
void QuicCryptoStream::OnDataAvailableInSequencer(
@@ -146,7 +146,8 @@
}
const bool had_buffered_data = HasBufferedCryptoFrames();
// Append |data| to the send buffer for this encryption level.
- QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ QuicStreamSendBuffer* send_buffer =
+ &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer;
QuicStreamOffset offset = send_buffer->stream_offset();
send_buffer->SaveStreamData(data);
if (kMaxStreamLength - offset < data.length()) {
@@ -173,8 +174,9 @@
bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame,
QuicTime::Delta /*ack_delay_time*/) {
QuicByteCount newly_acked_length = 0;
- if (!substreams_[frame.level].send_buffer.OnStreamDataAcked(
- frame.offset, frame.data_length, &newly_acked_length)) {
+ if (!substreams_[QuicUtils::GetPacketNumberSpace(frame.level)]
+ .send_buffer.OnStreamDataAcked(frame.offset, frame.data_length,
+ &newly_acked_length)) {
OnUnrecoverableError(QUIC_INTERNAL_ERROR,
"Trying to ack unsent crypto data.");
return false;
@@ -201,9 +203,10 @@
}
return;
}
- QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
- // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to
- // replace the following code.
+ QuicStreamSendBuffer* send_buffer =
+ &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer;
+ // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer
+ // to replace the following code.
QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked();
to_ack.Complement(0, send_buffer->stream_offset());
for (const auto& interval : to_ack) {
@@ -225,22 +228,13 @@
QuicStream::OnStreamDataConsumed(bytes_consumed);
}
-namespace {
-
-constexpr std::array<EncryptionLevel, NUM_ENCRYPTION_LEVELS>
-AllEncryptionLevels() {
- return {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT,
- ENCRYPTION_FORWARD_SECURE};
-}
-
-} // namespace
bool QuicCryptoStream::HasPendingCryptoRetransmission() const {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
return false;
}
- for (EncryptionLevel level : AllEncryptionLevels()) {
- if (substreams_[level].send_buffer.HasPendingRetransmission()) {
+ for (const auto& substream : substreams_) {
+ if (substream.send_buffer.HasPendingRetransmission()) {
return true;
}
}
@@ -251,12 +245,15 @@
QUIC_BUG_IF(quic_bug_12573_3,
!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't write CRYPTO frames";
- for (EncryptionLevel level : AllEncryptionLevels()) {
- QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
+ auto packet_number_space = static_cast<PacketNumberSpace>(i);
+ QuicStreamSendBuffer* send_buffer =
+ &substreams_[packet_number_space].send_buffer;
while (send_buffer->HasPendingRetransmission()) {
auto pending = send_buffer->NextPendingRetransmission();
size_t bytes_consumed = stream_delegate()->SendCryptoData(
- level, pending.length, pending.offset, HANDSHAKE_RETRANSMISSION);
+ GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space),
+ pending.length, pending.offset, HANDSHAKE_RETRANSMISSION);
send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed);
if (bytes_consumed < pending.length) {
return;
@@ -351,14 +348,17 @@
return stream_bytes_read();
}
uint64_t bytes_read = 0;
- for (EncryptionLevel level : AllEncryptionLevels()) {
- bytes_read += substreams_[level].sequencer.NumBytesConsumed();
+ for (const CryptoSubstream& substream : substreams_) {
+ bytes_read += substream.sequencer.NumBytesConsumed();
}
return bytes_read;
}
+// TODO(haoyuewang) Move this test-only method under
+// quiche/quic/test_tools.
uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const {
- return substreams_[level].sequencer.NumBytesConsumed();
+ return substreams_[QuicUtils::GetPacketNumberSpace(level)]
+ .sequencer.NumBytesConsumed();
}
bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level,
@@ -368,16 +368,17 @@
QUIC_BUG_IF(quic_bug_12573_4,
!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't write CRYPTO frames (2)";
- return substreams_[level].send_buffer.WriteStreamData(offset, data_length,
- writer);
+ return substreams_[QuicUtils::GetPacketNumberSpace(level)]
+ .send_buffer.WriteStreamData(offset, data_length, writer);
}
void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) {
QUIC_BUG_IF(quic_bug_12573_5,
!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't lose CRYPTO frames";
- substreams_[crypto_frame->level].send_buffer.OnStreamDataLost(
- crypto_frame->offset, crypto_frame->data_length);
+ substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)]
+ .send_buffer.OnStreamDataLost(crypto_frame->offset,
+ crypto_frame->data_length);
}
bool QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame,
@@ -388,7 +389,8 @@
QuicIntervalSet<QuicStreamOffset> retransmission(
crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length);
QuicStreamSendBuffer* send_buffer =
- &substreams_[crypto_frame->level].send_buffer;
+ &substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)]
+ .send_buffer;
retransmission.Difference(send_buffer->bytes_acked());
if (retransmission.Empty()) {
return true;
@@ -396,9 +398,12 @@
for (const auto& interval : retransmission) {
size_t retransmission_offset = interval.min();
size_t retransmission_length = interval.max() - interval.min();
+ EncryptionLevel retransmission_encryption_level =
+ GetEncryptionLevelToSendCryptoDataOfSpace(
+ QuicUtils::GetPacketNumberSpace(crypto_frame->level));
size_t bytes_consumed = stream_delegate()->SendCryptoData(
- crypto_frame->level, retransmission_length, retransmission_offset,
- type);
+ retransmission_encryption_level, retransmission_length,
+ retransmission_offset, type);
send_buffer->OnStreamDataRetransmitted(retransmission_offset,
bytes_consumed);
if (bytes_consumed < retransmission_length) {
@@ -412,8 +417,10 @@
QUIC_BUG_IF(quic_bug_12573_7,
!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't use CRYPTO frames";
- for (EncryptionLevel level : AllEncryptionLevels()) {
- QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
+ auto packet_number_space = static_cast<PacketNumberSpace>(i);
+ QuicStreamSendBuffer* send_buffer =
+ &substreams_[packet_number_space].send_buffer;
const size_t data_length =
send_buffer->stream_offset() - send_buffer->stream_bytes_written();
if (data_length == 0) {
@@ -421,8 +428,8 @@
continue;
}
size_t bytes_consumed = stream_delegate()->SendCryptoData(
- level, data_length, send_buffer->stream_bytes_written(),
- NOT_RETRANSMISSION);
+ GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space),
+ data_length, send_buffer->stream_bytes_written(), NOT_RETRANSMISSION);
send_buffer->OnStreamDataConsumed(bytes_consumed);
if (bytes_consumed < data_length) {
// Connection is write blocked.
@@ -435,8 +442,8 @@
QUIC_BUG_IF(quic_bug_12573_8,
!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't use CRYPTO frames";
- for (EncryptionLevel level : AllEncryptionLevels()) {
- const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer;
+ for (const CryptoSubstream& substream : substreams_) {
+ const QuicStreamSendBuffer& send_buffer = substream.send_buffer;
QUICHE_DCHECK_GE(send_buffer.stream_offset(),
send_buffer.stream_bytes_written());
if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) {
@@ -457,15 +464,16 @@
// the wrong transport version.
return false;
}
- return substreams_[level].send_buffer.IsStreamDataOutstanding(offset, length);
+ return substreams_[QuicUtils::GetPacketNumberSpace(level)]
+ .send_buffer.IsStreamDataOutstanding(offset, length);
}
bool QuicCryptoStream::IsWaitingForAcks() const {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
return QuicStream::IsWaitingForAcks();
}
- for (EncryptionLevel level : AllEncryptionLevels()) {
- if (substreams_[level].send_buffer.stream_bytes_outstanding()) {
+ for (const CryptoSubstream& substream : substreams_) {
+ if (substream.send_buffer.stream_bytes_outstanding()) {
return true;
}
}
@@ -473,7 +481,7 @@
}
QuicCryptoStream::CryptoSubstream::CryptoSubstream(
- QuicCryptoStream* crypto_stream, EncryptionLevel)
+ QuicCryptoStream* crypto_stream)
: sequencer(crypto_stream),
send_buffer(crypto_stream->session()
->connection()
diff --git a/quiche/quic/core/quic_crypto_stream.h b/quiche/quic/core/quic_crypto_stream.h
index be61a82..6d29d4b 100644
--- a/quiche/quic/core/quic_crypto_stream.h
+++ b/quiche/quic/core/quic_crypto_stream.h
@@ -236,8 +236,9 @@
virtual void OnDataAvailableInSequencer(QuicStreamSequencer* sequencer,
EncryptionLevel level);
- QuicStreamSequencer* GetStreamSequencerForLevel(EncryptionLevel level) {
- return &substreams_[level].sequencer;
+ QuicStreamSequencer* GetStreamSequencerForPacketNumberSpace(
+ PacketNumberSpace packet_number_space) {
+ return &substreams_[packet_number_space].sequencer;
}
// Called by OnCryptoFrame to check if a CRYPTO frame is received at an
@@ -245,13 +246,17 @@
virtual bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const = 0;
+ // Called to determine the encryption level to send/retransmit crypto data.
+ virtual EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const = 0;
+
private:
- // Data sent and received in CRYPTO frames is sent at multiple encryption
- // levels. Some of the state for the single logical crypto stream is split
- // across encryption levels, and a CryptoSubstream is used to manage that
- // state for a particular encryption level.
+ // Data sent and received in CRYPTO frames is sent at multiple packet number
+ // spaces. Some of the state for the single logical crypto stream is split
+ // across packet number spaces, and a CryptoSubstream is used to manage that
+ // state for a particular packet number space.
struct QUIC_EXPORT_PRIVATE CryptoSubstream {
- CryptoSubstream(QuicCryptoStream* crypto_stream, EncryptionLevel);
+ CryptoSubstream(QuicCryptoStream* crypto_stream);
QuicStreamSequencer sequencer;
QuicStreamSendBuffer send_buffer;
@@ -262,9 +267,9 @@
// TLS 1.3, which never encrypts crypto data.
QuicIntervalSet<QuicStreamOffset> bytes_consumed_[NUM_ENCRYPTION_LEVELS];
- // Keeps state for data sent/received in CRYPTO frames at each encryption
- // level.
- std::array<CryptoSubstream, NUM_ENCRYPTION_LEVELS> substreams_;
+ // Keeps state for data sent/received in CRYPTO frames at each packet number
+ // space;
+ std::array<CryptoSubstream, NUM_PACKET_NUMBER_SPACES> substreams_;
};
} // namespace quic
diff --git a/quiche/quic/core/quic_crypto_stream_test.cc b/quiche/quic/core/quic_crypto_stream_test.cc
index 7e27d77..ea99926 100644
--- a/quiche/quic/core/quic_crypto_stream_test.cc
+++ b/quiche/quic/core/quic_crypto_stream_test.cc
@@ -13,6 +13,7 @@
#include "quiche/quic/core/crypto/crypto_handshake.h"
#include "quiche/quic/core/crypto/crypto_protocol.h"
#include "quiche/quic/core/crypto/null_encrypter.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_utils.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
#include "quiche/quic/platform/api/quic_test.h"
@@ -101,6 +102,22 @@
return level != ENCRYPTION_ZERO_RTT;
}
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return QuicCryptoStream::session()
+ ->GetEncryptionLevelToSendApplicationData();
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+ }
+
private:
quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
std::vector<CryptoHandshakeMessage> messages_;
@@ -266,6 +283,17 @@
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+
+ // Before encryption moves to ENCRYPTION_FORWARD_SECURE, ZERO RTT data are
+ // retranmitted at ENCRYPTION_ZERO_RTT.
+ QuicCryptoFrame lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650);
+ stream_->OnCryptoFrameLost(&lost_frame);
+
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WritePendingCryptoRetransmission();
+
connection_->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
@@ -273,7 +301,7 @@
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
// Lost [0, 1000).
- QuicCryptoFrame lost_frame(ENCRYPTION_INITIAL, 0, 1000);
+ lost_frame = QuicCryptoFrame(ENCRYPTION_INITIAL, 0, 1000);
stream_->OnCryptoFrameLost(&lost_frame);
EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
// Lost [1200, 2000).
@@ -289,7 +317,7 @@
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 150, 1200))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
- EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 650, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
stream_->WritePendingCryptoRetransmission();
@@ -533,7 +561,7 @@
stream_->OnCryptoFrameAcked(acked_frame, QuicTime::Delta::Zero()));
// Retransmit only [1350, 1500).
- EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 150, 0))
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 150, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
QuicCryptoFrame frame_to_retransmit(ENCRYPTION_ZERO_RTT, 0, 150);
@@ -543,10 +571,11 @@
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
// Retransmit [1350, 2700) again and all data is sent.
- EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 650, 0))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
- EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 200, 1150))
+ EXPECT_CALL(*connection_,
+ SendCryptoData(ENCRYPTION_FORWARD_SECURE, 200, 1150))
.WillOnce(Invoke(connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
frame_to_retransmit = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 1350);
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index 6450da0..807bfdd 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -1558,7 +1558,7 @@
bool set_alternative_decrypter, bool latch_once_used) {
if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
!connection()->framer().HasEncrypterOfEncryptionLevel(
- QuicUtils::GetEncryptionLevel(
+ QuicUtils::GetEncryptionLevelToSendAckofSpace(
QuicUtils::GetPacketNumberSpace(level)))) {
// This should never happen because connection should never decrypt a packet
// while an ACK for it cannot be encrypted.
diff --git a/quiche/quic/core/quic_session_test.cc b/quiche/quic/core/quic_session_test.cc
index bb198e4..9b90c4f 100644
--- a/quiche/quic/core/quic_session_test.cc
+++ b/quiche/quic/core/quic_session_test.cc
@@ -38,6 +38,7 @@
#include "quiche/quic/test_tools/quic_stream_peer.h"
#include "quiche/quic/test_tools/quic_stream_send_buffer_peer.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
+#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/quiche_mem_slice_storage.h"
using spdy::kV3HighestPriority;
@@ -186,6 +187,21 @@
return level != ENCRYPTION_ZERO_RTT;
}
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+ }
+
private:
using QuicCryptoStream::session;
@@ -2959,7 +2975,11 @@
EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000))
.WillOnce(Return(350));
- EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ EXPECT_CALL(
+ *connection_,
+ SendCryptoData(crypto_stream->GetEncryptionLevelToSendCryptoDataOfSpace(
+ QuicUtils::GetPacketNumberSpace(ENCRYPTION_ZERO_RTT)),
+ 1350, 0))
.WillOnce(Return(1350));
session_.OnCanWrite();
EXPECT_FALSE(session_.HasPendingHandshake());
diff --git a/quiche/quic/core/quic_utils.cc b/quiche/quic/core/quic_utils.cc
index 6113c91..e1b1797 100644
--- a/quiche/quic/core/quic_utils.cc
+++ b/quiche/quic/core/quic_utils.cc
@@ -595,7 +595,7 @@
}
// static
-EncryptionLevel QuicUtils::GetEncryptionLevel(
+EncryptionLevel QuicUtils::GetEncryptionLevelToSendAckofSpace(
PacketNumberSpace packet_number_space) {
switch (packet_number_space) {
case INITIAL_DATA:
diff --git a/quiche/quic/core/quic_utils.h b/quiche/quic/core/quic_utils.h
index 202dc4b..2d4d5e8 100644
--- a/quiche/quic/core/quic_utils.h
+++ b/quiche/quic/core/quic_utils.h
@@ -209,8 +209,8 @@
static PacketNumberSpace GetPacketNumberSpace(
EncryptionLevel encryption_level);
- // Determines encryption level to send packets in |packet_number_space|.
- static EncryptionLevel GetEncryptionLevel(
+ // Determines encryption level to send ACK in |packet_number_space|.
+ static EncryptionLevel GetEncryptionLevelToSendAckofSpace(
PacketNumberSpace packet_number_space);
// Get the maximum value for a V99/IETF QUIC stream count. If a count
diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_client_handshaker.cc
index 7460263..36edcac 100644
--- a/quiche/quic/core/tls_client_handshaker.cc
+++ b/quiche/quic/core/tls_client_handshaker.cc
@@ -361,6 +361,19 @@
return level != ENCRYPTION_ZERO_RTT;
}
+EncryptionLevel TlsClientHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+}
+
bool TlsClientHandshaker::one_rtt_keys_available() const {
return state_ >= HANDSHAKE_COMPLETE;
}
diff --git a/quiche/quic/core/tls_client_handshaker.h b/quiche/quic/core/tls_client_handshaker.h
index 21b6033..06581b5 100644
--- a/quiche/quic/core/tls_client_handshaker.h
+++ b/quiche/quic/core/tls_client_handshaker.h
@@ -56,6 +56,8 @@
bool encryption_established() const override;
bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const override;
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc
index cee7a71..3274fa5 100644
--- a/quiche/quic/core/tls_server_handshaker.cc
+++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -1130,4 +1130,19 @@
return level != ENCRYPTION_ZERO_RTT;
}
+EncryptionLevel TlsServerHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+}
+
} // namespace quic
diff --git a/quiche/quic/core/tls_server_handshaker.h b/quiche/quic/core/tls_server_handshaker.h
index fa5ca75..68abf73 100644
--- a/quiche/quic/core/tls_server_handshaker.h
+++ b/quiche/quic/core/tls_server_handshaker.h
@@ -73,6 +73,8 @@
SSL* GetSsl() const override;
bool IsCryptoFrameExpectedForEncryptionLevel(
EncryptionLevel level) const override;
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override;
// From QuicCryptoServerStreamBase and TlsHandshaker
ssl_early_data_reason_t EarlyDataReason() const override;
diff --git a/quiche/quic/core/uber_received_packet_manager_test.cc b/quiche/quic/core/uber_received_packet_manager_test.cc
index 030e55c..5474421 100644
--- a/quiche/quic/core/uber_received_packet_manager_test.cc
+++ b/quiche/quic/core/uber_received_packet_manager_test.cc
@@ -33,6 +33,20 @@
const QuicTime::Delta kDelayedAckTime =
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+EncryptionLevel GetEncryptionLevel(PacketNumberSpace packet_number_space) {
+ switch (packet_number_space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+}
+
class UberReceivedPacketManagerTest : public QuicTest {
protected:
UberReceivedPacketManagerTest() {
@@ -108,7 +122,7 @@
continue;
}
manager_->ResetAckStates(
- QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)));
+ GetEncryptionLevel(static_cast<PacketNumberSpace>(i)));
}
}
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index f43b12d..df742be 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -859,6 +859,20 @@
quic::EncryptionLevel level) const override {
return level != ENCRYPTION_ZERO_RTT;
}
+ EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
+ PacketNumberSpace space) const override {
+ switch (space) {
+ case INITIAL_DATA:
+ return ENCRYPTION_INITIAL;
+ case HANDSHAKE_DATA:
+ return ENCRYPTION_HANDSHAKE;
+ case APPLICATION_DATA:
+ return ENCRYPTION_FORWARD_SECURE;
+ default:
+ QUICHE_DCHECK(false);
+ return NUM_ENCRYPTION_LEVELS;
+ }
+ }
private:
quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;