1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-08 09:42:06 +03:00

T24905463 - [quic][ping] Implement ping in Quic

Summary: Implement ping functionality in ping

Reviewed By: yangchi

Differential Revision: D17885286

fbshipit-source-id: 4c328d14a023057d6889818250c0129c06e60874
This commit is contained in:
Raghu Nallamothu
2019-10-21 17:05:43 -07:00
committed by Facebook Github Bot
parent dab5e1edb9
commit e06c0848e0
16 changed files with 231 additions and 67 deletions

View File

@@ -34,6 +34,7 @@ QuicTransportBase::QuicTransportBase(
pathValidationTimeout_(this), pathValidationTimeout_(this),
idleTimeout_(this), idleTimeout_(this),
drainTimeout_(this), drainTimeout_(this),
pingTimeout_(this),
readLooper_(new FunctionLooper( readLooper_(new FunctionLooper(
evb, evb,
[this](bool /* ignored */) { invokeReadDataAndCallbacks(); }, [this](bool /* ignored */) { invokeReadDataAndCallbacks(); },
@@ -316,6 +317,10 @@ void QuicTransportBase::closeImpl(
if (idleTimeout_.isScheduled()) { if (idleTimeout_.isScheduled()) {
idleTimeout_.cancelTimeout(); idleTimeout_.cancelTimeout();
} }
if (pingTimeout_.isScheduled()) {
pingTimeout_.cancelTimeout();
}
VLOG(10) << "Stopping read looper due to immediate close " << *this; VLOG(10) << "Stopping read looper due to immediate close " << *this;
readLooper_->stop(); readLooper_->stop();
peekLooper_->stop(); peekLooper_->stop();
@@ -1397,6 +1402,22 @@ folly::
} }
} }
void QuicTransportBase::handlePingCallback() {
if (!conn_->pendingEvents.cancelPingTimeout) {
return; // nothing to cancel
}
if (!pingTimeout_.isScheduled()) {
// set cancelpingTimeOut to false, delayed acks
conn_->pendingEvents.cancelPingTimeout = false;
return; // nothing to do, as timeout has already fired
}
pingTimeout_.cancelTimeout();
if (pingCallback_ != nullptr) {
runOnEvbAsync([](auto self) { self->pingCallback_->pingAcknowledged(); });
}
conn_->pendingEvents.cancelPingTimeout = false;
}
void QuicTransportBase::processCallbacksAfterNetworkData() { void QuicTransportBase::processCallbacksAfterNetworkData() {
if (UNLIKELY(closeState_ != CloseState::OPEN)) { if (UNLIKELY(closeState_ != CloseState::OPEN)) {
return; return;
@@ -1414,6 +1435,10 @@ void QuicTransportBase::processCallbacksAfterNetworkData() {
} }
} }
conn_->streamManager->clearNewPeerStreams(); conn_->streamManager->clearNewPeerStreams();
// Handle pingCallbacks
handlePingCallback();
// TODO: we're currently assuming that canceling write callbacks will not // TODO: we're currently assuming that canceling write callbacks will not
// cause reset of random streams. Maybe get rid of that assumption later. // cause reset of random streams. Maybe get rid of that assumption later.
for (auto pendingResetIt = conn_->pendingEvents.resets.begin(); for (auto pendingResetIt = conn_->pendingEvents.resets.begin();
@@ -2006,8 +2031,20 @@ void QuicTransportBase::checkForClosedStream() {
} }
void QuicTransportBase::sendPing( void QuicTransportBase::sendPing(
PingCallback* /*callback*/, PingCallback* callback,
std::chrono::milliseconds /*pingTimeout*/) {} std::chrono::milliseconds pingTimeout) {
/* Step 0: Connection should not be closed */
if (closeState_ == CloseState::CLOSED) {
return;
}
// Step 1: Send a simple ping frame
quic::sendSimpleFrame(*conn_, PingFrame());
updateWriteLooper(true);
// Step 2: Schedule the timeout on event base
schedulePingTimeout(callback, pingTimeout);
}
void QuicTransportBase::lossTimeoutExpired() noexcept { void QuicTransportBase::lossTimeoutExpired() noexcept {
CHECK_NE(closeState_, CloseState::CLOSED); CHECK_NE(closeState_, CloseState::CLOSED);
@@ -2045,6 +2082,14 @@ void QuicTransportBase::ackTimeoutExpired() noexcept {
pacedWriteDataToSocket(false); pacedWriteDataToSocket(false);
} }
void QuicTransportBase::pingTimeoutExpired() noexcept {
// If timeout expired just call the call back Provided
if (pingCallback_ == nullptr) {
return;
}
runOnEvbAsync([](auto self) { self->pingCallback_->pingTimeout(); });
}
void QuicTransportBase::pathValidationTimeoutExpired() noexcept { void QuicTransportBase::pathValidationTimeoutExpired() noexcept {
CHECK(conn_->outstandingPathValidation); CHECK(conn_->outstandingPathValidation);
@@ -2110,6 +2155,19 @@ void QuicTransportBase::scheduleAckTimeout() {
} }
} }
void QuicTransportBase::schedulePingTimeout(
PingCallback* pingCb,
std::chrono::milliseconds timeout) {
// if a ping timeout is already scheduled, nothing to do, return
if (pingTimeout_.isScheduled()) {
return;
}
pingCallback_ = pingCb;
auto& wheelTimer = getEventBase()->timer();
wheelTimer.scheduleTimeout(&pingTimeout_, timeout);
}
void QuicTransportBase::schedulePathValidationTimeout() { void QuicTransportBase::schedulePathValidationTimeout() {
if (closeState_ == CloseState::CLOSED) { if (closeState_ == CloseState::CLOSED) {
return; return;

View File

@@ -367,6 +367,26 @@ class QuicTransportBase : public QuicSocket {
QuicTransportBase* transport_; QuicTransportBase* transport_;
}; };
class PingTimeout : public folly::HHWheelTimer::Callback {
public:
~PingTimeout() override = default;
explicit PingTimeout(QuicTransportBase* transport)
: transport_(transport) {}
void timeoutExpired() noexcept override {
transport_->pingTimeoutExpired();
}
void callbackCanceled() noexcept override {
// ignore, as this happens only when event base dies
return;
}
private:
QuicTransportBase* transport_;
};
class PathValidationTimeout : public folly::HHWheelTimer::Callback { class PathValidationTimeout : public folly::HHWheelTimer::Callback {
public: public:
~PathValidationTimeout() override = default; ~PathValidationTimeout() override = default;
@@ -460,6 +480,7 @@ class QuicTransportBase : public QuicSocket {
void updateReadLooper(); void updateReadLooper();
void updatePeekLooper(); void updatePeekLooper();
void updateWriteLooper(bool thisIteration); void updateWriteLooper(bool thisIteration);
void handlePingCallback();
void runOnEvbAsync( void runOnEvbAsync(
folly::Function<void(std::shared_ptr<QuicTransportBase>)> func); folly::Function<void(std::shared_ptr<QuicTransportBase>)> func);
@@ -521,10 +542,14 @@ class QuicTransportBase : public QuicSocket {
void pathValidationTimeoutExpired() noexcept; void pathValidationTimeoutExpired() noexcept;
void idleTimeoutExpired(bool drain) noexcept; void idleTimeoutExpired(bool drain) noexcept;
void drainTimeoutExpired() noexcept; void drainTimeoutExpired() noexcept;
void pingTimeoutExpired() noexcept;
void setIdleTimer(); void setIdleTimer();
void scheduleAckTimeout(); void scheduleAckTimeout();
void schedulePathValidationTimeout(); void schedulePathValidationTimeout();
void schedulePingTimeout(
PingCallback* callback,
std::chrono::milliseconds pingTimeout);
std::atomic<folly::EventBase*> evb_; std::atomic<folly::EventBase*> evb_;
std::unique_ptr<folly::AsyncUDPSocket> socket_; std::unique_ptr<folly::AsyncUDPSocket> socket_;
@@ -570,6 +595,7 @@ class QuicTransportBase : public QuicSocket {
deliveryCallbacks_; deliveryCallbacks_;
std::unordered_map<StreamId, DataExpiredCallbackData> dataExpiredCallbacks_; std::unordered_map<StreamId, DataExpiredCallbackData> dataExpiredCallbacks_;
std::unordered_map<StreamId, DataRejectedCallbackData> dataRejectedCallbacks_; std::unordered_map<StreamId, DataRejectedCallbackData> dataRejectedCallbacks_;
PingCallback* pingCallback_;
WriteCallback* connWriteCallback_{nullptr}; WriteCallback* connWriteCallback_{nullptr};
std::map<StreamId, WriteCallback*> pendingWriteCallbacks_; std::map<StreamId, WriteCallback*> pendingWriteCallbacks_;
@@ -581,6 +607,7 @@ class QuicTransportBase : public QuicSocket {
PathValidationTimeout pathValidationTimeout_; PathValidationTimeout pathValidationTimeout_;
IdleTimeout idleTimeout_; IdleTimeout idleTimeout_;
DrainTimeout drainTimeout_; DrainTimeout drainTimeout_;
PingTimeout pingTimeout_;
FunctionLooper::Ptr readLooper_; FunctionLooper::Ptr readLooper_;
FunctionLooper::Ptr peekLooper_; FunctionLooper::Ptr peekLooper_;
FunctionLooper::Ptr writeLooper_; FunctionLooper::Ptr writeLooper_;

View File

@@ -369,7 +369,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
// Write those framses with a regular builder // Write those framses with a regular builder
writeFrame(connCloseFrame, regularBuilder); writeFrame(connCloseFrame, regularBuilder);
writeFrame(QuicSimpleFrame(maxStreamFrame), regularBuilder); writeFrame(QuicSimpleFrame(maxStreamFrame), regularBuilder);
writeFrame(pingFrame, regularBuilder); writeFrame(QuicSimpleFrame(pingFrame), regularBuilder);
writeAckFrame(ackMeta, regularBuilder); writeAckFrame(ackMeta, regularBuilder);
auto result = cloningScheduler.scheduleFramesForPacket( auto result = cloningScheduler.scheduleFramesForPacket(
@@ -395,7 +395,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
/* the next four frames should not be written */ /* the next four frames should not be written */
present |= frame.asConnectionCloseFrame() ? true : false; present |= frame.asConnectionCloseFrame() ? true : false;
present |= frame.asQuicSimpleFrame() ? true : false; present |= frame.asQuicSimpleFrame() ? true : false;
present |= frame.asPingFrame() ? true : false; present |= frame.asQuicSimpleFrame() ? true : false;
present |= frame.asWriteAckFrame() ? true : false; present |= frame.asWriteAckFrame() ? true : false;
ASSERT_FALSE(present); ASSERT_FALSE(present);
} }

View File

@@ -11,6 +11,7 @@
#include <folly/portability/GMock.h> #include <folly/portability/GMock.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <quic/api/QuicSocket.h>
#include <quic/api/QuicTransportBase.h> #include <quic/api/QuicTransportBase.h>
#include <quic/codec/DefaultConnectionIdAlgo.h> #include <quic/codec/DefaultConnectionIdAlgo.h>
#include <quic/common/test/TestUtils.h> #include <quic/common/test/TestUtils.h>
@@ -227,7 +228,7 @@ class TestQuicTransport
transportClosed = true; transportClosed = true;
} }
void invokeAckTimeout() { void AckTimeout() {
ackTimeoutExpired(); ackTimeoutExpired();
} }
@@ -239,6 +240,31 @@ class TestQuicTransport
idleTimeout_.timeoutExpired(); idleTimeout_.timeoutExpired();
} }
void invokeAckTimeout() {
ackTimeout_.timeoutExpired();
}
void invokeSendPing(
quic::QuicSocket::PingCallback* cb,
std::chrono::milliseconds interval) {
sendPing(cb, interval);
}
void invokeCancelPingTimeout() {
pingTimeout_.cancelTimeout();
}
void invokeHandlePingCallback() {
handlePingCallback();
}
bool isPingTimeoutScheduled() {
if (pingTimeout_.isScheduled()) {
return true;
}
return false;
}
auto& writeLooper() { auto& writeLooper() {
return writeLooper_; return writeLooper_;
} }
@@ -2428,5 +2454,29 @@ TEST_F(QuicTransportImplTest, CloseFromCancelDeliveryCallbacksForStream) {
transport->cancelDeliveryCallbacksForStream(stream1); transport->cancelDeliveryCallbacksForStream(stream1);
} }
TEST_F(QuicTransportImplTest, SuccessfulPing) {
auto conn = transport->transportConn;
std::chrono::milliseconds interval(10);
transport->invokeSendPing(nullptr, interval);
EXPECT_EQ(transport->isPingTimeoutScheduled(), true);
EXPECT_EQ(conn->pendingEvents.cancelPingTimeout, false);
conn->pendingEvents.cancelPingTimeout = true;
transport->invokeHandlePingCallback();
EXPECT_EQ(transport->isPingTimeoutScheduled(), false);
EXPECT_EQ(conn->pendingEvents.cancelPingTimeout, false);
}
TEST_F(QuicTransportImplTest, FailedPing) {
auto conn = transport->transportConn;
std::chrono::milliseconds interval(10);
transport->invokeSendPing(nullptr, interval);
EXPECT_EQ(transport->isPingTimeoutScheduled(), true);
EXPECT_EQ(conn->pendingEvents.cancelPingTimeout, false);
conn->pendingEvents.cancelPingTimeout = true;
transport->invokeCancelPingTimeout();
transport->invokeHandlePingCallback();
EXPECT_EQ(conn->pendingEvents.cancelPingTimeout, false);
}
} // namespace test } // namespace test
} // namespace quic } // namespace quic

View File

@@ -20,6 +20,7 @@
#include <quic/loss/QuicLossFunctions.h> #include <quic/loss/QuicLossFunctions.h>
#include <quic/state/AckHandlers.h> #include <quic/state/AckHandlers.h>
#include <quic/state/QuicPacingFunctions.h> #include <quic/state/QuicPacingFunctions.h>
#include <quic/state/SimpleFrameFunctions.h>
namespace fsp = folly::portability::sockets; namespace fsp = folly::portability::sockets;
@@ -351,6 +352,12 @@ void QuicClientTransport::processPacketData(
*cryptoStream, frame.offset, frame.len); *cryptoStream, frame.offset, frame.len);
break; break;
} }
case QuicWriteFrame::Type::QuicSimpleFrame_E: {
const quic::QuicSimpleFrame simpleFrame =
*packetFrame.asQuicSimpleFrame();
updateSimpleFrameOnAck(*conn_, simpleFrame);
break;
}
default: default:
// ignore other frames. // ignore other frames.
break; break;
@@ -502,10 +509,6 @@ void QuicClientTransport::processPacketData(
*conn_, simpleFrame, packetNum, false); *conn_, simpleFrame, packetNum, false);
break; break;
} }
case QuicFrame::Type::PingFrame_E: {
pktHasRetransmittableData = true;
break;
}
default: default:
break; break;
} }

View File

@@ -4478,7 +4478,7 @@ TEST_F(QuicClientTransportAfterStartTest, PingIsRetransmittable) {
client->getConn().udpSendPacketLen, client->getConn().udpSendPacketLen,
std::move(header), std::move(header),
0 /* largestAcked */); 0 /* largestAcked */);
writeFrame(pingFrame, builder); writeFrame(QuicSimpleFrame(pingFrame), builder);
auto packet = packetToBuf(std::move(builder).buildPacket()); auto packet = packetToBuf(std::move(builder).buildPacket());
deliverData(packet->coalesce()); deliverData(packet->coalesce());
EXPECT_TRUE(client->getConn().pendingEvents.scheduleAckTimeout); EXPECT_TRUE(client->getConn().pendingEvents.scheduleAckTimeout);

View File

@@ -60,7 +60,7 @@ PaddingFrame decodePaddingFrame(folly::io::Cursor&) {
return PaddingFrame(); return PaddingFrame();
} }
PingFrame decodePingFrame(folly::io::Cursor& /* cursor */) { PingFrame decodePingFrame(folly::io::Cursor&) {
return PingFrame(); return PingFrame();
} }

View File

@@ -318,6 +318,17 @@ size_t writeSimpleFrame(
uint64_t spaceLeft = builder.remainingSpaceInPkt(); uint64_t spaceLeft = builder.remainingSpaceInPkt();
switch (frame.type()) { switch (frame.type()) {
case QuicSimpleFrame::Type::PingFrame_E: {
const PingFrame& pingFrame = *frame.asPingFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PING));
if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
builder.write(intFrameType);
builder.appendFrame(QuicSimpleFrame(pingFrame));
return intFrameType.getSize();
}
// no space left in packet
return size_t(0);
}
case QuicSimpleFrame::Type::StopSendingFrame_E: { case QuicSimpleFrame::Type::StopSendingFrame_E: {
const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame(); const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::STOP_SENDING)); QuicInteger intFrameType(static_cast<uint8_t>(FrameType::STOP_SENDING));
@@ -495,17 +506,6 @@ size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
} }
return size_t(0); return size_t(0);
} }
case QuicWriteFrame::Type::PingFrame_E: {
PingFrame& pingFrame = *frame.asPingFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PING));
if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
builder.write(intFrameType);
builder.appendFrame(std::move(pingFrame));
return intFrameType.getSize();
}
// no space left in packet
return size_t(0);
}
case QuicWriteFrame::Type::RstStreamFrame_E: { case QuicWriteFrame::Type::RstStreamFrame_E: {
RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame(); RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM)); QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM));

View File

@@ -564,15 +564,16 @@ struct StatelessReset {
: token(std::move(tokenIn)) {} : token(std::move(tokenIn)) {}
}; };
#define QUIC_SIMPLE_FRAME(F, ...) \ #define QUIC_SIMPLE_FRAME(F, ...) \
F(StopSendingFrame, __VA_ARGS__) \ F(StopSendingFrame, __VA_ARGS__) \
F(MinStreamDataFrame, __VA_ARGS__) \ F(MinStreamDataFrame, __VA_ARGS__) \
F(ExpiredStreamDataFrame, __VA_ARGS__) \ F(ExpiredStreamDataFrame, __VA_ARGS__) \
F(PathChallengeFrame, __VA_ARGS__) \ F(PathChallengeFrame, __VA_ARGS__) \
F(PathResponseFrame, __VA_ARGS__) \ F(PathResponseFrame, __VA_ARGS__) \
F(NewConnectionIdFrame, __VA_ARGS__) \ F(NewConnectionIdFrame, __VA_ARGS__) \
F(MaxStreamsFrame, __VA_ARGS__) \ F(MaxStreamsFrame, __VA_ARGS__) \
F(RetireConnectionIdFrame, __VA_ARGS__) F(RetireConnectionIdFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__)
DECLARE_VARIANT_TYPE(QuicSimpleFrame, QUIC_SIMPLE_FRAME) DECLARE_VARIANT_TYPE(QuicSimpleFrame, QUIC_SIMPLE_FRAME)
@@ -583,7 +584,6 @@ DECLARE_VARIANT_TYPE(QuicSimpleFrame, QUIC_SIMPLE_FRAME)
F(ApplicationCloseFrame, __VA_ARGS__) \ F(ApplicationCloseFrame, __VA_ARGS__) \
F(MaxDataFrame, __VA_ARGS__) \ F(MaxDataFrame, __VA_ARGS__) \
F(MaxStreamDataFrame, __VA_ARGS__) \ F(MaxStreamDataFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__) \
F(DataBlockedFrame, __VA_ARGS__) \ F(DataBlockedFrame, __VA_ARGS__) \
F(StreamDataBlockedFrame, __VA_ARGS__) \ F(StreamDataBlockedFrame, __VA_ARGS__) \
F(StreamsBlockedFrame, __VA_ARGS__) \ F(StreamsBlockedFrame, __VA_ARGS__) \
@@ -603,7 +603,6 @@ DECLARE_VARIANT_TYPE(QuicFrame, QUIC_FRAME)
F(ApplicationCloseFrame, __VA_ARGS__) \ F(ApplicationCloseFrame, __VA_ARGS__) \
F(MaxDataFrame, __VA_ARGS__) \ F(MaxDataFrame, __VA_ARGS__) \
F(MaxStreamDataFrame, __VA_ARGS__) \ F(MaxStreamDataFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__) \
F(DataBlockedFrame, __VA_ARGS__) \ F(DataBlockedFrame, __VA_ARGS__) \
F(StreamDataBlockedFrame, __VA_ARGS__) \ F(StreamDataBlockedFrame, __VA_ARGS__) \
F(StreamsBlockedFrame, __VA_ARGS__) \ F(StreamsBlockedFrame, __VA_ARGS__) \
@@ -837,7 +836,8 @@ struct VersionNegotiationPacket {
struct RegularPacket { struct RegularPacket {
PacketHeader header; PacketHeader header;
explicit RegularPacket(PacketHeader&& headerIn) : header(std::move(headerIn)) {} explicit RegularPacket(PacketHeader&& headerIn)
: header(std::move(headerIn)) {}
}; };
/** /**

View File

@@ -62,7 +62,6 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
"The sun is in the sky.", "The sun is in the sky.",
FrameType::ACK); FrameType::ACK);
MaxStreamsFrame maxStreamsFrame(4321, true); MaxStreamsFrame maxStreamsFrame(4321, true);
PingFrame pingFrame;
IntervalSet<PacketNum> ackBlocks; IntervalSet<PacketNum> ackBlocks;
ackBlocks.insert(10, 100); ackBlocks.insert(10, 100);
ackBlocks.insert(200, 1000); ackBlocks.insert(200, 1000);
@@ -78,10 +77,11 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
uint64_t cryptoOffset = 0; uint64_t cryptoOffset = 0;
auto cryptoBuf = folly::IOBuf::copyBuffer("NewSessionTicket"); auto cryptoBuf = folly::IOBuf::copyBuffer("NewSessionTicket");
PingFrame pingFrame{};
// Write them with a regular builder // Write them with a regular builder
writeFrame(connCloseFrame, regularBuilder1); writeFrame(connCloseFrame, regularBuilder1);
writeFrame(QuicSimpleFrame(maxStreamsFrame), regularBuilder1); writeFrame(QuicSimpleFrame(maxStreamsFrame), regularBuilder1);
writeFrame(pingFrame, regularBuilder1); writeFrame(QuicSimpleFrame(pingFrame), regularBuilder1);
writeAckFrame(ackMeta, regularBuilder1); writeAckFrame(ackMeta, regularBuilder1);
writeStreamFrameHeader( writeStreamFrameHeader(
regularBuilder1, regularBuilder1,
@@ -135,14 +135,22 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
} }
case QuicWriteFrame::Type::QuicSimpleFrame_E: { case QuicWriteFrame::Type::QuicSimpleFrame_E: {
const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame(); const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
const MaxStreamsFrame* maxStreamFrame = simpleFrame.asMaxStreamsFrame(); switch (simpleFrame.type()) {
EXPECT_NE(maxStreamFrame, nullptr); case QuicSimpleFrame::Type::MaxStreamsFrame_E: {
EXPECT_EQ(4321, maxStreamFrame->maxStreams); const MaxStreamsFrame* maxStreamFrame =
break; simpleFrame.asMaxStreamsFrame();
} EXPECT_NE(maxStreamFrame, nullptr);
case QuicWriteFrame::Type::PingFrame_E: { EXPECT_EQ(4321, maxStreamFrame->maxStreams);
const PingFrame& ping = *frame.asPingFrame(); break;
EXPECT_EQ(PingFrame(), ping); }
case QuicSimpleFrame::Type::PingFrame_E: {
const PingFrame* simplePingFrame = simpleFrame.asPingFrame();
EXPECT_NE(simplePingFrame, nullptr);
break;
}
default:
EXPECT_TRUE(false); /* fail if this happens */
}
break; break;
} }
case QuicWriteFrame::Type::WriteAckFrame_E: { case QuicWriteFrame::Type::WriteAckFrame_E: {
@@ -356,7 +364,6 @@ TEST_F(QuicPacketRebuilderTest, CannotRebuild) {
"The sun is in the sky.", "The sun is in the sky.",
FrameType::ACK); FrameType::ACK);
StreamsBlockedFrame maxStreamIdFrame(0x1024, true); StreamsBlockedFrame maxStreamIdFrame(0x1024, true);
PingFrame pingFrame;
IntervalSet<PacketNum> ackBlocks; IntervalSet<PacketNum> ackBlocks;
ackBlocks.insert(10, 100); ackBlocks.insert(10, 100);
ackBlocks.insert(200, 1000); ackBlocks.insert(200, 1000);
@@ -367,11 +374,11 @@ TEST_F(QuicPacketRebuilderTest, CannotRebuild) {
auto streamId = stream->id; auto streamId = stream->id;
auto buf = auto buf =
folly::IOBuf::copyBuffer("You can't deny you are looking for the sunset"); folly::IOBuf::copyBuffer("You can't deny you are looking for the sunset");
PingFrame pingFrame;
// Write them with a regular builder // Write them with a regular builder
writeFrame(connCloseFrame, regularBuilder1); writeFrame(connCloseFrame, regularBuilder1);
writeFrame(maxStreamIdFrame, regularBuilder1); writeFrame(maxStreamIdFrame, regularBuilder1);
writeFrame(pingFrame, regularBuilder1); writeFrame(QuicSimpleFrame(pingFrame), regularBuilder1);
writeAckFrame(ackMeta, regularBuilder1); writeAckFrame(ackMeta, regularBuilder1);
writeStreamFrameHeader( writeStreamFrameHeader(
regularBuilder1, regularBuilder1,
@@ -407,7 +414,7 @@ TEST_F(QuicPacketRebuilderTest, CloneCounter) {
RegularQuicPacketBuilder regularBuilder( RegularQuicPacketBuilder regularBuilder(
kDefaultUDPSendPacketLen, std::move(shortHeader1), 0 /* largestAcked */); kDefaultUDPSendPacketLen, std::move(shortHeader1), 0 /* largestAcked */);
PingFrame pingFrame; PingFrame pingFrame;
writeFrame(pingFrame, regularBuilder); writeFrame(QuicSimpleFrame(pingFrame), regularBuilder);
auto packet = std::move(regularBuilder).buildPacket(); auto packet = std::move(regularBuilder).buildPacket();
auto outstandingPacket = makeDummyOutstandingPacket(packet.packet, 1000); auto outstandingPacket = makeDummyOutstandingPacket(packet.packet, 1000);
QuicServerConnectionState conn; QuicServerConnectionState conn;

View File

@@ -1115,17 +1115,19 @@ TEST_F(QuicWriteCodecTest, DecodeAppCloseLarge) {
TEST_F(QuicWriteCodecTest, WritePing) { TEST_F(QuicWriteCodecTest, WritePing) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
auto pingBytesWritten = writeFrame(PingFrame(), pktBuilder); auto pingBytesWritten = writeFrame(QuicSimpleFrame(PingFrame()), pktBuilder);
auto builtOut = std::move(pktBuilder).buildPacket(); auto builtOut = std::move(pktBuilder).buildPacket();
auto regularPacket = builtOut.first; auto regularPacket = builtOut.first;
EXPECT_EQ(1, pingBytesWritten); EXPECT_EQ(1, pingBytesWritten);
EXPECT_NE(regularPacket.frames[0].asPingFrame(), nullptr); auto simpleFrame = regularPacket.frames[0].asQuicSimpleFrame();
EXPECT_NE(simpleFrame->asPingFrame(), nullptr);
auto wireBuf = std::move(builtOut.second); auto wireBuf = std::move(builtOut.second);
folly::io::Cursor cursor(wireBuf.get()); folly::io::Cursor cursor(wireBuf.get());
QuicFrame decodedFrame = parseQuicFrame(cursor); QuicFrame decodedFrame = parseQuicFrame(cursor);
EXPECT_NE(decodedFrame.asPingFrame(), nullptr); auto decodedSimpleFrame = decodedFrame.asQuicSimpleFrame();
EXPECT_NE(decodedSimpleFrame->asPingFrame(), nullptr);
// At last, verify there is nothing left in the wire format bytes: // At last, verify there is nothing left in the wire format bytes:
EXPECT_TRUE(cursor.isAtEnd()); EXPECT_TRUE(cursor.isAtEnd());
@@ -1135,7 +1137,7 @@ TEST_F(QuicWriteCodecTest, NoSpaceForPing) {
MockQuicPacketBuilder pktBuilder; MockQuicPacketBuilder pktBuilder;
pktBuilder.remaining_ = 0; pktBuilder.remaining_ = 0;
setupCommonExpects(pktBuilder); setupCommonExpects(pktBuilder);
EXPECT_EQ(0, writeFrame(PingFrame(), pktBuilder)); EXPECT_EQ(0, writeFrame(QuicSimpleFrame(PingFrame()), pktBuilder));
} }
TEST_F(QuicWriteCodecTest, WritePadding) { TEST_F(QuicWriteCodecTest, WritePadding) {

View File

@@ -5,6 +5,10 @@ void addQuicSimpleFrameToEvent(
quic::QLogPacketEvent* event, quic::QLogPacketEvent* event,
const quic::QuicSimpleFrame& simpleFrame) { const quic::QuicSimpleFrame& simpleFrame) {
switch (simpleFrame.type()) { switch (simpleFrame.type()) {
case quic::QuicSimpleFrame::Type::PingFrame_E: {
event->frames.push_back(std::make_unique<quic::PingFrameLog>());
break;
}
case quic::QuicSimpleFrame::Type::StopSendingFrame_E: { case quic::QuicSimpleFrame::Type::StopSendingFrame_E: {
const quic::StopSendingFrame& frame = *simpleFrame.asStopSendingFrame(); const quic::StopSendingFrame& frame = *simpleFrame.asStopSendingFrame();
event->frames.push_back(std::make_unique<quic::StopSendingFrameLog>( event->frames.push_back(std::make_unique<quic::StopSendingFrameLog>(
@@ -123,10 +127,6 @@ std::unique_ptr<QLogPacketEvent> BaseQLogger::createPacketEvent(
frame.streamId, frame.maximumData)); frame.streamId, frame.maximumData));
break; break;
} }
case QuicFrame::Type::PingFrame_E: {
event->frames.push_back(std::make_unique<PingFrameLog>());
break;
}
case QuicFrame::Type::DataBlockedFrame_E: { case QuicFrame::Type::DataBlockedFrame_E: {
const auto& frame = *quicFrame.asDataBlockedFrame(); const auto& frame = *quicFrame.asDataBlockedFrame();
event->frames.push_back( event->frames.push_back(
@@ -244,9 +244,6 @@ std::unique_ptr<QLogPacketEvent> BaseQLogger::createPacketEvent(
frame.streamLimit, frame.isForBidirectional)); frame.streamLimit, frame.isForBidirectional));
break; break;
} }
case QuicWriteFrame::Type::PingFrame_E:
event->frames.push_back(std::make_unique<PingFrameLog>());
break;
case QuicWriteFrame::Type::DataBlockedFrame_E: { case QuicWriteFrame::Type::DataBlockedFrame_E: {
const DataBlockedFrame& frame = *quicFrame.asDataBlockedFrame(); const DataBlockedFrame& frame = *quicFrame.asDataBlockedFrame();
event->frames.push_back( event->frames.push_back(

View File

@@ -16,6 +16,7 @@
#include <quic/state/QuicPacingFunctions.h> #include <quic/state/QuicPacingFunctions.h>
#include <quic/state/QuicStreamFunctions.h> #include <quic/state/QuicStreamFunctions.h>
#include <quic/state/QuicTransportStatsCallback.h> #include <quic/state/QuicTransportStatsCallback.h>
#include <quic/state/SimpleFrameFunctions.h>
namespace quic { namespace quic {
using namespace std::chrono_literals; using namespace std::chrono_literals;
@@ -800,6 +801,12 @@ void onServerReadDataFromOpen(
commonAckVisitorForAckFrame(ackState, frame); commonAckVisitorForAckFrame(ackState, frame);
break; break;
} }
case QuicWriteFrame::Type::QuicSimpleFrame_E: {
const QuicSimpleFrame& frame =
*packetFrame.asQuicSimpleFrame();
updateSimpleFrameOnAck(conn, frame);
break;
}
default: { default: {
break; break;
} }
@@ -964,11 +971,6 @@ void onServerReadDataFromOpen(
conn, simpleFrame, packetNum, readData.peer != conn.peerAddress); conn, simpleFrame, packetNum, readData.peer != conn.peerAddress);
break; break;
} }
case QuicFrame::Type::PingFrame_E: {
pktHasRetransmittableData = true;
isNonProbingPacket = true;
break;
}
default: { default: {
break; break;
} }

View File

@@ -2779,7 +2779,7 @@ TEST_F(QuicServerTransportTest, PingIsRetransmittable) {
server->getConn().udpSendPacketLen, server->getConn().udpSendPacketLen,
std::move(header), std::move(header),
0 /* largestAcked */); 0 /* largestAcked */);
writeFrame(pingFrame, builder); writeFrame(QuicSimpleFrame(pingFrame), builder);
auto packet = std::move(builder).buildPacket(); auto packet = std::move(builder).buildPacket();
deliverData(packetToBuf(packet)); deliverData(packetToBuf(packet));
EXPECT_TRUE(server->getConn().pendingEvents.scheduleAckTimeout); EXPECT_TRUE(server->getConn().pendingEvents.scheduleAckTimeout);

View File

@@ -17,15 +17,25 @@ void sendSimpleFrame(QuicConnectionStateBase& conn, QuicSimpleFrame frame) {
} }
void updateSimpleFrameOnAck( void updateSimpleFrameOnAck(
QuicConnectionStateBase& /*conn*/, QuicConnectionStateBase& conn,
const QuicSimpleFrame& /*frame*/) { const QuicSimpleFrame& frame) {
// TODO implement. // TODO implement.
switch (frame.type()) {
case QuicSimpleFrame::Type::PingFrame_E: {
conn.pendingEvents.cancelPingTimeout = true;
break;
}
default:
break;
}
} }
folly::Optional<QuicSimpleFrame> updateSimpleFrameOnPacketClone( folly::Optional<QuicSimpleFrame> updateSimpleFrameOnPacketClone(
QuicConnectionStateBase& conn, QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame) { const QuicSimpleFrame& frame) {
switch (frame.type()) { switch (frame.type()) {
case QuicSimpleFrame::Type::PingFrame_E:
return QuicSimpleFrame(frame);
case QuicSimpleFrame::Type::StopSendingFrame_E: case QuicSimpleFrame::Type::StopSendingFrame_E:
if (!conn.streamManager->streamExists( if (!conn.streamManager->streamExists(
frame.asStopSendingFrame()->streamId)) { frame.asStopSendingFrame()->streamId)) {
@@ -87,6 +97,9 @@ void updateSimpleFrameOnPacketLoss(
QuicConnectionStateBase& conn, QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame) { const QuicSimpleFrame& frame) {
switch (frame.type()) { switch (frame.type()) {
case QuicSimpleFrame::Type::PingFrame_E: {
break;
}
case QuicSimpleFrame::Type::StopSendingFrame_E: { case QuicSimpleFrame::Type::StopSendingFrame_E: {
const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame(); const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame();
if (conn.streamManager->streamExists(stopSendingFrame.streamId)) { if (conn.streamManager->streamExists(stopSendingFrame.streamId)) {
@@ -138,6 +151,9 @@ bool updateSimpleFrameOnPacketReceived(
PacketNum packetNum, PacketNum packetNum,
bool fromChangedPeerAddress) { bool fromChangedPeerAddress) {
switch (frame.type()) { switch (frame.type()) {
case QuicSimpleFrame::Type::PingFrame_E: {
return true;
}
case QuicSimpleFrame::Type::StopSendingFrame_E: { case QuicSimpleFrame::Type::StopSendingFrame_E: {
const StopSendingFrame& stopSending = *frame.asStopSendingFrame(); const StopSendingFrame& stopSending = *frame.asStopSendingFrame();
auto stream = conn.streamManager->getStream(stopSending.streamId); auto stream = conn.streamManager->getStream(stopSending.streamId);

View File

@@ -598,6 +598,8 @@ struct QuicConnectionStateBase {
// Number of probing packets to send after PTO // Number of probing packets to send after PTO
uint8_t numProbePackets{0}; uint8_t numProbePackets{0};
bool cancelPingTimeout{false};
}; };
PendingEvents pendingEvents; PendingEvents pendingEvents;