1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-05 11:21:09 +03:00

Fix QUIC EOF sending when DSR is used

Summary:
This is a bug fix. When a stream finished sending all it's BufMetas, it can
send EOF from frontend QUIC host. In that case, it will use
currentWriteOffset value which is wrong.

This diff changes it so that (1) frontend can only write FIN only frame if
writeBufMeta's offset is <= finalWriteOffset; (2) When it writes such frame
it will use finalWriteOffset as the offset value in the frame.

Reviewed By: lnicco

Differential Revision: D28727029

fbshipit-source-id: 8f963c2e2d66f921f8a9704ed4671ec4f7c04df7
This commit is contained in:
Yang Chi
2021-06-01 13:15:40 -07:00
committed by Facebook GitHub Bot
parent 75820a1797
commit 0e6a998e05
4 changed files with 79 additions and 3 deletions

View File

@@ -1741,7 +1741,7 @@ TEST_F(QuicPacketSchedulerTest, RunOutFlowControlDuringStreamWrite) {
EXPECT_EQ(200, stream2->retransmissionBuffer[0]->data.chainLength());
}
TEST_F(QuicPacketSchedulerTest, NoFinWhenThereIsPendingWriteBuf) {
TEST_F(QuicPacketSchedulerTest, WritingFINWithAndWithoutBufMetas) {
QuicServerConnectionState conn(
FizzServerQuicHandshakeContext::Builder().build());
conn.streamManager->setMaxLocalBidirectionalStreams(10);
@@ -1772,6 +1772,74 @@ TEST_F(QuicPacketSchedulerTest, NoFinWhenThereIsPendingWriteBuf) {
EXPECT_EQ(streamFrame.len, 6);
EXPECT_EQ(streamFrame.offset, 0);
EXPECT_FALSE(streamFrame.fin);
handleNewStreamDataWritten(*stream, streamFrame.len, streamFrame.fin);
// Pretent all the bufMetas were sent, without FIN bit
stream->writeBufMeta.split(5000);
ASSERT_EQ(0, stream->writeBufMeta.length);
ASSERT_GT(stream->writeBufMeta.offset, 0);
conn.streamManager->updateWritableStreams(*stream);
// Do another non-DSR stream write, it will write FIN with correct offset
ShortHeader header2(
ProtectionType::KeyPhaseOne,
conn.clientConnectionId.value_or(getTestConnectionId()),
1);
RegularQuicPacketBuilder builder2(
conn.udpSendPacketLen,
std::move(header2),
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
builder2.encodePacketHeader();
StreamFrameScheduler scheduler2(conn);
scheduler2.writeStreams(builder2);
auto packet2 = std::move(builder2).buildPacket().packet;
EXPECT_EQ(1, packet2.frames.size());
auto streamFrame2 = *packet2.frames[0].asWriteStreamFrame();
EXPECT_EQ(streamFrame2.len, 0);
EXPECT_EQ(streamFrame2.offset, 6 + 5000);
EXPECT_TRUE(streamFrame2.fin);
}
TEST_F(QuicPacketSchedulerTest, NoFINWriteWhenBufMetaWrittenFIN) {
QuicServerConnectionState conn(
FizzServerQuicHandshakeContext::Builder().build());
conn.streamManager->setMaxLocalBidirectionalStreams(10);
conn.flowControlState.peerAdvertisedMaxOffset = 100000;
auto* stream = *(conn.streamManager->createNextBidirectionalStream());
stream->flowControlState.peerAdvertisedMaxOffset = 100000;
writeDataToQuicStream(*stream, folly::IOBuf::copyBuffer("Ascent"), false);
stream->dsrSender = std::make_unique<MockDSRPacketizationRequestSender>();
BufferMeta bufferMeta(5000);
writeBufMetaToQuicStream(*stream, bufferMeta, true);
EXPECT_TRUE(stream->finalWriteOffset.hasValue());
PacketNum packetNum = 0;
ShortHeader header(
ProtectionType::KeyPhaseOne,
conn.clientConnectionId.value_or(getTestConnectionId()),
packetNum);
RegularQuicPacketBuilder builder(
conn.udpSendPacketLen,
std::move(header),
conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0));
builder.encodePacketHeader();
StreamFrameScheduler scheduler(conn);
scheduler.writeStreams(builder);
auto packet = std::move(builder).buildPacket().packet;
EXPECT_EQ(1, packet.frames.size());
auto streamFrame = *packet.frames[0].asWriteStreamFrame();
EXPECT_EQ(streamFrame.len, 6);
EXPECT_EQ(streamFrame.offset, 0);
EXPECT_FALSE(streamFrame.fin);
handleNewStreamDataWritten(*stream, streamFrame.len, streamFrame.fin);
// Pretent all the bufMetas were sent, without FIN bit
stream->writeBufMeta.split(5000);
stream->writeBufMeta.offset++;
ASSERT_EQ(0, stream->writeBufMeta.length);
ASSERT_GT(stream->writeBufMeta.offset, 0);
conn.streamManager->updateWritableStreams(*stream);
StreamFrameScheduler scheduler2(conn);
EXPECT_FALSE(scheduler2.hasPendingData());
}
INSTANTIATE_TEST_CASE_P(