1
0
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:
Subodh Iyengar
2019-09-30 17:00:11 -07:00
committed by Facebook Github Bot
parent 208ea8b425
commit 322eb2ebc4
10 changed files with 345 additions and 206 deletions

View File

@@ -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();

View File

@@ -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 =

View File

@@ -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

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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());
}

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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;