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

Use custom variant type for write frames

Summary:
Use the custom variant type for write frames as well, now that
we use them for read frames.

Reviewed By: mjoras

Differential Revision: D17776862

fbshipit-source-id: 47093146d0f1565c22e5393ed012c70e2e23d279
This commit is contained in:
Subodh Iyengar
2019-10-07 22:41:31 -07:00
committed by Facebook Github Bot
parent 233346268e
commit 68c332acb1
22 changed files with 1201 additions and 994 deletions

View File

@@ -203,122 +203,141 @@ void updateConnection(
conn.qLogger->addPacket(packet, encodedSize); conn.qLogger->addPacket(packet, encodedSize);
} }
for (const auto& frame : packet.frames) { for (const auto& frame : packet.frames) {
folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::WriteStreamFrame_E: {
[&](const WriteStreamFrame& writeStreamFrame) { const WriteStreamFrame& writeStreamFrame = *frame.asWriteStreamFrame();
retransmittable = true; retransmittable = true;
auto stream = CHECK_NOTNULL( auto stream = CHECK_NOTNULL(
conn.streamManager->getStream(writeStreamFrame.streamId)); conn.streamManager->getStream(writeStreamFrame.streamId));
auto newStreamDataWritten = handleStreamWritten( auto newStreamDataWritten = handleStreamWritten(
conn, conn,
*stream, *stream,
writeStreamFrame.offset, writeStreamFrame.offset,
writeStreamFrame.len, writeStreamFrame.len,
writeStreamFrame.fin, writeStreamFrame.fin,
packetNum, packetNum,
packetNumberSpace); packetNumberSpace);
if (newStreamDataWritten) { if (newStreamDataWritten) {
updateFlowControlOnWriteToSocket(*stream, writeStreamFrame.len); updateFlowControlOnWriteToSocket(*stream, writeStreamFrame.len);
maybeWriteBlockAfterSocketWrite(*stream); maybeWriteBlockAfterSocketWrite(*stream);
conn.streamManager->updateWritableStreams(*stream); conn.streamManager->updateWritableStreams(*stream);
} }
conn.streamManager->updateLossStreams(*stream); conn.streamManager->updateLossStreams(*stream);
}, break;
[&](const WriteCryptoFrame& writeCryptoFrame) { }
retransmittable = true; case QuicWriteFrame::Type::WriteCryptoFrame_E: {
auto protectionType = packet.header.getProtectionType(); const WriteCryptoFrame& writeCryptoFrame = *frame.asWriteCryptoFrame();
// NewSessionTicket is sent in crypto frame encrypted with 1-rtt key, retransmittable = true;
// however, it is not part of handshake auto protectionType = packet.header.getProtectionType();
isHandshake = // NewSessionTicket is sent in crypto frame encrypted with 1-rtt key,
(protectionType == ProtectionType::Initial || // however, it is not part of handshake
protectionType == ProtectionType::Handshake); isHandshake =
auto encryptionLevel = (protectionType == ProtectionType::Initial ||
protectionTypeToEncryptionLevel(protectionType); protectionType == ProtectionType::Handshake);
handleStreamWritten( auto encryptionLevel = protectionTypeToEncryptionLevel(protectionType);
conn, handleStreamWritten(
*getCryptoStream(*conn.cryptoState, encryptionLevel), conn,
writeCryptoFrame.offset, *getCryptoStream(*conn.cryptoState, encryptionLevel),
writeCryptoFrame.len, writeCryptoFrame.offset,
false, writeCryptoFrame.len,
packetNum, false,
packetNumberSpace); packetNum,
}, packetNumberSpace);
[&](const WriteAckFrame& writeAckFrame) { break;
DCHECK(!ackFrameCounter++) }
<< "Send more than one WriteAckFrame " << conn; case QuicWriteFrame::Type::WriteAckFrame_E: {
auto largestAckedPacketWritten = writeAckFrame.ackBlocks.back().end; const WriteAckFrame& writeAckFrame = *frame.asWriteAckFrame();
VLOG(10) << nodeToString(conn.nodeType) DCHECK(!ackFrameCounter++)
<< " sent packet with largestAcked=" << "Send more than one WriteAckFrame " << conn;
<< largestAckedPacketWritten << " packetNum=" << packetNum auto largestAckedPacketWritten = writeAckFrame.ackBlocks.back().end;
<< " " << conn; VLOG(10) << nodeToString(conn.nodeType)
updateAckSendStateOnSentPacketWithAcks( << " sent packet with largestAcked="
conn, << largestAckedPacketWritten << " packetNum=" << packetNum
getAckState(conn, packetNumberSpace), << " " << conn;
largestAckedPacketWritten); updateAckSendStateOnSentPacketWithAcks(
}, conn,
[&](const RstStreamFrame& rstStreamFrame) { getAckState(conn, packetNumberSpace),
retransmittable = true; largestAckedPacketWritten);
VLOG(10) << nodeToString(conn.nodeType) break;
<< " sent reset streams in packetNum=" << packetNum << " " }
<< conn; case QuicWriteFrame::Type::RstStreamFrame_E: {
auto resetIter = const RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
conn.pendingEvents.resets.find(rstStreamFrame.streamId); retransmittable = true;
// TODO: this can happen because we clone RST_STREAM frames. Should we VLOG(10) << nodeToString(conn.nodeType)
// start to treat RST_STREAM in the same way we treat window update? << " sent reset streams in packetNum=" << packetNum << " "
if (resetIter != conn.pendingEvents.resets.end()) { << conn;
conn.pendingEvents.resets.erase(resetIter); auto resetIter =
} else { conn.pendingEvents.resets.find(rstStreamFrame.streamId);
DCHECK(packetEvent.hasValue()) // TODO: this can happen because we clone RST_STREAM frames. Should we
<< " reset missing from pendingEvents for non-clone packet"; // start to treat RST_STREAM in the same way we treat window update?
} if (resetIter != conn.pendingEvents.resets.end()) {
}, conn.pendingEvents.resets.erase(resetIter);
[&](const MaxDataFrame& maxDataFrame) { } else {
CHECK(!connWindowUpdateSent++) DCHECK(packetEvent.hasValue())
<< "Send more than one connection window update " << conn; << " reset missing from pendingEvents for non-clone packet";
VLOG(10) << nodeToString(conn.nodeType) }
<< " sent conn window update packetNum=" << packetNum << " " break;
<< conn; }
retransmittable = true; case QuicWriteFrame::Type::MaxDataFrame_E: {
VLOG(10) << nodeToString(conn.nodeType) const MaxDataFrame& maxDataFrame = *frame.asMaxDataFrame();
<< " sent conn window update in packetNum=" << packetNum CHECK(!connWindowUpdateSent++)
<< " " << conn; << "Send more than one connection window update " << conn;
onConnWindowUpdateSent( VLOG(10) << nodeToString(conn.nodeType)
conn, packetNum, maxDataFrame.maximumData, sentTime); << " sent conn window update packetNum=" << packetNum << " "
}, << conn;
[&](const MaxStreamDataFrame& maxStreamDataFrame) { retransmittable = true;
auto stream = CHECK_NOTNULL( VLOG(10) << nodeToString(conn.nodeType)
conn.streamManager->getStream(maxStreamDataFrame.streamId)); << " sent conn window update in packetNum=" << packetNum << " "
retransmittable = true; << conn;
VLOG(10) << nodeToString(conn.nodeType) onConnWindowUpdateSent(
<< " sent packet with window update packetNum=" << packetNum conn, packetNum, maxDataFrame.maximumData, sentTime);
<< " stream=" << maxStreamDataFrame.streamId << " " << conn; break;
onStreamWindowUpdateSent( }
*stream, packetNum, maxStreamDataFrame.maximumData, sentTime); case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
}, const MaxStreamDataFrame& maxStreamDataFrame =
[&](const StreamDataBlockedFrame& streamBlockedFrame) { *frame.asMaxStreamDataFrame();
VLOG(10) << nodeToString(conn.nodeType) auto stream = CHECK_NOTNULL(
<< " sent blocked stream frame packetNum=" << packetNum conn.streamManager->getStream(maxStreamDataFrame.streamId));
<< " " << conn; retransmittable = true;
retransmittable = true; VLOG(10) << nodeToString(conn.nodeType)
conn.streamManager->removeBlocked(streamBlockedFrame.streamId); << " sent packet with window update packetNum=" << packetNum
}, << " stream=" << maxStreamDataFrame.streamId << " " << conn;
[&](const PaddingFrame&) { onStreamWindowUpdateSent(
// do not mark padding as retransmittable. There are several reasons *stream, packetNum, maxStreamDataFrame.maximumData, sentTime);
// for this: break;
// 1. We might need to pad ACK packets to make it so that we can }
// sample them correctly for header encryption. ACK packets may not case QuicWriteFrame::Type::StreamDataBlockedFrame_E: {
// count towards congestion window, so the padding frames in those const StreamDataBlockedFrame& streamBlockedFrame =
// ack packets should not count towards the window either *frame.asStreamDataBlockedFrame();
// 2. Of course we do not want to retransmit the ACK frames. VLOG(10) << nodeToString(conn.nodeType)
}, << " sent blocked stream frame packetNum=" << packetNum << " "
[&](const QuicSimpleFrame& simpleFrame) { << conn;
retransmittable = true; retransmittable = true;
// We don't want this triggered for cloned frames. conn.streamManager->removeBlocked(streamBlockedFrame.streamId);
if (!packetEvent.hasValue()) { break;
updateSimpleFrameOnPacketSent(conn, simpleFrame); }
} case QuicWriteFrame::Type::QuicSimpleFrame_E: {
}, const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
[&](const auto&) { retransmittable = true; }); retransmittable = true;
// We don't want this triggered for cloned frames.
if (!packetEvent.hasValue()) {
updateSimpleFrameOnPacketSent(conn, simpleFrame);
}
break;
}
case QuicWriteFrame::Type::PaddingFrame_E: {
// do not mark padding as retransmittable. There are several reasons
// for this:
// 1. We might need to pad ACK packets to make it so that we can
// sample them correctly for header encryption. ACK packets may not
// count towards congestion window, so the padding frames in those
// ack packets should not count towards the window either
// 2. Of course we do not want to retransmit the ACK frames.
break;
}
default:
retransmittable = true;
}
} }
// TODO: Now pureAck is equivalent to non retransmittable packet. This might // TODO: Now pureAck is equivalent to non retransmittable packet. This might

View File

@@ -366,7 +366,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
// Write those framses with a regular builder // Write those framses with a regular builder
writeFrame(connCloseFrame, regularBuilder); writeFrame(connCloseFrame, regularBuilder);
writeFrame(maxStreamFrame, regularBuilder); writeFrame(QuicSimpleFrame(maxStreamFrame), regularBuilder);
writeFrame(pingFrame, regularBuilder); writeFrame(pingFrame, regularBuilder);
writeAckFrame(ackMeta, regularBuilder); writeAckFrame(ackMeta, regularBuilder);
@@ -386,15 +386,15 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
// Test that the only frame that's written is maxdataframe // Test that the only frame that's written is maxdataframe
EXPECT_GE(writtenPacket.packet.frames.size(), 1); EXPECT_GE(writtenPacket.packet.frames.size(), 1);
auto& writtenFrame = writtenPacket.packet.frames.at(0); auto& writtenFrame = writtenPacket.packet.frames.at(0);
auto maxDataFrame = boost::get<MaxDataFrame>(&writtenFrame); auto maxDataFrame = writtenFrame.asMaxDataFrame();
CHECK(maxDataFrame); CHECK(maxDataFrame);
for (auto& frame : writtenPacket.packet.frames) { for (auto& frame : writtenPacket.packet.frames) {
bool present = false; bool present = false;
/* the next four frames should not be written */ /* the next four frames should not be written */
present |= boost::get<ConnectionCloseFrame>(&frame) ? true : false; present |= frame.asConnectionCloseFrame() ? true : false;
present |= boost::get<QuicSimpleFrame>(&frame) ? true : false; present |= frame.asQuicSimpleFrame() ? true : false;
present |= boost::get<PingFrame>(&frame) ? true : false; present |= frame.asPingFrame() ? true : false;
present |= boost::get<WriteAckFrame>(&frame) ? true : false; present |= frame.asWriteAckFrame() ? true : false;
ASSERT_FALSE(present); ASSERT_FALSE(present);
} }
} }
@@ -535,12 +535,10 @@ TEST_F(QuicPacketSchedulerTest, CloneSchedulerUseNormalSchedulerFirst) {
conn.ackStates.appDataAckState.nextPacketNum, conn.ackStates.appDataAckState.nextPacketNum,
shortHeader.getPacketSequenceNum()); shortHeader.getPacketSequenceNum());
EXPECT_EQ(1, result.second->packet.frames.size()); EXPECT_EQ(1, result.second->packet.frames.size());
folly::variant_match( MaxDataFrame* maxDataFrame =
result.second->packet.frames.front(), result.second->packet.frames.front().asMaxDataFrame();
[&](const MaxDataFrame& frame) { EXPECT_EQ(2832, frame.maximumData); }, ASSERT_NE(maxDataFrame, nullptr);
[&](const auto&) { EXPECT_EQ(2832, maxDataFrame->maximumData);
ASSERT_FALSE(true); // should not happen
});
EXPECT_TRUE(folly::IOBufEqualTo{}( EXPECT_TRUE(folly::IOBufEqualTo{}(
*folly::IOBuf::copyBuffer("if you are the dealer"), *folly::IOBuf::copyBuffer("if you are the dealer"),
*result.second->header)); *result.second->header));
@@ -580,18 +578,25 @@ TEST_F(QuicPacketSchedulerTest, CloneWillGenerateNewWindowUpdate) {
EXPECT_EQ(expectedPacketEvent, *packetResult.first); EXPECT_EQ(expectedPacketEvent, *packetResult.first);
int32_t verifyConnWindowUpdate = 1, verifyStreamWindowUpdate = 1; int32_t verifyConnWindowUpdate = 1, verifyStreamWindowUpdate = 1;
for (const auto& frame : packetResult.second->packet.frames) { for (const auto& frame : packetResult.second->packet.frames) {
folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
[&](const MaxStreamDataFrame& maxStreamDataFrame) { const MaxStreamDataFrame& maxStreamDataFrame =
EXPECT_EQ(stream->id, maxStreamDataFrame.streamId); *frame.asMaxStreamDataFrame();
verifyStreamWindowUpdate--; EXPECT_EQ(stream->id, maxStreamDataFrame.streamId);
}, verifyStreamWindowUpdate--;
[&](const MaxDataFrame&) { verifyConnWindowUpdate--; }, break;
[&](const PaddingFrame&) {}, }
[&](const auto&) { case QuicWriteFrame::Type::MaxDataFrame_E: {
// should never happen verifyConnWindowUpdate--;
EXPECT_TRUE(false); break;
}); }
case QuicWriteFrame::Type::PaddingFrame_E: {
break;
}
default:
// should never happen
EXPECT_TRUE(false);
}
} }
EXPECT_EQ(0, verifyStreamWindowUpdate); EXPECT_EQ(0, verifyStreamWindowUpdate);
EXPECT_EQ(0, verifyConnWindowUpdate); EXPECT_EQ(0, verifyConnWindowUpdate);
@@ -600,15 +605,21 @@ TEST_F(QuicPacketSchedulerTest, CloneWillGenerateNewWindowUpdate) {
EXPECT_GE(packetResult.second->packet.frames.size(), 2); EXPECT_GE(packetResult.second->packet.frames.size(), 2);
uint32_t streamWindowUpdateCounter = 0; uint32_t streamWindowUpdateCounter = 0;
uint32_t connWindowUpdateCounter = 0; uint32_t connWindowUpdateCounter = 0;
for (auto& streamFlowControl : for (auto& frame : packetResult.second->packet.frames) {
all_frames<MaxStreamDataFrame>(packetResult.second->packet.frames)) { auto streamFlowControl = frame.asMaxStreamDataFrame();
if (!streamFlowControl) {
continue;
}
streamWindowUpdateCounter++; streamWindowUpdateCounter++;
EXPECT_EQ(1700, streamFlowControl.maximumData); EXPECT_EQ(1700, streamFlowControl->maximumData);
} }
for (auto& connFlowControl : for (auto& frame : packetResult.second->packet.frames) {
all_frames<MaxDataFrame>(packetResult.second->packet.frames)) { auto connFlowControl = frame.asMaxDataFrame();
if (!connFlowControl) {
continue;
}
connWindowUpdateCounter++; connWindowUpdateCounter++;
EXPECT_EQ(3300, connFlowControl.maximumData); EXPECT_EQ(3300, connFlowControl->maximumData);
} }
EXPECT_EQ(1, connWindowUpdateCounter); EXPECT_EQ(1, connWindowUpdateCounter);
EXPECT_EQ(1, streamWindowUpdateCounter); EXPECT_EQ(1, streamWindowUpdateCounter);

View File

@@ -1223,14 +1223,13 @@ TEST_F(QuicTransportFunctionsTest, NothingWritten) {
0); 0);
} }
template <class FrameType> const QuicWriteFrame& getFirstFrameInOutstandingPackets(
const FrameType& getFirstFrameInOutstandingPackets( const std::deque<OutstandingPacket>& outstandingPackets,
const std::deque<OutstandingPacket>& outstandingPackets) { QuicWriteFrame::Type frameType) {
for (const auto& packet : outstandingPackets) { for (const auto& packet : outstandingPackets) {
for (const auto& frame : packet.packet.frames) { for (const auto& frame : packet.packet.frames) {
auto decodedFrame = boost::get<FrameType>(&frame); if (frame.type() == frameType) {
if (decodedFrame) { return frame;
return *decodedFrame;
} }
} }
} }
@@ -1272,8 +1271,10 @@ TEST_F(QuicTransportFunctionsTest, WriteBlockedFrameWhenBlocked) {
EXPECT_LT(sentBytes, 200); EXPECT_LT(sentBytes, 200);
EXPECT_GT(conn->ackStates.appDataAckState.nextPacketNum, originalNextSeq); EXPECT_GT(conn->ackStates.appDataAckState.nextPacketNum, originalNextSeq);
auto blocked = getFirstFrameInOutstandingPackets<StreamDataBlockedFrame>( auto blocked = *getFirstFrameInOutstandingPackets(
conn->outstandingPackets); conn->outstandingPackets,
QuicWriteFrame::Type::StreamDataBlockedFrame_E)
.asStreamDataBlockedFrame();
EXPECT_EQ(blocked.streamId, stream1->id); EXPECT_EQ(blocked.streamId, stream1->id);
// Since everything is blocked, we shouldn't write a blocked again, so we // Since everything is blocked, we shouldn't write a blocked again, so we
@@ -1758,7 +1759,7 @@ TEST_F(QuicTransportFunctionsTest, UpdateConnectionCloneCounter) {
auto connWindowUpdate = auto connWindowUpdate =
MaxDataFrame(conn->flowControlState.advertisedMaxOffset); MaxDataFrame(conn->flowControlState.advertisedMaxOffset);
conn->pendingEvents.connWindowUpdate = true; conn->pendingEvents.connWindowUpdate = true;
packet.packet.frames.push_back(connWindowUpdate); packet.packet.frames.emplace_back(connWindowUpdate);
PacketEvent packetEvent = 100; PacketEvent packetEvent = 100;
conn->outstandingPacketEvents.insert(packetEvent); conn->outstandingPacketEvents.insert(packetEvent);
updateConnection(*conn, packetEvent, packet.packet, TimePoint(), 123); updateConnection(*conn, packetEvent, packet.packet, TimePoint(), 123);
@@ -1788,7 +1789,7 @@ TEST_F(QuicTransportFunctionsTest, ClonedBlocked) {
auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData); auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData);
auto stream = conn->streamManager->createNextBidirectionalStream().value(); auto stream = conn->streamManager->createNextBidirectionalStream().value();
StreamDataBlockedFrame blockedFrame(stream->id, 1000); StreamDataBlockedFrame blockedFrame(stream->id, 1000);
packet.packet.frames.push_back(blockedFrame); packet.packet.frames.emplace_back(blockedFrame);
conn->outstandingPacketEvents.insert(packetEvent); conn->outstandingPacketEvents.insert(packetEvent);
// This shall not crash // This shall not crash
updateConnection( updateConnection(
@@ -1805,8 +1806,8 @@ TEST_F(QuicTransportFunctionsTest, TwoConnWindowUpdateWillCrash) {
auto packet = buildEmptyPacket(*conn, PacketNumberSpace::Handshake); auto packet = buildEmptyPacket(*conn, PacketNumberSpace::Handshake);
MaxDataFrame connWindowUpdate( MaxDataFrame connWindowUpdate(
1000 + conn->flowControlState.advertisedMaxOffset); 1000 + conn->flowControlState.advertisedMaxOffset);
packet.packet.frames.push_back(connWindowUpdate); packet.packet.frames.emplace_back(connWindowUpdate);
packet.packet.frames.push_back(connWindowUpdate); packet.packet.frames.emplace_back(connWindowUpdate);
conn->pendingEvents.connWindowUpdate = true; conn->pendingEvents.connWindowUpdate = true;
EXPECT_DEATH( EXPECT_DEATH(
updateConnection( updateConnection(
@@ -1859,7 +1860,7 @@ TEST_F(QuicTransportFunctionsTest, ClonedRst) {
auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData); auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData);
RstStreamFrame rstStreamFrame( RstStreamFrame rstStreamFrame(
stream->id, GenericApplicationErrorCode::UNKNOWN, 0); stream->id, GenericApplicationErrorCode::UNKNOWN, 0);
packet.packet.frames.push_back(rstStreamFrame); packet.packet.frames.emplace_back(std::move(rstStreamFrame));
conn->outstandingPacketEvents.insert(packetEvent); conn->outstandingPacketEvents.insert(packetEvent);
// This shall not crash // This shall not crash
updateConnection( updateConnection(

View File

@@ -235,8 +235,7 @@ size_t bufLength(
void dropPackets(QuicServerConnectionState& conn) { void dropPackets(QuicServerConnectionState& conn) {
for (const auto& packet : conn.outstandingPackets) { for (const auto& packet : conn.outstandingPackets) {
for (const auto& frame : packet.packet.frames) { for (const auto& frame : packet.packet.frames) {
const WriteStreamFrame* streamFrame = const WriteStreamFrame* streamFrame = frame.asWriteStreamFrame();
boost::get<WriteStreamFrame>(&frame);
if (!streamFrame) { if (!streamFrame) {
continue; continue;
} }
@@ -285,15 +284,18 @@ void verifyCorrectness(
bool finSet = false; bool finSet = false;
std::vector<uint64_t> offsets; std::vector<uint64_t> offsets;
for (const auto& packet : conn.outstandingPackets) { for (const auto& packet : conn.outstandingPackets) {
for (const auto& streamFrame : for (const auto& frame : packet.packet.frames) {
all_frames<WriteStreamFrame>(packet.packet.frames)) { auto streamFrame = frame.asWriteStreamFrame();
if (streamFrame.streamId != id) { if (!streamFrame) {
continue; continue;
} }
offsets.push_back(streamFrame.offset); if (streamFrame->streamId != id) {
endOffset = std::max(endOffset, streamFrame.offset + streamFrame.len); continue;
totalLen += streamFrame.len; }
finSet |= streamFrame.fin; offsets.push_back(streamFrame->offset);
endOffset = std::max(endOffset, streamFrame->offset + streamFrame->len);
totalLen += streamFrame->len;
finSet |= streamFrame->fin;
} }
} }
auto stream = conn.streamManager->findStream(id); auto stream = conn.streamManager->findStream(id);
@@ -592,8 +594,12 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
auto& packet = auto& packet =
getFirstOutstandingPacket(conn, PacketNumberSpace::AppData)->packet; getFirstOutstandingPacket(conn, PacketNumberSpace::AppData)->packet;
bool blockedFound = false; bool blockedFound = false;
for (auto& blocked : all_frames<StreamDataBlockedFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(blocked.streamId, streamId); auto blocked = frame.asStreamDataBlockedFrame();
if (!blocked) {
continue;
}
EXPECT_EQ(blocked->streamId, streamId);
blockedFound = true; blockedFound = true;
} }
EXPECT_TRUE(blockedFound); EXPECT_TRUE(blockedFound);
@@ -782,10 +788,14 @@ TEST_F(QuicTransportTest, WriteImmediateAcks) {
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool ackFound = false; bool ackFound = false;
for (auto& ackFrame : all_frames<WriteAckFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(ackFrame.ackBlocks.size(), 1); auto ackFrame = frame.asWriteAckFrame();
EXPECT_EQ(start, ackFrame.ackBlocks.front().start); if (!ackFrame) {
EXPECT_EQ(end, ackFrame.ackBlocks.front().end); continue;
}
EXPECT_EQ(ackFrame->ackBlocks.size(), 1);
EXPECT_EQ(start, ackFrame->ackBlocks.front().start);
EXPECT_EQ(end, ackFrame->ackBlocks.front().end);
ackFound = true; ackFound = true;
} }
EXPECT_TRUE(ackFound); EXPECT_TRUE(ackFound);
@@ -835,10 +845,14 @@ TEST_F(QuicTransportTest, WritePendingAckIfHavingData) {
EXPECT_GE(packet.frames.size(), 2); EXPECT_GE(packet.frames.size(), 2);
bool ackFound = false; bool ackFound = false;
for (auto& ackFrame : all_frames<WriteAckFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(ackFrame.ackBlocks.size(), 1); auto ackFrame = frame.asWriteAckFrame();
EXPECT_EQ(ackFrame.ackBlocks.front().start, start); if (!ackFrame) {
EXPECT_EQ(ackFrame.ackBlocks.front().end, end); continue;
}
EXPECT_EQ(ackFrame->ackBlocks.size(), 1);
EXPECT_EQ(ackFrame->ackBlocks.front().start, start);
EXPECT_EQ(ackFrame->ackBlocks.front().end, end);
ackFound = true; ackFound = true;
} }
EXPECT_TRUE(ackFound); EXPECT_TRUE(ackFound);
@@ -864,10 +878,14 @@ TEST_F(QuicTransportTest, RstStream) {
->packet; ->packet;
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool rstFound = false; bool rstFound = false;
for (auto& frame : all_frames<RstStreamFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(streamId, frame.streamId); auto rstFrame = frame.asRstStreamFrame();
EXPECT_EQ(0, frame.offset); if (!rstFrame) {
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); continue;
}
EXPECT_EQ(streamId, rstFrame->streamId);
EXPECT_EQ(0, rstFrame->offset);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, rstFrame->errorCode);
rstFound = true; rstFound = true;
} }
EXPECT_TRUE(rstFound); EXPECT_TRUE(rstFound);
@@ -896,15 +914,20 @@ TEST_F(QuicTransportTest, StopSending) {
->packet; ->packet;
EXPECT_EQ(14, packet.frames.size()); EXPECT_EQ(14, packet.frames.size());
bool foundStopSending = false; bool foundStopSending = false;
for (auto& simpleFrame : all_frames<QuicSimpleFrame>(packet.frames)) { for (auto& frame : packet.frames) {
const QuicSimpleFrame* simpleFrame = frame.asQuicSimpleFrame();
if (!simpleFrame) {
continue;
}
folly::variant_match( folly::variant_match(
simpleFrame, *simpleFrame,
[&](const StopSendingFrame& frame) { [&](const StopSendingFrame& frame) {
EXPECT_EQ(streamId, frame.streamId); EXPECT_EQ(streamId, frame.streamId);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode);
foundStopSending = true; foundStopSending = true;
}, },
[&](auto&) {}); [&](auto&) {
});
} }
EXPECT_TRUE(foundStopSending); EXPECT_TRUE(foundStopSending);
} }
@@ -932,9 +955,13 @@ TEST_F(QuicTransportTest, SendPathChallenge) {
transport_->getConnectionState(), PacketNumberSpace::AppData) transport_->getConnectionState(), PacketNumberSpace::AppData)
->packet; ->packet;
bool foundPathChallenge = false; bool foundPathChallenge = false;
for (auto& simpleFrame : all_frames<QuicSimpleFrame>(packet.frames)) { for (auto& frame : packet.frames) {
const QuicSimpleFrame* simpleFrame = frame.asQuicSimpleFrame();
if (!simpleFrame) {
continue;
}
folly::variant_match( folly::variant_match(
simpleFrame, *simpleFrame,
[&](const PathChallengeFrame& frame) { [&](const PathChallengeFrame& frame) {
EXPECT_EQ(frame, pathChallenge); EXPECT_EQ(frame, pathChallenge);
foundPathChallenge = true; foundPathChallenge = true;
@@ -1133,9 +1160,13 @@ TEST_F(QuicTransportTest, SendPathResponse) {
auto packet = auto packet =
getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet; getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet;
bool foundPathResponse = false; bool foundPathResponse = false;
for (auto& simpleFrame : all_frames<QuicSimpleFrame>(packet.frames)) { for (auto& frame : packet.frames) {
const QuicSimpleFrame* simpleFrame = frame.asQuicSimpleFrame();
if (!simpleFrame) {
continue;
}
folly::variant_match( folly::variant_match(
simpleFrame, *simpleFrame,
[&](const PathResponseFrame& frame) { [&](const PathResponseFrame& frame) {
EXPECT_EQ(frame, pathResponse); EXPECT_EQ(frame, pathResponse);
foundPathResponse = true; foundPathResponse = true;
@@ -1244,9 +1275,13 @@ TEST_F(QuicTransportTest, SendNewConnectionIdFrame) {
transport_->getConnectionState(), PacketNumberSpace::AppData) transport_->getConnectionState(), PacketNumberSpace::AppData)
->packet; ->packet;
bool foundNewConnectionId = false; bool foundNewConnectionId = false;
for (auto& simpleFrame : all_frames<QuicSimpleFrame>(packet.frames)) { for (auto& frame : packet.frames) {
const QuicSimpleFrame* simpleFrame = frame.asQuicSimpleFrame();
if (!simpleFrame) {
continue;
}
folly::variant_match( folly::variant_match(
simpleFrame, *simpleFrame,
[&](const NewConnectionIdFrame& frame) { [&](const NewConnectionIdFrame& frame) {
EXPECT_EQ(frame, newConnId); EXPECT_EQ(frame, newConnId);
foundNewConnectionId = true; foundNewConnectionId = true;
@@ -1379,9 +1414,13 @@ TEST_F(QuicTransportTest, SendRetireConnectionIdFrame) {
transport_->getConnectionState(), PacketNumberSpace::AppData) transport_->getConnectionState(), PacketNumberSpace::AppData)
->packet; ->packet;
bool foundRetireConnectionId = false; bool foundRetireConnectionId = false;
for (auto& simpleFrame : all_frames<QuicSimpleFrame>(packet.frames)) { for (auto& frame : packet.frames) {
const QuicSimpleFrame* simpleFrame = frame.asQuicSimpleFrame();
if (!simpleFrame) {
continue;
}
folly::variant_match( folly::variant_match(
simpleFrame, *simpleFrame,
[&](const RetireConnectionIdFrame& frame) { [&](const RetireConnectionIdFrame& frame) {
EXPECT_EQ(frame, retireConnId); EXPECT_EQ(frame, retireConnId);
foundRetireConnectionId = true; foundRetireConnectionId = true;
@@ -1500,10 +1539,14 @@ TEST_F(QuicTransportTest, RstWrittenStream) {
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool foundReset = false; bool foundReset = false;
for (auto& frame : all_frames<RstStreamFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(streamId, frame.streamId); auto rstStream = frame.asRstStreamFrame();
EXPECT_EQ(currentWriteOffset, frame.offset); if (!rstStream) {
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); continue;
}
EXPECT_EQ(streamId, rstStream->streamId);
EXPECT_EQ(currentWriteOffset, rstStream->offset);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, rstStream->errorCode);
foundReset = true; foundReset = true;
} }
EXPECT_TRUE(foundReset); EXPECT_TRUE(foundReset);
@@ -1530,9 +1573,13 @@ TEST_F(QuicTransportTest, RstStreamUDPWriteFailNonFatal) {
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool foundReset = false; bool foundReset = false;
for (auto& frame : all_frames<RstStreamFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(streamId, frame.streamId); auto rstStream = frame.asRstStreamFrame();
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); if (!rstStream) {
continue;
}
EXPECT_EQ(streamId, rstStream->streamId);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, rstStream->errorCode);
foundReset = true; foundReset = true;
} }
EXPECT_TRUE(foundReset); EXPECT_TRUE(foundReset);
@@ -1596,10 +1643,14 @@ TEST_F(QuicTransportTest, WriteAfterSendRst) {
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool foundReset = false; bool foundReset = false;
for (auto& frame : all_frames<RstStreamFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(streamId, frame.streamId); auto rstFrame = frame.asRstStreamFrame();
EXPECT_EQ(currentWriteOffset, frame.offset); if (!rstFrame) {
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); continue;
}
EXPECT_EQ(streamId, rstFrame->streamId);
EXPECT_EQ(currentWriteOffset, rstFrame->offset);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, rstFrame->errorCode);
foundReset = true; foundReset = true;
} }
EXPECT_TRUE(foundReset); EXPECT_TRUE(foundReset);
@@ -1671,8 +1722,12 @@ TEST_F(QuicTransportTest, WriteWindowUpdate) {
getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet; getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet;
EXPECT_GE(packet.frames.size(), 1); EXPECT_GE(packet.frames.size(), 1);
bool connWindowFound = false; bool connWindowFound = false;
for (auto& connWindowUpdate : all_frames<MaxDataFrame>(packet.frames)) { for (auto& frame : packet.frames) {
EXPECT_EQ(100, connWindowUpdate.maximumData); auto connWindowUpdate = frame.asMaxDataFrame();
if (!connWindowUpdate) {
continue;
}
EXPECT_EQ(100, connWindowUpdate->maximumData);
connWindowFound = true; connWindowFound = true;
} }
@@ -1702,7 +1757,7 @@ TEST_F(QuicTransportTest, WriteWindowUpdate) {
auto packet1 = auto packet1 =
getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet; getLastOutstandingPacket(conn, PacketNumberSpace::AppData)->packet;
const MaxStreamDataFrame* streamWindowUpdate = const MaxStreamDataFrame* streamWindowUpdate =
boost::get<MaxStreamDataFrame>(&packet1.frames.front()); packet1.frames.front().asMaxStreamDataFrame();
EXPECT_TRUE(streamWindowUpdate); EXPECT_TRUE(streamWindowUpdate);
} }
@@ -2278,7 +2333,7 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
auto& packet = *getFirstOutstandingPacket(conn, PacketNumberSpace::AppData); auto& packet = *getFirstOutstandingPacket(conn, PacketNumberSpace::AppData);
EXPECT_EQ(1, packet.packet.frames.size()); EXPECT_EQ(1, packet.packet.frames.size());
auto& frame = packet.packet.frames.front(); auto& frame = packet.packet.frames.front();
const WriteStreamFrame* streamFrame = boost::get<WriteStreamFrame>(&frame); const WriteStreamFrame* streamFrame = frame.asWriteStreamFrame();
EXPECT_TRUE(streamFrame); EXPECT_TRUE(streamFrame);
EXPECT_EQ(streamFrame->streamId, s1); EXPECT_EQ(streamFrame->streamId, s1);
conn.outstandingPackets.clear(); conn.outstandingPackets.clear();
@@ -2301,7 +2356,7 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
auto& packet2 = *getFirstOutstandingPacket(conn, PacketNumberSpace::AppData); auto& packet2 = *getFirstOutstandingPacket(conn, PacketNumberSpace::AppData);
EXPECT_EQ(1, packet2.packet.frames.size()); EXPECT_EQ(1, packet2.packet.frames.size());
auto& frame2 = packet2.packet.frames.front(); auto& frame2 = packet2.packet.frames.front();
const WriteStreamFrame* streamFrame2 = boost::get<WriteStreamFrame>(&frame2); const WriteStreamFrame* streamFrame2 = frame2.asWriteStreamFrame();
EXPECT_TRUE(streamFrame2); EXPECT_TRUE(streamFrame2);
EXPECT_EQ(streamFrame2->streamId, s2); EXPECT_EQ(streamFrame2->streamId, s2);
conn.outstandingPackets.clear(); conn.outstandingPackets.clear();
@@ -2324,10 +2379,10 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
EXPECT_EQ(2, packet3.packet.frames.size()); EXPECT_EQ(2, packet3.packet.frames.size());
auto& frame3 = packet3.packet.frames.front(); auto& frame3 = packet3.packet.frames.front();
auto& frame4 = packet3.packet.frames.back(); auto& frame4 = packet3.packet.frames.back();
const WriteStreamFrame* streamFrame3 = boost::get<WriteStreamFrame>(&frame3); const WriteStreamFrame* streamFrame3 = frame3.asWriteStreamFrame();
EXPECT_TRUE(streamFrame3); EXPECT_TRUE(streamFrame3);
EXPECT_EQ(streamFrame3->streamId, s2); EXPECT_EQ(streamFrame3->streamId, s2);
const WriteStreamFrame* streamFrame4 = boost::get<WriteStreamFrame>(&frame4); const WriteStreamFrame* streamFrame4 = frame4.asWriteStreamFrame();
EXPECT_TRUE(streamFrame4); EXPECT_TRUE(streamFrame4);
EXPECT_EQ(streamFrame4->streamId, s1); EXPECT_EQ(streamFrame4->streamId, s1);
transport_->close(folly::none); transport_->close(folly::none);

View File

@@ -295,51 +295,61 @@ void QuicClientTransport::processPacketData(
// TODO: replace this with a better solution later. // TODO: replace this with a better solution later.
cancelHandshakeCryptoStreamRetransmissions(*conn_->cryptoState); cancelHandshakeCryptoStreamRetransmissions(*conn_->cryptoState);
} }
folly::variant_match( switch (packetFrame.type()) {
packetFrame, case QuicWriteFrame::Type::WriteAckFrame_E: {
[&](const WriteAckFrame& frame) { const WriteAckFrame& frame = *packetFrame.asWriteAckFrame();
DCHECK(!frame.ackBlocks.empty()); DCHECK(!frame.ackBlocks.empty());
VLOG(4) << "Client received ack for largestAcked=" VLOG(4) << "Client received ack for largestAcked="
<< frame.ackBlocks.back().end << " " << *this; << frame.ackBlocks.back().end << " " << *this;
commonAckVisitorForAckFrame(ackState, frame); commonAckVisitorForAckFrame(ackState, frame);
}, break;
[&](const RstStreamFrame& frame) { }
VLOG(4) << "Client received ack for reset frame stream=" case QuicWriteFrame::Type::RstStreamFrame_E: {
<< frame.streamId << " " << *this; const RstStreamFrame& frame = *packetFrame.asRstStreamFrame();
VLOG(4) << "Client received ack for reset frame stream="
<< frame.streamId << " " << *this;
auto stream = auto stream = conn_->streamManager->getStream(frame.streamId);
conn_->streamManager->getStream(frame.streamId); if (stream) {
if (stream) { invokeStreamSendStateMachine(
invokeStreamSendStateMachine( *conn_, *stream, StreamEvents::RstAck(frame));
*conn_, *stream, StreamEvents::RstAck(frame)); }
} break;
}, }
[&](const WriteStreamFrame& frame) { case QuicWriteFrame::Type::WriteStreamFrame_E: {
auto ackedStream = const WriteStreamFrame& frame =
conn_->streamManager->getStream(frame.streamId); *packetFrame.asWriteStreamFrame();
VLOG(4) << "Client got ack for stream=" << frame.streamId
<< " offset=" << frame.offset auto ackedStream =
<< " fin=" << frame.fin << " data=" << frame.len conn_->streamManager->getStream(frame.streamId);
<< " closed=" << (ackedStream == nullptr) << " " VLOG(4) << "Client got ack for stream=" << frame.streamId
<< *this; << " offset=" << frame.offset << " fin=" << frame.fin
if (ackedStream) { << " data=" << frame.len
invokeStreamSendStateMachine( << " closed=" << (ackedStream == nullptr) << " "
*conn_, << *this;
*ackedStream, if (ackedStream) {
StreamEvents::AckStreamFrame(frame)); invokeStreamSendStateMachine(
} *conn_,
}, *ackedStream,
[&](const WriteCryptoFrame& frame) { StreamEvents::AckStreamFrame(frame));
auto cryptoStream = getCryptoStream( }
*conn_->cryptoState, break;
protectionTypeToEncryptionLevel( }
outstandingProtectionType)); case QuicWriteFrame::Type::WriteCryptoFrame_E: {
processCryptoStreamAck( const WriteCryptoFrame& frame =
*cryptoStream, frame.offset, frame.len); *packetFrame.asWriteCryptoFrame();
}, auto cryptoStream = getCryptoStream(
[&](const auto& /* frame */) { *conn_->cryptoState,
// Ignore other frames. protectionTypeToEncryptionLevel(
}); outstandingProtectionType));
processCryptoStreamAck(
*cryptoStream, frame.offset, frame.len);
break;
}
default:
// ignore other frames.
break;
}
}, },
markPacketLoss, markPacketLoss,
receiveTimePoint); receiveTimePoint);

View File

@@ -167,6 +167,11 @@ class QuicClientTransport
void happyEyeballsConnAttemptDelayTimeoutExpired() noexcept; void happyEyeballsConnAttemptDelayTimeoutExpired() noexcept;
void handleAckFrame(
const OutstandingPacket& outstandingPacket,
const QuicWriteFrame& packetFrame,
const ReadAckFrame&);
// From ClientHandshake::HandshakeCallback // From ClientHandshake::HandshakeCallback
void onNewCachedPsk( void onNewCachedPsk(
fizz::client::NewCachedPsk& newCachedPsk) noexcept override; fizz::client::NewCachedPsk& newCachedPsk) noexcept override;

View File

@@ -3934,12 +3934,11 @@ RegularQuicWritePacket* findPacketWithStream(
StreamId streamId) { StreamId streamId) {
auto op = findOutstandingPacket(conn, [=](OutstandingPacket& packet) { auto op = findOutstandingPacket(conn, [=](OutstandingPacket& packet) {
for (auto& frame : packet.packet.frames) { for (auto& frame : packet.packet.frames) {
bool tryPacket = folly::variant_match( bool tryPacket = false;
frame, WriteStreamFrame* streamFrame = frame.asWriteStreamFrame();
[streamId](WriteStreamFrame& streamFrame) { if (streamFrame) {
return streamFrame.streamId == streamId; tryPacket = streamFrame->streamId == streamId;
}, }
[](auto&) { return false; });
if (tryPacket) { if (tryPacket) {
return true; return true;
} }

View File

@@ -53,108 +53,128 @@ folly::Optional<PacketEvent> PacketRebuilder::rebuildFromPacket(
iter != packet.packet.frames.cend(); iter != packet.packet.frames.cend();
iter++) { iter++) {
const QuicWriteFrame& frame = *iter; const QuicWriteFrame& frame = *iter;
writeSuccess = folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::WriteAckFrame_E: {
[&](const WriteAckFrame& ackFrame) { const WriteAckFrame& ackFrame = *frame.asWriteAckFrame();
auto& packetHeader = builder_.getPacketHeader(); auto& packetHeader = builder_.getPacketHeader();
uint64_t ackDelayExponent = uint64_t ackDelayExponent =
(packetHeader.getHeaderForm() == HeaderForm::Long) (packetHeader.getHeaderForm() == HeaderForm::Long)
? kDefaultAckDelayExponent ? kDefaultAckDelayExponent
: conn_.transportSettings.ackDelayExponent; : conn_.transportSettings.ackDelayExponent;
AckFrameMetaData meta( AckFrameMetaData meta(
ackFrame.ackBlocks, ackFrame.ackDelay, ackDelayExponent); ackFrame.ackBlocks, ackFrame.ackDelay, ackDelayExponent);
auto ackWriteResult = writeAckFrame(meta, builder_); auto ackWriteResult = writeAckFrame(meta, builder_);
return ackWriteResult.hasValue(); writeSuccess = ackWriteResult.hasValue();
}, break;
[&](const WriteStreamFrame& streamFrame) { }
auto stream = conn_.streamManager->getStream(streamFrame.streamId); case QuicWriteFrame::Type::WriteStreamFrame_E: {
if (stream && retransmittable(*stream)) { const WriteStreamFrame& streamFrame = *frame.asWriteStreamFrame();
auto streamData = cloneRetransmissionBuffer(streamFrame, stream); auto stream = conn_.streamManager->getStream(streamFrame.streamId);
auto bufferLen = if (stream && retransmittable(*stream)) {
streamData ? streamData->computeChainDataLength() : 0; auto streamData = cloneRetransmissionBuffer(streamFrame, stream);
auto dataLen = writeStreamFrameHeader( auto bufferLen =
builder_, streamData ? streamData->computeChainDataLength() : 0;
streamFrame.streamId, auto dataLen = writeStreamFrameHeader(
streamFrame.offset, builder_,
bufferLen, streamFrame.streamId,
bufferLen, streamFrame.offset,
streamFrame.fin); bufferLen,
bool ret = dataLen.hasValue() && *dataLen == streamFrame.len; bufferLen,
if (ret) { streamFrame.fin);
writeStreamFrameData(builder_, std::move(streamData), *dataLen); bool ret = dataLen.hasValue() && *dataLen == streamFrame.len;
notPureAck = true; if (ret) {
return true; writeStreamFrameData(builder_, std::move(streamData), *dataLen);
} notPureAck = true;
return false; writeSuccess = true;
break;
} }
// If a stream is already Closed, we should not clone and resend this writeSuccess = false;
// stream data. But should we abort the cloning of this packet and break;
// move on to the next packet? I'm gonna err on the aggressive side }
// for now and call it success. // If a stream is already Closed, we should not clone and resend this
return true; // stream data. But should we abort the cloning of this packet and
}, // move on to the next packet? I'm gonna err on the aggressive side
[&](const WriteCryptoFrame& cryptoFrame) { // for now and call it success.
// initialStream and handshakeStream can only be in handshake packet, writeSuccess = true;
// so they are not clonable break;
CHECK(!packet.isHandshake); }
// key update not supported case QuicWriteFrame::Type::WriteCryptoFrame_E: {
DCHECK( const WriteCryptoFrame& cryptoFrame = *frame.asWriteCryptoFrame();
packet.packet.header.getProtectionType() == // initialStream and handshakeStream can only be in handshake packet,
ProtectionType::KeyPhaseZero); // so they are not clonable
auto& stream = conn_.cryptoState->oneRttStream; CHECK(!packet.isHandshake);
auto buf = cloneCryptoRetransmissionBuffer(cryptoFrame, stream); // key update not supported
DCHECK(
packet.packet.header.getProtectionType() ==
ProtectionType::KeyPhaseZero);
auto& stream = conn_.cryptoState->oneRttStream;
auto buf = cloneCryptoRetransmissionBuffer(cryptoFrame, stream);
// No crypto data found to be cloned, just skip // No crypto data found to be cloned, just skip
if (!buf) { if (!buf) {
return true; writeSuccess = true;
} break;
auto cryptoWriteResult = }
writeCryptoFrame(cryptoFrame.offset, std::move(buf), builder_); auto cryptoWriteResult =
bool ret = cryptoWriteResult.hasValue() && writeCryptoFrame(cryptoFrame.offset, std::move(buf), builder_);
cryptoWriteResult->offset == cryptoFrame.offset && bool ret = cryptoWriteResult.hasValue() &&
cryptoWriteResult->len == cryptoFrame.len; cryptoWriteResult->offset == cryptoFrame.offset &&
notPureAck |= ret; cryptoWriteResult->len == cryptoFrame.len;
return ret; notPureAck |= ret;
}, writeSuccess = ret;
[&](const MaxDataFrame&) { break;
shouldWriteWindowUpdate = true; }
auto ret = 0 != writeFrame(generateMaxDataFrame(conn_), builder_); case QuicWriteFrame::Type::MaxDataFrame_E: {
windowUpdateWritten |= ret; shouldWriteWindowUpdate = true;
notPureAck |= ret; auto ret = 0 != writeFrame(generateMaxDataFrame(conn_), builder_);
return true; windowUpdateWritten |= ret;
}, notPureAck |= ret;
[&](const MaxStreamDataFrame& maxStreamDataFrame) { writeSuccess = true;
auto stream = break;
conn_.streamManager->getStream(maxStreamDataFrame.streamId); }
if (!stream || !stream->shouldSendFlowControl()) { case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
return true; const MaxStreamDataFrame& maxStreamDataFrame =
} *frame.asMaxStreamDataFrame();
shouldWriteWindowUpdate = true; auto stream =
auto ret = conn_.streamManager->getStream(maxStreamDataFrame.streamId);
0 != writeFrame(generateMaxStreamDataFrame(*stream), builder_); if (!stream || !stream->shouldSendFlowControl()) {
windowUpdateWritten |= ret; writeSuccess = true;
notPureAck |= ret; break;
return true; }
}, shouldWriteWindowUpdate = true;
[&](const PaddingFrame& paddingFrame) { auto ret =
return writeFrame(paddingFrame, builder_) != 0; 0 != writeFrame(generateMaxStreamDataFrame(*stream), builder_);
}, windowUpdateWritten |= ret;
[&](const QuicSimpleFrame& simpleFrame) { notPureAck |= ret;
auto updatedSimpleFrame = writeSuccess = true;
updateSimpleFrameOnPacketClone(conn_, simpleFrame); break;
if (!updatedSimpleFrame) { }
return true; case QuicWriteFrame::Type::PaddingFrame_E: {
} const PaddingFrame& paddingFrame = *frame.asPaddingFrame();
bool ret = writeSuccess = writeFrame(paddingFrame, builder_) != 0;
writeSimpleFrame(std::move(*updatedSimpleFrame), builder_) != 0; break;
notPureAck |= ret; }
return ret; case QuicWriteFrame::Type::QuicSimpleFrame_E: {
}, const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
[&](const auto& otherFrame) { auto updatedSimpleFrame =
bool ret = writeFrame(otherFrame, builder_) != 0; updateSimpleFrameOnPacketClone(conn_, simpleFrame);
notPureAck |= ret; if (!updatedSimpleFrame) {
return ret; writeSuccess = true;
}); break;
}
bool ret =
writeSimpleFrame(std::move(*updatedSimpleFrame), builder_) != 0;
notPureAck |= ret;
writeSuccess = ret;
break;
}
default: {
bool ret = writeFrame(QuicWriteFrame(frame), builder_) != 0;
notPureAck |= ret;
writeSuccess = ret;
break;
}
}
if (!writeSuccess) { if (!writeSuccess) {
return folly::none; return folly::none;
} }

View File

@@ -339,7 +339,7 @@ size_t writeSimpleFrame(
} else { } else {
builder.write(errorCode); builder.write(errorCode);
} }
builder.appendFrame(std::move(stopSendingFrame)); builder.appendFrame(QuicSimpleFrame(std::move(stopSendingFrame)));
return stopSendingFrameSize; return stopSendingFrameSize;
} }
// no space left in packet // no space left in packet
@@ -358,7 +358,7 @@ size_t writeSimpleFrame(
builder.write(streamId); builder.write(streamId);
builder.write(maximumData); builder.write(maximumData);
builder.write(minimumStreamOffset); builder.write(minimumStreamOffset);
builder.appendFrame(std::move(minStreamDataFrame)); builder.appendFrame(QuicSimpleFrame(std::move(minStreamDataFrame)));
return minStreamDataFrameSize; return minStreamDataFrameSize;
} }
// no space left in packet // no space left in packet
@@ -376,7 +376,8 @@ size_t writeSimpleFrame(
builder.write(frameType); builder.write(frameType);
builder.write(streamId); builder.write(streamId);
builder.write(minimumStreamOffset); builder.write(minimumStreamOffset);
builder.appendFrame(std::move(expiredStreamDataFrame)); builder.appendFrame(
QuicSimpleFrame(std::move(expiredStreamDataFrame)));
return expiredStreamDataFrameSize; return expiredStreamDataFrameSize;
} }
// no space left in packet // no space left in packet
@@ -389,7 +390,7 @@ size_t writeSimpleFrame(
if (packetSpaceCheck(spaceLeft, pathChallengeFrameSize)) { if (packetSpaceCheck(spaceLeft, pathChallengeFrameSize)) {
builder.write(frameType); builder.write(frameType);
builder.writeBE(pathChallengeFrame.pathData); builder.writeBE(pathChallengeFrame.pathData);
builder.appendFrame(std::move(pathChallengeFrame)); builder.appendFrame(QuicSimpleFrame(std::move(pathChallengeFrame)));
return pathChallengeFrameSize; return pathChallengeFrameSize;
} }
// no space left in packet // no space left in packet
@@ -402,7 +403,7 @@ size_t writeSimpleFrame(
if (packetSpaceCheck(spaceLeft, pathResponseFrameSize)) { if (packetSpaceCheck(spaceLeft, pathResponseFrameSize)) {
builder.write(frameType); builder.write(frameType);
builder.writeBE(pathResponseFrame.pathData); builder.writeBE(pathResponseFrame.pathData);
builder.appendFrame(std::move(pathResponseFrame)); builder.appendFrame(QuicSimpleFrame(std::move(pathResponseFrame)));
return pathResponseFrameSize; return pathResponseFrameSize;
} }
// no space left in packet // no space left in packet
@@ -429,7 +430,7 @@ size_t writeSimpleFrame(
builder.push( builder.push(
newConnectionIdFrame.token.data(), newConnectionIdFrame.token.data(),
newConnectionIdFrame.token.size()); newConnectionIdFrame.token.size());
builder.appendFrame(std::move(newConnectionIdFrame)); builder.appendFrame(QuicSimpleFrame(std::move(newConnectionIdFrame)));
return newConnectionIdFrameSize; return newConnectionIdFrameSize;
} }
// no space left in packet // no space left in packet
@@ -446,7 +447,7 @@ size_t writeSimpleFrame(
if (packetSpaceCheck(spaceLeft, maxStreamsFrameSize)) { if (packetSpaceCheck(spaceLeft, maxStreamsFrameSize)) {
builder.write(intFrameType); builder.write(intFrameType);
builder.write(streamCount); builder.write(streamCount);
builder.appendFrame(maxStreamsFrame); builder.appendFrame(QuicSimpleFrame(maxStreamsFrame));
return maxStreamsFrameSize; return maxStreamsFrameSize;
} }
return size_t(0); return size_t(0);
@@ -460,7 +461,7 @@ size_t writeSimpleFrame(
if (packetSpaceCheck(spaceLeft, retireConnectionIdFrameSize)) { if (packetSpaceCheck(spaceLeft, retireConnectionIdFrameSize)) {
builder.write(frameType); builder.write(frameType);
builder.write(sequence); builder.write(sequence);
builder.appendFrame(retireConnectionIdFrame); builder.appendFrame(QuicSimpleFrame(retireConnectionIdFrame));
return retireConnectionIdFrameSize; return retireConnectionIdFrameSize;
} }
// no space left in packet // no space left in packet
@@ -473,206 +474,218 @@ size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
uint64_t spaceLeft = builder.remainingSpaceInPkt(); uint64_t spaceLeft = builder.remainingSpaceInPkt();
return folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::PaddingFrame_E: {
[&](PaddingFrame& paddingFrame) { PaddingFrame& paddingFrame = *frame.asPaddingFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PADDING)); QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PADDING));
if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) { if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
builder.write(intFrameType); builder.write(intFrameType);
builder.appendFrame(std::move(paddingFrame)); builder.appendFrame(std::move(paddingFrame));
return intFrameType.getSize(); return intFrameType.getSize();
}
return size_t(0);
}
case QuicWriteFrame::Type::PingFrame_E: {
PingFrame& pingFrame = *frame.asPingFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PING));
if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
builder.write(intFrameType);
builder.appendFrame(std::move(pingFrame));
return intFrameType.getSize();
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::RstStreamFrame_E: {
RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM));
QuicInteger streamId(rstStreamFrame.streamId);
QuicInteger offset(rstStreamFrame.offset);
QuicInteger errorCode(static_cast<uint64_t>(rstStreamFrame.errorCode));
auto version = builder.getVersion();
size_t errorSize = version == QuicVersion::MVFST_OLD
? sizeof(ApplicationErrorCode)
: errorCode.getSize();
auto rstStreamFrameSize = intFrameType.getSize() + errorSize +
streamId.getSize() + offset.getSize();
if (packetSpaceCheck(spaceLeft, rstStreamFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
if (version == QuicVersion::MVFST_OLD) {
builder.writeBE(
static_cast<ApplicationErrorCode>(rstStreamFrame.errorCode));
} else {
builder.write(errorCode);
} }
return size_t(0); builder.write(offset);
}, builder.appendFrame(std::move(rstStreamFrame));
[&](PingFrame& pingFrame) { return rstStreamFrameSize;
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PING)); }
if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) { // no space left in packet
builder.write(intFrameType); return size_t(0);
builder.appendFrame(std::move(pingFrame)); }
return intFrameType.getSize(); case QuicWriteFrame::Type::MaxDataFrame_E: {
MaxDataFrame& maxDataFrame = *frame.asMaxDataFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::MAX_DATA));
QuicInteger maximumData(maxDataFrame.maximumData);
auto frameSize = intFrameType.getSize() + maximumData.getSize();
if (packetSpaceCheck(spaceLeft, frameSize)) {
builder.write(intFrameType);
builder.write(maximumData);
builder.appendFrame(std::move(maxDataFrame));
return frameSize;
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
MaxStreamDataFrame& maxStreamDataFrame = *frame.asMaxStreamDataFrame();
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::MAX_STREAM_DATA));
QuicInteger streamId(maxStreamDataFrame.streamId);
QuicInteger maximumData(maxStreamDataFrame.maximumData);
auto maxStreamDataFrameSize =
intFrameType.getSize() + streamId.getSize() + maximumData.getSize();
if (packetSpaceCheck(spaceLeft, maxStreamDataFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.write(maximumData);
builder.appendFrame(std::move(maxStreamDataFrame));
return maxStreamDataFrameSize;
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::DataBlockedFrame_E: {
DataBlockedFrame& blockedFrame = *frame.asDataBlockedFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::DATA_BLOCKED));
QuicInteger dataLimit(blockedFrame.dataLimit);
auto blockedFrameSize = intFrameType.getSize() + dataLimit.getSize();
if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
builder.write(intFrameType);
builder.write(dataLimit);
builder.appendFrame(std::move(blockedFrame));
return blockedFrameSize;
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::StreamDataBlockedFrame_E: {
StreamDataBlockedFrame& streamBlockedFrame =
*frame.asStreamDataBlockedFrame();
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::STREAM_DATA_BLOCKED));
QuicInteger streamId(streamBlockedFrame.streamId);
QuicInteger dataLimit(streamBlockedFrame.dataLimit);
auto blockedFrameSize =
intFrameType.getSize() + streamId.getSize() + dataLimit.getSize();
if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.write(dataLimit);
builder.appendFrame(std::move(streamBlockedFrame));
return blockedFrameSize;
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::StreamsBlockedFrame_E: {
StreamsBlockedFrame& streamsBlockedFrame = *frame.asStreamsBlockedFrame();
auto frameType = streamsBlockedFrame.isForBidirectionalStream()
? FrameType::STREAMS_BLOCKED_BIDI
: FrameType::STREAMS_BLOCKED_UNI;
QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
QuicInteger streamId(streamsBlockedFrame.streamLimit);
auto streamBlockedFrameSize = intFrameType.getSize() + streamId.getSize();
if (packetSpaceCheck(spaceLeft, streamBlockedFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.appendFrame(std::move(streamsBlockedFrame));
return streamBlockedFrameSize;
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::ConnectionCloseFrame_E: {
ConnectionCloseFrame& connectionCloseFrame =
*frame.asConnectionCloseFrame();
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::CONNECTION_CLOSE));
QuicInteger reasonLength(connectionCloseFrame.reasonPhrase.size());
QuicInteger closingFrameType(
static_cast<FrameTypeType>(connectionCloseFrame.closingFrameType));
QuicInteger errorCode(
static_cast<uint64_t>(connectionCloseFrame.errorCode));
auto version = builder.getVersion();
size_t errorSize = version == QuicVersion::MVFST_OLD
? sizeof(TransportErrorCode)
: errorCode.getSize();
auto connCloseFrameSize = intFrameType.getSize() + errorSize +
closingFrameType.getSize() + reasonLength.getSize() +
connectionCloseFrame.reasonPhrase.size();
if (packetSpaceCheck(spaceLeft, connCloseFrameSize)) {
builder.write(intFrameType);
if (version == QuicVersion::MVFST_OLD) {
builder.writeBE(
static_cast<std::underlying_type<TransportErrorCode>::type>(
connectionCloseFrame.errorCode));
} else {
builder.write(errorCode);
} }
// no space left in packet builder.write(closingFrameType);
return size_t(0); builder.write(reasonLength);
}, builder.push(
[&](RstStreamFrame& rstStreamFrame) { (const uint8_t*)connectionCloseFrame.reasonPhrase.data(),
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM)); connectionCloseFrame.reasonPhrase.size());
QuicInteger streamId(rstStreamFrame.streamId); builder.appendFrame(std::move(connectionCloseFrame));
QuicInteger offset(rstStreamFrame.offset); return connCloseFrameSize;
QuicInteger errorCode(static_cast<uint64_t>(rstStreamFrame.errorCode)); }
auto version = builder.getVersion(); // no space left in packet
size_t errorSize = version == QuicVersion::MVFST_OLD return size_t(0);
? sizeof(ApplicationErrorCode) }
: errorCode.getSize(); case QuicWriteFrame::Type::ApplicationCloseFrame_E: {
auto rstStreamFrameSize = intFrameType.getSize() + errorSize + ApplicationCloseFrame& applicationCloseFrame =
streamId.getSize() + offset.getSize(); *frame.asApplicationCloseFrame();
if (packetSpaceCheck(spaceLeft, rstStreamFrameSize)) { QuicInteger intFrameType(
builder.write(intFrameType); static_cast<uint8_t>(FrameType::APPLICATION_CLOSE));
builder.write(streamId); QuicInteger reasonLength(applicationCloseFrame.reasonPhrase.size());
if (version == QuicVersion::MVFST_OLD) { QuicInteger errorCode(
builder.writeBE( static_cast<uint64_t>(applicationCloseFrame.errorCode));
static_cast<ApplicationErrorCode>(rstStreamFrame.errorCode)); auto version = builder.getVersion();
} else { size_t errorSize = version == QuicVersion::MVFST_OLD
builder.write(errorCode); ? sizeof(ApplicationErrorCode)
} : errorCode.getSize();
builder.write(offset); auto applicationCloseFrameSize = intFrameType.getSize() + errorSize +
builder.appendFrame(std::move(rstStreamFrame)); reasonLength.getSize() + applicationCloseFrame.reasonPhrase.size();
return rstStreamFrameSize; if (packetSpaceCheck(spaceLeft, applicationCloseFrameSize)) {
builder.write(intFrameType);
if (version == QuicVersion::MVFST_OLD) {
builder.writeBE(static_cast<ApplicationErrorCode>(
applicationCloseFrame.errorCode));
} else {
builder.write(errorCode);
} }
// no space left in packet builder.write(reasonLength);
return size_t(0); builder.push(
}, (const uint8_t*)applicationCloseFrame.reasonPhrase.data(),
[&](MaxDataFrame& maxDataFrame) { applicationCloseFrame.reasonPhrase.size());
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::MAX_DATA)); builder.appendFrame(std::move(applicationCloseFrame));
QuicInteger maximumData(maxDataFrame.maximumData); return applicationCloseFrameSize;
auto frameSize = intFrameType.getSize() + maximumData.getSize(); }
if (packetSpaceCheck(spaceLeft, frameSize)) { // no space left in packet
builder.write(intFrameType); return size_t(0);
builder.write(maximumData); }
builder.appendFrame(std::move(maxDataFrame)); case QuicWriteFrame::Type::QuicSimpleFrame_E: {
return frameSize; return writeSimpleFrame(std::move(*frame.asQuicSimpleFrame()), builder);
} }
// no space left in packet default: {
return size_t(0); // TODO add support for: RETIRE_CONNECTION_ID and NEW_TOKEN frames
}, auto errorStr = folly::to<std::string>(
[&](MaxStreamDataFrame& maxStreamDataFrame) { "Unknown / unsupported frame type received at ", __func__);
QuicInteger intFrameType( VLOG(2) << errorStr;
static_cast<uint8_t>(FrameType::MAX_STREAM_DATA)); throw QuicTransportException(
QuicInteger streamId(maxStreamDataFrame.streamId); errorStr, TransportErrorCode::FRAME_ENCODING_ERROR);
QuicInteger maximumData(maxStreamDataFrame.maximumData); }
auto maxStreamDataFrameSize = }
intFrameType.getSize() + streamId.getSize() + maximumData.getSize();
if (packetSpaceCheck(spaceLeft, maxStreamDataFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.write(maximumData);
builder.appendFrame(std::move(maxStreamDataFrame));
return maxStreamDataFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](DataBlockedFrame& blockedFrame) {
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::DATA_BLOCKED));
QuicInteger dataLimit(blockedFrame.dataLimit);
auto blockedFrameSize = intFrameType.getSize() + dataLimit.getSize();
if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
builder.write(intFrameType);
builder.write(dataLimit);
builder.appendFrame(std::move(blockedFrame));
return blockedFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](StreamDataBlockedFrame& streamBlockedFrame) {
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::STREAM_DATA_BLOCKED));
QuicInteger streamId(streamBlockedFrame.streamId);
QuicInteger dataLimit(streamBlockedFrame.dataLimit);
auto blockedFrameSize =
intFrameType.getSize() + streamId.getSize() + dataLimit.getSize();
if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.write(dataLimit);
builder.appendFrame(std::move(streamBlockedFrame));
return blockedFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](StreamsBlockedFrame& streamsBlockedFrame) {
auto frameType = streamsBlockedFrame.isForBidirectionalStream()
? FrameType::STREAMS_BLOCKED_BIDI
: FrameType::STREAMS_BLOCKED_UNI;
QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
QuicInteger streamId(streamsBlockedFrame.streamLimit);
auto streamBlockedFrameSize =
intFrameType.getSize() + streamId.getSize();
if (packetSpaceCheck(spaceLeft, streamBlockedFrameSize)) {
builder.write(intFrameType);
builder.write(streamId);
builder.appendFrame(std::move(streamsBlockedFrame));
return streamBlockedFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](ConnectionCloseFrame& connectionCloseFrame) {
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::CONNECTION_CLOSE));
QuicInteger reasonLength(connectionCloseFrame.reasonPhrase.size());
QuicInteger closingFrameType(
static_cast<FrameTypeType>(connectionCloseFrame.closingFrameType));
QuicInteger errorCode(
static_cast<uint64_t>(connectionCloseFrame.errorCode));
auto version = builder.getVersion();
size_t errorSize = version == QuicVersion::MVFST_OLD
? sizeof(TransportErrorCode)
: errorCode.getSize();
auto connCloseFrameSize = intFrameType.getSize() + errorSize +
closingFrameType.getSize() + reasonLength.getSize() +
connectionCloseFrame.reasonPhrase.size();
if (packetSpaceCheck(spaceLeft, connCloseFrameSize)) {
builder.write(intFrameType);
if (version == QuicVersion::MVFST_OLD) {
builder.writeBE(
static_cast<std::underlying_type<TransportErrorCode>::type>(
connectionCloseFrame.errorCode));
} else {
builder.write(errorCode);
}
builder.write(closingFrameType);
builder.write(reasonLength);
builder.push(
(const uint8_t*)connectionCloseFrame.reasonPhrase.data(),
connectionCloseFrame.reasonPhrase.size());
builder.appendFrame(std::move(connectionCloseFrame));
return connCloseFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](ApplicationCloseFrame& applicationCloseFrame) {
QuicInteger intFrameType(
static_cast<uint8_t>(FrameType::APPLICATION_CLOSE));
QuicInteger reasonLength(applicationCloseFrame.reasonPhrase.size());
QuicInteger errorCode(
static_cast<uint64_t>(applicationCloseFrame.errorCode));
auto version = builder.getVersion();
size_t errorSize = version == QuicVersion::MVFST_OLD
? sizeof(ApplicationErrorCode)
: errorCode.getSize();
auto applicationCloseFrameSize = intFrameType.getSize() + errorSize +
reasonLength.getSize() + applicationCloseFrame.reasonPhrase.size();
if (packetSpaceCheck(spaceLeft, applicationCloseFrameSize)) {
builder.write(intFrameType);
if (version == QuicVersion::MVFST_OLD) {
builder.writeBE(static_cast<ApplicationErrorCode>(
applicationCloseFrame.errorCode));
} else {
builder.write(errorCode);
}
builder.write(reasonLength);
builder.push(
(const uint8_t*)applicationCloseFrame.reasonPhrase.data(),
applicationCloseFrame.reasonPhrase.size());
builder.appendFrame(std::move(applicationCloseFrame));
return applicationCloseFrameSize;
}
// no space left in packet
return size_t(0);
},
[&](QuicSimpleFrame& simpleFrame) {
return writeSimpleFrame(std::move(simpleFrame), builder);
},
[&](auto&) -> size_t {
// TODO add support for: RETIRE_CONNECTION_ID and NEW_TOKEN frames
auto errorStr = folly::to<std::string>(
"Unknown / unsupported frame type received at ", __func__);
VLOG(2) << errorStr;
throw QuicTransportException(
errorStr, TransportErrorCode::FRAME_ENCODING_ERROR);
});
} }
} // namespace quic } // namespace quic

View File

@@ -592,22 +592,25 @@ using QuicSimpleFrame = boost::variant<
DECLARE_VARIANT_TYPE(QuicFrame, QUIC_FRAME) DECLARE_VARIANT_TYPE(QuicFrame, QUIC_FRAME)
#define QUIC_WRITE_FRAME(F, ...) \
F(PaddingFrame, __VA_ARGS__) \
F(RstStreamFrame, __VA_ARGS__) \
F(ConnectionCloseFrame, __VA_ARGS__) \
F(ApplicationCloseFrame, __VA_ARGS__) \
F(MaxDataFrame, __VA_ARGS__) \
F(MaxStreamDataFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__) \
F(DataBlockedFrame, __VA_ARGS__) \
F(StreamDataBlockedFrame, __VA_ARGS__) \
F(StreamsBlockedFrame, __VA_ARGS__) \
F(WriteAckFrame, __VA_ARGS__) \
F(WriteStreamFrame, __VA_ARGS__) \
F(WriteCryptoFrame, __VA_ARGS__) \
F(QuicSimpleFrame, __VA_ARGS__) \
F(NoopFrame, __VA_ARGS__)
// Types of frames which are written. // Types of frames which are written.
using QuicWriteFrame = boost::variant< DECLARE_VARIANT_TYPE(QuicWriteFrame, QUIC_WRITE_FRAME)
PaddingFrame,
RstStreamFrame,
ConnectionCloseFrame,
ApplicationCloseFrame,
MaxDataFrame,
MaxStreamDataFrame,
PingFrame,
DataBlockedFrame,
StreamDataBlockedFrame,
StreamsBlockedFrame,
WriteAckFrame,
WriteStreamFrame,
WriteCryptoFrame,
QuicSimpleFrame>;
enum class HeaderForm : bool { enum class HeaderForm : bool {
Long = 1, Long = 1,

View File

@@ -80,7 +80,7 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
// Write them with a regular builder // Write them with a regular builder
writeFrame(connCloseFrame, regularBuilder1); writeFrame(connCloseFrame, regularBuilder1);
writeFrame(maxStreamsFrame, regularBuilder1); writeFrame(QuicSimpleFrame(maxStreamsFrame), regularBuilder1);
writeFrame(pingFrame, regularBuilder1); writeFrame(pingFrame, regularBuilder1);
writeAckFrame(ackMeta, regularBuilder1); writeAckFrame(ackMeta, regularBuilder1);
writeStreamFrameHeader( writeStreamFrameHeader(
@@ -123,44 +123,61 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
stream->currentReadOffset + stream->flowControlState.windowSize, stream->currentReadOffset + stream->flowControlState.windowSize,
stream->flowControlState.advertisedMaxOffset); stream->flowControlState.advertisedMaxOffset);
for (const auto& frame : packet2.packet.frames) { for (const auto& frame : packet2.packet.frames) {
folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::ConnectionCloseFrame_E: {
[](const ConnectionCloseFrame& closeFrame) { const ConnectionCloseFrame& closeFrame =
EXPECT_EQ( *frame.asConnectionCloseFrame();
TransportErrorCode::FRAME_ENCODING_ERROR, closeFrame.errorCode); EXPECT_EQ(
EXPECT_EQ("The sun is in the sky.", closeFrame.reasonPhrase); TransportErrorCode::FRAME_ENCODING_ERROR, closeFrame.errorCode);
EXPECT_EQ(FrameType::ACK, closeFrame.closingFrameType); EXPECT_EQ("The sun is in the sky.", closeFrame.reasonPhrase);
}, EXPECT_EQ(FrameType::ACK, closeFrame.closingFrameType);
[](const QuicSimpleFrame& simpleFrame) { break;
auto maxStreamFrame = boost::get<MaxStreamsFrame>(simpleFrame); }
EXPECT_EQ(4321, maxStreamFrame.maxStreams); case QuicWriteFrame::Type::QuicSimpleFrame_E: {
}, const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
[](const PingFrame& ping) { EXPECT_EQ(PingFrame(), ping); }, auto maxStreamFrame = boost::get<MaxStreamsFrame>(simpleFrame);
[](const WriteAckFrame& ack) { EXPECT_EQ(4321, maxStreamFrame.maxStreams);
EXPECT_EQ(Interval<PacketNum>(10, 100), ack.ackBlocks.front()); break;
EXPECT_EQ(Interval<PacketNum>(200, 1000), ack.ackBlocks.back()); }
}, case QuicWriteFrame::Type::PingFrame_E: {
[&buf, &streamId](const WriteStreamFrame& streamFrame) { const PingFrame& ping = *frame.asPingFrame();
EXPECT_EQ(streamId, streamFrame.streamId); EXPECT_EQ(PingFrame(), ping);
EXPECT_EQ(0, streamFrame.offset); break;
EXPECT_EQ(buf->computeChainDataLength(), streamFrame.len); }
EXPECT_EQ(true, streamFrame.fin); case QuicWriteFrame::Type::WriteAckFrame_E: {
}, const WriteAckFrame& ack = *frame.asWriteAckFrame();
[&cryptoOffset, &cryptoBuf](const WriteCryptoFrame& frame) { EXPECT_EQ(Interval<PacketNum>(10, 100), ack.ackBlocks.front());
EXPECT_EQ(frame.offset, cryptoOffset); EXPECT_EQ(Interval<PacketNum>(200, 1000), ack.ackBlocks.back());
EXPECT_EQ(frame.len, cryptoBuf->computeChainDataLength()); break;
}, }
[&expectedConnFlowControlValue](const MaxDataFrame& maxData) { case QuicWriteFrame::Type::WriteStreamFrame_E: {
EXPECT_EQ(expectedConnFlowControlValue, maxData.maximumData); const WriteStreamFrame& streamFrame = *frame.asWriteStreamFrame();
}, EXPECT_EQ(streamId, streamFrame.streamId);
[&streamId, &expectedStreamFlowControlValue]( EXPECT_EQ(0, streamFrame.offset);
const MaxStreamDataFrame& maxStreamData) { EXPECT_EQ(buf->computeChainDataLength(), streamFrame.len);
EXPECT_EQ(streamId, maxStreamData.streamId); EXPECT_EQ(true, streamFrame.fin);
EXPECT_EQ(expectedStreamFlowControlValue, maxStreamData.maximumData); break;
}, }
[](const auto&) { case QuicWriteFrame::Type::WriteCryptoFrame_E: {
EXPECT_TRUE(false); /* should never happen*/ const WriteCryptoFrame& cryptoFrame = *frame.asWriteCryptoFrame();
}); EXPECT_EQ(cryptoFrame.offset, cryptoOffset);
EXPECT_EQ(cryptoFrame.len, cryptoBuf->computeChainDataLength());
break;
}
case QuicWriteFrame::Type::MaxDataFrame_E: {
const MaxDataFrame& maxData = *frame.asMaxDataFrame();
EXPECT_EQ(expectedConnFlowControlValue, maxData.maximumData);
break;
}
case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
const MaxStreamDataFrame& maxStreamData = *frame.asMaxStreamDataFrame();
EXPECT_EQ(streamId, maxStreamData.streamId);
EXPECT_EQ(expectedStreamFlowControlValue, maxStreamData.maximumData);
break;
}
default:
EXPECT_TRUE(false); /* should never happen*/
}
} }
EXPECT_TRUE(folly::IOBufEqualTo()(*packet1.header, *packet2.header)); EXPECT_TRUE(folly::IOBufEqualTo()(*packet1.header, *packet2.header));
// TODO: I don't have a good way to verify body without decode them // TODO: I don't have a good way to verify body without decode them
@@ -286,17 +303,14 @@ TEST_F(QuicPacketRebuilderTest, RebuildDataStreamAndEmptyCryptoStream) {
// rebuilder writes frames to regularBuilder2 // rebuilder writes frames to regularBuilder2
EXPECT_EQ(packet1.packet.frames.size(), packet2.packet.frames.size() + 1); EXPECT_EQ(packet1.packet.frames.size(), packet2.packet.frames.size() + 1);
for (const auto& frame : packet2.packet.frames) { for (const auto& frame : packet2.packet.frames) {
folly::variant_match( const WriteStreamFrame* streamFrame = frame.asWriteStreamFrame();
frame, if (!streamFrame) {
[&buf, &streamId](const WriteStreamFrame& streamFrame) { EXPECT_TRUE(false); /* should never happen*/
EXPECT_EQ(streamId, streamFrame.streamId); }
EXPECT_EQ(0, streamFrame.offset); EXPECT_EQ(streamId, streamFrame->streamId);
EXPECT_EQ(buf->computeChainDataLength(), streamFrame.len); EXPECT_EQ(0, streamFrame->offset);
EXPECT_EQ(true, streamFrame.fin); EXPECT_EQ(buf->computeChainDataLength(), streamFrame->len);
}, EXPECT_EQ(true, streamFrame->fin);
[](const auto&) {
EXPECT_TRUE(false); /* should never happen*/
});
} }
EXPECT_TRUE(folly::IOBufEqualTo()(*packet1.header, *packet2.header)); EXPECT_TRUE(folly::IOBufEqualTo()(*packet1.header, *packet2.header));
} }

View File

@@ -127,7 +127,7 @@ TEST_F(QuicWriteCodecTest, WriteStreamFrameToEmptyPacket) {
auto regularPacket = std::move(builtOut.first); auto regularPacket = std::move(builtOut.first);
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId); EXPECT_EQ(resultFrame.streamId, streamId);
EXPECT_EQ(resultFrame.offset, offset); EXPECT_EQ(resultFrame.offset, offset);
EXPECT_EQ(resultFrame.len, 10); EXPECT_EQ(resultFrame.len, 10);
@@ -174,7 +174,7 @@ TEST_F(QuicWriteCodecTest, WriteStreamFrameToPartialPacket) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = std::move(builtOut.first); auto regularPacket = std::move(builtOut.first);
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId); EXPECT_EQ(resultFrame.streamId, streamId);
EXPECT_EQ(resultFrame.offset, offset); EXPECT_EQ(resultFrame.offset, offset);
EXPECT_EQ(resultFrame.len, 20); EXPECT_EQ(resultFrame.len, 20);
@@ -241,14 +241,14 @@ TEST_F(QuicWriteCodecTest, WriteTwoStreamFrames) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = std::move(builtOut.first); auto regularPacket = std::move(builtOut.first);
EXPECT_EQ(regularPacket.frames.size(), 2); EXPECT_EQ(regularPacket.frames.size(), 2);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.front()); auto& resultFrame = *regularPacket.frames.front().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId1); EXPECT_EQ(resultFrame.streamId, streamId1);
EXPECT_EQ(resultFrame.offset, offset1); EXPECT_EQ(resultFrame.offset, offset1);
EXPECT_EQ(resultFrame.len, 30); EXPECT_EQ(resultFrame.len, 30);
outputBuf->trimStart(8); outputBuf->trimStart(8);
EXPECT_TRUE(folly::IOBufEqualTo()(inputBuf, outputBuf)); EXPECT_TRUE(folly::IOBufEqualTo()(inputBuf, outputBuf));
auto resultFrame2 = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame2 = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame2.streamId, streamId2); EXPECT_EQ(resultFrame2.streamId, streamId2);
EXPECT_EQ(resultFrame2.offset, offset2); EXPECT_EQ(resultFrame2.offset, offset2);
EXPECT_EQ(resultFrame2.len, remainingSpace - 7); EXPECT_EQ(resultFrame2.len, remainingSpace - 7);
@@ -307,7 +307,7 @@ TEST_F(QuicWriteCodecTest, WriteStreamFramePartialData) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId); EXPECT_EQ(resultFrame.streamId, streamId);
EXPECT_EQ(resultFrame.offset, offset); EXPECT_EQ(resultFrame.offset, offset);
EXPECT_EQ(resultFrame.len, 33); EXPECT_EQ(resultFrame.len, 33);
@@ -385,7 +385,7 @@ TEST_F(QuicWriteCodecTest, WriteStreamSpaceForOneByte) {
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId); EXPECT_EQ(resultFrame.streamId, streamId);
EXPECT_EQ(resultFrame.offset, offset); EXPECT_EQ(resultFrame.offset, offset);
EXPECT_EQ(resultFrame.len, 1); EXPECT_EQ(resultFrame.len, 1);
@@ -430,7 +430,7 @@ TEST_F(QuicWriteCodecTest, WriteFinToEmptyPacket) {
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
auto resultFrame = boost::get<WriteStreamFrame>(regularPacket.frames.back()); auto& resultFrame = *regularPacket.frames.back().asWriteStreamFrame();
EXPECT_EQ(resultFrame.streamId, streamId); EXPECT_EQ(resultFrame.streamId, streamId);
EXPECT_EQ(resultFrame.offset, offset); EXPECT_EQ(resultFrame.offset, offset);
EXPECT_EQ(inputBuf->computeChainDataLength(), resultFrame.len); EXPECT_EQ(inputBuf->computeChainDataLength(), resultFrame.len);
@@ -592,8 +592,7 @@ TEST_F(QuicWriteCodecTest, AckFrameVeryLargeAckRange) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 1); EXPECT_EQ(ackFrame.ackBlocks.size(), 1);
EXPECT_EQ(ackFrame.ackBlocks.front().start, 1); EXPECT_EQ(ackFrame.ackBlocks.front().start, 1);
@@ -640,8 +639,7 @@ TEST_F(QuicWriteCodecTest, WriteSimpleAckFrame) {
EXPECT_EQ(kDefaultUDPSendPacketLen - 11, pktBuilder.remainingSpaceInPkt()); EXPECT_EQ(kDefaultUDPSendPacketLen - 11, pktBuilder.remainingSpaceInPkt());
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 2); EXPECT_EQ(ackFrame.ackBlocks.size(), 2);
auto iter = ackFrame.ackBlocks.cbegin(); auto iter = ackFrame.ackBlocks.cbegin();
EXPECT_EQ(iter->start, 101); EXPECT_EQ(iter->start, 101);
@@ -675,8 +673,7 @@ TEST_F(QuicWriteCodecTest, WriteAckFrameWillSaveAckDelay) {
writeAckFrame(meta, pktBuilder); writeAckFrame(meta, pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackDelay, ackFrame.ackDelay); EXPECT_EQ(ackDelay, ackFrame.ackDelay);
} }
@@ -714,8 +711,7 @@ TEST_F(QuicWriteCodecTest, VerifyNumAckBlocksSizeAccounted) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 64); EXPECT_EQ(ackFrame.ackBlocks.size(), 64);
EXPECT_EQ(ackFrame.ackBlocks.front().start, 746); EXPECT_EQ(ackFrame.ackBlocks.front().start, 746);
@@ -787,8 +783,7 @@ TEST_F(QuicWriteCodecTest, OnlyAckLargestPacket) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 1); EXPECT_EQ(ackFrame.ackBlocks.size(), 1);
EXPECT_EQ(ackFrame.ackBlocks.front().start, 1000); EXPECT_EQ(ackFrame.ackBlocks.front().start, 1000);
EXPECT_EQ(ackFrame.ackBlocks.front().end, 1000); EXPECT_EQ(ackFrame.ackBlocks.front().end, 1000);
@@ -838,8 +833,7 @@ TEST_F(QuicWriteCodecTest, WriteSomeAckBlocks) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(regularPacket.frames.size(), 1); EXPECT_EQ(regularPacket.frames.size(), 1);
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *regularPacket.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(regularPacket.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 14); EXPECT_EQ(ackFrame.ackBlocks.size(), 14);
// Verify the on wire bytes via decoder: // Verify the on wire bytes via decoder:
@@ -886,8 +880,7 @@ TEST_F(QuicWriteCodecTest, OnlyHasSpaceForFirstAckBlock) {
EXPECT_EQ(ackFrameWriteResult.bytesWritten, 7); EXPECT_EQ(ackFrameWriteResult.bytesWritten, 7);
EXPECT_EQ(pktBuilder.remainingSpaceInPkt(), 3); EXPECT_EQ(pktBuilder.remainingSpaceInPkt(), 3);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
WriteAckFrame ackFrame = WriteAckFrame& ackFrame = *builtOut.first.frames.back().asWriteAckFrame();
boost::get<WriteAckFrame>(builtOut.first.frames.back());
EXPECT_EQ(ackFrame.ackBlocks.size(), 1); EXPECT_EQ(ackFrame.ackBlocks.size(), 1);
EXPECT_EQ(ackFrame.ackBlocks.front().start, 1000); EXPECT_EQ(ackFrame.ackBlocks.front().start, 1000);
EXPECT_EQ(ackFrame.ackBlocks.front().end, 1000); EXPECT_EQ(ackFrame.ackBlocks.front().end, 1000);
@@ -917,7 +910,7 @@ TEST_F(QuicWriteCodecTest, WriteMaxStreamData) {
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 3); EXPECT_EQ(bytesWritten, 3);
auto& resultMaxStreamDataFrame = auto& resultMaxStreamDataFrame =
boost::get<MaxStreamDataFrame>(regularPacket.frames[0]); *regularPacket.frames[0].asMaxStreamDataFrame();
EXPECT_EQ(id, resultMaxStreamDataFrame.streamId); EXPECT_EQ(id, resultMaxStreamDataFrame.streamId);
EXPECT_EQ(offset, resultMaxStreamDataFrame.maximumData); EXPECT_EQ(offset, resultMaxStreamDataFrame.maximumData);
@@ -949,7 +942,7 @@ TEST_F(QuicWriteCodecTest, WriteMaxData) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 3); EXPECT_EQ(bytesWritten, 3);
auto& resultMaxDataFrame = boost::get<MaxDataFrame>(regularPacket.frames[0]); auto& resultMaxDataFrame = *regularPacket.frames[0].asMaxDataFrame();
EXPECT_EQ(1000, resultMaxDataFrame.maximumData); EXPECT_EQ(1000, resultMaxDataFrame.maximumData);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
@@ -975,7 +968,8 @@ TEST_F(QuicWriteCodecTest, WriteMaxStreamId) {
uint64_t maxStream = i; uint64_t maxStream = i;
bool isBidirectional = true; bool isBidirectional = true;
MaxStreamsFrame maxStreamsFrame(maxStream, isBidirectional); MaxStreamsFrame maxStreamsFrame(maxStream, isBidirectional);
auto bytesWritten = writeFrame(maxStreamsFrame, pktBuilder); auto bytesWritten =
writeFrame(QuicSimpleFrame(maxStreamsFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
@@ -983,7 +977,7 @@ TEST_F(QuicWriteCodecTest, WriteMaxStreamId) {
// 1 byte for the type and up to 2 bytes for the stream count. // 1 byte for the type and up to 2 bytes for the stream count.
EXPECT_EQ(1 + streamCountSize, bytesWritten); EXPECT_EQ(1 + streamCountSize, bytesWritten);
auto& resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>( auto& resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams); EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
@@ -1003,7 +997,8 @@ TEST_F(QuicWriteCodecTest, WriteUniMaxStreamId) {
uint64_t maxStream = i; uint64_t maxStream = i;
bool isBidirectional = false; bool isBidirectional = false;
MaxStreamsFrame maxStreamsFrame(maxStream, isBidirectional); MaxStreamsFrame maxStreamsFrame(maxStream, isBidirectional);
auto bytesWritten = writeFrame(maxStreamsFrame, pktBuilder); auto bytesWritten =
writeFrame(QuicSimpleFrame(maxStreamsFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
@@ -1011,7 +1006,7 @@ TEST_F(QuicWriteCodecTest, WriteUniMaxStreamId) {
// 1 byte for the type and up to 2 bytes for the stream count. // 1 byte for the type and up to 2 bytes for the stream count.
EXPECT_EQ(1 + streamCountSize, bytesWritten); EXPECT_EQ(1 + streamCountSize, bytesWritten);
auto& resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>( auto& resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams); EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
@@ -1030,7 +1025,7 @@ TEST_F(QuicWriteCodecTest, NoSpaceForMaxStreamId) {
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
StreamId maxStream = 0x1234; StreamId maxStream = 0x1234;
MaxStreamsFrame maxStreamIdFrame(maxStream, true); MaxStreamsFrame maxStreamIdFrame(maxStream, true);
EXPECT_EQ(0, writeFrame(maxStreamIdFrame, pktBuilder)); EXPECT_EQ(0, writeFrame(QuicSimpleFrame(maxStreamIdFrame), pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WriteConnClose) { TEST_F(QuicWriteCodecTest, WriteConnClose) {
@@ -1039,14 +1034,15 @@ TEST_F(QuicWriteCodecTest, WriteConnClose) {
std::string reasonPhrase("You are fired"); std::string reasonPhrase("You are fired");
ConnectionCloseFrame connectionCloseFrame( ConnectionCloseFrame connectionCloseFrame(
TransportErrorCode::PROTOCOL_VIOLATION, reasonPhrase); TransportErrorCode::PROTOCOL_VIOLATION, reasonPhrase);
auto connCloseBytesWritten = writeFrame(connectionCloseFrame, pktBuilder); auto connCloseBytesWritten =
writeFrame(std::move(connectionCloseFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
// 6 == ErrorCode(2) + FrameType(1) + reasonPhrase-len(2) // 6 == ErrorCode(2) + FrameType(1) + reasonPhrase-len(2)
EXPECT_EQ(4 + reasonPhrase.size(), connCloseBytesWritten); EXPECT_EQ(4 + reasonPhrase.size(), connCloseBytesWritten);
auto& resultConnCloseFrame = auto& resultConnCloseFrame =
boost::get<ConnectionCloseFrame>(regularPacket.frames[0]); *regularPacket.frames[0].asConnectionCloseFrame();
EXPECT_EQ( EXPECT_EQ(
TransportErrorCode::PROTOCOL_VIOLATION, resultConnCloseFrame.errorCode); TransportErrorCode::PROTOCOL_VIOLATION, resultConnCloseFrame.errorCode);
EXPECT_EQ("You are fired", resultConnCloseFrame.reasonPhrase); EXPECT_EQ("You are fired", resultConnCloseFrame.reasonPhrase);
@@ -1074,7 +1070,7 @@ TEST_F(QuicWriteCodecTest, DecodeConnCloseLarge) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
auto& resultConnCloseFrame = auto& resultConnCloseFrame =
boost::get<ConnectionCloseFrame>(regularPacket.frames[0]); *regularPacket.frames[0].asConnectionCloseFrame();
EXPECT_EQ( EXPECT_EQ(
TransportErrorCode::PROTOCOL_VIOLATION, resultConnCloseFrame.errorCode); TransportErrorCode::PROTOCOL_VIOLATION, resultConnCloseFrame.errorCode);
EXPECT_EQ(resultConnCloseFrame.reasonPhrase, reasonPhrase); EXPECT_EQ(resultConnCloseFrame.reasonPhrase, reasonPhrase);
@@ -1091,7 +1087,7 @@ TEST_F(QuicWriteCodecTest, NoSpaceConnClose) {
std::string reasonPhrase("You are all fired"); std::string reasonPhrase("You are all fired");
ConnectionCloseFrame connCloseFrame( ConnectionCloseFrame connCloseFrame(
TransportErrorCode::PROTOCOL_VIOLATION, reasonPhrase); TransportErrorCode::PROTOCOL_VIOLATION, reasonPhrase);
EXPECT_EQ(0, writeFrame(connCloseFrame, pktBuilder)); EXPECT_EQ(0, writeFrame(std::move(connCloseFrame), pktBuilder));
} }
TEST_F(QuicWriteCodecTest, DecodeAppCloseLarge) { TEST_F(QuicWriteCodecTest, DecodeAppCloseLarge) {
@@ -1101,12 +1097,12 @@ TEST_F(QuicWriteCodecTest, DecodeAppCloseLarge) {
reasonPhrase.resize(kMaxReasonPhraseLength + 10); reasonPhrase.resize(kMaxReasonPhraseLength + 10);
ApplicationCloseFrame applicationCloseFrame( ApplicationCloseFrame applicationCloseFrame(
GenericApplicationErrorCode::UNKNOWN, reasonPhrase); GenericApplicationErrorCode::UNKNOWN, reasonPhrase);
writeFrame(applicationCloseFrame, pktBuilder); writeFrame(std::move(applicationCloseFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
auto& resultAppCloseFrame = auto& resultAppCloseFrame =
boost::get<ApplicationCloseFrame>(regularPacket.frames[0]); *regularPacket.frames[0].asApplicationCloseFrame();
EXPECT_EQ( EXPECT_EQ(
GenericApplicationErrorCode::UNKNOWN, resultAppCloseFrame.errorCode); GenericApplicationErrorCode::UNKNOWN, resultAppCloseFrame.errorCode);
EXPECT_EQ(resultAppCloseFrame.reasonPhrase, reasonPhrase); EXPECT_EQ(resultAppCloseFrame.reasonPhrase, reasonPhrase);
@@ -1119,13 +1115,12 @@ TEST_F(QuicWriteCodecTest, DecodeAppCloseLarge) {
TEST_F(QuicWriteCodecTest, WritePing) { TEST_F(QuicWriteCodecTest, WritePing) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
PingFrame pingFrame; auto pingBytesWritten = writeFrame(PingFrame(), pktBuilder);
auto pingBytesWritten = writeFrame(pingFrame, pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(1, pingBytesWritten); EXPECT_EQ(1, pingBytesWritten);
EXPECT_NO_THROW(boost::get<PingFrame>(regularPacket.frames[0])); EXPECT_NE(regularPacket.frames[0].asPingFrame(), nullptr);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
@@ -1140,20 +1135,18 @@ TEST_F(QuicWriteCodecTest, NoSpaceForPing) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
pktBuilder.remaining_ = 0; pktBuilder.remaining_ = 0;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
PingFrame pingFrame; EXPECT_EQ(0, writeFrame(PingFrame(), pktBuilder));
EXPECT_EQ(0, writeFrame(pingFrame, pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WritePadding) { TEST_F(QuicWriteCodecTest, WritePadding) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
PaddingFrame paddingFrame; auto paddingBytesWritten = writeFrame(PaddingFrame(), pktBuilder);
auto paddingBytesWritten = writeFrame(paddingFrame, pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(1, paddingBytesWritten); EXPECT_EQ(1, paddingBytesWritten);
EXPECT_NO_THROW(boost::get<PaddingFrame>(regularPacket.frames[0])); EXPECT_NE(regularPacket.frames[0].asPaddingFrame(), nullptr);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
@@ -1183,7 +1176,7 @@ TEST_F(QuicWriteCodecTest, WriteStreamBlocked) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(blockedBytesWritten, 7); EXPECT_EQ(blockedBytesWritten, 7);
EXPECT_NO_THROW(boost::get<StreamDataBlockedFrame>(regularPacket.frames[0])); EXPECT_NE(regularPacket.frames[0].asStreamDataBlockedFrame(), nullptr);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
@@ -1217,8 +1210,7 @@ TEST_F(QuicWriteCodecTest, WriteRstStream) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(13, rstStreamBytesWritten); EXPECT_EQ(13, rstStreamBytesWritten);
auto& resultRstStreamFrame = auto& resultRstStreamFrame = *regularPacket.frames[0].asRstStreamFrame();
boost::get<RstStreamFrame>(regularPacket.frames[0]);
EXPECT_EQ(errorCode, resultRstStreamFrame.errorCode); EXPECT_EQ(errorCode, resultRstStreamFrame.errorCode);
EXPECT_EQ(id, resultRstStreamFrame.streamId); EXPECT_EQ(id, resultRstStreamFrame.streamId);
EXPECT_EQ(offset, resultRstStreamFrame.offset); EXPECT_EQ(offset, resultRstStreamFrame.offset);
@@ -1255,7 +1247,7 @@ TEST_F(QuicWriteCodecTest, WriteBlockedFrame) {
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 5); EXPECT_EQ(bytesWritten, 5);
EXPECT_NO_THROW(boost::get<DataBlockedFrame>(regularPacket.frames[0])); EXPECT_NE(regularPacket.frames[0].asDataBlockedFrame(), nullptr);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
@@ -1279,13 +1271,13 @@ TEST_F(QuicWriteCodecTest, WriteStreamIdNeeded) {
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
StreamId blockedStreamId = 0x211; StreamId blockedStreamId = 0x211;
MaxStreamsFrame streamIdNeeded(blockedStreamId, true); MaxStreamsFrame streamIdNeeded(blockedStreamId, true);
auto bytesWritten = writeFrame(streamIdNeeded, pktBuilder); auto bytesWritten = writeFrame(QuicSimpleFrame(streamIdNeeded), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 3); EXPECT_EQ(bytesWritten, 3);
EXPECT_NO_THROW(boost::get<MaxStreamsFrame>( EXPECT_NO_THROW(boost::get<MaxStreamsFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0]))); *regularPacket.frames[0].asQuicSimpleFrame()));
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
@@ -1302,7 +1294,7 @@ TEST_F(QuicWriteCodecTest, NoSpaceForStreamIdNeeded) {
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
StreamId blockedStreamId = 0x211; StreamId blockedStreamId = 0x211;
MaxStreamsFrame streamIdNeeded(blockedStreamId, true); MaxStreamsFrame streamIdNeeded(blockedStreamId, true);
EXPECT_EQ(0, writeFrame(streamIdNeeded, pktBuilder)); EXPECT_EQ(0, writeFrame(QuicSimpleFrame(streamIdNeeded), pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WriteNewConnId) { TEST_F(QuicWriteCodecTest, WriteNewConnId) {
@@ -1311,13 +1303,13 @@ TEST_F(QuicWriteCodecTest, WriteNewConnId) {
StatelessResetToken token; StatelessResetToken token;
memset(token.data(), 'a', token.size()); memset(token.data(), 'a', token.size());
NewConnectionIdFrame newConnId(1, 0, getTestConnectionId(), token); NewConnectionIdFrame newConnId(1, 0, getTestConnectionId(), token);
auto bytesWritten = writeFrame(newConnId, pktBuilder); auto bytesWritten = writeFrame(QuicSimpleFrame(newConnId), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 28); EXPECT_EQ(bytesWritten, 28);
auto& resultNewConnIdFrame = boost::get<NewConnectionIdFrame>( auto& resultNewConnIdFrame = boost::get<NewConnectionIdFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(resultNewConnIdFrame.sequenceNumber, 1); EXPECT_EQ(resultNewConnIdFrame.sequenceNumber, 1);
EXPECT_EQ(resultNewConnIdFrame.retirePriorTo, 0); EXPECT_EQ(resultNewConnIdFrame.retirePriorTo, 0);
EXPECT_EQ(resultNewConnIdFrame.connectionId, getTestConnectionId()); EXPECT_EQ(resultNewConnIdFrame.connectionId, getTestConnectionId());
@@ -1338,13 +1330,13 @@ TEST_F(QuicWriteCodecTest, WriteRetireConnId) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
RetireConnectionIdFrame retireConnId(3); RetireConnectionIdFrame retireConnId(3);
auto bytesWritten = writeFrame(retireConnId, pktBuilder); auto bytesWritten = writeFrame(QuicSimpleFrame(retireConnId), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 2); EXPECT_EQ(bytesWritten, 2);
auto resultRetireConnIdFrame = boost::get<RetireConnectionIdFrame>( auto resultRetireConnIdFrame = boost::get<RetireConnectionIdFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(resultRetireConnIdFrame.sequenceNumber, 3); EXPECT_EQ(resultRetireConnIdFrame.sequenceNumber, 3);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
@@ -1385,7 +1377,7 @@ TEST_F(QuicWriteCodecTest, NoSpaceForNewConnId) {
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
NewConnectionIdFrame newConnId( NewConnectionIdFrame newConnId(
1, 0, getTestConnectionId(), StatelessResetToken()); 1, 0, getTestConnectionId(), StatelessResetToken());
EXPECT_EQ(0, writeFrame(newConnId, pktBuilder)); EXPECT_EQ(0, writeFrame(QuicSimpleFrame(newConnId), pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WriteExpiredStreamDataFrame) { TEST_F(QuicWriteCodecTest, WriteExpiredStreamDataFrame) {
@@ -1394,13 +1386,14 @@ TEST_F(QuicWriteCodecTest, WriteExpiredStreamDataFrame) {
StreamId id = 10; StreamId id = 10;
uint64_t offset = 0x08; uint64_t offset = 0x08;
ExpiredStreamDataFrame expiredStreamDataFrame(id, offset); ExpiredStreamDataFrame expiredStreamDataFrame(id, offset);
auto bytesWritten = writeFrame(expiredStreamDataFrame, pktBuilder); auto bytesWritten =
writeFrame(QuicSimpleFrame(expiredStreamDataFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 4); EXPECT_EQ(bytesWritten, 4);
auto result = boost::get<ExpiredStreamDataFrame>( auto result = boost::get<ExpiredStreamDataFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(id, result.streamId); EXPECT_EQ(id, result.streamId);
EXPECT_EQ(offset, result.minimumStreamOffset); EXPECT_EQ(offset, result.minimumStreamOffset);
@@ -1424,13 +1417,14 @@ TEST_F(QuicWriteCodecTest, WriteMinStreamDataFrame) {
uint64_t maximumData = 0x64; uint64_t maximumData = 0x64;
uint64_t offset = 0x08; uint64_t offset = 0x08;
MinStreamDataFrame minStreamDataFrame(id, maximumData, offset); MinStreamDataFrame minStreamDataFrame(id, maximumData, offset);
auto bytesWritten = writeFrame(minStreamDataFrame, pktBuilder); auto bytesWritten =
writeFrame(QuicSimpleFrame(minStreamDataFrame), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(bytesWritten, 6); EXPECT_EQ(bytesWritten, 6);
auto result = boost::get<MinStreamDataFrame>( auto result = boost::get<MinStreamDataFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(id, result.streamId); EXPECT_EQ(id, result.streamId);
EXPECT_EQ(maximumData, result.maximumData); EXPECT_EQ(maximumData, result.maximumData);
EXPECT_EQ(offset, result.minimumStreamOffset); EXPECT_EQ(offset, result.minimumStreamOffset);
@@ -1461,7 +1455,7 @@ TEST_F(QuicWriteCodecTest, WritePathChallenge) {
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
auto result = boost::get<PathChallengeFrame>( auto result = boost::get<PathChallengeFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(result.pathData, pathData); EXPECT_EQ(result.pathData, pathData);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
@@ -1486,7 +1480,7 @@ TEST_F(QuicWriteCodecTest, WritePathResponse) {
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
auto result = boost::get<PathResponseFrame>( auto result = boost::get<PathResponseFrame>(
boost::get<QuicSimpleFrame>(regularPacket.frames[0])); *regularPacket.frames[0].asQuicSimpleFrame());
EXPECT_EQ(result.pathData, pathData); EXPECT_EQ(result.pathData, pathData);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);

View File

@@ -30,9 +30,14 @@ namespace quic {
return nullptr; \ return nullptr; \
} }
#define UNION_CTORS(X, NAME) \ #define UNION_CTORS(X, NAME) \
NAME(X&& x) : type_(Type::X##_E) { \ NAME(X&& x) : type_(Type::X##_E) { \
new (&X##_) X(std::move(x)); \ new (&X##_) X(std::move(x)); \
}
#define UNION_COPY_CTORS(X, NAME) \
NAME(const X& x) : type_(Type::X##_E) { \
new (&X##_) X(x); \
} }
#define UNION_MOVE_CASES(X, other) \ #define UNION_MOVE_CASES(X, other) \
@@ -56,6 +61,8 @@ namespace quic {
\ \
X(UNION_CTORS, NAME) \ X(UNION_CTORS, NAME) \
\ \
X(UNION_COPY_CTORS, NAME) \
\
NAME(NAME&& other) { \ NAME(NAME&& other) { \
switch (other.type_) { X(UNION_MOVE_CASES, other) } \ switch (other.type_) { X(UNION_MOVE_CASES, other) } \
type_ = other.type_; \ type_ = other.type_; \

View File

@@ -70,8 +70,12 @@ PacketNum rstStreamAndSendPacket(
conn.transportSettings.writeConnectionDataPacketsLimit); conn.transportSettings.writeConnectionDataPacketsLimit);
for (const auto& packet : conn.outstandingPackets) { for (const auto& packet : conn.outstandingPackets) {
for (const auto& frame : all_frames<RstStreamFrame>(packet.packet.frames)) { for (const auto& frame : packet.packet.frames) {
if (frame.streamId == stream.id) { auto rstFrame = frame.asRstStreamFrame();
if (!rstFrame) {
continue;
}
if (rstFrame->streamId == stream.id) {
return packet.packet.header.getPacketSequenceNum(); return packet.packet.header.getPacketSequenceNum();
} }
} }

View File

@@ -276,14 +276,13 @@ auto findFrameInPacketFunc() {
return [&](auto& p) { return [&](auto& p) {
return std::find_if( return std::find_if(
p.packet.frames.begin(), p.packet.frames.end(), [&](auto& f) { p.packet.frames.begin(), p.packet.frames.end(), [&](auto& f) {
QuicSimpleFrame* simpleFrame = f.asQuicSimpleFrame();
if (!simpleFrame) {
return false;
}
return folly::variant_match( return folly::variant_match(
f, *simpleFrame,
[&](QuicSimpleFrame& s) { [&](FrameType&) { return true; },
return folly::variant_match(
s,
[&](FrameType&) { return true; },
[&](auto&) { return false; });
},
[&](auto&) { return false; }); [&](auto&) { return false; });
}) != p.packet.frames.end(); }) != p.packet.frames.end();
}; };

View File

@@ -195,62 +195,88 @@ std::unique_ptr<QLogPacketEvent> QLogger::createPacketEvent(
uint64_t numPaddingFrames = 0; uint64_t numPaddingFrames = 0;
// looping through the packet to store logs created from frames in the packet // looping through the packet to store logs created from frames in the packet
for (const auto& quicFrame : writePacket.frames) { for (const auto& quicFrame : writePacket.frames) {
folly::variant_match( switch (quicFrame.type()) {
quicFrame, case QuicWriteFrame::Type::PaddingFrame_E:
[&](const PaddingFrame& /* unused */) { ++numPaddingFrames; }, ++numPaddingFrames;
[&](const RstStreamFrame& frame) { break;
event->frames.push_back(std::make_unique<RstStreamFrameLog>( case QuicWriteFrame::Type::RstStreamFrame_E: {
frame.streamId, frame.errorCode, frame.offset)); const RstStreamFrame& frame = *quicFrame.asRstStreamFrame();
}, event->frames.push_back(std::make_unique<RstStreamFrameLog>(
[&](const ConnectionCloseFrame& frame) { frame.streamId, frame.errorCode, frame.offset));
event->frames.push_back(std::make_unique<ConnectionCloseFrameLog>( break;
frame.errorCode, frame.reasonPhrase, frame.closingFrameType)); }
}, case QuicWriteFrame::Type::ConnectionCloseFrame_E: {
[&](const ApplicationCloseFrame& frame) { const ConnectionCloseFrame& frame = *quicFrame.asConnectionCloseFrame();
event->frames.push_back(std::make_unique<ApplicationCloseFrameLog>( event->frames.push_back(std::make_unique<ConnectionCloseFrameLog>(
frame.errorCode, frame.reasonPhrase)); frame.errorCode, frame.reasonPhrase, frame.closingFrameType));
}, break;
[&](const MaxDataFrame& frame) { }
event->frames.push_back( case QuicWriteFrame::Type::ApplicationCloseFrame_E: {
std::make_unique<MaxDataFrameLog>(frame.maximumData)); const ApplicationCloseFrame& frame =
}, *quicFrame.asApplicationCloseFrame();
[&](const MaxStreamDataFrame& frame) { event->frames.push_back(std::make_unique<ApplicationCloseFrameLog>(
event->frames.push_back(std::make_unique<MaxStreamDataFrameLog>( frame.errorCode, frame.reasonPhrase));
frame.streamId, frame.maximumData)); break;
}, }
[&](const StreamsBlockedFrame& frame) { case QuicWriteFrame::Type::MaxDataFrame_E: {
event->frames.push_back(std::make_unique<StreamsBlockedFrameLog>( const MaxDataFrame& frame = *quicFrame.asMaxDataFrame();
frame.streamLimit, frame.isForBidirectional)); event->frames.push_back(
}, std::make_unique<MaxDataFrameLog>(frame.maximumData));
[&](const PingFrame& /* unused */) { break;
event->frames.push_back(std::make_unique<PingFrameLog>()); }
}, case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
[&](const DataBlockedFrame& frame) { const MaxStreamDataFrame& frame = *quicFrame.asMaxStreamDataFrame();
event->frames.push_back( event->frames.push_back(std::make_unique<MaxStreamDataFrameLog>(
std::make_unique<DataBlockedFrameLog>(frame.dataLimit)); frame.streamId, frame.maximumData));
}, break;
[&](const StreamDataBlockedFrame& frame) { }
event->frames.push_back(std::make_unique<StreamDataBlockedFrameLog>( case QuicWriteFrame::Type::StreamsBlockedFrame_E: {
frame.streamId, frame.dataLimit)); const StreamsBlockedFrame& frame = *quicFrame.asStreamsBlockedFrame();
}, event->frames.push_back(std::make_unique<StreamsBlockedFrameLog>(
[&](const WriteAckFrame& frame) { frame.streamLimit, frame.isForBidirectional));
event->frames.push_back(std::make_unique<WriteAckFrameLog>( break;
frame.ackBlocks, frame.ackDelay)); }
}, case QuicWriteFrame::Type::PingFrame_E:
[&](const WriteStreamFrame& frame) { event->frames.push_back(std::make_unique<PingFrameLog>());
event->frames.push_back(std::make_unique<StreamFrameLog>( break;
frame.streamId, frame.offset, frame.len, frame.fin)); case QuicWriteFrame::Type::DataBlockedFrame_E: {
}, const DataBlockedFrame& frame = *quicFrame.asDataBlockedFrame();
[&](const WriteCryptoFrame& frame) { event->frames.push_back(
event->frames.push_back( std::make_unique<DataBlockedFrameLog>(frame.dataLimit));
std::make_unique<CryptoFrameLog>(frame.offset, frame.len)); break;
}, }
[&](const QuicSimpleFrame& simpleFrame) { case QuicWriteFrame::Type::StreamDataBlockedFrame_E: {
addQuicSimpleFrameToEvent(event.get(), simpleFrame); const StreamDataBlockedFrame& frame = *quicFrame.asStreamDataBlockedFrame();
}, event->frames.push_back(std::make_unique<StreamDataBlockedFrameLog>(
[&](const auto& /* unused */) { frame.streamId, frame.dataLimit));
// Ignore other frames. break;
}); }
case QuicWriteFrame::Type::WriteAckFrame_E: {
const WriteAckFrame& frame = *quicFrame.asWriteAckFrame();
event->frames.push_back(std::make_unique<WriteAckFrameLog>(
frame.ackBlocks, frame.ackDelay));
break;
}
case QuicWriteFrame::Type::WriteStreamFrame_E: {
const WriteStreamFrame& frame = *quicFrame.asWriteStreamFrame();
event->frames.push_back(std::make_unique<StreamFrameLog>(
frame.streamId, frame.offset, frame.len, frame.fin));
break;
}
case QuicWriteFrame::Type::WriteCryptoFrame_E: {
const WriteCryptoFrame& frame = *quicFrame.asWriteCryptoFrame();
event->frames.push_back(
std::make_unique<CryptoFrameLog>(frame.offset, frame.len));
break;
}
case QuicWriteFrame::Type::QuicSimpleFrame_E: {
const QuicSimpleFrame& simpleFrame = *quicFrame.asQuicSimpleFrame();
addQuicSimpleFrameToEvent(event.get(), simpleFrame);
break;
}
default:
break;
}
} }
if (numPaddingFrames > 0) { if (numPaddingFrames > 0) {
event->frames.push_back( event->frames.push_back(

View File

@@ -57,138 +57,149 @@ void markPacketLoss(
bool processed, bool processed,
PacketNum currentPacketNum) { PacketNum currentPacketNum) {
for (auto& packetFrame : packet.frames) { for (auto& packetFrame : packet.frames) {
folly::variant_match( switch (packetFrame.type()) {
packetFrame, case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
[&](MaxStreamDataFrame& frame) { MaxStreamDataFrame& frame = *packetFrame.asMaxStreamDataFrame();
// For all other frames, we process it if it's not from a clone // For all other frames, we process it if it's not from a clone
// packet, or if the clone and its siblings have never been processed. // packet, or if the clone and its siblings have never been processed.
// But for both MaxData and MaxStreamData, clone and its siblings may // But for both MaxData and MaxStreamData, clone and its siblings may
// have different values. So we process it if it matches the // have different values. So we process it if it matches the
// latestMaxDataPacket or latestMaxStreamDataPacket. If an older // latestMaxDataPacket or latestMaxStreamDataPacket. If an older
// packet also has such frames, it's ok to skip process of such loss // packet also has such frames, it's ok to skip process of such loss
// since newer value is already sent in later packets. // since newer value is already sent in later packets.
auto stream = conn.streamManager->getStream(frame.streamId); auto stream = conn.streamManager->getStream(frame.streamId);
if (!stream) { if (!stream) {
return; break;
} }
// TODO: check for the stream is in Open or HalfClosedLocal state, the // TODO: check for the stream is in Open or HalfClosedLocal state, the
// peer doesn't need a flow control update in these cases. // peer doesn't need a flow control update in these cases.
if (stream->latestMaxStreamDataPacket == currentPacketNum) { if (stream->latestMaxStreamDataPacket == currentPacketNum) {
onStreamWindowUpdateLost(*stream); onStreamWindowUpdateLost(*stream);
} }
}, break;
[&](MaxDataFrame&) { }
if (conn.latestMaxDataPacket == currentPacketNum) { case QuicWriteFrame::Type::MaxDataFrame_E: {
onConnWindowUpdateLost(conn); if (conn.latestMaxDataPacket == currentPacketNum) {
} onConnWindowUpdateLost(conn);
}, }
// For other frame types, we only process them if the packet is not a break;
// processed clone. }
[&](WriteStreamFrame& frame) { // For other frame types, we only process them if the packet is not a
if (processed) { // processed clone.
return; case QuicWriteFrame::Type::WriteStreamFrame_E: {
} WriteStreamFrame frame = *packetFrame.asWriteStreamFrame();
auto stream = conn.streamManager->getStream(frame.streamId); if (processed) {
if (!stream) { break;
return; }
} auto stream = conn.streamManager->getStream(frame.streamId);
auto bufferItr = std::lower_bound( if (!stream) {
stream->retransmissionBuffer.begin(), break;
stream->retransmissionBuffer.end(), }
frame.offset, auto bufferItr = std::lower_bound(
[](const auto& buffer, const auto& offset) { stream->retransmissionBuffer.begin(),
return buffer.offset < offset; stream->retransmissionBuffer.end(),
}); frame.offset,
if (bufferItr == stream->retransmissionBuffer.end()) { [](const auto& buffer, const auto& offset) {
// It's possible that the stream was reset or data on the stream was return buffer.offset < offset;
// skipped while we discovered that its packet was lost so we might });
// not have the offset. if (bufferItr == stream->retransmissionBuffer.end()) {
return; // It's possible that the stream was reset or data on the stream was
} // skipped while we discovered that its packet was lost so we might
// The original rxmt offset might have been bumped up after it was // not have the offset.
// shrunk due to egress partially reliable skip. break;
if (!ackFrameMatchesRetransmitBuffer(*stream, frame, *bufferItr)) { }
return; // The original rxmt offset might have been bumped up after it was
} // shrunk due to egress partially reliable skip.
stream->lossBuffer.insert( if (!ackFrameMatchesRetransmitBuffer(*stream, frame, *bufferItr)) {
std::upper_bound( break;
stream->lossBuffer.begin(), }
stream->lossBuffer.end(), stream->lossBuffer.insert(
bufferItr->offset, std::upper_bound(
[](const auto& offset, const auto& buffer) { stream->lossBuffer.begin(),
return offset < buffer.offset; stream->lossBuffer.end(),
}), bufferItr->offset,
std::move(*bufferItr)); [](const auto& offset, const auto& buffer) {
stream->retransmissionBuffer.erase(bufferItr); return offset < buffer.offset;
conn.streamManager->updateLossStreams(*stream); }),
}, std::move(*bufferItr));
[&](WriteCryptoFrame& frame) { stream->retransmissionBuffer.erase(bufferItr);
if (processed) { conn.streamManager->updateLossStreams(*stream);
return; break;
} }
auto protectionType = packet.header.getProtectionType(); case QuicWriteFrame::Type::WriteCryptoFrame_E: {
auto encryptionLevel = WriteCryptoFrame& frame = *packetFrame.asWriteCryptoFrame();
protectionTypeToEncryptionLevel(protectionType); if (processed) {
auto cryptoStream = break;
getCryptoStream(*conn.cryptoState, encryptionLevel); }
auto protectionType = packet.header.getProtectionType();
auto encryptionLevel = protectionTypeToEncryptionLevel(protectionType);
auto cryptoStream = getCryptoStream(*conn.cryptoState, encryptionLevel);
auto bufferItr = std::lower_bound( auto bufferItr = std::lower_bound(
cryptoStream->retransmissionBuffer.begin(), cryptoStream->retransmissionBuffer.begin(),
cryptoStream->retransmissionBuffer.end(), cryptoStream->retransmissionBuffer.end(),
frame.offset, frame.offset,
[](const auto& buffer, const auto& offset) { [](const auto& buffer, const auto& offset) {
return buffer.offset < offset; return buffer.offset < offset;
}); });
if (bufferItr == cryptoStream->retransmissionBuffer.end()) { if (bufferItr == cryptoStream->retransmissionBuffer.end()) {
// It's possible that the stream was reset while we discovered that // It's possible that the stream was reset while we discovered that
// it's packet was lost so we might not have the offset. // it's packet was lost so we might not have the offset.
return; break;
} }
DCHECK_EQ(bufferItr->offset, frame.offset); DCHECK_EQ(bufferItr->offset, frame.offset);
cryptoStream->lossBuffer.insert( cryptoStream->lossBuffer.insert(
std::upper_bound( std::upper_bound(
cryptoStream->lossBuffer.begin(), cryptoStream->lossBuffer.begin(),
cryptoStream->lossBuffer.end(), cryptoStream->lossBuffer.end(),
bufferItr->offset, bufferItr->offset,
[](const auto& offset, const auto& buffer) { [](const auto& offset, const auto& buffer) {
return offset < buffer.offset; return offset < buffer.offset;
}), }),
std::move(*bufferItr)); std::move(*bufferItr));
cryptoStream->retransmissionBuffer.erase(bufferItr); cryptoStream->retransmissionBuffer.erase(bufferItr);
}, break;
[&](RstStreamFrame& frame) { }
if (processed) { case QuicWriteFrame::Type::RstStreamFrame_E: {
return; RstStreamFrame& frame = *packetFrame.asRstStreamFrame();
} if (processed) {
auto stream = conn.streamManager->getStream(frame.streamId); break;
if (!stream) { }
// If the stream is dead, ignore the retransmissions of the rst auto stream = conn.streamManager->getStream(frame.streamId);
// stream. if (!stream) {
return; // If the stream is dead, ignore the retransmissions of the rst
} // stream.
// Add the lost RstStreamFrame back to pendingEvents: break;
conn.pendingEvents.resets.insert({frame.streamId, frame}); }
}, // Add the lost RstStreamFrame back to pendingEvents:
[&](StreamDataBlockedFrame& frame) { conn.pendingEvents.resets.insert({frame.streamId, frame});
if (processed) { break;
return; }
} case QuicWriteFrame::Type::StreamDataBlockedFrame_E: {
auto stream = conn.streamManager->getStream(frame.streamId); StreamDataBlockedFrame& frame = *packetFrame.asStreamDataBlockedFrame();
// TODO: check for retransmittable if (processed) {
if (!stream) { break;
return; }
} auto stream = conn.streamManager->getStream(frame.streamId);
onBlockedLost(*stream); // TODO: check for retransmittable
}, if (!stream) {
[&](QuicSimpleFrame& frame) { break;
if (processed) { }
return; onBlockedLost(*stream);
} break;
updateSimpleFrameOnPacketLoss(conn, frame); }
}, case QuicWriteFrame::Type::QuicSimpleFrame_E: {
[&](auto&) { QuicSimpleFrame& frame = *packetFrame.asQuicSimpleFrame();
// ignore the rest of the frames. if (processed) {
}); break;
}
updateSimpleFrameOnPacketLoss(conn, frame);
break;
}
default:
// ignore the rest of the frames.
break;
}
} }
} }
} // namespace quic } // namespace quic

View File

@@ -696,10 +696,14 @@ TEST_F(QuicLossFunctionsTest, TestMarkRstLoss) {
auto& packet2 = auto& packet2 =
getLastOutstandingPacket(*conn, PacketNumberSpace::AppData)->packet; getLastOutstandingPacket(*conn, PacketNumberSpace::AppData)->packet;
bool rstFound = false; bool rstFound = false;
for (auto& frame : all_frames<RstStreamFrame>(packet2.frames)) { for (auto& frame : packet2.frames) {
EXPECT_EQ(stream->id, frame.streamId); auto resetFrame = frame.asRstStreamFrame();
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, frame.errorCode); if (!resetFrame) {
EXPECT_EQ(currentOffset, frame.offset); continue;
}
EXPECT_EQ(stream->id, resetFrame->streamId);
EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, resetFrame->errorCode);
EXPECT_EQ(currentOffset, resetFrame->offset);
rstFound = true; rstFound = true;
} }
EXPECT_TRUE(rstFound); EXPECT_TRUE(rstFound);
@@ -1235,12 +1239,19 @@ TEST_F(QuicLossFunctionsTest, TestMarkPacketLossProcessedPacket) {
for (const auto& frame : for (const auto& frame :
getLastOutstandingPacket(*conn, PacketNumberSpace::AppData) getLastOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames) { ->packet.frames) {
folly::variant_match( switch (frame.type()) {
frame, case QuicWriteFrame::Type::WriteStreamFrame_E:
[&](const WriteStreamFrame&) { streamDataCounter++; }, streamDataCounter++;
[&](const MaxStreamDataFrame&) { streamWindowUpdateCounter++; }, break;
[&](const MaxDataFrame&) { connWindowUpdateCounter++; }, case QuicWriteFrame::Type::MaxStreamDataFrame_E:
[](const auto&) { ASSERT_TRUE(false); }); streamWindowUpdateCounter++;
break;
case QuicWriteFrame::Type::MaxDataFrame_E:
connWindowUpdateCounter++;
break;
default:
CHECK(false) << "unexpected frame=" << (int)frame.type();
}
} }
EXPECT_EQ(1, streamDataCounter); EXPECT_EQ(1, streamDataCounter);
EXPECT_EQ(1, streamWindowUpdateCounter); EXPECT_EQ(1, streamWindowUpdateCounter);

View File

@@ -756,47 +756,56 @@ void onServerReadDataFromOpen(
[&](const OutstandingPacket&, [&](const OutstandingPacket&,
const QuicWriteFrame& packetFrame, const QuicWriteFrame& packetFrame,
const ReadAckFrame&) { const ReadAckFrame&) {
folly::variant_match( switch (packetFrame.type()) {
packetFrame, case QuicWriteFrame::Type::WriteStreamFrame_E: {
[&](const WriteStreamFrame& frame) { const WriteStreamFrame& frame =
VLOG(4) *packetFrame.asWriteStreamFrame();
<< "Server received ack for stream=" << frame.streamId VLOG(4)
<< " offset=" << frame.offset << " fin=" << frame.fin << "Server received ack for stream=" << frame.streamId
<< " len=" << frame.len << " " << conn; << " offset=" << frame.offset << " fin=" << frame.fin
auto ackedStream = << " len=" << frame.len << " " << conn;
conn.streamManager->getStream(frame.streamId); auto ackedStream =
if (ackedStream) { conn.streamManager->getStream(frame.streamId);
invokeStreamSendStateMachine( if (ackedStream) {
conn, invokeStreamSendStateMachine(
*ackedStream, conn,
StreamEvents::AckStreamFrame(frame)); *ackedStream,
} StreamEvents::AckStreamFrame(frame));
}, }
[&](const WriteCryptoFrame& frame) { break;
auto cryptoStream = }
getCryptoStream(*conn.cryptoState, encryptionLevel); case QuicWriteFrame::Type::WriteCryptoFrame_E: {
processCryptoStreamAck( const WriteCryptoFrame& frame =
*cryptoStream, frame.offset, frame.len); *packetFrame.asWriteCryptoFrame();
}, auto cryptoStream =
[&](const RstStreamFrame& frame) { getCryptoStream(*conn.cryptoState, encryptionLevel);
VLOG(4) << "Server received ack for reset stream=" processCryptoStreamAck(
<< frame.streamId << " " << conn; *cryptoStream, frame.offset, frame.len);
auto stream = break;
conn.streamManager->getStream(frame.streamId); }
if (stream) { case QuicWriteFrame::Type::RstStreamFrame_E: {
invokeStreamSendStateMachine( const RstStreamFrame& frame = *packetFrame.asRstStreamFrame();
conn, *stream, StreamEvents::RstAck(frame)); VLOG(4) << "Server received ack for reset stream="
} << frame.streamId << " " << conn;
}, auto stream = conn.streamManager->getStream(frame.streamId);
[&](const WriteAckFrame& frame) { if (stream) {
DCHECK(!frame.ackBlocks.empty()); invokeStreamSendStateMachine(
VLOG(4) << "Server received ack for largestAcked=" conn, *stream, StreamEvents::RstAck(frame));
<< frame.ackBlocks.back().end << " " << conn; }
commonAckVisitorForAckFrame(ackState, frame); break;
}, }
[&](const auto& /*frame*/) { case QuicWriteFrame::Type::WriteAckFrame_E: {
// Ignore other frames. const WriteAckFrame& frame = *packetFrame.asWriteAckFrame();
}); DCHECK(!frame.ackBlocks.empty());
VLOG(4) << "Server received ack for largestAcked="
<< frame.ackBlocks.back().end << " " << conn;
commonAckVisitorForAckFrame(ackState, frame);
break;
}
default: {
break;
}
}
}, },
markPacketLoss, markPacketLoss,
readData.networkData.receiveTimePoint); readData.networkData.receiveTimePoint);

View File

@@ -1116,7 +1116,7 @@ TEST_F(QuicServerTransportTest, TestOpenAckStreamFrame) {
PacketNum currentPacket = packet.packet.header.getPacketSequenceNum(); PacketNum currentPacket = packet.packet.header.getPacketSequenceNum();
ASSERT_FALSE(packet.packet.frames.empty()); ASSERT_FALSE(packet.packet.frames.empty());
for (auto& quicFrame : packet.packet.frames) { for (auto& quicFrame : packet.packet.frames) {
auto frame = boost::get<WriteStreamFrame>(&quicFrame); auto frame = quicFrame.asWriteStreamFrame();
if (!frame) { if (!frame) {
continue; continue;
} }
@@ -1374,7 +1374,7 @@ TEST_F(QuicServerTransportTest, RecvStopSendingFrame) {
StopSendingFrame stopSendingFrame( StopSendingFrame stopSendingFrame(
streamId, GenericApplicationErrorCode::UNKNOWN); streamId, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(std::move(stopSendingFrame), builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
EXPECT_CALL( EXPECT_CALL(
connCallback, connCallback,
@@ -1416,7 +1416,7 @@ TEST_F(QuicServerTransportTest, RecvStopSendingFrameAfterCloseStream) {
StopSendingFrame stopSendingFrame( StopSendingFrame stopSendingFrame(
streamId, GenericApplicationErrorCode::UNKNOWN); streamId, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(std::move(stopSendingFrame), builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
server->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN); server->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
EXPECT_CALL(connCallback, onStopSending(_, _)).Times(0); EXPECT_CALL(connCallback, onStopSending(_, _)).Times(0);
@@ -1499,7 +1499,7 @@ TEST_F(QuicServerTransportTest, RecvStopSendingFrameAfterHalfCloseRemote) {
builder, 0x00, stream->currentReadOffset, 0, 10, true); builder, 0x00, stream->currentReadOffset, 0, 10, true);
ASSERT_TRUE(dataLen.hasValue()); ASSERT_TRUE(dataLen.hasValue());
ASSERT_EQ(*dataLen, 0); ASSERT_EQ(*dataLen, 0);
writeFrame(std::move(stopSendingFrame), builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
EXPECT_CALL( EXPECT_CALL(
connCallback, connCallback,
@@ -1523,7 +1523,7 @@ TEST_F(QuicServerTransportTest, RecvStopSendingBeforeStream) {
StopSendingFrame stopSendingFrame( StopSendingFrame stopSendingFrame(
streamId, GenericApplicationErrorCode::UNKNOWN); streamId, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(std::move(stopSendingFrame), builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
EXPECT_CALL(connCallback, onNewBidirectionalStream(streamId)); EXPECT_CALL(connCallback, onNewBidirectionalStream(streamId));
EXPECT_CALL( EXPECT_CALL(
@@ -1578,8 +1578,8 @@ TEST_F(QuicServerTransportTest, RecvStopSendingFrameAfterReset) {
StopSendingFrame stopSendingFrame2( StopSendingFrame stopSendingFrame2(
streamId2, GenericApplicationErrorCode::UNKNOWN); streamId2, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(std::move(stopSendingFrame1), builder); writeFrame(QuicSimpleFrame(stopSendingFrame1), builder);
writeFrame(std::move(stopSendingFrame2), builder); writeFrame(QuicSimpleFrame(stopSendingFrame2), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
EXPECT_CALL( EXPECT_CALL(
connCallback, onStopSending(_, GenericApplicationErrorCode::UNKNOWN)) connCallback, onStopSending(_, GenericApplicationErrorCode::UNKNOWN))
@@ -1605,7 +1605,7 @@ TEST_F(QuicServerTransportTest, StopSendingLoss) {
StopSendingFrame stopSendingFrame( StopSendingFrame stopSendingFrame(
streamId, GenericApplicationErrorCode::UNKNOWN); streamId, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(stopSendingFrame, builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
markPacketLoss( markPacketLoss(
server->getNonConstConn(), server->getNonConstConn(),
@@ -1635,7 +1635,7 @@ TEST_F(QuicServerTransportTest, StopSendingLossAfterStreamClosed) {
StopSendingFrame stopSendingFrame( StopSendingFrame stopSendingFrame(
streamId, GenericApplicationErrorCode::UNKNOWN); streamId, GenericApplicationErrorCode::UNKNOWN);
ASSERT_TRUE(builder.canBuildPacket()); ASSERT_TRUE(builder.canBuildPacket());
writeFrame(stopSendingFrame, builder); writeFrame(QuicSimpleFrame(stopSendingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
// clear out all the streams, this is not a great way to simulate closed // clear out all the streams, this is not a great way to simulate closed

View File

@@ -205,9 +205,10 @@ TEST_F(QuicOpenStateTest, AckStream) {
EXPECT_EQ(stream->retransmissionBuffer.size(), 1); EXPECT_EQ(stream->retransmissionBuffer.size(), 1);
EXPECT_EQ(1, conn->outstandingPackets.size()); EXPECT_EQ(1, conn->outstandingPackets.size());
auto& streamFrame = boost::get<WriteStreamFrame>( auto& streamFrame =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) *getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames.front()); ->packet.frames.front()
.asWriteStreamFrame();
StreamEvents::AckStreamFrame ack(streamFrame); StreamEvents::AckStreamFrame ack(streamFrame);
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream); invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
@@ -256,8 +257,9 @@ TEST_F(QuicOpenStateTest, RetxBufferSortedAfterAck) {
EXPECT_EQ(3, stream->retransmissionBuffer.size()); EXPECT_EQ(3, stream->retransmissionBuffer.size());
EXPECT_EQ(3, conn->outstandingPackets.size()); EXPECT_EQ(3, conn->outstandingPackets.size());
auto packet = conn->outstandingPackets[folly::Random::rand32() % 3]; auto packet = conn->outstandingPackets[folly::Random::rand32() % 3];
auto streamFrame = boost::get<WriteStreamFrame>( auto streamFrame = *conn->outstandingPackets[std::rand() % 3]
conn->outstandingPackets[std::rand() % 3].packet.frames.front()); .packet.frames.front()
.asWriteStreamFrame();
StreamEvents::AckStreamFrame ack(streamFrame); StreamEvents::AckStreamFrame ack(streamFrame);
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream); invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
EXPECT_EQ(2, stream->retransmissionBuffer.size()); EXPECT_EQ(2, stream->retransmissionBuffer.size());
@@ -289,9 +291,10 @@ TEST_F(QuicOpenStateTest, AckStreamAfterSkip) {
EXPECT_EQ(stream->retransmissionBuffer.size(), 1); EXPECT_EQ(stream->retransmissionBuffer.size(), 1);
EXPECT_EQ(1, conn->outstandingPackets.size()); EXPECT_EQ(1, conn->outstandingPackets.size());
auto& streamFrame = boost::get<WriteStreamFrame>( auto& streamFrame =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) *getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames.front()); ->packet.frames.front()
.asWriteStreamFrame();
PacketNum packetNum(1); PacketNum packetNum(1);
MinStreamDataFrame minDataFrame(stream->id, 1000, 100); MinStreamDataFrame minDataFrame(stream->id, 1000, 100);
@@ -333,9 +336,10 @@ TEST_F(QuicOpenStateTest, AckStreamAfterSkipHalfBuf) {
EXPECT_EQ(stream->retransmissionBuffer.size(), 1); EXPECT_EQ(stream->retransmissionBuffer.size(), 1);
EXPECT_EQ(1, conn->outstandingPackets.size()); EXPECT_EQ(1, conn->outstandingPackets.size());
auto& streamFrame = boost::get<WriteStreamFrame>( auto& streamFrame =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) *getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames.front()); ->packet.frames.front()
.asWriteStreamFrame();
PacketNum packetNum(1); PacketNum packetNum(1);
// Skip ~0.5 buffers. // Skip ~0.5 buffers.
@@ -387,11 +391,11 @@ TEST_F(QuicOpenStateTest, AckStreamAfterSkipOneAndAHalfBuf) {
auto streamFrameIt = auto streamFrameIt =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData);
auto& streamFrame1 = auto& streamFrame1 =
boost::get<WriteStreamFrame>(streamFrameIt->packet.frames.front()); *streamFrameIt->packet.frames.front().asWriteStreamFrame();
auto& streamFrame2 = boost::get<WriteStreamFrame>( auto& streamFrame2 = *getNextOutstandingPacket(
getNextOutstandingPacket( *conn, PacketNumberSpace::AppData, ++streamFrameIt)
*conn, PacketNumberSpace::AppData, ++streamFrameIt) ->packet.frames.front()
->packet.frames.front()); .asWriteStreamFrame();
PacketNum packetNum(1); PacketNum packetNum(1);
// Skip ~1.5 buffers. // Skip ~1.5 buffers.
@@ -502,9 +506,10 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStream) {
EXPECT_EQ(stream->retransmissionBuffer.size(), 1); EXPECT_EQ(stream->retransmissionBuffer.size(), 1);
EXPECT_EQ(1, conn->outstandingPackets.size()); EXPECT_EQ(1, conn->outstandingPackets.size());
auto& streamFrame = boost::get<WriteStreamFrame>( auto& streamFrame =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) *getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames.front()); ->packet.frames.front()
.asWriteStreamFrame();
StreamEvents::AckStreamFrame ack(streamFrame); StreamEvents::AckStreamFrame ack(streamFrame);
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream); invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
@@ -541,9 +546,10 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStreamAfterSkip) {
EXPECT_EQ(stream->retransmissionBuffer.size(), 1); EXPECT_EQ(stream->retransmissionBuffer.size(), 1);
EXPECT_EQ(1, conn->outstandingPackets.size()); EXPECT_EQ(1, conn->outstandingPackets.size());
auto& streamFrame = boost::get<WriteStreamFrame>( auto& streamFrame =
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) *getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData)
->packet.frames.front()); ->packet.frames.front()
.asWriteStreamFrame();
PacketNum packetNum(1); PacketNum packetNum(1);
MinStreamDataFrame minDataFrame(stream->id, 1000, 100); MinStreamDataFrame minDataFrame(stream->id, 1000, 100);

View File

@@ -81,7 +81,7 @@ TEST_P(AckHandlersTest, TestAckMultipleSequentialBlocks) {
GetParam(), GetParam(),
ackFrame, ackFrame,
[&](const auto&, const auto& packetFrame, const ReadAckFrame&) { [&](const auto&, const auto& packetFrame, const ReadAckFrame&) {
auto& stream = boost::get<WriteStreamFrame>(packetFrame); auto& stream = *packetFrame.asWriteStreamFrame();
streams.emplace_back(stream); streams.emplace_back(stream);
}, },
testLossHandler(lostPackets), testLossHandler(lostPackets),
@@ -152,7 +152,7 @@ TEST_P(AckHandlersTest, TestAckBlocksWithGaps) {
GetParam(), GetParam(),
ackFrame, ackFrame,
[&](const auto&, const auto& packetFrame, const ReadAckFrame&) { [&](const auto&, const auto& packetFrame, const ReadAckFrame&) {
auto& stream = boost::get<WriteStreamFrame>(packetFrame); auto& stream = *packetFrame.asWriteStreamFrame();
streams.emplace_back(stream); streams.emplace_back(stream);
}, },
testLossHandler(lostPackets), testLossHandler(lostPackets),
@@ -259,7 +259,7 @@ TEST_P(AckHandlersTest, TestNonSequentialPacketNumbers) {
GetParam(), GetParam(),
ackFrame, ackFrame,
[&](const auto&, const auto& packetFrame, const ReadAckFrame&) { [&](const auto&, const auto& packetFrame, const ReadAckFrame&) {
auto& stream = boost::get<WriteStreamFrame>(packetFrame); auto& stream = *packetFrame.asWriteStreamFrame();
streams.emplace_back(stream); streams.emplace_back(stream);
}, },
testLossHandler(lostPackets), testLossHandler(lostPackets),
@@ -337,15 +337,10 @@ TEST_P(AckHandlersTest, AckVisitorForAckTest) {
auto ackedPacketNum = auto ackedPacketNum =
outstandingPacket.packet.header.getPacketSequenceNum(); outstandingPacket.packet.header.getPacketSequenceNum();
EXPECT_EQ(ackedPacketNum, firstReceivedAck.largestAcked); EXPECT_EQ(ackedPacketNum, firstReceivedAck.largestAcked);
folly::variant_match( const WriteAckFrame* frame = packetFrame.asWriteAckFrame();
packetFrame, if (frame) {
[&](const WriteAckFrame& frame) { commonAckVisitorForAckFrame(conn.ackStates.appDataAckState, *frame);
commonAckVisitorForAckFrame( }
conn.ackStates.appDataAckState, frame);
},
[&](const auto& /* frame */) {
// Ignore other frames.
});
}, },
[](auto& /* conn */, [](auto& /* conn */,
auto& /* packet */, auto& /* packet */,
@@ -368,15 +363,10 @@ TEST_P(AckHandlersTest, AckVisitorForAckTest) {
GetParam(), GetParam(),
secondReceivedAck, secondReceivedAck,
[&](const auto&, const auto& packetFrame, const ReadAckFrame&) { [&](const auto&, const auto& packetFrame, const ReadAckFrame&) {
folly::variant_match( const WriteAckFrame* frame = packetFrame.asWriteAckFrame();
packetFrame, if (frame) {
[&](const WriteAckFrame& frame) { commonAckVisitorForAckFrame(conn.ackStates.appDataAckState, *frame);
commonAckVisitorForAckFrame( }
conn.ackStates.appDataAckState, frame);
},
[&](const auto& /* frame */) {
// Ignore other frames.
});
}, },
[](auto& /* conn */, [](auto& /* conn */,
auto& /* packet */, auto& /* packet */,