1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-24 04:01:07 +03:00

Codec changes to support ACK_RECEIVE_TIMESTAMPS

Summary: Create a new ACK_RECEIVE_TIMESTAMPS frame, as outlined in https://www.ietf.org/archive/id/draft-smith-quic-receive-ts-00.html#name-ack_receive_timestamps-fram

Reviewed By: mjoras

Differential Revision: D37799050

fbshipit-source-id: 0157c7fa7c4e489bb310f7c9cd6c0c1877e4967f
This commit is contained in:
Sharad Jaiswal (Eng)
2022-11-16 13:02:27 -08:00
committed by Facebook GitHub Bot
parent 9ef63d6b46
commit 96abc8160d
23 changed files with 1468 additions and 185 deletions

View File

@@ -8,9 +8,13 @@
#include <quic/codec/Decode.h>
#include <folly/String.h>
#include <quic/QuicConstants.h>
#include <quic/QuicException.h>
#include <quic/codec/PacketNumber.h>
#include <quic/codec/QuicInteger.h>
#include <chrono>
#include <cstdint>
#include <sstream>
namespace {
@@ -140,11 +144,41 @@ ImmediateAckFrame decodeImmediateAckFrame(folly::io::Cursor&) {
return ImmediateAckFrame();
}
uint64_t computeAdjustedDelay(
FrameType frameType,
uint8_t exponentToUse,
folly::Optional<std::pair<uint64_t, size_t>> delay) {
// ackDelayExponentToUse is guaranteed to be less than the size of uint64_t
uint64_t delayOverflowMask = 0xFFFFFFFFFFFFFFFF;
uint8_t leftShift = (sizeof(delay->first) * 8 - exponentToUse);
DCHECK_LT(leftShift, sizeof(delayOverflowMask) * 8);
delayOverflowMask = delayOverflowMask << leftShift;
if ((delay->first & delayOverflowMask) != 0) {
throw QuicTransportException(
"Decoded delay overflows",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
frameType);
}
uint64_t adjustedDelay = delay->first << exponentToUse;
if (adjustedDelay >
static_cast<uint64_t>(
std::numeric_limits<std::chrono::microseconds::rep>::max())) {
throw QuicTransportException(
"Bad delay", quic::TransportErrorCode::FRAME_ENCODING_ERROR, frameType);
} else if (UNLIKELY(adjustedDelay > 1000 * 1000 * 1000 /* 1000s */)) {
LOG(ERROR) << "Quic recvd long ack delay=" << adjustedDelay;
adjustedDelay = 0;
}
return adjustedDelay;
}
ReadAckFrame decodeAckFrame(
folly::io::Cursor& cursor,
const PacketHeader& header,
const CodecParameters& params) {
const CodecParameters& params,
FrameType frameType) {
ReadAckFrame frame;
frame.frameType = frameType;
auto largestAckedInt = decodeQuicInteger(cursor);
if (!largestAckedInt) {
throw QuicTransportException(
@@ -182,33 +216,12 @@ ReadAckFrame decodeAckFrame(
? kDefaultAckDelayExponent
: params.peerAckDelayExponent;
DCHECK_LT(ackDelayExponentToUse, sizeof(ackDelay->first) * 8);
// ackDelayExponentToUse is guaranteed to be less than the size of uint64_t
uint64_t delayOverflowMask = 0xFFFFFFFFFFFFFFFF;
uint8_t leftShift = (sizeof(ackDelay->first) * 8 - ackDelayExponentToUse);
DCHECK_LT(leftShift, sizeof(delayOverflowMask) * 8);
delayOverflowMask = delayOverflowMask << leftShift;
if ((ackDelay->first & delayOverflowMask) != 0) {
throw QuicTransportException(
"Decoded ack delay overflows",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK);
}
uint64_t adjustedAckDelay = ackDelay->first << ackDelayExponentToUse;
if (adjustedAckDelay >
static_cast<uint64_t>(
std::numeric_limits<std::chrono::microseconds::rep>::max())) {
throw QuicTransportException(
"Bad ack delay",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK);
} else if (UNLIKELY(adjustedAckDelay > 1000 * 1000 * 1000 /* 1000s */)) {
LOG(ERROR) << "Quic recvd long ack delay=" << adjustedAckDelay;
adjustedAckDelay = 0;
}
PacketNum currentPacketNum =
nextAckedPacketLen(largestAcked, firstAckBlockLen->first);
frame.largestAcked = largestAcked;
frame.ackDelay = std::chrono::microseconds(adjustedAckDelay);
frame.ackDelay = std::chrono::microseconds(
computeAdjustedDelay(frameType, ackDelayExponentToUse, ackDelay));
frame.ackBlocks.emplace_back(currentPacketNum, largestAcked);
for (uint64_t numBlocks = 0; numBlocks < additionalAckBlocks->first;
++numBlocks) {
@@ -233,6 +246,84 @@ ReadAckFrame decodeAckFrame(
// already would have processed it in the previous iteration.
frame.ackBlocks.emplace_back(currentPacketNum, nextEndPacket);
}
return frame;
}
ReadAckFrame decodeAckFrameWithReceivedTimestamps(
folly::io::Cursor& cursor,
const PacketHeader& header,
const CodecParameters& params,
FrameType frameType) {
ReadAckFrame frame;
frame = decodeAckFrame(cursor, header, params, frameType);
auto latestRecvdPacketNum = decodeQuicInteger(cursor);
if (!latestRecvdPacketNum) {
throw QuicTransportException(
"Bad latest received packet number",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
frame.maybeLatestRecvdPacketNum = latestRecvdPacketNum->first;
auto latestRecvdPacketTimeDelta = decodeQuicInteger(cursor);
if (!latestRecvdPacketTimeDelta) {
throw QuicTransportException(
"Bad receive packet timestamp delta",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
frame.maybeLatestRecvdPacketTime =
std::chrono::microseconds(latestRecvdPacketTimeDelta->first);
auto timeStampRangeCount = decodeQuicInteger(cursor);
if (!timeStampRangeCount) {
throw QuicTransportException(
"Bad receive timestamps range count",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
for (uint64_t numRanges = 0; numRanges < timeStampRangeCount->first;
numRanges++) {
RecvdPacketsTimestampsRange timeStampRange;
auto receiveTimeStampsGap = decodeQuicInteger(cursor);
if (!receiveTimeStampsGap) {
throw QuicTransportException(
"Bad receive timestamps gap",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
timeStampRange.gap = receiveTimeStampsGap->first;
auto receiveTimeStampsLen = decodeQuicInteger(cursor);
if (!receiveTimeStampsLen) {
throw QuicTransportException(
"Bad receive timestamps block length",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
timeStampRange.timestamp_delta_count = receiveTimeStampsLen->first;
uint8_t receiveTimestampsExponentToUse =
(params.maybeAckReceiveTimestampsConfig)
? params.maybeAckReceiveTimestampsConfig.value()
.receive_timestamps_exponent
: kDefaultReceiveTimestampsExponent;
for (uint64_t i = 0; i < receiveTimeStampsLen->first; i++) {
auto delta = decodeQuicInteger(cursor);
if (!delta) {
throw QuicTransportException(
"Bad receive timestamps delta",
quic::TransportErrorCode::FRAME_ENCODING_ERROR,
quic::FrameType::ACK_RECEIVE_TIMESTAMPS);
}
DCHECK_LT(receiveTimestampsExponentToUse, sizeof(delta->first) * 8);
auto adjustedDelta = computeAdjustedDelay(
frameType, receiveTimestampsExponentToUse, delta);
timeStampRange.deltas.push_back(adjustedDelta);
}
frame.recvdPacketsTimestampRanges.emplace_back(timeStampRange);
}
return frame;
}
@@ -754,7 +845,9 @@ QuicFrame parseFrame(
};
cursor.reset(queue.front());
FrameType frameType = static_cast<FrameType>(frameTypeInt->first);
try {
try
{
switch (frameType) {
case FrameType::PADDING:
return QuicFrame(decodePaddingFrame(cursor));
@@ -842,6 +935,10 @@ QuicFrame parseFrame(
return QuicFrame(decodeAckFrequencyFrame(cursor));
case FrameType::IMMEDIATE_ACK:
return QuicFrame(decodeImmediateAckFrame(cursor));
case FrameType::ACK_RECEIVE_TIMESTAMPS:
auto frame = QuicFrame(decodeAckFrameWithReceivedTimestamps(
cursor, header, params, FrameType::ACK_RECEIVE_TIMESTAMPS));
return frame;
}
} catch (const std::exception& e) {
error = true;