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.