Add supports to write NewConnectionId/RetireConnectionId via QuicControlFrameManager.
PiperOrigin-RevId: 350575619
Change-Id: I406aad18f793a1594ed94e39b620aaef9e28155d
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
index ee7ff0f..dd1163f 100644
--- a/quic/core/frames/quic_frame.cc
+++ b/quic/core/frames/quic_frame.cc
@@ -4,6 +4,8 @@
#include "quic/core/frames/quic_frame.h"
+#include "quic/core/frames/quic_new_connection_id_frame.h"
+#include "quic/core/frames/quic_retire_connection_id_frame.h"
#include "quic/core/quic_buffer_allocator.h"
#include "quic/core/quic_constants.h"
#include "quic/core/quic_types.h"
@@ -179,6 +181,8 @@
case MAX_STREAMS_FRAME:
case PING_FRAME:
case STOP_SENDING_FRAME:
+ case NEW_CONNECTION_ID_FRAME:
+ case RETIRE_CONNECTION_ID_FRAME:
case HANDSHAKE_DONE_FRAME:
case ACK_FREQUENCY_FRAME:
case NEW_TOKEN_FRAME:
@@ -206,6 +210,10 @@
return frame.ping_frame.control_frame_id;
case STOP_SENDING_FRAME:
return frame.stop_sending_frame->control_frame_id;
+ case NEW_CONNECTION_ID_FRAME:
+ return frame.new_connection_id_frame->control_frame_id;
+ case RETIRE_CONNECTION_ID_FRAME:
+ return frame.retire_connection_id_frame->control_frame_id;
case HANDSHAKE_DONE_FRAME:
return frame.handshake_done_frame.control_frame_id;
case ACK_FREQUENCY_FRAME:
@@ -243,6 +251,12 @@
case STOP_SENDING_FRAME:
frame->stop_sending_frame->control_frame_id = control_frame_id;
return;
+ case NEW_CONNECTION_ID_FRAME:
+ frame->new_connection_id_frame->control_frame_id = control_frame_id;
+ return;
+ case RETIRE_CONNECTION_ID_FRAME:
+ frame->retire_connection_id_frame->control_frame_id = control_frame_id;
+ return;
case HANDSHAKE_DONE_FRAME:
frame->handshake_done_frame.control_frame_id = control_frame_id;
return;
@@ -279,6 +293,14 @@
case STOP_SENDING_FRAME:
copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
break;
+ case NEW_CONNECTION_ID_FRAME:
+ copy = QuicFrame(
+ new QuicNewConnectionIdFrame(*frame.new_connection_id_frame));
+ break;
+ case RETIRE_CONNECTION_ID_FRAME:
+ copy = QuicFrame(
+ new QuicRetireConnectionIdFrame(*frame.retire_connection_id_frame));
+ break;
case STREAMS_BLOCKED_FRAME:
copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame));
break;
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 9d96c68..d5ca0a4 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -8,6 +8,7 @@
#include "quic/core/frames/quic_frame.h"
#include "quic/core/frames/quic_goaway_frame.h"
#include "quic/core/frames/quic_mtu_discovery_frame.h"
+#include "quic/core/frames/quic_new_connection_id_frame.h"
#include "quic/core/frames/quic_padding_frame.h"
#include "quic/core/frames/quic_ping_frame.h"
#include "quic/core/frames/quic_rst_stream_frame.h"
@@ -104,7 +105,40 @@
"{ control_frame_id: 1, stream_id: 321, error_code: 6, ietf_error_code: "
"268 }\n",
stream.str());
- EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, NewConnectionIdFrameToString) {
+ QuicNewConnectionIdFrame new_connection_id_frame;
+ QuicFrame frame(&new_connection_id_frame);
+ SetControlFrameId(1, &frame);
+ QuicFrame frame_copy = CopyRetransmittableControlFrame(frame);
+ EXPECT_EQ(1u, GetControlFrameId(frame_copy));
+ new_connection_id_frame.connection_id = TestConnectionId(2);
+ new_connection_id_frame.sequence_number = 2u;
+ new_connection_id_frame.retire_prior_to = 1u;
+ new_connection_id_frame.stateless_reset_token = MakeQuicUint128(0, 1);
+ std::ostringstream stream;
+ stream << new_connection_id_frame;
+ EXPECT_EQ(
+ "{ control_frame_id: 1, connection_id: 0000000000000002, "
+ "sequence_number: 2, retire_prior_to: 1 }\n",
+ stream.str());
+ EXPECT_TRUE(IsControlFrame(frame_copy.type));
+ DeleteFrame(&frame_copy);
+}
+
+TEST_F(QuicFramesTest, RetireConnectionIdFrameToString) {
+ QuicRetireConnectionIdFrame retire_connection_id_frame;
+ QuicFrame frame(&retire_connection_id_frame);
+ SetControlFrameId(1, &frame);
+ QuicFrame frame_copy = CopyRetransmittableControlFrame(frame);
+ EXPECT_EQ(1u, GetControlFrameId(frame_copy));
+ retire_connection_id_frame.sequence_number = 1u;
+ std::ostringstream stream;
+ stream << retire_connection_id_frame;
+ EXPECT_EQ("{ control_frame_id: 1, sequence_number: 1 }\n", stream.str());
+ EXPECT_TRUE(IsControlFrame(frame_copy.type));
+ DeleteFrame(&frame_copy);
}
TEST_F(QuicFramesTest, StreamsBlockedFrameToString) {
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc
index d6cff94..31d67c3 100644
--- a/quic/core/quic_control_frame_manager.cc
+++ b/quic/core/quic_control_frame_manager.cc
@@ -9,9 +9,12 @@
#include "absl/strings/str_cat.h"
#include "quic/core/frames/quic_ack_frequency_frame.h"
#include "quic/core/frames/quic_frame.h"
+#include "quic/core/frames/quic_new_connection_id_frame.h"
+#include "quic/core/frames/quic_retire_connection_id_frame.h"
#include "quic/core/quic_constants.h"
#include "quic/core/quic_session.h"
#include "quic/core/quic_types.h"
+#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_map_util.h"
@@ -131,6 +134,24 @@
ack_frequency_frame.max_ack_delay)));
}
+void QuicControlFrameManager::WriteOrBufferNewConnectionId(
+ const QuicConnectionId& connection_id,
+ uint64_t sequence_number,
+ uint64_t retire_prior_to,
+ QuicUint128 stateless_reset_token) {
+ QUIC_DVLOG(1) << "Writing NEW_CONNECTION_ID frame";
+ WriteOrBufferQuicFrame(QuicFrame(new QuicNewConnectionIdFrame(
+ ++last_control_frame_id_, connection_id, sequence_number,
+ stateless_reset_token, retire_prior_to)));
+}
+
+void QuicControlFrameManager::WriteOrBufferRetireConnectionId(
+ uint64_t sequence_number) {
+ QUIC_DVLOG(1) << "Writing RETIRE_CONNECTION_ID frame";
+ WriteOrBufferQuicFrame(QuicFrame(new QuicRetireConnectionIdFrame(
+ ++last_control_frame_id_, sequence_number)));
+}
+
void QuicControlFrameManager::WriteOrBufferNewToken(absl::string_view token) {
QUIC_DVLOG(1) << "Writing NEW_TOKEN frame";
WriteOrBufferQuicFrame(
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h
index 8119b51..cb0a8cb 100644
--- a/quic/core/quic_control_frame_manager.h
+++ b/quic/core/quic_control_frame_manager.h
@@ -5,10 +5,12 @@
#ifndef QUICHE_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_
#define QUICHE_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_
+#include <cstdint>
#include <string>
#include "quic/core/frames/quic_frame.h"
#include "quic/core/quic_circular_deque.h"
+#include "quic/core/quic_connection_id.h"
#include "common/platform/api/quiche_str_cat.h"
namespace quic {
@@ -89,6 +91,17 @@
void WriteOrBufferAckFrequency(
const QuicAckFrequencyFrame& ack_frequency_frame);
+ // Tries to send a NEW_CONNECTION_ID frame. The frame is buffered if it cannot
+ // be sent immediately.
+ void WriteOrBufferNewConnectionId(const QuicConnectionId& connection_id,
+ uint64_t sequence_number,
+ uint64_t retire_prior_to,
+ QuicUint128 stateless_reset_token);
+
+ // Tries to send a RETIRE_CONNNECTION_ID frame. The frame is buffered if it
+ // cannot be sent immediately.
+ void WriteOrBufferRetireConnectionId(uint64_t sequence_number);
+
// Tries to send a NEW_TOKEN frame. Buffers the frame if it cannot be sent
// immediately.
void WriteOrBufferNewToken(absl::string_view token);
diff --git a/quic/core/quic_control_frame_manager_test.cc b/quic/core/quic_control_frame_manager_test.cc
index f6e43eb..5aed6e0 100644
--- a/quic/core/quic_control_frame_manager_test.cc
+++ b/quic/core/quic_control_frame_manager_test.cc
@@ -8,6 +8,7 @@
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/frames/quic_ack_frequency_frame.h"
+#include "quic/core/frames/quic_retire_connection_id_frame.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
@@ -232,6 +233,39 @@
manager_->OnControlFrameAcked(QuicFrame(&expected_ack_frequency)));
}
+TEST_F(QuicControlFrameManagerTest, NewAndRetireConnectionIdFrames) {
+ Initialize();
+ InSequence s;
+
+ // Send other frames 1-5.
+ EXPECT_CALL(*session_, WriteControlFrame(_, _))
+ .Times(5)
+ .WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
+ manager_->OnCanWrite();
+
+ EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*session_, WriteControlFrame(_, _))
+ .Times(2)
+ .WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
+ // Send NewConnectionIdFrame as frame 6.
+ manager_->WriteOrBufferNewConnectionId(
+ TestConnectionId(3), /*sequence_number=*/2, /*retire_prior_to=*/1,
+ /*stateless_reset_token=*/MakeQuicUint128(1, 1));
+ // Send RetireConnectionIdFrame as frame 7.
+ manager_->WriteOrBufferRetireConnectionId(/*sequence_number=*/0);
+ manager_->OnCanWrite();
+
+ // Ack both frames.
+ QuicNewConnectionIdFrame new_connection_id_frame;
+ new_connection_id_frame.control_frame_id = 6;
+ QuicRetireConnectionIdFrame retire_connection_id_frame;
+ retire_connection_id_frame.control_frame_id = 7;
+ EXPECT_TRUE(
+ manager_->OnControlFrameAcked(QuicFrame(&new_connection_id_frame)));
+ EXPECT_TRUE(
+ manager_->OnControlFrameAcked(QuicFrame(&retire_connection_id_frame)));
+}
+
TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
Initialize();
// Send two more window updates of the same stream.