mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-11-09 10:00:57 +03:00
Add received packets timestamps to AckState
Summary: Store timestamps/packet numbers of recently received packets in AckState. - The maximum number of packets stored is controlled by kMaxReceivedPktsTimestampsStored. - The packet number of entries in the deque is guarenteed to increase monotonically because an entry is only added for a received packet if the packet number is greater than the packet number of the last element in the deque (e.g., entries are not added for packets that arrive out of order relative to previously received packets). Reviewed By: bschlinker Differential Revision: D37799023 fbshipit-source-id: 3b6bf2ba8ea15219a87bbdc2724fe23eebe66b70
This commit is contained in:
committed by
Facebook GitHub Bot
parent
650773ed59
commit
328c78d0e2
@@ -721,4 +721,7 @@ constexpr size_t kShortHeaderPaddingModulo = 32;
|
|||||||
// Custom transport param enabling stream groups support.
|
// Custom transport param enabling stream groups support.
|
||||||
constexpr uint16_t kStreamGroupsEnabledCustomParamId = 0xFF99;
|
constexpr uint16_t kStreamGroupsEnabledCustomParamId = 0xFF99;
|
||||||
|
|
||||||
|
// Maximum packet receive timestamps stored.
|
||||||
|
constexpr uint8_t kMaxReceivedPktsTimestampsStored = 5;
|
||||||
|
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
|||||||
@@ -185,25 +185,25 @@ CodecResult QuicReadCodec::parseLongHeaderPacket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
PacketNum expectedNextPacketNum = 0;
|
PacketNum expectedNextPacketNum = 0;
|
||||||
folly::Optional<PacketNum> largestReceivedPacketNum;
|
folly::Optional<PacketNum> largestRecvdPacketNum;
|
||||||
switch (longHeaderTypeToProtectionType(type)) {
|
switch (longHeaderTypeToProtectionType(type)) {
|
||||||
case ProtectionType::Initial:
|
case ProtectionType::Initial:
|
||||||
largestReceivedPacketNum =
|
largestRecvdPacketNum = ackStates.initialAckState.largestRecvdPacketNum;
|
||||||
ackStates.initialAckState.largestReceivedPacketNum;
|
|
||||||
break;
|
break;
|
||||||
case ProtectionType::Handshake:
|
case ProtectionType::Handshake:
|
||||||
largestReceivedPacketNum =
|
largestRecvdPacketNum = ackStates.handshakeAckState.largestRecvdPacketNum;
|
||||||
ackStates.handshakeAckState.largestReceivedPacketNum;
|
|
||||||
break;
|
break;
|
||||||
case ProtectionType::ZeroRtt:
|
case ProtectionType::ZeroRtt:
|
||||||
largestReceivedPacketNum =
|
largestRecvdPacketNum = ackStates.appDataAckState.largestRecvdPacketNum;
|
||||||
ackStates.appDataAckState.largestReceivedPacketNum;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
folly::assume_unreachable();
|
folly::assume_unreachable();
|
||||||
}
|
}
|
||||||
if (largestReceivedPacketNum) {
|
if (largestRecvdPacketNum) {
|
||||||
expectedNextPacketNum = 1 + *largestReceivedPacketNum;
|
expectedNextPacketNum = 1 + *largestRecvdPacketNum;
|
||||||
}
|
}
|
||||||
folly::MutableByteRange initialByteRange(
|
folly::MutableByteRange initialByteRange(
|
||||||
currentPacketData->writableData(), 1);
|
currentPacketData->writableData(), 1);
|
||||||
@@ -259,8 +259,8 @@ CodecResult QuicReadCodec::tryParseShortHeaderPacket(
|
|||||||
// TODO: allow other connid lengths from the state.
|
// TODO: allow other connid lengths from the state.
|
||||||
size_t packetNumberOffset = 1 + dstConnIdSize;
|
size_t packetNumberOffset = 1 + dstConnIdSize;
|
||||||
PacketNum expectedNextPacketNum =
|
PacketNum expectedNextPacketNum =
|
||||||
ackStates.appDataAckState.largestReceivedPacketNum
|
ackStates.appDataAckState.largestRecvdPacketNum
|
||||||
? (1 + *ackStates.appDataAckState.largestReceivedPacketNum)
|
? (1 + *ackStates.appDataAckState.largestRecvdPacketNum)
|
||||||
: 0;
|
: 0;
|
||||||
size_t sampleOffset = packetNumberOffset + kMaxPacketNumEncodingSize;
|
size_t sampleOffset = packetNumberOffset + kMaxPacketNumEncodingSize;
|
||||||
Sample sample;
|
Sample sample;
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ template <class T>
|
|||||||
using IntervalSetVec = SmallVec<T, kNumInitialAckBlocksPerFrame>;
|
using IntervalSetVec = SmallVec<T, kNumInitialAckBlocksPerFrame>;
|
||||||
using AckBlocks = IntervalSet<PacketNum, 1, IntervalSetVec>;
|
using AckBlocks = IntervalSet<PacketNum, 1, IntervalSetVec>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info stored on receipt of a packet for use in subsequent ACK.
|
||||||
|
*/
|
||||||
|
struct RecvdPacketInfo {
|
||||||
|
PacketNum pktNum;
|
||||||
|
TimePoint timeStamp;
|
||||||
|
};
|
||||||
|
|
||||||
struct PaddingFrame {
|
struct PaddingFrame {
|
||||||
bool operator==(const PaddingFrame& /*rhs*/) const {
|
bool operator==(const PaddingFrame& /*rhs*/) const {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ struct CircularDeque {
|
|||||||
|
|
||||||
~CircularDeque() {
|
~CircularDeque() {
|
||||||
if (capacity_ == 0) {
|
if (capacity_ == 0) {
|
||||||
DCHECK_EQ(storage_, nullptr);
|
DCHECK(!storage_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clear();
|
clear();
|
||||||
|
|||||||
@@ -5722,9 +5722,9 @@ TEST_P(QuicProcessDataTest, ProcessDataHeaderOnly) {
|
|||||||
auto serverHello = IOBuf::copyBuffer("Fake SHLO");
|
auto serverHello = IOBuf::copyBuffer("Fake SHLO");
|
||||||
PacketNum nextPacketNum = initialPacketNum++;
|
PacketNum nextPacketNum = initialPacketNum++;
|
||||||
auto& aead = getInitialCipher();
|
auto& aead = getInitialCipher();
|
||||||
auto largestReceivedPacketNum =
|
auto largestRecvdPacketNum =
|
||||||
getAckState(client->getConn(), PacketNumberSpace::Handshake)
|
getAckState(client->getConn(), PacketNumberSpace::Handshake)
|
||||||
.largestReceivedPacketNum;
|
.largestRecvdPacketNum;
|
||||||
auto packet = createCryptoPacket(
|
auto packet = createCryptoPacket(
|
||||||
*serverChosenConnId,
|
*serverChosenConnId,
|
||||||
*originalConnId,
|
*originalConnId,
|
||||||
@@ -5738,8 +5738,8 @@ TEST_P(QuicProcessDataTest, ProcessDataHeaderOnly) {
|
|||||||
deliverData(serverAddr, packet.header->coalesce());
|
deliverData(serverAddr, packet.header->coalesce());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
getAckState(client->getConn(), PacketNumberSpace::Handshake)
|
getAckState(client->getConn(), PacketNumberSpace::Handshake)
|
||||||
.largestReceivedPacketNum,
|
.largestRecvdPacketNum,
|
||||||
largestReceivedPacketNum);
|
largestRecvdPacketNum);
|
||||||
|
|
||||||
std::vector<int> indices =
|
std::vector<int> indices =
|
||||||
getQLogEventIndices(QLogEventType::DatagramReceived, qLogger);
|
getQLogEventIndices(QLogEventType::DatagramReceived, qLogger);
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ QuicServerTransport::QuicServerTransport(
|
|||||||
serverConn_ = tempConn.get();
|
serverConn_ = tempConn.get();
|
||||||
conn_.reset(tempConn.release());
|
conn_.reset(tempConn.release());
|
||||||
conn_->observerContainer = observerContainer_;
|
conn_->observerContainer = observerContainer_;
|
||||||
|
|
||||||
setConnectionSetupCallback(connSetupCb);
|
setConnectionSetupCallback(connSetupCb);
|
||||||
setConnectionCallback(connStreamsCb);
|
setConnectionCallback(connStreamsCb);
|
||||||
registerAllTransportKnobParamHandlers();
|
registerAllTransportKnobParamHandlers();
|
||||||
|
|||||||
@@ -1318,7 +1318,7 @@ void onServerReadDataFromOpen(
|
|||||||
if (conn.peerAddress != readData.peer) {
|
if (conn.peerAddress != readData.peer) {
|
||||||
// TODO use new conn id, make sure the other endpoint has new conn id
|
// TODO use new conn id, make sure the other endpoint has new conn id
|
||||||
if (isNonProbingPacket) {
|
if (isNonProbingPacket) {
|
||||||
if (packetNum == ackState.largestReceivedPacketNum) {
|
if (packetNum == ackState.largestRecvdPacketNum) {
|
||||||
ShortHeader* shortHeader = regularPacket.header.asShort();
|
ShortHeader* shortHeader = regularPacket.header.asShort();
|
||||||
bool intentionalMigration = false;
|
bool intentionalMigration = false;
|
||||||
if (shortHeader &&
|
if (shortHeader &&
|
||||||
@@ -1531,10 +1531,10 @@ void onServerReadDataFromClosed(
|
|||||||
|
|
||||||
// We only need to set the largest received packet number in order to
|
// We only need to set the largest received packet number in order to
|
||||||
// determine whether or not we need to send a new close.
|
// determine whether or not we need to send a new close.
|
||||||
auto& largestReceivedPacketNum =
|
auto& largestRecvdPacketNum =
|
||||||
getAckState(conn, pnSpace).largestReceivedPacketNum;
|
getAckState(conn, pnSpace).largestRecvdPacketNum;
|
||||||
largestReceivedPacketNum = std::max<PacketNum>(
|
largestRecvdPacketNum =
|
||||||
largestReceivedPacketNum.value_or(packetNum), packetNum);
|
std::max<PacketNum>(largestRecvdPacketNum.value_or(packetNum), packetNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onServerClose(QuicServerConnectionState& conn) {
|
void onServerClose(QuicServerConnectionState& conn) {
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ TEST_F(QuicServerTransportTest, ReceiveCloseAfterLocalError) {
|
|||||||
serverWrites.clear();
|
serverWrites.clear();
|
||||||
|
|
||||||
auto currLargestReceivedPacketNum =
|
auto currLargestReceivedPacketNum =
|
||||||
server->getConn().ackStates.appDataAckState.largestReceivedPacketNum;
|
server->getConn().ackStates.appDataAckState.largestRecvdPacketNum;
|
||||||
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(server->getConn()));
|
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(server->getConn()));
|
||||||
|
|
||||||
ShortHeader header2(
|
ShortHeader header2(
|
||||||
@@ -517,7 +517,7 @@ TEST_F(QuicServerTransportTest, ReceiveCloseAfterLocalError) {
|
|||||||
*makeClientEncryptedCodec(),
|
*makeClientEncryptedCodec(),
|
||||||
QuicFrame::Type::ConnectionCloseFrame));
|
QuicFrame::Type::ConnectionCloseFrame));
|
||||||
EXPECT_GT(
|
EXPECT_GT(
|
||||||
server->getConn().ackStates.appDataAckState.largestReceivedPacketNum,
|
server->getConn().ackStates.appDataAckState.largestRecvdPacketNum,
|
||||||
currLargestReceivedPacketNum);
|
currLargestReceivedPacketNum);
|
||||||
|
|
||||||
// Deliver the same bad data again
|
// Deliver the same bad data again
|
||||||
@@ -526,7 +526,7 @@ TEST_F(QuicServerTransportTest, ReceiveCloseAfterLocalError) {
|
|||||||
EXPECT_LT(
|
EXPECT_LT(
|
||||||
server->getConn()
|
server->getConn()
|
||||||
.ackStates.appDataAckState.largestReceivedAtLastCloseSent,
|
.ackStates.appDataAckState.largestReceivedAtLastCloseSent,
|
||||||
server->getConn().ackStates.appDataAckState.largestReceivedPacketNum);
|
server->getConn().ackStates.appDataAckState.largestRecvdPacketNum);
|
||||||
EXPECT_FALSE(verifyFramePresent(
|
EXPECT_FALSE(verifyFramePresent(
|
||||||
serverWrites,
|
serverWrites,
|
||||||
*makeClientEncryptedCodec(),
|
*makeClientEncryptedCodec(),
|
||||||
@@ -575,11 +575,11 @@ TEST_F(QuicServerTransportTest, NoDataExceptCloseProcessedAfterClosing) {
|
|||||||
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(server->getConn()));
|
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(server->getConn()));
|
||||||
serverWrites.clear();
|
serverWrites.clear();
|
||||||
|
|
||||||
// largestReceivedPacketNum won't be accurate because we will throw
|
// largestRecvdPacketNum won't be accurate because we will throw
|
||||||
// before updating the ack state.
|
// before updating the ack state.
|
||||||
deliverDataWithoutErrorCheck(packetToBuf(packet));
|
deliverDataWithoutErrorCheck(packetToBuf(packet));
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
server->getConn().ackStates.appDataAckState.largestReceivedPacketNum,
|
server->getConn().ackStates.appDataAckState.largestRecvdPacketNum,
|
||||||
packetNum);
|
packetNum);
|
||||||
EXPECT_FALSE(verifyFramePresent(
|
EXPECT_FALSE(verifyFramePresent(
|
||||||
serverWrites,
|
serverWrites,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <quic/QuicConstants.h>
|
#include <quic/QuicConstants.h>
|
||||||
#include <quic/codec/Types.h>
|
#include <quic/codec/Types.h>
|
||||||
|
#include <quic/common/CircularDeque.h>
|
||||||
#include <quic/common/IntervalSet.h>
|
#include <quic/common/IntervalSet.h>
|
||||||
|
|
||||||
#include <folly/Random.h>
|
#include <folly/Random.h>
|
||||||
@@ -23,10 +24,23 @@ struct AckState {
|
|||||||
uint64_t numNonRxPacketsRecvd{0};
|
uint64_t numNonRxPacketsRecvd{0};
|
||||||
// The receive time of the largest ack packet
|
// The receive time of the largest ack packet
|
||||||
folly::Optional<TimePoint> largestRecvdPacketTime;
|
folly::Optional<TimePoint> largestRecvdPacketTime;
|
||||||
|
// Largest received packet numbers on the connection.
|
||||||
|
folly::Optional<PacketNum> largestRecvdPacketNum;
|
||||||
|
// Receive timestamp and packet number for the largest received packet.
|
||||||
|
//
|
||||||
|
// Updated whenever we receive a packet with a larger packet number
|
||||||
|
// than all previously received packets in the packet number space
|
||||||
|
// tracked by this AckState.
|
||||||
|
folly::Optional<RecvdPacketInfo> largestRecvdPacketInfo;
|
||||||
|
// Receive timestamp and packet number for the last received packet.
|
||||||
|
//
|
||||||
|
// Will be different from the value stored in largestRecvdPacketInfo
|
||||||
|
// if the last packet was received out of order and thus had a packet
|
||||||
|
// number less than that of a previously received packet in the packet
|
||||||
|
// number space tracked by this AckState.
|
||||||
|
folly::Optional<RecvdPacketInfo> lastRecvdPacketInfo;
|
||||||
// Latest packet number acked by peer
|
// Latest packet number acked by peer
|
||||||
folly::Optional<PacketNum> largestAckedByPeer;
|
folly::Optional<PacketNum> largestAckedByPeer;
|
||||||
// Largest received packet numbers on the connection.
|
|
||||||
folly::Optional<PacketNum> largestReceivedPacketNum;
|
|
||||||
// Largest received packet number at the time we sent our last close message.
|
// Largest received packet number at the time we sent our last close message.
|
||||||
folly::Optional<PacketNum> largestReceivedAtLastCloseSent;
|
folly::Optional<PacketNum> largestReceivedAtLastCloseSent;
|
||||||
// Next PacketNum we will send for packet in this packet number space
|
// Next PacketNum we will send for packet in this packet number space
|
||||||
@@ -43,6 +57,21 @@ struct AckState {
|
|||||||
bool needsToSendAckImmediately{false};
|
bool needsToSendAckImmediately{false};
|
||||||
// Count of oustanding packets received with retransmittable data.
|
// Count of oustanding packets received with retransmittable data.
|
||||||
uint8_t numRxPacketsRecvd{0};
|
uint8_t numRxPacketsRecvd{0};
|
||||||
|
// Receive time of the latest packet
|
||||||
|
folly::Optional<TimePoint> latestRecvdPacketTime;
|
||||||
|
// Packet number of the latest packet
|
||||||
|
folly::Optional<PacketNum> latestReceivedPacketNum;
|
||||||
|
// Packet number and timestamp of recently received packets.
|
||||||
|
//
|
||||||
|
// The maximum number of packets stored in pktsReceivedTimestamps is
|
||||||
|
// controlled by kMaxReceivedPktsTimestampsStored.
|
||||||
|
//
|
||||||
|
// The packet number of entries in the deque is guarenteed to increase
|
||||||
|
// monotonically because an entry is only added for a received packet
|
||||||
|
// if the packet number is greater than the packet number of the last
|
||||||
|
// element in the deque (e.g., entries are not added for packets that
|
||||||
|
// arrive out of order relative to previously received packets).
|
||||||
|
CircularDeque<RecvdPacketInfo> recvdPacketInfos;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AckStates {
|
struct AckStates {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ void updateAckSendStateOnRecvPacket(
|
|||||||
if (ackState.tolerance.hasValue()) {
|
if (ackState.tolerance.hasValue()) {
|
||||||
thresh = ackState.tolerance.value();
|
thresh = ackState.tolerance.value();
|
||||||
} else {
|
} else {
|
||||||
thresh = ackState.largestReceivedPacketNum.value_or(0) >
|
thresh = ackState.largestRecvdPacketNum.value_or(0) >
|
||||||
conn.transportSettings.rxPacketsBeforeAckInitThreshold
|
conn.transportSettings.rxPacketsBeforeAckInitThreshold
|
||||||
? conn.transportSettings.rxPacketsBeforeAckAfterInit
|
? conn.transportSettings.rxPacketsBeforeAckAfterInit
|
||||||
: conn.transportSettings.rxPacketsBeforeAckBeforeInit;
|
: conn.transportSettings.rxPacketsBeforeAckBeforeInit;
|
||||||
@@ -290,37 +290,37 @@ bool hasNotReceivedNewPacketsSinceLastCloseSent(
|
|||||||
DCHECK(
|
DCHECK(
|
||||||
!conn.ackStates.initialAckState.largestReceivedAtLastCloseSent ||
|
!conn.ackStates.initialAckState.largestReceivedAtLastCloseSent ||
|
||||||
*conn.ackStates.initialAckState.largestReceivedAtLastCloseSent <=
|
*conn.ackStates.initialAckState.largestReceivedAtLastCloseSent <=
|
||||||
*conn.ackStates.initialAckState.largestReceivedPacketNum);
|
*conn.ackStates.initialAckState.largestRecvdPacketNum);
|
||||||
DCHECK(
|
DCHECK(
|
||||||
!conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent ||
|
!conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent ||
|
||||||
*conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent <=
|
*conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent <=
|
||||||
*conn.ackStates.handshakeAckState.largestReceivedPacketNum);
|
*conn.ackStates.handshakeAckState.largestRecvdPacketNum);
|
||||||
DCHECK(
|
DCHECK(
|
||||||
!conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent ||
|
!conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent ||
|
||||||
*conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent <=
|
*conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent <=
|
||||||
*conn.ackStates.appDataAckState.largestReceivedPacketNum);
|
*conn.ackStates.appDataAckState.largestRecvdPacketNum);
|
||||||
return conn.ackStates.initialAckState.largestReceivedAtLastCloseSent ==
|
return conn.ackStates.initialAckState.largestReceivedAtLastCloseSent ==
|
||||||
conn.ackStates.initialAckState.largestReceivedPacketNum &&
|
conn.ackStates.initialAckState.largestRecvdPacketNum &&
|
||||||
conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent ==
|
conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent ==
|
||||||
conn.ackStates.handshakeAckState.largestReceivedPacketNum &&
|
conn.ackStates.handshakeAckState.largestRecvdPacketNum &&
|
||||||
conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent ==
|
conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent ==
|
||||||
conn.ackStates.appDataAckState.largestReceivedPacketNum;
|
conn.ackStates.appDataAckState.largestRecvdPacketNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLargestReceivedPacketsAtLastCloseSent(
|
void updateLargestReceivedPacketsAtLastCloseSent(
|
||||||
QuicConnectionStateBase& conn) noexcept {
|
QuicConnectionStateBase& conn) noexcept {
|
||||||
conn.ackStates.initialAckState.largestReceivedAtLastCloseSent =
|
conn.ackStates.initialAckState.largestReceivedAtLastCloseSent =
|
||||||
conn.ackStates.initialAckState.largestReceivedPacketNum;
|
conn.ackStates.initialAckState.largestRecvdPacketNum;
|
||||||
conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent =
|
conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent =
|
||||||
conn.ackStates.handshakeAckState.largestReceivedPacketNum;
|
conn.ackStates.handshakeAckState.largestRecvdPacketNum;
|
||||||
conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent =
|
conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent =
|
||||||
conn.ackStates.appDataAckState.largestReceivedPacketNum;
|
conn.ackStates.appDataAckState.largestRecvdPacketNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasReceivedPackets(const QuicConnectionStateBase& conn) noexcept {
|
bool hasReceivedPackets(const QuicConnectionStateBase& conn) noexcept {
|
||||||
return conn.ackStates.initialAckState.largestReceivedPacketNum ||
|
return conn.ackStates.initialAckState.largestRecvdPacketNum ||
|
||||||
conn.ackStates.handshakeAckState.largestReceivedPacketNum ||
|
conn.ackStates.handshakeAckState.largestRecvdPacketNum ||
|
||||||
conn.ackStates.appDataAckState.largestReceivedPacketNum;
|
conn.ackStates.appDataAckState.largestRecvdPacketNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
folly::Optional<TimePoint>& getLossTime(
|
folly::Optional<TimePoint>& getLossTime(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <quic/QuicConstants.h>
|
||||||
#include <quic/codec/QuicPacketBuilder.h>
|
#include <quic/codec/QuicPacketBuilder.h>
|
||||||
#include <quic/codec/Types.h>
|
#include <quic/codec/Types.h>
|
||||||
#include <quic/state/StateData.h>
|
#include <quic/state/StateData.h>
|
||||||
@@ -64,16 +65,27 @@ uint64_t updateLargestReceivedPacketNum(
|
|||||||
PacketNum packetNum,
|
PacketNum packetNum,
|
||||||
TimePoint receivedTime) {
|
TimePoint receivedTime) {
|
||||||
PacketNum expectedNextPacket = 0;
|
PacketNum expectedNextPacket = 0;
|
||||||
if (ackState.largestReceivedPacketNum) {
|
if (ackState.largestRecvdPacketNum) {
|
||||||
expectedNextPacket = *ackState.largestReceivedPacketNum + 1;
|
expectedNextPacket = *ackState.largestRecvdPacketNum + 1;
|
||||||
}
|
}
|
||||||
ackState.largestReceivedPacketNum = std::max<PacketNum>(
|
ackState.largestRecvdPacketNum = std::max<PacketNum>(
|
||||||
ackState.largestReceivedPacketNum.value_or(packetNum), packetNum);
|
ackState.largestRecvdPacketNum.value_or(packetNum), packetNum);
|
||||||
ackState.acks.insert(packetNum);
|
ackState.acks.insert(packetNum);
|
||||||
if (ackState.largestReceivedPacketNum == packetNum) {
|
if (ackState.largestRecvdPacketNum == packetNum) {
|
||||||
ackState.largestRecvdPacketTime = receivedTime;
|
ackState.largestRecvdPacketTime = receivedTime;
|
||||||
}
|
}
|
||||||
static_assert(ClockType::is_steady, "Needs steady clock");
|
static_assert(ClockType::is_steady, "Needs steady clock");
|
||||||
|
|
||||||
|
ackState.lastRecvdPacketInfo.assign({packetNum, receivedTime});
|
||||||
|
|
||||||
|
if (packetNum >= expectedNextPacket) {
|
||||||
|
if (ackState.recvdPacketInfos.size() == kMaxReceivedPktsTimestampsStored) {
|
||||||
|
ackState.recvdPacketInfos.pop_front();
|
||||||
|
}
|
||||||
|
ackState.recvdPacketInfos.emplace_back(
|
||||||
|
RecvdPacketInfo{packetNum, receivedTime});
|
||||||
|
}
|
||||||
|
|
||||||
if (expectedNextPacket) {
|
if (expectedNextPacket) {
|
||||||
return (packetNum > expectedNextPacket) ? packetNum - expectedNextPacket
|
return (packetNum > expectedNextPacket) ? packetNum - expectedNextPacket
|
||||||
: expectedNextPacket - packetNum;
|
: expectedNextPacket - packetNum;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <quic/state/OutstandingPacket.h>
|
#include <quic/state/OutstandingPacket.h>
|
||||||
|
|
||||||
|
#include <quic/codec/Types.h>
|
||||||
#include <quic/common/test/TestUtils.h>
|
#include <quic/common/test/TestUtils.h>
|
||||||
#include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
|
#include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
|
||||||
#include <quic/server/state/ServerStateMachine.h>
|
#include <quic/server/state/ServerStateMachine.h>
|
||||||
@@ -16,6 +17,9 @@
|
|||||||
#include <quic/state/stream/StreamReceiveHandlers.h>
|
#include <quic/state/stream/StreamReceiveHandlers.h>
|
||||||
#include <quic/state/stream/StreamSendHandlers.h>
|
#include <quic/state/stream/StreamSendHandlers.h>
|
||||||
#include <quic/state/test/Mocks.h>
|
#include <quic/state/test/Mocks.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
using namespace testing;
|
using namespace testing;
|
||||||
|
|
||||||
@@ -71,60 +75,60 @@ TEST_P(UpdateLargestReceivedPacketNumTest, FirstPacketNotOutOfOrder) {
|
|||||||
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveNew) {
|
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveNew) {
|
||||||
QuicServerConnectionState conn(
|
QuicServerConnectionState conn(
|
||||||
FizzServerQuicHandshakeContext::Builder().build());
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 100;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 100;
|
||||||
auto currentLargestReceived =
|
auto currentLargestReceived =
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum;
|
*getAckState(conn, GetParam()).largestRecvdPacketNum;
|
||||||
PacketNum newReceived = currentLargestReceived + 1;
|
PacketNum newReceived = currentLargestReceived + 1;
|
||||||
auto distance = updateLargestReceivedPacketNum(
|
auto distance = updateLargestReceivedPacketNum(
|
||||||
getAckState(conn, GetParam()), newReceived, Clock::now());
|
getAckState(conn, GetParam()), newReceived, Clock::now());
|
||||||
EXPECT_EQ(distance, 0);
|
EXPECT_EQ(distance, 0);
|
||||||
EXPECT_GT(
|
EXPECT_GT(
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum,
|
*getAckState(conn, GetParam()).largestRecvdPacketNum,
|
||||||
currentLargestReceived);
|
currentLargestReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveNewWithGap) {
|
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveNewWithGap) {
|
||||||
QuicServerConnectionState conn(
|
QuicServerConnectionState conn(
|
||||||
FizzServerQuicHandshakeContext::Builder().build());
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 100;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 100;
|
||||||
auto currentLargestReceived =
|
auto currentLargestReceived =
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum;
|
*getAckState(conn, GetParam()).largestRecvdPacketNum;
|
||||||
PacketNum newReceived = currentLargestReceived + 3;
|
PacketNum newReceived = currentLargestReceived + 3;
|
||||||
auto distance = updateLargestReceivedPacketNum(
|
auto distance = updateLargestReceivedPacketNum(
|
||||||
getAckState(conn, GetParam()), newReceived, Clock::now());
|
getAckState(conn, GetParam()), newReceived, Clock::now());
|
||||||
EXPECT_EQ(distance, 2); // newReceived is 2 after the expected pkt num
|
EXPECT_EQ(distance, 2); // newReceived is 2 after the expected pkt num
|
||||||
EXPECT_GT(
|
EXPECT_GT(
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum,
|
*getAckState(conn, GetParam()).largestRecvdPacketNum,
|
||||||
currentLargestReceived);
|
currentLargestReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveOld) {
|
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveOld) {
|
||||||
QuicServerConnectionState conn(
|
QuicServerConnectionState conn(
|
||||||
FizzServerQuicHandshakeContext::Builder().build());
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 100;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 100;
|
||||||
auto currentLargestReceived =
|
auto currentLargestReceived =
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum;
|
*getAckState(conn, GetParam()).largestRecvdPacketNum;
|
||||||
PacketNum newReceived = currentLargestReceived - 1;
|
PacketNum newReceived = currentLargestReceived - 1;
|
||||||
auto distance = updateLargestReceivedPacketNum(
|
auto distance = updateLargestReceivedPacketNum(
|
||||||
getAckState(conn, GetParam()), newReceived, Clock::now());
|
getAckState(conn, GetParam()), newReceived, Clock::now());
|
||||||
EXPECT_EQ(distance, 2); // newReceived is 2 before the expected pkt num
|
EXPECT_EQ(distance, 2); // newReceived is 2 before the expected pkt num
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum,
|
*getAckState(conn, GetParam()).largestRecvdPacketNum,
|
||||||
currentLargestReceived);
|
currentLargestReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveOldWithGap) {
|
TEST_P(UpdateLargestReceivedPacketNumTest, ReceiveOldWithGap) {
|
||||||
QuicServerConnectionState conn(
|
QuicServerConnectionState conn(
|
||||||
FizzServerQuicHandshakeContext::Builder().build());
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 100;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 100;
|
||||||
auto currentLargestReceived =
|
auto currentLargestReceived =
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum;
|
*getAckState(conn, GetParam()).largestRecvdPacketNum;
|
||||||
PacketNum newReceived = currentLargestReceived - 5;
|
PacketNum newReceived = currentLargestReceived - 5;
|
||||||
auto distance = updateLargestReceivedPacketNum(
|
auto distance = updateLargestReceivedPacketNum(
|
||||||
getAckState(conn, GetParam()), newReceived, Clock::now());
|
getAckState(conn, GetParam()), newReceived, Clock::now());
|
||||||
EXPECT_EQ(distance, 6); // newReceived is 6 before the expected pkt num
|
EXPECT_EQ(distance, 6); // newReceived is 6 before the expected pkt num
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
*getAckState(conn, GetParam()).largestReceivedPacketNum,
|
*getAckState(conn, GetParam()).largestRecvdPacketNum,
|
||||||
currentLargestReceived);
|
currentLargestReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +140,78 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
PacketNumberSpace::Handshake,
|
PacketNumberSpace::Handshake,
|
||||||
PacketNumberSpace::AppData));
|
PacketNumberSpace::AppData));
|
||||||
|
|
||||||
|
class UpdateReceivedPacketTimestampsTest
|
||||||
|
: public TestWithParam<PacketNumberSpace> {};
|
||||||
|
|
||||||
|
TEST_P(UpdateReceivedPacketTimestampsTest, TestUpdatePktReceiveTimestamps) {
|
||||||
|
QuicServerConnectionState conn(
|
||||||
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
|
|
||||||
|
PacketNum nextPacketNum = 0;
|
||||||
|
TimePoint latestTimeStamp = Clock::now();
|
||||||
|
conn.ackStates = AckStates(nextPacketNum);
|
||||||
|
for (int i = 0; i < kMaxReceivedPktsTimestampsStored + 2; i++) {
|
||||||
|
updateAckState(
|
||||||
|
conn,
|
||||||
|
PacketNumberSpace::AppData,
|
||||||
|
nextPacketNum++,
|
||||||
|
true /* pktHasRetransmattableData */,
|
||||||
|
false /* pktHasCryptoData */,
|
||||||
|
latestTimeStamp);
|
||||||
|
latestTimeStamp += 1ms;
|
||||||
|
}
|
||||||
|
auto& ackState = getAckState(conn, PacketNumberSpace::AppData);
|
||||||
|
EXPECT_EQ(ackState.recvdPacketInfos.size(), kMaxReceivedPktsTimestampsStored);
|
||||||
|
// First 2 packets (0, 1) should be popped.
|
||||||
|
EXPECT_EQ(ackState.recvdPacketInfos.front().pktNum, 2);
|
||||||
|
EXPECT_TRUE(ackState.largestRecvdPacketNum.has_value());
|
||||||
|
EXPECT_TRUE(ackState.lastRecvdPacketInfo.has_value());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
ackState.largestRecvdPacketNum.value(),
|
||||||
|
kMaxReceivedPktsTimestampsStored + 1);
|
||||||
|
EXPECT_EQ(
|
||||||
|
ackState.lastRecvdPacketInfo.value().pktNum,
|
||||||
|
kMaxReceivedPktsTimestampsStored + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(
|
||||||
|
UpdateReceivedPacketTimestampsTest,
|
||||||
|
TestUpdateOutOfOrderPktReceiveTimestamps) {
|
||||||
|
QuicServerConnectionState conn(
|
||||||
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
|
|
||||||
|
std::vector<PacketNum> receivedPkts = {0, 2, 3, 1, 4, 6, 5};
|
||||||
|
conn.ackStates = AckStates(receivedPkts.front());
|
||||||
|
auto recvdTs = Clock::now();
|
||||||
|
for (auto pktNum : receivedPkts) {
|
||||||
|
updateAckState(
|
||||||
|
conn,
|
||||||
|
PacketNumberSpace::AppData,
|
||||||
|
pktNum,
|
||||||
|
true /* pktHasRetransmattableData */,
|
||||||
|
false /* pktHasCryptoData */,
|
||||||
|
recvdTs);
|
||||||
|
}
|
||||||
|
// Packets 1 and 5 are out of order and will not be stored.
|
||||||
|
auto& ackState = getAckState(conn, PacketNumberSpace::AppData);
|
||||||
|
std::deque<RecvdPacketInfo> expectedPktsInfo = {
|
||||||
|
{0, recvdTs}, {2, recvdTs}, {3, recvdTs}, {4, recvdTs}, {6, recvdTs}};
|
||||||
|
EXPECT_EQ(expectedPktsInfo.size(), ackState.recvdPacketInfos.size());
|
||||||
|
for (unsigned long i = 0; i < expectedPktsInfo.size(); i++) {
|
||||||
|
EXPECT_EQ(expectedPktsInfo[i].pktNum, ackState.recvdPacketInfos[i].pktNum);
|
||||||
|
EXPECT_EQ(
|
||||||
|
expectedPktsInfo[i].timeStamp, ackState.recvdPacketInfos[i].timeStamp);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(ackState.lastRecvdPacketInfo.value().pktNum, 5);
|
||||||
|
EXPECT_EQ(ackState.lastRecvdPacketInfo.value().timeStamp, recvdTs);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
UpdateReceivedPacketTimestampsTests,
|
||||||
|
UpdateReceivedPacketTimestampsTest,
|
||||||
|
Values(PacketNumberSpace::AppData));
|
||||||
|
|
||||||
class UpdateAckStateTest : public TestWithParam<PacketNumberSpace> {};
|
class UpdateAckStateTest : public TestWithParam<PacketNumberSpace> {};
|
||||||
|
|
||||||
TEST_P(UpdateAckStateTest, TestUpdateAckState) {
|
TEST_P(UpdateAckStateTest, TestUpdateAckState) {
|
||||||
@@ -246,7 +322,7 @@ TEST_P(UpdateAckStateTest, TestUpdateAckStateFrequency) {
|
|||||||
updateAckState(conn, GetParam(), nextPacketNum, true, false, Clock::now());
|
updateAckState(conn, GetParam(), nextPacketNum, true, false, Clock::now());
|
||||||
}
|
}
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(
|
||||||
ackState.largestReceivedPacketNum.value(),
|
ackState.largestRecvdPacketNum.value(),
|
||||||
conn.transportSettings.rxPacketsBeforeAckInitThreshold);
|
conn.transportSettings.rxPacketsBeforeAckInitThreshold);
|
||||||
ackState.needsToSendAckImmediately = false;
|
ackState.needsToSendAckImmediately = false;
|
||||||
conn.pendingEvents.scheduleAckTimeout = false;
|
conn.pendingEvents.scheduleAckTimeout = false;
|
||||||
@@ -270,7 +346,7 @@ TEST_P(UpdateAckStateTest, TestUpdateAckStateFrequencyFromTolerance) {
|
|||||||
FizzServerQuicHandshakeContext::Builder().build());
|
FizzServerQuicHandshakeContext::Builder().build());
|
||||||
PacketNum nextPacketNum = 1;
|
PacketNum nextPacketNum = 1;
|
||||||
auto& ackState = getAckState(conn, GetParam());
|
auto& ackState = getAckState(conn, GetParam());
|
||||||
ackState.largestReceivedPacketNum = nextPacketNum - 1;
|
ackState.largestRecvdPacketNum = nextPacketNum - 1;
|
||||||
ackState.tolerance = 2;
|
ackState.tolerance = 2;
|
||||||
for (; nextPacketNum <= 10; nextPacketNum++) {
|
for (; nextPacketNum <= 10; nextPacketNum++) {
|
||||||
updateAckState(conn, GetParam(), nextPacketNum, true, false, Clock::now());
|
updateAckState(conn, GetParam(), nextPacketNum, true, false, Clock::now());
|
||||||
@@ -1088,9 +1164,9 @@ TEST_F(QuicStateFunctionsTest, UpdateLargestReceivePacketsAtLatCloseSent) {
|
|||||||
EXPECT_FALSE(conn.ackStates.initialAckState.largestReceivedAtLastCloseSent);
|
EXPECT_FALSE(conn.ackStates.initialAckState.largestReceivedAtLastCloseSent);
|
||||||
EXPECT_FALSE(conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent);
|
EXPECT_FALSE(conn.ackStates.handshakeAckState.largestReceivedAtLastCloseSent);
|
||||||
EXPECT_FALSE(conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent);
|
EXPECT_FALSE(conn.ackStates.appDataAckState.largestReceivedAtLastCloseSent);
|
||||||
conn.ackStates.initialAckState.largestReceivedPacketNum = 123;
|
conn.ackStates.initialAckState.largestRecvdPacketNum = 123;
|
||||||
conn.ackStates.handshakeAckState.largestReceivedPacketNum = 654;
|
conn.ackStates.handshakeAckState.largestRecvdPacketNum = 654;
|
||||||
conn.ackStates.appDataAckState.largestReceivedPacketNum = 789;
|
conn.ackStates.appDataAckState.largestRecvdPacketNum = 789;
|
||||||
updateLargestReceivedPacketsAtLastCloseSent(conn);
|
updateLargestReceivedPacketsAtLastCloseSent(conn);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
123, *conn.ackStates.initialAckState.largestReceivedAtLastCloseSent);
|
123, *conn.ackStates.initialAckState.largestReceivedAtLastCloseSent);
|
||||||
@@ -1103,7 +1179,7 @@ TEST_F(QuicStateFunctionsTest, UpdateLargestReceivePacketsAtLatCloseSent) {
|
|||||||
TEST_P(QuicStateFunctionsTest, HasReceivedPackets) {
|
TEST_P(QuicStateFunctionsTest, HasReceivedPackets) {
|
||||||
QuicConnectionStateBase conn(QuicNodeType::Server);
|
QuicConnectionStateBase conn(QuicNodeType::Server);
|
||||||
EXPECT_FALSE(hasReceivedPackets(conn));
|
EXPECT_FALSE(hasReceivedPackets(conn));
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 123;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 123;
|
||||||
EXPECT_TRUE(hasReceivedPackets(conn));
|
EXPECT_TRUE(hasReceivedPackets(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1117,7 +1193,7 @@ TEST_P(QuicStateFunctionsTest, HasReceivedPacketsAtLastCloseSent) {
|
|||||||
TEST_P(QuicStateFunctionsTest, HasNotReceivedNewPacketsSinceLastClose) {
|
TEST_P(QuicStateFunctionsTest, HasNotReceivedNewPacketsSinceLastClose) {
|
||||||
QuicConnectionStateBase conn(QuicNodeType::Server);
|
QuicConnectionStateBase conn(QuicNodeType::Server);
|
||||||
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(conn));
|
EXPECT_TRUE(hasNotReceivedNewPacketsSinceLastCloseSent(conn));
|
||||||
getAckState(conn, GetParam()).largestReceivedPacketNum = 1;
|
getAckState(conn, GetParam()).largestRecvdPacketNum = 1;
|
||||||
EXPECT_FALSE(hasNotReceivedNewPacketsSinceLastCloseSent(conn));
|
EXPECT_FALSE(hasNotReceivedNewPacketsSinceLastCloseSent(conn));
|
||||||
getAckState(conn, GetParam()).largestReceivedAtLastCloseSent = 1;
|
getAckState(conn, GetParam()).largestReceivedAtLastCloseSent = 1;
|
||||||
EXPECT_TRUE(hasReceivedPacketsAtLastCloseSent(conn));
|
EXPECT_TRUE(hasReceivedPacketsAtLastCloseSent(conn));
|
||||||
|
|||||||
Reference in New Issue
Block a user