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.