1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-24 04:01:07 +03:00

Add reliable reset functionality to QuicWriteCodec

Summary: In this diff, I'm writing functionality to enable us to write RESET_STREAM_AT frames. You can find the format of the RST_STREAM_AT frame in the [RFC](https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset-06#name-reset_stream_at-frame).

Reviewed By: jbeshay

Differential Revision: D64907958

fbshipit-source-id: 55e82278ebd0649dc33c82b472be80893af02509
This commit is contained in:
Aman Sharma
2024-11-18 13:06:34 -08:00
committed by Facebook GitHub Bot
parent 67794c5022
commit 568f19c17d
4 changed files with 58 additions and 7 deletions

View File

@@ -814,18 +814,28 @@ size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
} }
case QuicWriteFrame::Type::RstStreamFrame: { case QuicWriteFrame::Type::RstStreamFrame: {
RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame(); RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM)); QuicInteger intFrameType(static_cast<uint8_t>(
rstStreamFrame.reliableSize ? FrameType::RST_STREAM_AT
: FrameType::RST_STREAM));
QuicInteger streamId(rstStreamFrame.streamId); QuicInteger streamId(rstStreamFrame.streamId);
QuicInteger offset(rstStreamFrame.finalSize); QuicInteger finalSize(rstStreamFrame.finalSize);
QuicInteger errorCode(static_cast<uint64_t>(rstStreamFrame.errorCode)); QuicInteger errorCode(static_cast<uint64_t>(rstStreamFrame.errorCode));
folly::Optional<QuicInteger> maybeReliableSize = folly::none;
size_t errorSize = errorCode.getSize(); size_t errorSize = errorCode.getSize();
auto rstStreamFrameSize = intFrameType.getSize() + errorSize + auto rstStreamFrameSize = intFrameType.getSize() + errorSize +
streamId.getSize() + offset.getSize(); streamId.getSize() + finalSize.getSize();
if (rstStreamFrame.reliableSize) {
maybeReliableSize = QuicInteger(*rstStreamFrame.reliableSize);
rstStreamFrameSize += maybeReliableSize->getSize();
}
if (packetSpaceCheck(spaceLeft, rstStreamFrameSize)) { if (packetSpaceCheck(spaceLeft, rstStreamFrameSize)) {
builder.write(intFrameType); builder.write(intFrameType);
builder.write(streamId); builder.write(streamId);
builder.write(errorCode); builder.write(errorCode);
builder.write(offset); builder.write(finalSize);
if (maybeReliableSize) {
builder.write(*maybeReliableSize);
}
builder.appendFrame(std::move(rstStreamFrame)); builder.appendFrame(std::move(rstStreamFrame));
return rstStreamFrameSize; return rstStreamFrameSize;
} }

View File

@@ -2122,6 +2122,38 @@ TEST_F(QuicWriteCodecTest, NoSpaceForRst) {
EXPECT_EQ(0, writeFrame(rstStreamFrame, pktBuilder)); EXPECT_EQ(0, writeFrame(rstStreamFrame, pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WriteRstStreamAt) {
MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder);
StreamId id = 0xBAAD;
ApplicationErrorCode errorCode = GenericApplicationErrorCode::UNKNOWN;
uint64_t finalSize = 0xF00D;
uint64_t reliableSize = 0xF00C;
RstStreamFrame rstStreamFrame(id, errorCode, finalSize, reliableSize);
auto rstStreamBytesWritten = writeFrame(rstStreamFrame, pktBuilder);
auto builtOut = std::move(pktBuilder).buildTestPacket();
auto regularPacket = builtOut.first;
EXPECT_EQ(21, rstStreamBytesWritten);
auto& resultRstStreamFrame = *regularPacket.frames[0].asRstStreamFrame();
EXPECT_EQ(errorCode, resultRstStreamFrame.errorCode);
EXPECT_EQ(id, resultRstStreamFrame.streamId);
EXPECT_EQ(finalSize, resultRstStreamFrame.finalSize);
EXPECT_EQ(reliableSize, resultRstStreamFrame.reliableSize);
auto wireBuf = std::move(builtOut.second);
BufQueue queue;
queue.append(wireBuf->clone());
QuicFrame decodedFrame = parseQuicFrame(queue);
auto& wireRstStreamFrame = *decodedFrame.asRstStreamFrame();
EXPECT_EQ(errorCode, wireRstStreamFrame.errorCode);
EXPECT_EQ(id, wireRstStreamFrame.streamId);
EXPECT_EQ(finalSize, wireRstStreamFrame.finalSize);
EXPECT_EQ(reliableSize, wireRstStreamFrame.reliableSize);
// At last, verify there is nothing left in the wire format bytes:
EXPECT_EQ(queue.chainLength(), 0);
}
TEST_F(QuicWriteCodecTest, WriteBlockedFrame) { TEST_F(QuicWriteCodecTest, WriteBlockedFrame) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);

View File

@@ -28,10 +28,14 @@ folly::dynamic NewTokenFrameLog::toDynamic() const {
folly::dynamic RstStreamFrameLog::toDynamic() const { folly::dynamic RstStreamFrameLog::toDynamic() const {
folly::dynamic d = folly::dynamic::object(); folly::dynamic d = folly::dynamic::object();
d["frame_type"] = toQlogString(FrameType::RST_STREAM); d["frame_type"] = toQlogString(
reliableOffset ? FrameType::RST_STREAM_AT : FrameType::RST_STREAM);
d["stream_id"] = streamId; d["stream_id"] = streamId;
d["error_code"] = errorCode; d["error_code"] = errorCode;
d["offset"] = offset; d["offset"] = offset;
if (reliableOffset) {
d["reliable_offset"] = reliableOffset.value();
}
return d; return d;
} }

View File

@@ -37,12 +37,17 @@ class RstStreamFrameLog : public QLogFrame {
StreamId streamId; StreamId streamId;
ApplicationErrorCode errorCode; ApplicationErrorCode errorCode;
uint64_t offset; uint64_t offset;
folly::Optional<uint64_t> reliableOffset;
RstStreamFrameLog( RstStreamFrameLog(
StreamId streamIdIn, StreamId streamIdIn,
ApplicationErrorCode errorCodeIn, ApplicationErrorCode errorCodeIn,
uint64_t offsetIn) uint64_t offsetIn,
: streamId{streamIdIn}, errorCode{errorCodeIn}, offset{offsetIn} {} folly::Optional<uint64_t> reliableOffsetIn = folly::none)
: streamId{streamIdIn},
errorCode{errorCodeIn},
offset{offsetIn},
reliableOffset{reliableOffsetIn} {}
~RstStreamFrameLog() override = default; ~RstStreamFrameLog() override = default;
FOLLY_NODISCARD folly::dynamic toDynamic() const override; FOLLY_NODISCARD folly::dynamic toDynamic() const override;