Add two copy utility function CopyQuicFrame and CopyQuicFrames.
gfe-relnote: n/a (add unused utility functions)
PiperOrigin-RevId: 275463436
Change-Id: Ib084cac65d1cf9c060abe492cc47aa10032972f6
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
index 5e85fc0..e640179 100644
--- a/quic/core/frames/quic_frame.cc
+++ b/quic/core/frames/quic_frame.cc
@@ -254,6 +254,101 @@
return copy;
}
+QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator,
+ const QuicFrame& frame) {
+ QuicFrame copy;
+ switch (frame.type) {
+ case PADDING_FRAME:
+ copy = QuicFrame(QuicPaddingFrame(frame.padding_frame));
+ break;
+ case RST_STREAM_FRAME:
+ copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame));
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ copy = QuicFrame(
+ new QuicConnectionCloseFrame(*frame.connection_close_frame));
+ break;
+ case GOAWAY_FRAME:
+ copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame));
+ break;
+ case WINDOW_UPDATE_FRAME:
+ copy = QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame));
+ break;
+ case BLOCKED_FRAME:
+ copy = QuicFrame(new QuicBlockedFrame(*frame.blocked_frame));
+ break;
+ case STOP_WAITING_FRAME:
+ copy = QuicFrame(QuicStopWaitingFrame(frame.stop_waiting_frame));
+ break;
+ case PING_FRAME:
+ copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
+ break;
+ case CRYPTO_FRAME:
+ copy = QuicFrame(new QuicCryptoFrame(*frame.crypto_frame));
+ break;
+ case STREAM_FRAME:
+ copy = QuicFrame(QuicStreamFrame(frame.stream_frame));
+ break;
+ case ACK_FRAME:
+ copy = QuicFrame(new QuicAckFrame(*frame.ack_frame));
+ break;
+ case MTU_DISCOVERY_FRAME:
+ copy = QuicFrame(QuicMtuDiscoveryFrame(frame.mtu_discovery_frame));
+ break;
+ case NEW_CONNECTION_ID_FRAME:
+ copy = QuicFrame(
+ new QuicNewConnectionIdFrame(*frame.new_connection_id_frame));
+ break;
+ case MAX_STREAMS_FRAME:
+ copy = QuicFrame(QuicMaxStreamsFrame(frame.max_streams_frame));
+ break;
+ case STREAMS_BLOCKED_FRAME:
+ copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame));
+ break;
+ case PATH_RESPONSE_FRAME:
+ copy = QuicFrame(new QuicPathResponseFrame(*frame.path_response_frame));
+ break;
+ case PATH_CHALLENGE_FRAME:
+ copy = QuicFrame(new QuicPathChallengeFrame(*frame.path_challenge_frame));
+ break;
+ case STOP_SENDING_FRAME:
+ copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
+ break;
+ case MESSAGE_FRAME:
+ copy = QuicFrame(new QuicMessageFrame(frame.message_frame->message_id));
+ copy.message_frame->data = frame.message_frame->data;
+ copy.message_frame->message_length = frame.message_frame->message_length;
+ for (const auto& slice : frame.message_frame->message_data) {
+ QuicMemSlice copy_slice(allocator, slice.length());
+ memcpy(const_cast<char*>(copy_slice.data()), slice.data(),
+ slice.length());
+ copy.message_frame->message_data.push_back(std::move(copy_slice));
+ }
+ break;
+ case NEW_TOKEN_FRAME:
+ copy = QuicFrame(new QuicNewTokenFrame(*frame.new_token_frame));
+ break;
+ case RETIRE_CONNECTION_ID_FRAME:
+ copy = QuicFrame(
+ new QuicRetireConnectionIdFrame(*frame.retire_connection_id_frame));
+ break;
+ default:
+ QUIC_BUG << "Cannot copy frame: " << frame;
+ copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
+ break;
+ }
+ return copy;
+}
+
+QuicFrames CopyQuicFrames(QuicBufferAllocator* allocator,
+ const QuicFrames& frames) {
+ QuicFrames copy;
+ for (const auto& frame : frames) {
+ copy.push_back(CopyQuicFrame(allocator, frame));
+ }
+ return copy;
+}
+
std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) {
switch (frame.type) {
case PADDING_FRAME: {
diff --git a/quic/core/frames/quic_frame.h b/quic/core/frames/quic_frame.h
index 1fa9e01..226cbfb 100644
--- a/quic/core/frames/quic_frame.h
+++ b/quic/core/frames/quic_frame.h
@@ -140,6 +140,14 @@
QUIC_EXPORT_PRIVATE QuicFrame
CopyRetransmittableControlFrame(const QuicFrame& frame);
+// Returns a copy of |frame|.
+QUIC_EXPORT_PRIVATE QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator,
+ const QuicFrame& frame);
+
+// Returns a copy of |frames|.
+QUIC_EXPORT_PRIVATE QuicFrames CopyQuicFrames(QuicBufferAllocator* allocator,
+ const QuicFrames& frames);
+
// Human-readable description suitable for logging.
QUIC_EXPORT_PRIVATE std::string QuicFramesToString(const QuicFrames& frames);
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 8492a0c..63fe653 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -481,6 +481,104 @@
EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
}
+TEST_F(QuicFramesTest, CopyQuicFrames) {
+ QuicFrames frames;
+ SimpleBufferAllocator allocator;
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
+ QuicMessageFrame* message_frame =
+ new QuicMessageFrame(1, MakeSpan(&allocator, "message", &storage));
+ // Construct a frame list.
+ for (uint8_t i = 0; i < NUM_FRAME_TYPES; ++i) {
+ switch (i) {
+ case PADDING_FRAME:
+ frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
+ break;
+ case RST_STREAM_FRAME:
+ frames.push_back(QuicFrame(new QuicRstStreamFrame()));
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ frames.push_back(QuicFrame(new QuicConnectionCloseFrame()));
+ break;
+ case GOAWAY_FRAME:
+ frames.push_back(QuicFrame(new QuicGoAwayFrame()));
+ break;
+ case WINDOW_UPDATE_FRAME:
+ frames.push_back(QuicFrame(new QuicWindowUpdateFrame()));
+ break;
+ case BLOCKED_FRAME:
+ frames.push_back(QuicFrame(new QuicBlockedFrame()));
+ break;
+ case STOP_WAITING_FRAME:
+ frames.push_back(QuicFrame(QuicStopWaitingFrame()));
+ break;
+ case PING_FRAME:
+ frames.push_back(QuicFrame(QuicPingFrame()));
+ break;
+ case CRYPTO_FRAME:
+ frames.push_back(QuicFrame(new QuicCryptoFrame()));
+ break;
+ case STREAM_FRAME:
+ frames.push_back(QuicFrame(QuicStreamFrame()));
+ break;
+ case ACK_FRAME:
+ frames.push_back(QuicFrame(new QuicAckFrame()));
+ break;
+ case MTU_DISCOVERY_FRAME:
+ frames.push_back(QuicFrame(QuicMtuDiscoveryFrame()));
+ break;
+ case NEW_CONNECTION_ID_FRAME:
+ frames.push_back(QuicFrame(new QuicNewConnectionIdFrame()));
+ break;
+ case MAX_STREAMS_FRAME:
+ frames.push_back(QuicFrame(QuicMaxStreamsFrame()));
+ break;
+ case STREAMS_BLOCKED_FRAME:
+ frames.push_back(QuicFrame(QuicStreamsBlockedFrame()));
+ break;
+ case PATH_RESPONSE_FRAME:
+ frames.push_back(QuicFrame(new QuicPathResponseFrame()));
+ break;
+ case PATH_CHALLENGE_FRAME:
+ frames.push_back(QuicFrame(new QuicPathChallengeFrame()));
+ break;
+ case STOP_SENDING_FRAME:
+ frames.push_back(QuicFrame(new QuicStopSendingFrame()));
+ break;
+ case MESSAGE_FRAME:
+ frames.push_back(QuicFrame(message_frame));
+ break;
+ case NEW_TOKEN_FRAME:
+ frames.push_back(QuicFrame(new QuicNewTokenFrame()));
+ break;
+ case RETIRE_CONNECTION_ID_FRAME:
+ frames.push_back(QuicFrame(new QuicRetireConnectionIdFrame()));
+ break;
+ default:
+ ASSERT_TRUE(false)
+ << "Please fix CopyQuicFrames if a new frame type is added.";
+ break;
+ }
+ }
+
+ QuicFrames copy = CopyQuicFrames(&allocator, frames);
+ ASSERT_EQ(NUM_FRAME_TYPES, copy.size());
+ for (uint8_t i = 0; i < NUM_FRAME_TYPES; ++i) {
+ EXPECT_EQ(i, copy[i].type);
+ if (i != MESSAGE_FRAME) {
+ continue;
+ }
+ // Verify message frame is correctly copied.
+ EXPECT_EQ(1u, copy[i].message_frame->message_id);
+ EXPECT_EQ(nullptr, copy[i].message_frame->data);
+ EXPECT_EQ(7u, copy[i].message_frame->message_length);
+ ASSERT_EQ(1u, copy[i].message_frame->message_data.size());
+ EXPECT_EQ(0, memcmp(copy[i].message_frame->message_data[0].data(),
+ frames[i].message_frame->message_data[0].data(), 7));
+ }
+ DeleteFrames(&frames);
+ DeleteFrames(©);
+}
+
class PacketNumberQueueTest : public QuicTest {};
// Tests that a queue contains the expected data after calls to Add().