/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include #include #include #include namespace { folly::Expected nextAckedPacketGap( quic::PacketNum packetNum, uint64_t gap) noexcept { // Gap cannot overflow because of the definition of quic integer encoding, so // we can just add to gap. uint64_t adjustedGap = gap + 2; if (packetNum < adjustedGap) { return folly::makeUnexpected(quic::QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad gap")); } return packetNum - adjustedGap; } folly::Expected nextAckedPacketLen( quic::PacketNum packetNum, uint64_t ackBlockLen) noexcept { // Going to allow 0 as a valid value. if (packetNum < ackBlockLen) { return folly::makeUnexpected(quic::QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad block len")); } return packetNum - ackBlockLen; } } // namespace namespace quic { folly::Expected decodePaddingFrame( folly::io::Cursor& cursor) { // we might have multiple padding frames in sequence in the common case. // Let's consume all the padding and return 1 padding frame for everything. static_assert( static_cast(FrameType::PADDING) == 0, "Padding value is 0"); folly::ByteRange paddingBytes = cursor.peekBytes(); if (paddingBytes.size() == 0) { return PaddingFrame(); } uint8_t firstByte = paddingBytes.data()[0]; // While type can be variable length, since PADDING frame is always a 0 // byte frame, the length of the type should be 1 byte. if (static_cast(firstByte) != FrameType::PADDING) { return PaddingFrame(); } int ret = memcmp( paddingBytes.data(), paddingBytes.data() + 1, paddingBytes.size() - 1); if (ret == 0) { cursor.skip(paddingBytes.size()); } return PaddingFrame(); } folly::Expected decodePingFrame(folly::io::Cursor&) { return PingFrame(); } folly::Expected decodeKnobFrame( folly::io::Cursor& cursor) { auto knobSpace = decodeQuicInteger(cursor); if (!knobSpace) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad knob space")); } auto knobId = decodeQuicInteger(cursor); if (!knobId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad knob id")); } auto knobLen = decodeQuicInteger(cursor); if (!knobLen) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad knob len")); } Buf knobBlob; cursor.cloneAtMost(knobBlob, knobLen->first); return QuicFrame( KnobFrame(knobSpace->first, knobId->first, std::move(knobBlob))); } folly::Expected decodeAckFrequencyFrame( folly::io::Cursor& cursor) { auto sequenceNumber = decodeQuicInteger(cursor); if (!sequenceNumber) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad sequence number")); } auto packetTolerance = decodeQuicInteger(cursor); if (!packetTolerance) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad packet tolerance")); } auto updateMaxAckDelay = decodeQuicInteger(cursor); if (!updateMaxAckDelay) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad update max ack delay")); } auto reorderThreshold = decodeQuicInteger(cursor); if (!reorderThreshold) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad reorder threshold")); } AckFrequencyFrame frame; frame.sequenceNumber = sequenceNumber->first; frame.packetTolerance = packetTolerance->first; frame.updateMaxAckDelay = updateMaxAckDelay->first; frame.reorderThreshold = reorderThreshold->first; return QuicSimpleFrame(frame); } folly::Expected decodeImmediateAckFrame( folly::io::Cursor&) { return ImmediateAckFrame(); } folly::Expected convertEncodedDurationToMicroseconds( uint8_t exponentToUse, uint64_t delay) noexcept { // ackDelayExponentToUse is guaranteed to be less than the size of uint64_t uint64_t delayOverflowMask = 0xFFFFFFFFFFFFFFFF; constexpr uint8_t delayValWidth = sizeof(delay) * 8; if (exponentToUse == 0 || exponentToUse >= delayValWidth) { return delay; } uint8_t leftShift = (delayValWidth - exponentToUse); delayOverflowMask = delayOverflowMask << leftShift; if ((delay & delayOverflowMask) != 0) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Decoded delay overflows")); } uint64_t adjustedDelay = delay << exponentToUse; if (adjustedDelay > static_cast( std::numeric_limits::max())) { return folly::makeUnexpected( QuicError(quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad delay")); } return adjustedDelay; } folly::Expected decodeAckFrame( folly::io::Cursor& cursor, const PacketHeader& header, const CodecParameters& params, FrameType frameType) { ReadAckFrame frame; frame.frameType = frameType; auto largestAckedInt = decodeQuicInteger(cursor); if (!largestAckedInt) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad largest acked")); } auto largestAcked = folly::to(largestAckedInt->first); auto ackDelay = decodeQuicInteger(cursor); if (!ackDelay) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad ack delay")); } auto additionalAckBlocks = decodeQuicInteger(cursor); if (!additionalAckBlocks) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad ack block count")); } auto firstAckBlockLen = decodeQuicInteger(cursor); if (!firstAckBlockLen) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad first block")); } // Using default ack delay for long header packets. Before negotiating // and ack delay, the sender has to use something, so they use the default // ack delay. To keep it consistent the protocol specifies using the same // ack delay for all the long header packets. uint8_t ackDelayExponentToUse = (header.getHeaderForm() == HeaderForm::Long) ? kDefaultAckDelayExponent : params.peerAckDelayExponent; DCHECK_LT(ackDelayExponentToUse, sizeof(ackDelay->first) * 8); auto res = nextAckedPacketLen(largestAcked, firstAckBlockLen->first); if (res.hasError()) { return folly::makeUnexpected(res.error()); } PacketNum currentPacketNum = *res; frame.largestAcked = largestAcked; auto delayRes = convertEncodedDurationToMicroseconds( ackDelayExponentToUse, ackDelay->first); if (delayRes.hasError()) { return folly::makeUnexpected(delayRes.error()); } auto adjustedDelay = *delayRes; if (UNLIKELY(adjustedDelay > 1000 * 1000 * 1000 /* 1000s */)) { LOG(ERROR) << "Quic recvd long ack delay=" << adjustedDelay << " frame type: " << static_cast(frameType); adjustedDelay = 0; } frame.ackDelay = std::chrono::microseconds(adjustedDelay); frame.ackBlocks.emplace_back(currentPacketNum, largestAcked); for (uint64_t numBlocks = 0; numBlocks < additionalAckBlocks->first; ++numBlocks) { auto currentGap = decodeQuicInteger(cursor); if (!currentGap) { return folly::makeUnexpected( QuicError(quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad gap")); } auto blockLen = decodeQuicInteger(cursor); if (!blockLen) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad block len")); } res = nextAckedPacketGap(currentPacketNum, currentGap->first); if (res.hasError()) { return folly::makeUnexpected(res.error()); } PacketNum nextEndPacket = *res; res = nextAckedPacketLen(nextEndPacket, blockLen->first); if (res.hasError()) { return folly::makeUnexpected(res.error()); } currentPacketNum = *res; // We don't need to add the entry when the block length is zero since we // already would have processed it in the previous iteration. frame.ackBlocks.emplace_back(currentPacketNum, nextEndPacket); } return frame; } static folly::Expected decodeReceiveTimestampsInAck( ReadAckFrame& frame, folly::io::Cursor& cursor, const CodecParameters& params) { auto latestRecvdPacketNum = decodeQuicInteger(cursor); if (!latestRecvdPacketNum) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad latest received packet number")); } frame.maybeLatestRecvdPacketNum = latestRecvdPacketNum->first; auto latestRecvdPacketTimeDelta = decodeQuicInteger(cursor); if (!latestRecvdPacketTimeDelta) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad receive packet timestamp delta")); } frame.maybeLatestRecvdPacketTime = std::chrono::microseconds(latestRecvdPacketTimeDelta->first); auto timeStampRangeCount = decodeQuicInteger(cursor); if (!timeStampRangeCount) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad receive timestamps range count")); } for (uint64_t numRanges = 0; numRanges < timeStampRangeCount->first; numRanges++) { RecvdPacketsTimestampsRange timeStampRange; auto receiveTimeStampsGap = decodeQuicInteger(cursor); if (!receiveTimeStampsGap) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad receive timestamps gap")); } timeStampRange.gap = receiveTimeStampsGap->first; auto receiveTimeStampsLen = decodeQuicInteger(cursor); if (!receiveTimeStampsLen) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad receive timestamps block length")); } timeStampRange.timestamp_delta_count = receiveTimeStampsLen->first; uint8_t receiveTimestampsExponentToUse = (params.maybeAckReceiveTimestampsConfig) ? params.maybeAckReceiveTimestampsConfig.value() .receiveTimestampsExponent : kDefaultReceiveTimestampsExponent; for (uint64_t i = 0; i < receiveTimeStampsLen->first; i++) { auto delta = decodeQuicInteger(cursor); if (!delta) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad receive timestamps delta")); } DCHECK_LT(receiveTimestampsExponentToUse, sizeof(delta->first) * 8); auto res = convertEncodedDurationToMicroseconds( receiveTimestampsExponentToUse, delta->first); if (res.hasError()) { return folly::makeUnexpected(res.error()); } auto adjustedDelta = *res; timeStampRange.deltas.push_back(adjustedDelta); } frame.recvdPacketsTimestampRanges.emplace_back(timeStampRange); } return folly::unit; } static folly::Expected decodeEcnCountsInAck( ReadAckFrame& frame, folly::io::Cursor& cursor) { auto ect_0 = decodeQuicInteger(cursor); auto ect_1 = decodeQuicInteger(cursor); auto ce = decodeQuicInteger(cursor); if (!ect_0 || !ect_1 || !ce) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad ECN value")); } frame.ecnECT0Count = ect_0->first; frame.ecnECT1Count = ect_1->first; frame.ecnCECount = ce->first; return folly::unit; } folly::Expected decodeAckExtendedFrame( folly::io::Cursor& cursor, const PacketHeader& header, const CodecParameters& params) { ReadAckFrame frame; auto res = decodeAckFrame(cursor, header, params, FrameType::ACK_EXTENDED); if (res.hasError()) { return folly::makeUnexpected(res.error()); } frame = *res; auto extendedAckFeatures = decodeQuicInteger(cursor); if (!extendedAckFeatures) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad extended ACK features field")); } auto includedFeatures = extendedAckFeatures->first; if ((includedFeatures | params.extendedAckFeatures) != params.extendedAckFeatures) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Extended ACK has unexpected features")); } if (includedFeatures & static_cast( ExtendedAckFeatureMask::ECN_COUNTS)) { auto ecnResult = decodeEcnCountsInAck(frame, cursor); if (ecnResult.hasError()) { return folly::makeUnexpected(ecnResult.error()); } } if (includedFeatures & static_cast( ExtendedAckFeatureMask::RECEIVE_TIMESTAMPS)) { auto tsResult = decodeReceiveTimestampsInAck(frame, cursor, params); if (tsResult.hasError()) { return folly::makeUnexpected(tsResult.error()); } } return frame; } folly::Expected decodeAckFrameWithReceivedTimestamps( folly::io::Cursor& cursor, const PacketHeader& header, const CodecParameters& params, FrameType frameType) { ReadAckFrame frame; auto ack = decodeAckFrame(cursor, header, params, frameType); if (ack.hasError()) { return folly::makeUnexpected(ack.error()); } frame = *ack; frame.frameType = frameType; auto ts = decodeReceiveTimestampsInAck(frame, cursor, params); if (ts.hasError()) { return folly::makeUnexpected(ts.error()); } return QuicFrame(frame); } folly::Expected decodeAckFrameWithECN( folly::io::Cursor& cursor, const PacketHeader& header, const CodecParameters& params) { ReadAckFrame readAckFrame; auto ack = decodeAckFrame(cursor, header, params); if (ack.hasError()) { return folly::makeUnexpected(ack.error()); } readAckFrame = *ack; readAckFrame.frameType = FrameType::ACK_ECN; auto ecn = decodeEcnCountsInAck(readAckFrame, cursor); if (ecn.hasError()) { return folly::makeUnexpected(ecn.error()); } return QuicFrame(readAckFrame); } folly::Expected decodeRstStreamFrame( folly::io::Cursor& cursor, bool reliable) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad streamId")); } ApplicationErrorCode errorCode; auto varCode = decodeQuicInteger(cursor); if (varCode) { errorCode = static_cast(varCode->first); } else { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Cannot decode error code")); } auto finalSize = decodeQuicInteger(cursor); if (!finalSize) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad offset")); } folly::Optional> reliableSize = folly::none; if (reliable) { reliableSize = decodeQuicInteger(cursor); if (!reliableSize) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad value of reliable size")); } if (reliableSize->first > finalSize->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Reliable size is greater than final size")); } } return RstStreamFrame( folly::to(streamId->first), errorCode, finalSize->first, reliableSize ? folly::Optional(reliableSize->first) : folly::none); } folly::Expected decodeStopSendingFrame( folly::io::Cursor& cursor) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad streamId")); } ApplicationErrorCode errorCode; auto varCode = decodeQuicInteger(cursor); if (varCode) { errorCode = static_cast(varCode->first); } else { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Cannot decode error code")); } return StopSendingFrame(folly::to(streamId->first), errorCode); } folly::Expected decodeCryptoFrame( folly::io::Cursor& cursor) { auto optionalOffset = decodeQuicInteger(cursor); if (!optionalOffset) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid offset")); } uint64_t offset = optionalOffset->first; auto dataLength = decodeQuicInteger(cursor); if (!dataLength) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid length")); } Buf data; if (cursor.totalLength() < dataLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Length mismatch")); } size_t cloned = cursor.cloneAtMost(data, dataLength->first); if (cloned < dataLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to clone complete data")); } return ReadCryptoFrame(offset, std::move(data)); } folly::Expected decodeNewTokenFrame( folly::io::Cursor& cursor) { auto tokenLength = decodeQuicInteger(cursor); if (!tokenLength) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid length")); } Buf token; if (cursor.totalLength() < tokenLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Length mismatch")); } size_t cloned = cursor.cloneAtMost(token, tokenLength->first); if (cloned < tokenLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to clone token")); } return ReadNewTokenFrame(std::move(token)); } folly::Expected decodeStreamFrame( BufQueue& queue, StreamTypeField frameTypeField, bool isGroupFrame) { folly::io::Cursor cursor(queue.front()); auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid stream id")); } OptionalIntegral groupId; if (isGroupFrame) { auto gId = decodeQuicInteger(cursor); if (!gId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid group stream id")); } groupId = gId->first; } uint64_t offset = 0; if (frameTypeField.hasOffset()) { auto optionalOffset = decodeQuicInteger(cursor); if (!optionalOffset) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid offset")); } offset = optionalOffset->first; } auto fin = frameTypeField.hasFin(); Optional> dataLength; if (frameTypeField.hasDataLength()) { dataLength = decodeQuicInteger(cursor); if (!dataLength) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid length")); } } Buf data; // Calculate how much to trim from the start of the queue size_t trimAmount = cursor - queue.front(); if (trimAmount > 0) { size_t trimmed = queue.trimStartAtMost(trimAmount); if (trimmed < trimAmount) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to trim queue")); } } if (dataLength.has_value()) { if (queue.chainLength() < dataLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Length mismatch")); } data = queue.splitAtMost(dataLength->first); if (!data || data->computeChainDataLength() < dataLength->first) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to extract data")); } } else { // Missing Data Length field doesn't mean no data. It means the rest of the // frame are all data. data = queue.move(); if (!data) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to extract data")); } } return ReadStreamFrame( folly::to(streamId->first), offset, std::move(data), fin, groupId); } folly::Expected decodeMaxDataFrame( folly::io::Cursor& cursor) { auto maximumData = decodeQuicInteger(cursor); if (!maximumData) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad Max Data")); } return MaxDataFrame(maximumData->first); } folly::Expected decodeMaxStreamDataFrame( folly::io::Cursor& cursor) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid streamId")); } auto offset = decodeQuicInteger(cursor); if (!offset) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid offset")); } return MaxStreamDataFrame( folly::to(streamId->first), offset->first); } folly::Expected decodeBiDiMaxStreamsFrame( folly::io::Cursor& cursor) { auto streamCount = decodeQuicInteger(cursor); if (!streamCount || streamCount->first > kMaxMaxStreams) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid Bi-directional streamId")); } return MaxStreamsFrame(streamCount->first, true /* isBidirectional*/); } folly::Expected decodeUniMaxStreamsFrame( folly::io::Cursor& cursor) { auto streamCount = decodeQuicInteger(cursor); if (!streamCount || streamCount->first > kMaxMaxStreams) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid Uni-directional streamId")); } return MaxStreamsFrame(streamCount->first, false /* isUnidirectional */); } folly::Expected decodeDataBlockedFrame( folly::io::Cursor& cursor) { auto dataLimit = decodeQuicInteger(cursor); if (!dataLimit) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad offset")); } return DataBlockedFrame(dataLimit->first); } folly::Expected decodeStreamDataBlockedFrame( folly::io::Cursor& cursor) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad streamId")); } auto dataLimit = decodeQuicInteger(cursor); if (!dataLimit) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad offset")); } return StreamDataBlockedFrame( folly::to(streamId->first), dataLimit->first); } folly::Expected decodeBiDiStreamsBlockedFrame( folly::io::Cursor& cursor) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad Bi-Directional streamId")); } return StreamsBlockedFrame( folly::to(streamId->first), true /* isBidirectional */); } folly::Expected decodeUniStreamsBlockedFrame( folly::io::Cursor& cursor) { auto streamId = decodeQuicInteger(cursor); if (!streamId) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad Uni-direcitonal streamId")); } return StreamsBlockedFrame( folly::to(streamId->first), false /* isBidirectional */); } folly::Expected decodeNewConnectionIdFrame( folly::io::Cursor& cursor) { auto sequenceNumber = decodeQuicInteger(cursor); if (!sequenceNumber) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad sequence")); } auto retirePriorTo = decodeQuicInteger(cursor); if (!retirePriorTo) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad retire prior to")); } if (!cursor.canAdvance(sizeof(uint8_t))) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Not enough input bytes to read Dest. ConnectionId")); } auto connIdLen = cursor.readBE(); if (cursor.totalLength() < connIdLen) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad connid")); } if (connIdLen > kMaxConnectionIdSize) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "ConnectionId invalid length")); } ConnectionId connId(cursor, connIdLen); StatelessResetToken statelessResetToken; size_t bytesRead = cursor.pullAtMost(statelessResetToken.data(), statelessResetToken.size()); if (bytesRead < statelessResetToken.size()) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to read StatelessResetToken")); } return NewConnectionIdFrame( sequenceNumber->first, retirePriorTo->first, std::move(connId), std::move(statelessResetToken)); } folly::Expected decodeRetireConnectionIdFrame(folly::io::Cursor& cursor) { auto sequenceNum = decodeQuicInteger(cursor); if (!sequenceNum) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad sequence num")); } return RetireConnectionIdFrame(sequenceNum->first); } folly::Expected decodePathChallengeFrame( folly::io::Cursor& cursor) { if (!cursor.canAdvance(sizeof(uint64_t))) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Not enough input bytes to read path challenge frame.")); } auto pathData = cursor.readBE(); return PathChallengeFrame(pathData); } folly::Expected decodePathResponseFrame( folly::io::Cursor& cursor) { if (!cursor.canAdvance(sizeof(uint64_t))) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Not enough input bytes to read path response frame.")); } auto pathData = cursor.readBE(); return PathResponseFrame(pathData); } folly::Expected decodeConnectionCloseFrame( folly::io::Cursor& cursor) { TransportErrorCode errorCode{}; auto varCode = decodeQuicInteger(cursor); if (!varCode) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to parse error code.")); } errorCode = static_cast(varCode->first); auto frameTypeField = decodeQuicInteger(cursor); if (!frameTypeField || frameTypeField->second != sizeof(uint8_t)) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad connection close triggering frame type value")); } FrameType triggeringFrameType = static_cast(frameTypeField->first); auto reasonPhraseLength = decodeQuicInteger(cursor); if (!reasonPhraseLength || reasonPhraseLength->first > kMaxReasonPhraseLength) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad reason phrase length")); } std::string reasonPhrase; size_t len = static_cast(reasonPhraseLength->first); auto bytes = cursor.peekBytes(); size_t available = std::min(bytes.size(), len); reasonPhrase.append(reinterpret_cast(bytes.data()), available); cursor.skip(available); return ConnectionCloseFrame( QuicErrorCode(errorCode), std::move(reasonPhrase), triggeringFrameType); } folly::Expected decodeApplicationClose( folly::io::Cursor& cursor) { ApplicationErrorCode errorCode{}; auto varCode = decodeQuicInteger(cursor); if (!varCode) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Failed to parse error code.")); } errorCode = static_cast(varCode->first); auto reasonPhraseLength = decodeQuicInteger(cursor); if (!reasonPhraseLength || reasonPhraseLength->first > kMaxReasonPhraseLength) { return folly::makeUnexpected(QuicError( quic::TransportErrorCode::FRAME_ENCODING_ERROR, "Bad reason phrase length")); } std::string reasonPhrase; size_t len = static_cast(reasonPhraseLength->first); auto bytes = cursor.peekBytes(); size_t available = std::min(bytes.size(), len); reasonPhrase.append(reinterpret_cast(bytes.data()), available); cursor.skip(available); return ConnectionCloseFrame( QuicErrorCode(errorCode), std::move(reasonPhrase)); } folly::Expected decodeHandshakeDoneFrame( folly::io::Cursor& /*cursor*/) { return HandshakeDoneFrame(); } /** * Both retry and new tokens have the same plaintext encoding: timestamp. We * differentiate tokens based on the success of decrypting with differing aead * associated data. */ folly::Expected parsePlaintextRetryOrNewToken( folly::io::Cursor& cursor) { // Read in the timestamp if (!cursor.canAdvance(sizeof(uint64_t))) { return folly::makeUnexpected(TransportErrorCode::INVALID_TOKEN); } auto timestampInMs = cursor.readBE(); return timestampInMs; } folly::Expected decodeDatagramFrame( BufQueue& queue, bool hasLen) { folly::io::Cursor cursor(queue.front()); size_t length = cursor.length(); if (hasLen) { auto decodeLength = decodeQuicInteger(cursor); if (!decodeLength) { return folly::makeUnexpected(QuicError( TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid datagram len")); } length = decodeLength->first; if (cursor.length() < length) { return folly::makeUnexpected(QuicError( TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid datagram frame")); } queue.trimStart(decodeLength->second); } return DatagramFrame(length, queue.splitAtMost(length)); } folly::Expected parseFrame( BufQueue& queue, const PacketHeader& header, const CodecParameters& params) { folly::io::Cursor cursor(queue.front()); auto frameTypeInt = decodeQuicInteger(cursor); if (!frameTypeInt) { return folly::makeUnexpected(QuicError( TransportErrorCode::FRAME_ENCODING_ERROR, "Invalid frame-type field")); } queue.trimStart(cursor - queue.front()); cursor.reset(queue.front()); FrameType frameType = static_cast(frameTypeInt->first); // No more try/catch, just use Expected/makeUnexpected pattern switch (frameType) { case FrameType::PADDING: { auto paddingRes = decodePaddingFrame(cursor); if (!paddingRes.hasValue()) { return folly::makeUnexpected(paddingRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*paddingRes); } case FrameType::PING: { auto pingRes = decodePingFrame(cursor); if (!pingRes.hasValue()) { return folly::makeUnexpected(pingRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*pingRes); } case FrameType::ACK: { auto ackFrameRes = decodeAckFrame(cursor, header, params); if (ackFrameRes.hasError()) { return ackFrameRes; } queue.trimStart(cursor - queue.front()); return ackFrameRes; } case FrameType::ACK_ECN: { auto ackFrameWithEcnRes = decodeAckFrameWithECN(cursor, header, params); if (ackFrameWithEcnRes.hasError()) { return ackFrameWithEcnRes; } queue.trimStart(cursor - queue.front()); return ackFrameWithEcnRes; } case FrameType::RST_STREAM: case FrameType::RST_STREAM_AT: { auto rstRes = decodeRstStreamFrame(cursor, frameType == FrameType::RST_STREAM_AT); if (!rstRes.hasValue()) { return folly::makeUnexpected(rstRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*rstRes); } case FrameType::STOP_SENDING: { auto stopRes = decodeStopSendingFrame(cursor); if (!stopRes.hasValue()) { return folly::makeUnexpected(stopRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*stopRes); } case FrameType::CRYPTO_FRAME: { auto cryptoRes = decodeCryptoFrame(cursor); if (!cryptoRes.hasValue()) { return folly::makeUnexpected(cryptoRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*cryptoRes); } case FrameType::NEW_TOKEN: { auto tokenRes = decodeNewTokenFrame(cursor); if (!tokenRes.hasValue()) { return folly::makeUnexpected(tokenRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*tokenRes); } case FrameType::STREAM: case FrameType::STREAM_FIN: case FrameType::STREAM_LEN: case FrameType::STREAM_LEN_FIN: case FrameType::STREAM_OFF: case FrameType::STREAM_OFF_FIN: case FrameType::STREAM_OFF_LEN: case FrameType::STREAM_OFF_LEN_FIN: { auto streamRes = decodeStreamFrame( queue, StreamTypeField(frameTypeInt->first), false /* isGroupFrame */); if (!streamRes.hasValue()) { return folly::makeUnexpected(streamRes.error()); } return QuicFrame(*streamRes); } case FrameType::GROUP_STREAM: case FrameType::GROUP_STREAM_FIN: case FrameType::GROUP_STREAM_LEN: case FrameType::GROUP_STREAM_LEN_FIN: case FrameType::GROUP_STREAM_OFF: case FrameType::GROUP_STREAM_OFF_FIN: case FrameType::GROUP_STREAM_OFF_LEN: case FrameType::GROUP_STREAM_OFF_LEN_FIN: { auto streamRes = decodeStreamFrame( queue, StreamTypeField(frameTypeInt->first), true /* isGroupFrame */); if (!streamRes.hasValue()) { return folly::makeUnexpected(streamRes.error()); } return QuicFrame(*streamRes); } case FrameType::MAX_DATA: { auto maxDataRes = decodeMaxDataFrame(cursor); if (!maxDataRes.hasValue()) { return folly::makeUnexpected(maxDataRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*maxDataRes); } case FrameType::MAX_STREAM_DATA: { auto maxStreamRes = decodeMaxStreamDataFrame(cursor); if (!maxStreamRes.hasValue()) { return folly::makeUnexpected(maxStreamRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*maxStreamRes); } case FrameType::MAX_STREAMS_BIDI: { auto streamsBidiRes = decodeBiDiMaxStreamsFrame(cursor); if (!streamsBidiRes.hasValue()) { return folly::makeUnexpected(streamsBidiRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*streamsBidiRes); } case FrameType::MAX_STREAMS_UNI: { auto streamsUniRes = decodeUniMaxStreamsFrame(cursor); if (!streamsUniRes.hasValue()) { return folly::makeUnexpected(streamsUniRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*streamsUniRes); } case FrameType::DATA_BLOCKED: { auto blockedRes = decodeDataBlockedFrame(cursor); if (!blockedRes.hasValue()) { return folly::makeUnexpected(blockedRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*blockedRes); } case FrameType::STREAM_DATA_BLOCKED: { auto streamBlockedRes = decodeStreamDataBlockedFrame(cursor); if (!streamBlockedRes.hasValue()) { return folly::makeUnexpected(streamBlockedRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*streamBlockedRes); } case FrameType::STREAMS_BLOCKED_BIDI: { auto streamsBidiBlockedRes = decodeBiDiStreamsBlockedFrame(cursor); if (!streamsBidiBlockedRes.hasValue()) { return folly::makeUnexpected(streamsBidiBlockedRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*streamsBidiBlockedRes); } case FrameType::STREAMS_BLOCKED_UNI: { auto streamsUniBlockedRes = decodeUniStreamsBlockedFrame(cursor); if (!streamsUniBlockedRes.hasValue()) { return folly::makeUnexpected(streamsUniBlockedRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*streamsUniBlockedRes); } case FrameType::NEW_CONNECTION_ID: { auto newConnIdRes = decodeNewConnectionIdFrame(cursor); if (!newConnIdRes.hasValue()) { return folly::makeUnexpected(newConnIdRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*newConnIdRes); } case FrameType::RETIRE_CONNECTION_ID: { auto retireConnIdRes = decodeRetireConnectionIdFrame(cursor); if (!retireConnIdRes.hasValue()) { return folly::makeUnexpected(retireConnIdRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*retireConnIdRes); } case FrameType::PATH_CHALLENGE: { auto pathChallengeRes = decodePathChallengeFrame(cursor); if (!pathChallengeRes.hasValue()) { return folly::makeUnexpected(pathChallengeRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*pathChallengeRes); } case FrameType::PATH_RESPONSE: { auto pathResponseRes = decodePathResponseFrame(cursor); if (!pathResponseRes.hasValue()) { return folly::makeUnexpected(pathResponseRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*pathResponseRes); } case FrameType::CONNECTION_CLOSE: { auto connCloseRes = decodeConnectionCloseFrame(cursor); if (!connCloseRes.hasValue()) { return folly::makeUnexpected(connCloseRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*connCloseRes); } case FrameType::CONNECTION_CLOSE_APP_ERR: { auto appCloseRes = decodeApplicationClose(cursor); if (!appCloseRes.hasValue()) { return folly::makeUnexpected(appCloseRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*appCloseRes); } case FrameType::HANDSHAKE_DONE: { auto handshakeDoneRes = decodeHandshakeDoneFrame(cursor); if (!handshakeDoneRes.hasValue()) { return folly::makeUnexpected(handshakeDoneRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*handshakeDoneRes); } case FrameType::DATAGRAM: { auto datagramRes = decodeDatagramFrame(queue, false /* hasLen */); if (!datagramRes.hasValue()) { return folly::makeUnexpected(datagramRes.error()); } return QuicFrame(*datagramRes); } case FrameType::DATAGRAM_LEN: { auto datagramRes = decodeDatagramFrame(queue, true /* hasLen */); if (!datagramRes.hasValue()) { return folly::makeUnexpected(datagramRes.error()); } return QuicFrame(*datagramRes); } case FrameType::KNOB: { auto knobRes = decodeKnobFrame(cursor); if (knobRes.hasError()) { return knobRes; } queue.trimStart(cursor - queue.front()); return QuicFrame(*knobRes); } case FrameType::ACK_FREQUENCY: { auto ackFreqRes = decodeAckFrequencyFrame(cursor); if (!ackFreqRes.hasValue()) { return folly::makeUnexpected(ackFreqRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*ackFreqRes); } case FrameType::IMMEDIATE_ACK: { auto immediateAckRes = decodeImmediateAckFrame(cursor); if (!immediateAckRes.hasValue()) { return folly::makeUnexpected(immediateAckRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*immediateAckRes); } case FrameType::ACK_RECEIVE_TIMESTAMPS: { auto ackWithReceiveTiemstampsRes = decodeAckFrameWithReceivedTimestamps( cursor, header, params, FrameType::ACK_RECEIVE_TIMESTAMPS); if (ackWithReceiveTiemstampsRes.hasError()) { return ackWithReceiveTiemstampsRes; } queue.trimStart(cursor - queue.front()); return ackWithReceiveTiemstampsRes; } case FrameType::ACK_EXTENDED: { auto ackExtRes = decodeAckExtendedFrame(cursor, header, params); if (!ackExtRes.hasValue()) { return folly::makeUnexpected(ackExtRes.error()); } queue.trimStart(cursor - queue.front()); return QuicFrame(*ackExtRes); } } return folly::makeUnexpected(QuicError( TransportErrorCode::FRAME_ENCODING_ERROR, folly::to("Unknown frame, type=", frameTypeInt->first))); } // Parse packet folly::Expected decodeRegularPacket( PacketHeader&& header, const CodecParameters& params, Buf packetData) { RegularQuicPacket packet(std::move(header)); BufQueue queue; queue.append(std::move(packetData)); if (UNLIKELY(queue.chainLength() == 0)) { return packet; } // Parse out one packet before any conditionals. auto frameRes = parseFrame(queue, packet.header, params); if (!frameRes.hasValue()) { return folly::makeUnexpected(frameRes.error()); } packet.frames.push_back(std::move(*frameRes)); while (queue.chainLength() > 0) { auto fRes = parseFrame(queue, packet.header, params); if (!fRes.hasValue()) { return folly::makeUnexpected(fRes.error()); } if (packet.frames.back().asPaddingFrame() && fRes->asPaddingFrame()) { packet.frames.back().asPaddingFrame()->numFrames++; } else { packet.frames.push_back(std::move(*fRes)); } } return packet; } Optional decodeVersionNegotiation( const ParsedLongHeaderInvariant& longHeaderInvariant, folly::io::Cursor& cursor) { auto cursorLength = cursor.totalLength(); if (cursorLength < sizeof(QuicVersionType) || cursorLength % sizeof(QuicVersionType)) { VLOG(4) << "Version negotiation packet invalid"; return none; } VersionNegotiationPacket packet( longHeaderInvariant.initialByte, longHeaderInvariant.invariant.srcConnId, longHeaderInvariant.invariant.dstConnId); while (!cursor.isAtEnd()) { packet.versions.push_back( static_cast(cursor.readBE())); } return packet; } ParsedLongHeaderResult::ParsedLongHeaderResult( bool isVersionNegotiationIn, Optional parsedLongHeaderIn) : isVersionNegotiation(isVersionNegotiationIn), parsedLongHeader(std::move(parsedLongHeaderIn)) { CHECK(isVersionNegotiation || parsedLongHeader); } ParsedLongHeaderInvariant::ParsedLongHeaderInvariant( uint8_t initialByteIn, LongHeaderInvariant headerInvariant, size_t length) : initialByte(initialByteIn), invariant(std::move(headerInvariant)), invariantLength(length) {} folly::Expected parseLongHeaderInvariant(uint8_t initialByte, folly::io::Cursor& cursor) { size_t initialLength = cursor.totalLength(); if (!cursor.canAdvance(sizeof(QuicVersionType))) { VLOG(5) << "Not enough input bytes to read Version or connection-id"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } auto version = static_cast(cursor.readBE()); if (!cursor.canAdvance(1)) { VLOG(5) << "Not enough input bytes to read Dest. ConnectionId length"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } uint8_t destConnIdLen = cursor.readBE(); if (destConnIdLen > kMaxConnectionIdSize) { VLOG(5) << "destConnIdLen > kMaxConnectionIdSize: " << destConnIdLen; return folly::makeUnexpected(TransportErrorCode::PROTOCOL_VIOLATION); } if (!cursor.canAdvance(destConnIdLen)) { VLOG(5) << "Not enough input bytes to read Dest. ConnectionId"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } ConnectionId destConnId(cursor, destConnIdLen); if (!cursor.canAdvance(1)) { VLOG(5) << "Not enough input bytes to read Source ConnectionId length"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } uint8_t srcConnIdLen = cursor.readBE(); if (srcConnIdLen > kMaxConnectionIdSize) { VLOG(5) << "srcConnIdLen > kMaxConnectionIdSize: " << srcConnIdLen; return folly::makeUnexpected(TransportErrorCode::PROTOCOL_VIOLATION); } if (!cursor.canAdvance(srcConnIdLen)) { VLOG(5) << "Not enough input bytes to read Source ConnectionId"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } ConnectionId srcConnId(cursor, srcConnIdLen); size_t currentLength = cursor.totalLength(); size_t bytesRead = initialLength - currentLength; return ParsedLongHeaderInvariant( initialByte, LongHeaderInvariant(version, std::move(srcConnId), std::move(destConnId)), bytesRead); } LongHeader::Types parseLongHeaderType(uint8_t initialByte) { return static_cast( (initialByte & LongHeader::kPacketTypeMask) >> LongHeader::kTypeShift); } size_t parsePacketNumberLength(uint8_t initialByte) { static_assert( LongHeader::kPacketNumLenMask == ShortHeader::kPacketNumLenMask, "Expected both pn masks are the same"); return (initialByte & LongHeader::kPacketNumLenMask) + 1; } /** * Returns the packet number and the length of the packet number */ std::pair parsePacketNumber( uint8_t initialByte, folly::ByteRange packetNumberRange, PacketNum expectedNextPacketNum) { size_t packetNumLen = parsePacketNumberLength(initialByte); uint32_t encodedPacketNum = 0; memcpy( reinterpret_cast(&encodedPacketNum) + sizeof(uint32_t) - packetNumLen, packetNumberRange.data(), packetNumLen); uint32_t bigEncodedPacketNum = folly::Endian::big(encodedPacketNum); return std::make_pair( decodePacketNumber( bigEncodedPacketNum, packetNumLen, expectedNextPacketNum), packetNumLen); } folly::Expected parseLongHeader( uint8_t initialByte, folly::io::Cursor& cursor) { if (getHeaderForm(initialByte) != HeaderForm::Long) { VLOG(5) << "Bad header form bit"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } LongHeader::Types type = parseLongHeaderType(initialByte); switch (type) { case LongHeader::Types::Initial: case LongHeader::Types::Retry: case LongHeader::Types::Handshake: case LongHeader::Types::ZeroRtt: break; default: return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } auto parsedLongHeaderInvariant = parseLongHeaderInvariant(initialByte, cursor); if (!parsedLongHeaderInvariant) { VLOG(5) << "Bad invariants fields in long header"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } auto version = parsedLongHeaderInvariant->invariant.version; if (version == QuicVersion::VERSION_NEGOTIATION) { return ParsedLongHeaderResult(true, none); } auto parsedHeader = parseLongHeaderVariants( type, std::move(*parsedLongHeaderInvariant), cursor); if (!parsedHeader) { return folly::makeUnexpected(parsedHeader.error()); } return ParsedLongHeaderResult(false, std::move(*parsedHeader)); } folly::Expected parseLongHeaderVariants( LongHeader::Types type, ParsedLongHeaderInvariant parsedLongHeaderInvariant, folly::io::Cursor& cursor, QuicNodeType nodeType) { if (type == LongHeader::Types::Retry) { // The integrity tag is kRetryIntegrityTagLen bytes in length, and the // token must be at least one byte, so the remaining length must // be > kRetryIntegrityTagLen. if (cursor.totalLength() <= kRetryIntegrityTagLen) { VLOG(5) << "Not enough bytes for retry token"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } Buf token; cursor.clone(token, cursor.totalLength() - kRetryIntegrityTagLen); return ParsedLongHeader( LongHeader( type, std::move(parsedLongHeaderInvariant.invariant), token ? token->to() : std::string()), PacketLength(0, 0)); } // TODO Checking kMinInitialDestinationConnIdLength isn't necessary // if this packet is in response to a retry. if (type == LongHeader::Types::Initial && nodeType == QuicNodeType::Server && parsedLongHeaderInvariant.invariant.dstConnId.size() < kMinInitialDestinationConnIdLength) { VLOG(5) << "Dest Conn-Id length in client initial packet must be >= 8 bytes."; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } Buf token; if (type == LongHeader::Types::Initial) { auto tokenLen = decodeQuicInteger(cursor); if (!tokenLen) { VLOG(5) << "Token len not found in Long header"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (!cursor.canAdvance(tokenLen->first)) { VLOG(5) << "Not enough input bytes to read input token"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (tokenLen->first > 0) { Buf tokenBuf; // If tokenLen > token's actual length then the cursor will throw. cursor.clone(tokenBuf, tokenLen->first); token = std::move(tokenBuf); } } auto pktLen = decodeQuicInteger(cursor); if (!pktLen) { VLOG(5) << "Packet len not found in Long header"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (!cursor.canAdvance(pktLen->first)) { VLOG(5) << "Not enough input bytes to read packet number"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } size_t packetNumLen = parsePacketNumberLength(parsedLongHeaderInvariant.initialByte); if (!cursor.canAdvance(packetNumLen)) { return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (packetNumLen > kMaxPacketNumEncodingSize) { return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } return ParsedLongHeader( LongHeader( type, std::move(parsedLongHeaderInvariant.invariant), token ? token->to() : std::string()), PacketLength(pktLen->first, pktLen->second)); } folly::Expected parseShortHeaderInvariants( uint8_t initialByte, folly::io::Cursor& cursor, size_t dstConnIdSize) { if (getHeaderForm(initialByte) != HeaderForm::Short) { VLOG(5) << "Bad header form bit"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } // TODO(t39154014, yangchi): read the length from the connection state in // draft-17 if (dstConnIdSize > kMaxConnectionIdSize) { VLOG(5) << "dstConnIdSize > kMaxConnectionIdSize: " << dstConnIdSize; return folly::makeUnexpected(TransportErrorCode::PROTOCOL_VIOLATION); } if (!cursor.canAdvance(dstConnIdSize)) { VLOG(5) << "Not enough input bytes for ConnectionId"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } ConnectionId connId(cursor, dstConnIdSize); return ShortHeaderInvariant(std::move(connId)); } folly::Expected parseShortHeader( uint8_t initialByte, folly::io::Cursor& cursor, size_t dstConnIdSize) { if (getHeaderForm(initialByte) != HeaderForm::Short) { VLOG(5) << "Bad header form bit"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (!(initialByte & ShortHeader::kFixedBitMask)) { VLOG(5) << "Fixed bit in ShortHeader is 0"; // Specs doesn't say which error code to use return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } if (initialByte & ShortHeader::kReservedBitsMask) { VLOG(5) << "Non-zero reserved bits in ShortHeader"; // Specs asks this to be PROTOCOL_VIOLATION return folly::makeUnexpected(TransportErrorCode::PROTOCOL_VIOLATION); } auto invariant = parseShortHeaderInvariants(initialByte, cursor, dstConnIdSize); if (!invariant) { VLOG(5) << "Error parsing short header invariant"; return folly::makeUnexpected(TransportErrorCode::FRAME_ENCODING_ERROR); } auto protectionType = initialByte & ShortHeader::kKeyPhaseMask ? ProtectionType::KeyPhaseOne : ProtectionType::KeyPhaseZero; return ShortHeader(protectionType, std::move(invariant->destinationConnId)); } } // namespace quic