mirror of
https://github.com/facebookincubator/mvfst.git
synced 2026-01-06 03:41:10 +03:00
remove codecresult variant
Summary: remove the variant for codec result and replace it with a custom variant type Reviewed By: yangchi Differential Revision: D17247099 fbshipit-source-id: 19e24c14732eb6e8496aee7064f20c48bdf254e0
This commit is contained in:
committed by
Facebook Github Bot
parent
208ea8b425
commit
322eb2ebc4
@@ -126,39 +126,32 @@ void QuicClientTransport::processPacketData(
|
||||
}
|
||||
auto parsedPacket = conn_->readCodec->parsePacket(
|
||||
packetQueue, conn_->ackStates, conn_->clientConnectionId->size());
|
||||
bool parseSuccess = folly::variant_match(
|
||||
parsedPacket,
|
||||
[&](RegularQuicPacket&) { return true; },
|
||||
[&](StatelessReset& reset) {
|
||||
auto& token = clientConn_->statelessResetToken;
|
||||
if (reset.token != token) {
|
||||
VLOG(4) << "Drop StatelessReset for bad connId or token " << *this;
|
||||
return false;
|
||||
}
|
||||
VLOG(4) << "Received Stateless Reset " << *this;
|
||||
conn_->peerConnectionError = std::make_pair(
|
||||
QuicErrorCode(LocalErrorCode::CONNECTION_RESET),
|
||||
toString(LocalErrorCode::CONNECTION_RESET));
|
||||
throw QuicInternalException("Peer reset", LocalErrorCode::NO_ERROR);
|
||||
folly::assume_unreachable();
|
||||
},
|
||||
[&](auto&) { return false; });
|
||||
if (!parseSuccess) {
|
||||
StatelessReset* statelessReset = parsedPacket.statelessReset();
|
||||
if (statelessReset) {
|
||||
auto& token = clientConn_->statelessResetToken;
|
||||
if (statelessReset->token == token) {
|
||||
VLOG(4) << "Received Stateless Reset " << *this;
|
||||
conn_->peerConnectionError = std::make_pair(
|
||||
QuicErrorCode(LocalErrorCode::CONNECTION_RESET),
|
||||
toString(LocalErrorCode::CONNECTION_RESET));
|
||||
throw QuicInternalException("Peer reset", LocalErrorCode::NO_ERROR);
|
||||
}
|
||||
VLOG(4) << "Drop StatelessReset for bad connId or token " << *this;
|
||||
}
|
||||
|
||||
RegularQuicPacket* regularOptional = parsedPacket.regularPacket();
|
||||
if (!regularOptional) {
|
||||
if (conn_->qLogger) {
|
||||
conn_->qLogger->addPacketDrop(packetSize, kParse);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, *conn_, "parse");
|
||||
return;
|
||||
}
|
||||
|
||||
if (happyEyeballsEnabled_) {
|
||||
happyEyeballsOnDataReceived(
|
||||
*conn_, happyEyeballsConnAttemptDelayTimeout_, socket_, peer);
|
||||
}
|
||||
|
||||
auto regularOptional = boost::get<RegularQuicPacket>(&parsedPacket);
|
||||
DCHECK(regularOptional);
|
||||
|
||||
LongHeader* longHeader = regularOptional->header.asLong();
|
||||
ShortHeader* shortHeader = regularOptional->header.asShort();
|
||||
|
||||
|
||||
@@ -1507,7 +1507,7 @@ class QuicClientTransportTest : public Test {
|
||||
}
|
||||
|
||||
RegularQuicPacket* parseRegularQuicPacket(CodecResult& codecResult) {
|
||||
return boost::get<RegularQuicPacket>(&codecResult);
|
||||
return codecResult.regularPacket();
|
||||
}
|
||||
|
||||
void verifyShortPackets(IntervalSet<PacketNum>& sentPackets) {
|
||||
@@ -2710,7 +2710,7 @@ bool verifyFramePresent(
|
||||
for (auto& write : socketWrites) {
|
||||
auto packetQueue = bufToQueue(write->clone());
|
||||
auto result = readCodec.parsePacket(packetQueue, ackStates);
|
||||
auto regularPacket = boost::get<RegularQuicPacket>(&result);
|
||||
auto regularPacket = result.regularPacket();
|
||||
if (!regularPacket) {
|
||||
continue;
|
||||
}
|
||||
@@ -3682,7 +3682,7 @@ TEST_F(QuicClientTransportVersionAndRetryTest, RetryPacket) {
|
||||
auto codecResult =
|
||||
makeEncryptedCodec(true)->parsePacket(packetQueue, ackStates);
|
||||
|
||||
auto regularQuicPacket = boost::get<RegularQuicPacket>(codecResult);
|
||||
auto& regularQuicPacket = *codecResult.regularPacket();
|
||||
auto& header = *regularQuicPacket.header.asLong();
|
||||
|
||||
std::vector<int> indices =
|
||||
|
||||
@@ -58,7 +58,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
// packet ends. Clear the queue since no other data in this packet is
|
||||
// parse-able.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
if (longHeaderInvariant->invariant.version ==
|
||||
QuicVersion::VERSION_NEGOTIATION) {
|
||||
@@ -68,7 +68,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
// Since VN is not allowed to be coalesced with another packet
|
||||
// type, we clear out the buffer to avoid anyone else parsing it.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
auto type = parseLongHeaderType(initialByte);
|
||||
|
||||
@@ -80,7 +80,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
// packet ends. Clear the queue since no other data in this packet is
|
||||
// parse-able.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
// As soon as we have parsed out the long header we can split off any
|
||||
// coalesced packets. We do this early since the spec mandates that decryption
|
||||
@@ -97,7 +97,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
if (queue.chainLength() < currentPacketLen) {
|
||||
// Packet appears truncated, there's no parse-able data left.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
auto currentPacketData = queue.split(currentPacketLen);
|
||||
cursor.reset(currentPacketData.get());
|
||||
@@ -109,7 +109,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
<< connIdToHex();
|
||||
// Packet appears truncated, there's no parse-able data left.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
cursor.skip(kMaxPacketNumEncodingSize);
|
||||
Sample sample;
|
||||
@@ -117,7 +117,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
VLOG(4) << "Dropping packet, sample too small " << connIdToHex();
|
||||
// Packet appears truncated, there's no parse-able data left.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
cursor.pull(sample.data(), sample.size());
|
||||
const PacketNumberCipher* headerCipher{nullptr};
|
||||
@@ -131,7 +131,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
VLOG(4) << nodeToString(nodeType_)
|
||||
<< " dropping initial packet for exceeding key timeout"
|
||||
<< connIdToHex();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
}
|
||||
headerCipher = initialHeaderCipher_.get();
|
||||
@@ -148,7 +148,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
VLOG(4) << nodeToString(nodeType_)
|
||||
<< " dropping zero rtt packet for exceeding key timeout"
|
||||
<< connIdToHex();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
}
|
||||
headerCipher = zeroRttHeaderCipher_.get();
|
||||
@@ -219,7 +219,7 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
||||
<< " packetNumLen=" << parsePacketNumberLength(initialByte)
|
||||
<< " protectionType=" << toString(protectionType) << " "
|
||||
<< connIdToHex();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
decrypted = std::move(*decryptAttempt);
|
||||
|
||||
@@ -237,12 +237,12 @@ CodecResult QuicReadCodec::parsePacket(
|
||||
const AckStates& ackStates,
|
||||
size_t dstConnIdSize) {
|
||||
if (queue.empty()) {
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
DCHECK(!queue.front()->isChained());
|
||||
folly::io::Cursor cursor(queue.front());
|
||||
if (!cursor.canAdvance(sizeof(uint8_t))) {
|
||||
return folly::none;
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
uint8_t initialByte = cursor.readBE<uint8_t>();
|
||||
auto headerForm = getHeaderForm(initialByte);
|
||||
@@ -273,7 +273,7 @@ CodecResult QuicReadCodec::parsePacket(
|
||||
// There's not enough space for the short header packet, clear the queue
|
||||
// to indicate there's no more parse-able data.
|
||||
queue.clear();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
// Take it out of the queue so we can do some writing.
|
||||
auto data = queue.move();
|
||||
@@ -291,13 +291,13 @@ CodecResult QuicReadCodec::parsePacket(
|
||||
parseShortHeader(initialByteRange.data()[0], cursor, dstConnIdSize);
|
||||
if (!shortHeader) {
|
||||
VLOG(10) << "Dropping packet, cannot parse " << connIdToHex();
|
||||
return folly::none;
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
shortHeader->setPacketNumber(packetNum.first);
|
||||
if (shortHeader->getProtectionType() == ProtectionType::KeyPhaseOne) {
|
||||
VLOG(4) << nodeToString(nodeType_) << " cannot read key phase one packet "
|
||||
<< connIdToHex();
|
||||
return folly::none;
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
|
||||
// Back in the queue so we can split.
|
||||
@@ -341,7 +341,7 @@ CodecResult QuicReadCodec::parsePacket(
|
||||
VLOG(10) << "Unable to decrypt packet=" << packetNum.first
|
||||
<< " protectionType=" << (int)protectionType << " "
|
||||
<< connIdToHex();
|
||||
return CodecResult(folly::none);
|
||||
return CodecResult(Nothing());
|
||||
}
|
||||
decrypted = std::move(*decryptAttempt);
|
||||
if (!decrypted) {
|
||||
@@ -472,4 +472,114 @@ std::string QuicReadCodec::connIdToHex() {
|
||||
return folly::to<std::string>(
|
||||
"server=", serverId.hex(), " ", "client=", clientId.hex());
|
||||
}
|
||||
|
||||
CodecResult::CodecResult(RegularQuicPacket&& regularPacketIn)
|
||||
: type_(CodecResult::Type::REGULAR_PACKET) {
|
||||
new (&packet) RegularQuicPacket(std::move(regularPacketIn));
|
||||
}
|
||||
|
||||
CodecResult::CodecResult(CipherUnavailable&& cipherUnavailableIn)
|
||||
: type_(CodecResult::Type::CIPHER_UNAVAILABLE) {
|
||||
new (&cipher) CipherUnavailable(std::move(cipherUnavailableIn));
|
||||
}
|
||||
|
||||
CodecResult::CodecResult(StatelessReset&& statelessResetIn)
|
||||
: type_(CodecResult::Type::STATELESS_RESET) {
|
||||
new (&reset) StatelessReset(std::move(statelessResetIn));
|
||||
}
|
||||
|
||||
CodecResult::CodecResult(Nothing&&) : type_(CodecResult::Type::NOTHING) {
|
||||
new (&none) Nothing();
|
||||
}
|
||||
|
||||
void CodecResult::destroyCodecResult() {
|
||||
switch (type_) {
|
||||
case CodecResult::Type::REGULAR_PACKET:
|
||||
packet.~RegularQuicPacket();
|
||||
break;
|
||||
case CodecResult::Type::CIPHER_UNAVAILABLE:
|
||||
cipher.~CipherUnavailable();
|
||||
break;
|
||||
case CodecResult::Type::STATELESS_RESET:
|
||||
reset.~StatelessReset();
|
||||
break;
|
||||
case CodecResult::Type::NOTHING:
|
||||
none.~Nothing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CodecResult::~CodecResult() {
|
||||
destroyCodecResult();
|
||||
}
|
||||
|
||||
CodecResult::CodecResult(CodecResult&& other) noexcept {
|
||||
switch (other.type_) {
|
||||
case CodecResult::Type::REGULAR_PACKET:
|
||||
new (&packet) RegularQuicPacket(std::move(other.packet));
|
||||
break;
|
||||
case CodecResult::Type::CIPHER_UNAVAILABLE:
|
||||
new (&cipher) CipherUnavailable(std::move(other.cipher));
|
||||
break;
|
||||
case CodecResult::Type::STATELESS_RESET:
|
||||
new (&reset) StatelessReset(std::move(other.reset));
|
||||
break;
|
||||
case CodecResult::Type::NOTHING:
|
||||
new (&none) Nothing(std::move(other.none));
|
||||
break;
|
||||
}
|
||||
type_ = other.type_;
|
||||
}
|
||||
|
||||
CodecResult& CodecResult::operator=(CodecResult&& other) noexcept {
|
||||
destroyCodecResult();
|
||||
switch (other.type_) {
|
||||
case CodecResult::Type::REGULAR_PACKET:
|
||||
new (&packet) RegularQuicPacket(std::move(other.packet));
|
||||
break;
|
||||
case CodecResult::Type::CIPHER_UNAVAILABLE:
|
||||
new (&cipher) CipherUnavailable(std::move(other.cipher));
|
||||
break;
|
||||
case CodecResult::Type::STATELESS_RESET:
|
||||
new (&reset) StatelessReset(std::move(other.reset));
|
||||
break;
|
||||
case CodecResult::Type::NOTHING:
|
||||
new (&none) Nothing(std::move(other.none));
|
||||
break;
|
||||
}
|
||||
type_ = other.type_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CodecResult::Type CodecResult::type() {
|
||||
return type_;
|
||||
}
|
||||
|
||||
RegularQuicPacket* CodecResult::regularPacket() {
|
||||
if (type_ == CodecResult::Type::REGULAR_PACKET) {
|
||||
return &packet;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CipherUnavailable* CodecResult::cipherUnavailable() {
|
||||
if (type_ == CodecResult::Type::CIPHER_UNAVAILABLE) {
|
||||
return &cipher;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StatelessReset* CodecResult::statelessReset() {
|
||||
if (type_ == CodecResult::Type::STATELESS_RESET) {
|
||||
return &reset;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Nothing* CodecResult::nothing() {
|
||||
if (type_ == CodecResult::Type::NOTHING) {
|
||||
return &none;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace quic
|
||||
|
||||
@@ -37,10 +37,47 @@ struct CipherUnavailable {
|
||||
protectionType(protectionTypeIn) {}
|
||||
};
|
||||
|
||||
using CodecResult = boost::variant<
|
||||
RegularQuicPacket,
|
||||
folly::Optional<CipherUnavailable>,
|
||||
StatelessReset>;
|
||||
/**
|
||||
* A type which represents no data.
|
||||
*/
|
||||
struct Nothing {};
|
||||
|
||||
struct CodecResult {
|
||||
enum class Type {
|
||||
REGULAR_PACKET,
|
||||
CIPHER_UNAVAILABLE,
|
||||
STATELESS_RESET,
|
||||
NOTHING
|
||||
};
|
||||
|
||||
~CodecResult();
|
||||
|
||||
CodecResult(CodecResult&& other) noexcept;
|
||||
CodecResult& operator=(CodecResult&& other) noexcept;
|
||||
|
||||
/* implicit */ CodecResult(RegularQuicPacket&& regularPacketIn);
|
||||
/* implicit */ CodecResult(CipherUnavailable&& cipherUnavailableIn);
|
||||
/* implicit */ CodecResult(StatelessReset&& statelessReset);
|
||||
/* implicit */ CodecResult(Nothing&& nothing);
|
||||
|
||||
Type type();
|
||||
RegularQuicPacket* regularPacket();
|
||||
CipherUnavailable* cipherUnavailable();
|
||||
StatelessReset* statelessReset();
|
||||
Nothing* nothing();
|
||||
|
||||
private:
|
||||
void destroyCodecResult();
|
||||
|
||||
union {
|
||||
RegularQuicPacket packet;
|
||||
CipherUnavailable cipher;
|
||||
StatelessReset reset;
|
||||
Nothing none;
|
||||
};
|
||||
|
||||
Type type_;
|
||||
};
|
||||
|
||||
class QuicReadCodec {
|
||||
public:
|
||||
|
||||
@@ -182,13 +182,13 @@ TEST_F(DecodeTest, VersionNegotiationPacketBadPacketTest) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(std::move(buf));
|
||||
auto packet = codec->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_THROW(boost::get<RegularQuicPacket>(packet), boost::bad_get);
|
||||
EXPECT_EQ(packet.regularPacket(), nullptr);
|
||||
|
||||
buf = folly::IOBuf::create(0);
|
||||
packetQueue = bufToQueue(std::move(buf));
|
||||
packet = codec->parsePacket(packetQueue, ackStates);
|
||||
// Packet with empty versions
|
||||
EXPECT_THROW(boost::get<RegularQuicPacket>(packet), boost::bad_get);
|
||||
EXPECT_EQ(packet.regularPacket(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DecodeTest, ValidAckFrame) {
|
||||
|
||||
@@ -132,8 +132,8 @@ TEST_F(QuicPacketBuilderTest, SimpleRetryPacket) {
|
||||
auto optionalDecodedPacket =
|
||||
makeCodec(getTestConnectionId(1), QuicNodeType::Client)
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_NO_THROW(boost::get<RegularQuicPacket>(optionalDecodedPacket));
|
||||
auto retryPacket = boost::get<RegularQuicPacket>(optionalDecodedPacket);
|
||||
ASSERT_NE(optionalDecodedPacket.regularPacket(), nullptr);
|
||||
auto& retryPacket = *optionalDecodedPacket.regularPacket();
|
||||
|
||||
auto& headerOut = *retryPacket.header.asLong();
|
||||
|
||||
@@ -215,9 +215,8 @@ TEST_F(QuicPacketBuilderTest, LongHeaderRegularPacket) {
|
||||
auto packetQueue = bufToQueue(std::move(resultBuf));
|
||||
auto optionalDecodedPacket = makeCodec(serverConnId, QuicNodeType::Server)
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_NO_THROW(boost::get<RegularQuicPacket>(optionalDecodedPacket));
|
||||
auto decodedRegularPacket =
|
||||
boost::get<RegularQuicPacket>(optionalDecodedPacket);
|
||||
ASSERT_NE(optionalDecodedPacket.regularPacket(), nullptr);
|
||||
auto& decodedRegularPacket = *optionalDecodedPacket.regularPacket();
|
||||
auto& decodedHeader = *decodedRegularPacket.header.asLong();
|
||||
EXPECT_EQ(LongHeader::Types::Initial, decodedHeader.getHeaderType());
|
||||
EXPECT_EQ(clientConnId, decodedHeader.getDestinationConnId());
|
||||
@@ -261,7 +260,7 @@ TEST_F(QuicPacketBuilderTest, ShortHeaderRegularPacket) {
|
||||
makeCodec(
|
||||
connId, QuicNodeType::Client, nullptr, quic::test::createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
auto decodedRegularPacket = boost::get<RegularQuicPacket>(parsedPacket);
|
||||
auto& decodedRegularPacket = *parsedPacket.regularPacket();
|
||||
auto& decodedHeader = *decodedRegularPacket.header.asShort();
|
||||
EXPECT_EQ(ProtectionType::KeyPhaseZero, decodedHeader.getProtectionType());
|
||||
EXPECT_EQ(connId, decodedHeader.getConnectionId());
|
||||
@@ -290,7 +289,7 @@ TEST_F(QuicPacketBuilderTest, ShortHeaderWithNoFrames) {
|
||||
makeCodec(
|
||||
connId, QuicNodeType::Client, nullptr, quic::test::createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
auto decodedPacket = boost::get<RegularQuicPacket>(&parsedPacket);
|
||||
auto decodedPacket = parsedPacket.regularPacket();
|
||||
EXPECT_EQ(decodedPacket, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,12 @@ using namespace quic;
|
||||
using namespace quic::test;
|
||||
using namespace testing;
|
||||
|
||||
bool parseSuccess(const CodecResult& result) {
|
||||
return folly::variant_match(
|
||||
result,
|
||||
[&](const RegularQuicPacket&) { return true; },
|
||||
[&](auto&) { return false; });
|
||||
bool parseSuccess(CodecResult&& result) {
|
||||
return result.regularPacket() != nullptr;
|
||||
}
|
||||
|
||||
bool isReset(const CodecResult& result) {
|
||||
return folly::variant_match(
|
||||
result,
|
||||
[](const StatelessReset&) { return true; },
|
||||
[](const auto&) { return false; });
|
||||
bool isReset(CodecResult&& result) {
|
||||
return result.statelessReset() != nullptr;
|
||||
}
|
||||
|
||||
class QuicReadCodecTest : public Test {};
|
||||
@@ -117,8 +111,9 @@ TEST_F(QuicReadCodecTest, RetryPacketTest) {
|
||||
auto packetQueue = bufToQueue(std::move(packet));
|
||||
|
||||
AckStates ackStates;
|
||||
auto retryPacket = boost::get<RegularQuicPacket>(
|
||||
makeUnencryptedCodec()->parsePacket(packetQueue, ackStates));
|
||||
auto retryPacket = *makeUnencryptedCodec()
|
||||
->parsePacket(packetQueue, ackStates)
|
||||
.regularPacket();
|
||||
|
||||
auto headerOut = *retryPacket.header.asLong();
|
||||
|
||||
@@ -181,7 +176,7 @@ TEST_F(QuicReadCodecTest, StreamWithShortHeader) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_TRUE(parseSuccess(packet));
|
||||
EXPECT_TRUE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, StreamWithShortHeaderOnlyHeader) {
|
||||
@@ -200,7 +195,7 @@ TEST_F(QuicReadCodecTest, StreamWithShortHeaderOnlyHeader) {
|
||||
auto packetQueue = bufToQueue(std::move(packetBuf));
|
||||
auto packet = makeEncryptedCodec(connId, std::move(aead))
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(parseSuccess(packet));
|
||||
EXPECT_FALSE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, PacketDecryptFail) {
|
||||
@@ -225,7 +220,7 @@ TEST_F(QuicReadCodecTest, PacketDecryptFail) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, std::move(aead))
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(parseSuccess(packet));
|
||||
EXPECT_FALSE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, ShortOneRttPacketWithZeroRttCipher) {
|
||||
@@ -247,7 +242,7 @@ TEST_F(QuicReadCodecTest, ShortOneRttPacketWithZeroRttCipher) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, nullptr, createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(parseSuccess(packet));
|
||||
EXPECT_FALSE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, ZeroRttPacketWithOneRttCipher) {
|
||||
@@ -270,7 +265,7 @@ TEST_F(QuicReadCodecTest, ZeroRttPacketWithOneRttCipher) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(parseSuccess(packet));
|
||||
EXPECT_FALSE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, ZeroRttPacketWithZeroRttCipher) {
|
||||
@@ -293,7 +288,7 @@ TEST_F(QuicReadCodecTest, ZeroRttPacketWithZeroRttCipher) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, nullptr, createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_TRUE(parseSuccess(packet));
|
||||
EXPECT_TRUE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, KeyPhaseOnePacket) {
|
||||
@@ -317,7 +312,7 @@ TEST_F(QuicReadCodecTest, KeyPhaseOnePacket) {
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = makeEncryptedCodec(connId, createNoOpAead(), createNoOpAead())
|
||||
->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(parseSuccess(packet));
|
||||
EXPECT_FALSE(parseSuccess(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, FailToDecryptLeadsToReset) {
|
||||
@@ -351,7 +346,7 @@ TEST_F(QuicReadCodecTest, FailToDecryptLeadsToReset) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = codec->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_TRUE(isReset(packet));
|
||||
EXPECT_TRUE(isReset(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, ShortPacketAutoPaddedIsReset) {
|
||||
@@ -385,7 +380,7 @@ TEST_F(QuicReadCodecTest, ShortPacketAutoPaddedIsReset) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = codec->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_TRUE(isReset(packet));
|
||||
EXPECT_TRUE(isReset(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, FailToDecryptLongHeaderNoReset) {
|
||||
@@ -418,7 +413,7 @@ TEST_F(QuicReadCodecTest, FailToDecryptLongHeaderNoReset) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = codec->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(isReset(packet));
|
||||
EXPECT_FALSE(isReset(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, FailToDecryptNoTokenNoReset) {
|
||||
@@ -449,7 +444,7 @@ TEST_F(QuicReadCodecTest, FailToDecryptNoTokenNoReset) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(packetToBuf(streamPacket));
|
||||
auto packet = codec->parsePacket(packetQueue, ackStates);
|
||||
EXPECT_FALSE(isReset(packet));
|
||||
EXPECT_FALSE(isReset(std::move(packet)));
|
||||
}
|
||||
|
||||
TEST_F(QuicReadCodecTest, TestInitialPacket) {
|
||||
@@ -478,11 +473,11 @@ TEST_F(QuicReadCodecTest, TestInitialPacket) {
|
||||
bufToQueue(packetToBufCleartext(packet, *aead, *headerCipher, packetNum));
|
||||
auto res = codec->parsePacket(packetQueue, ackStates);
|
||||
|
||||
EXPECT_NO_THROW(boost::get<RegularQuicPacket>(res));
|
||||
auto regularQuicPacket = boost::get<RegularQuicPacket>(res);
|
||||
auto regularQuicPacket = res.regularPacket();
|
||||
ASSERT_NE(regularQuicPacket, nullptr);
|
||||
|
||||
EXPECT_NE(regularQuicPacket.header.asLong(), nullptr);
|
||||
auto longPacketHeader = regularQuicPacket.header.asLong();
|
||||
EXPECT_NE(regularQuicPacket->header.asLong(), nullptr);
|
||||
auto longPacketHeader = regularQuicPacket->header.asLong();
|
||||
|
||||
EXPECT_FALSE(longPacketHeader->hasToken());
|
||||
}
|
||||
|
||||
@@ -414,6 +414,73 @@ void onServerReadData(
|
||||
}
|
||||
}
|
||||
|
||||
void handleCipherUnavailable(
|
||||
CipherUnavailable* originalData,
|
||||
QuicServerConnectionState& conn,
|
||||
size_t packetSize,
|
||||
ServerEvents::ReadData& readData) {
|
||||
if (!originalData->packet || originalData->packet->empty()) {
|
||||
VLOG(10) << "drop because no data " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kNoData);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "no_data");
|
||||
return;
|
||||
}
|
||||
if (originalData->protectionType != ProtectionType::ZeroRtt &&
|
||||
originalData->protectionType != ProtectionType::KeyPhaseZero) {
|
||||
VLOG(10) << "drop because unexpected protection level " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kUnexpectedProtectionLevel);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "unexpected_protection_level");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t combinedSize =
|
||||
(conn.pendingZeroRttData ? conn.pendingZeroRttData->size() : 0) +
|
||||
(conn.pendingOneRttData ? conn.pendingOneRttData->size() : 0);
|
||||
if (combinedSize >= conn.transportSettings.maxPacketsToBuffer) {
|
||||
VLOG(10) << "drop because max buffered " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kMaxBuffered);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "max_buffered");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& pendingData = originalData->protectionType == ProtectionType::ZeroRtt
|
||||
? conn.pendingZeroRttData
|
||||
: conn.pendingOneRttData;
|
||||
if (pendingData) {
|
||||
QUIC_TRACE(
|
||||
packet_buffered,
|
||||
conn,
|
||||
originalData->packetNum,
|
||||
originalData->protectionType,
|
||||
packetSize);
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketBuffered(
|
||||
originalData->packetNum, originalData->protectionType, packetSize);
|
||||
}
|
||||
ServerEvents::ReadData pendingReadData;
|
||||
pendingReadData.peer = readData.peer;
|
||||
pendingReadData.networkData = NetworkData(
|
||||
std::move(originalData->packet), readData.networkData.receiveTimePoint);
|
||||
pendingData->emplace_back(std::move(pendingReadData));
|
||||
VLOG(10) << "Adding pending data to "
|
||||
<< toString(originalData->protectionType)
|
||||
<< " buffer size=" << pendingData->size() << " " << conn;
|
||||
} else {
|
||||
VLOG(10) << "drop because " << toString(originalData->protectionType)
|
||||
<< " buffer no longer available " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kBufferUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "buffer_unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
void onServerReadDataFromOpen(
|
||||
QuicServerConnectionState& conn,
|
||||
ServerEvents::ReadData& readData) {
|
||||
@@ -534,95 +601,35 @@ void onServerReadDataFromOpen(
|
||||
size_t dataSize = udpData.chainLength();
|
||||
auto parsedPacket = conn.readCodec->parsePacket(udpData, conn.ackStates);
|
||||
size_t packetSize = dataSize - udpData.chainLength();
|
||||
bool parseSuccess = folly::variant_match(
|
||||
parsedPacket,
|
||||
[&](RegularQuicPacket&) { return true; },
|
||||
[&](folly::Optional<CipherUnavailable>& originalData) {
|
||||
if (!originalData.hasValue()) {
|
||||
VLOG(10) << "drop cipher unavailable, no data " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kCipherUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "cipher_unavailable");
|
||||
return false;
|
||||
}
|
||||
if (!originalData->packet || originalData->packet->empty()) {
|
||||
VLOG(10) << "drop because no data " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kNoData);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "no_data");
|
||||
return false;
|
||||
}
|
||||
if (originalData->protectionType != ProtectionType::ZeroRtt &&
|
||||
originalData->protectionType != ProtectionType::KeyPhaseZero) {
|
||||
VLOG(10) << "drop because unexpected protection level " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(
|
||||
packetSize, kUnexpectedProtectionLevel);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "unexpected_protection_level");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t combinedSize =
|
||||
(conn.pendingZeroRttData ? conn.pendingZeroRttData->size() : 0) +
|
||||
(conn.pendingOneRttData ? conn.pendingOneRttData->size() : 0);
|
||||
if (combinedSize >= conn.transportSettings.maxPacketsToBuffer) {
|
||||
VLOG(10) << "drop because max buffered " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kMaxBuffered);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "max_buffered");
|
||||
return false;
|
||||
}
|
||||
switch (parsedPacket.type()) {
|
||||
case CodecResult::Type::CIPHER_UNAVAILABLE: {
|
||||
handleCipherUnavailable(
|
||||
parsedPacket.cipherUnavailable(), conn, packetSize, readData);
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::STATELESS_RESET: {
|
||||
VLOG(10) << "drop because reset " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kReset);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "reset");
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::NOTHING: {
|
||||
VLOG(10) << "drop cipher unavailable, no data " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kCipherUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "cipher_unavailable");
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::REGULAR_PACKET:
|
||||
break;
|
||||
}
|
||||
|
||||
auto& pendingData =
|
||||
originalData->protectionType == ProtectionType::ZeroRtt
|
||||
? conn.pendingZeroRttData
|
||||
: conn.pendingOneRttData;
|
||||
if (pendingData) {
|
||||
QUIC_TRACE(
|
||||
packet_buffered,
|
||||
conn,
|
||||
originalData->packetNum,
|
||||
originalData->protectionType,
|
||||
packetSize);
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketBuffered(
|
||||
originalData->packetNum,
|
||||
originalData->protectionType,
|
||||
packetSize);
|
||||
}
|
||||
ServerEvents::ReadData pendingReadData;
|
||||
pendingReadData.peer = readData.peer;
|
||||
pendingReadData.networkData = NetworkData(
|
||||
std::move(originalData->packet),
|
||||
readData.networkData.receiveTimePoint);
|
||||
pendingData->emplace_back(std::move(pendingReadData));
|
||||
VLOG(10) << "Adding pending data to "
|
||||
<< toString(originalData->protectionType)
|
||||
<< " buffer size=" << pendingData->size() << " " << conn;
|
||||
} else {
|
||||
VLOG(10) << "drop because "
|
||||
<< toString(originalData->protectionType)
|
||||
<< " buffer no longer available " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kBufferUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "buffer_unavailable");
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[&](const auto&) {
|
||||
VLOG(10) << "drop because reset " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kReset);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "reset");
|
||||
return false;
|
||||
});
|
||||
if (!parseSuccess) {
|
||||
RegularQuicPacket* regularOptional = parsedPacket.regularPacket();
|
||||
if (!regularOptional) {
|
||||
// We were unable to parse the packet, drop for now.
|
||||
VLOG(10) << "Not able to parse QUIC packet " << conn;
|
||||
if (conn.qLogger) {
|
||||
@@ -635,8 +642,6 @@ void onServerReadDataFromOpen(
|
||||
conn.infoCallback, onPacketDropped, PacketDropReason::PARSE_ERROR);
|
||||
continue;
|
||||
}
|
||||
auto regularOptional = boost::get<RegularQuicPacket>(&parsedPacket);
|
||||
DCHECK(regularOptional);
|
||||
|
||||
auto protectionLevel = regularOptional->header.getProtectionType();
|
||||
auto encryptionLevel = protectionTypeToEncryptionLevel(protectionLevel);
|
||||
@@ -1038,26 +1043,36 @@ void onServerReadDataFromClosed(
|
||||
return;
|
||||
}
|
||||
auto parsedPacket = conn.readCodec->parsePacket(udpData, conn.ackStates);
|
||||
bool parseSuccess = folly::variant_match(
|
||||
parsedPacket,
|
||||
[&](RegularQuicPacket&) { return true; },
|
||||
[&](folly::Optional<CipherUnavailable>&) {
|
||||
VLOG(10) << "drop cipher unavailable " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kCipherUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "cipher_unavailable");
|
||||
return false;
|
||||
},
|
||||
[&](const auto&) {
|
||||
VLOG(10) << "drop because reset " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kReset);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "reset");
|
||||
return false;
|
||||
});
|
||||
if (!parseSuccess) {
|
||||
switch (parsedPacket.type()) {
|
||||
case CodecResult::Type::CIPHER_UNAVAILABLE: {
|
||||
VLOG(10) << "drop cipher unavailable " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kCipherUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "cipher_unavailable");
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::STATELESS_RESET: {
|
||||
VLOG(10) << "drop because reset " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kReset);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "reset");
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::NOTHING: {
|
||||
VLOG(10) << "drop cipher unavailable, no data " << conn;
|
||||
if (conn.qLogger) {
|
||||
conn.qLogger->addPacketDrop(packetSize, kCipherUnavailable);
|
||||
}
|
||||
QUIC_TRACE(packet_drop, conn, "cipher_unavailable");
|
||||
break;
|
||||
}
|
||||
case CodecResult::Type::REGULAR_PACKET:
|
||||
break;
|
||||
}
|
||||
auto regularOptional = parsedPacket.regularPacket();
|
||||
if (!regularOptional) {
|
||||
// We were unable to parse the packet, drop for now.
|
||||
VLOG(10) << "Not able to parse QUIC packet " << conn;
|
||||
if (conn.qLogger) {
|
||||
@@ -1069,12 +1084,8 @@ void onServerReadDataFromClosed(
|
||||
conn.infoCallback, onPacketDropped, PacketDropReason::PARSE_ERROR);
|
||||
return;
|
||||
}
|
||||
// Before we know what the protection level of the packet is, we should
|
||||
// not throw an error.
|
||||
auto regularOptional = boost::get<RegularQuicPacket>(&parsedPacket);
|
||||
DCHECK(regularOptional);
|
||||
auto& regularPacket = *regularOptional;
|
||||
|
||||
auto& regularPacket = *regularOptional;
|
||||
auto protectionLevel = regularPacket.header.getProtectionType();
|
||||
auto packetNum = regularPacket.header.getPacketSequenceNum();
|
||||
auto pnSpace = regularPacket.header.getPacketNumberSpace();
|
||||
|
||||
@@ -248,11 +248,7 @@ void QuicServerWorkerTest::testSendReset(
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(buf->clone());
|
||||
auto res = codec.parsePacket(packetQueue, ackStates);
|
||||
bool isReset = folly::variant_match(
|
||||
res,
|
||||
[](StatelessReset&) { return true; },
|
||||
[](auto&) { return false; });
|
||||
EXPECT_TRUE(isReset);
|
||||
EXPECT_NE(res.statelessReset(), nullptr);
|
||||
return buf->computeChainDataLength();
|
||||
}));
|
||||
|
||||
@@ -1715,9 +1711,7 @@ void QuicServerTest::testReset(Buf packet) {
|
||||
AckStates ackStates;
|
||||
auto packetQueue = bufToQueue(serverData->clone());
|
||||
auto res = codec.parsePacket(packetQueue, ackStates);
|
||||
bool isReset = folly::variant_match(
|
||||
res, [](StatelessReset&) { return true; }, [](auto&) { return false; });
|
||||
EXPECT_TRUE(isReset);
|
||||
EXPECT_NE(res.statelessReset(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(QuicServerTest, NetworkTestReset) {
|
||||
|
||||
@@ -188,7 +188,7 @@ bool verifyFramePresent(
|
||||
for (auto& write : socketWrites) {
|
||||
auto packetQueue = bufToQueue(write->clone());
|
||||
auto result = readCodec.parsePacket(packetQueue, ackStates);
|
||||
auto regularPacket = boost::get<RegularQuicPacket>(&result);
|
||||
auto regularPacket = result.regularPacket();
|
||||
if (!regularPacket) {
|
||||
continue;
|
||||
}
|
||||
@@ -560,8 +560,8 @@ class QuicServerTransportTest : public Test {
|
||||
AckStates ackStates;
|
||||
for (auto& serverWrite : serverWrites) {
|
||||
auto packetQueue = bufToQueue(serverWrite->clone());
|
||||
auto parsedPacket = boost::get<RegularQuicPacket>(
|
||||
clientReadCodec->parsePacket(packetQueue, ackStates));
|
||||
auto parsedPacket =
|
||||
*clientReadCodec->parsePacket(packetQueue, ackStates).regularPacket();
|
||||
for (auto& frame : all_frames<ReadCryptoFrame>(parsedPacket.frames)) {
|
||||
cryptoBuf->prependChain(frame.data->clone());
|
||||
}
|
||||
@@ -2968,7 +2968,7 @@ TEST_F(QuicUnencryptedServerTransportTest, TestWriteHandshakeAndZeroRtt) {
|
||||
for (auto& write : serverWrites) {
|
||||
auto packetQueue = bufToQueue(write->clone());
|
||||
auto result = clientCodec->parsePacket(packetQueue, ackStates);
|
||||
auto& regularPacket = boost::get<RegularQuicPacket>(result);
|
||||
auto& regularPacket = *result.regularPacket();
|
||||
ProtectionType protectionType = regularPacket.header.getProtectionType();
|
||||
bool handshakePacket = protectionType == ProtectionType::Initial ||
|
||||
protectionType == ProtectionType::Handshake;
|
||||
|
||||
Reference in New Issue
Block a user