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

Add idle timer checker

Reviewed By: mjoras

Differential Revision: D60913168

fbshipit-source-id: 1b14a2e17545ba24f879e7212153eee19cfe9972
This commit is contained in:
Konstantin Tsoy
2024-08-07 18:55:45 -07:00
committed by Facebook GitHub Bot
parent 901fcc5847
commit b51ee87995
4 changed files with 102 additions and 0 deletions

View File

@@ -1122,6 +1122,13 @@ void QuicTransportBase::updateWriteLooper(bool thisIteration) {
return;
}
if (conn_->transportSettings.checkIdleTimerOnWrite) {
checkIdleTimer(Clock::now());
if (closeState_ == CloseState::CLOSED) {
return;
}
}
// If socket writable events are in use, do nothing if we are already waiting
// for the write event.
if (conn_->transportSettings.useSockWritableEvents &&
@@ -1961,6 +1968,34 @@ void QuicTransportBase::onNetworkData(
}
}
void QuicTransportBase::checkIdleTimer(TimePoint now) {
if (closeState_ == CloseState::CLOSED) {
return;
}
if (!idleTimeout_.isTimerCallbackScheduled()) {
return;
}
if (!idleTimeoutCheck_.lastTimeIdleTimeoutScheduled_.has_value()) {
return;
}
if (idleTimeoutCheck_.forcedIdleTimeoutScheduled_) {
return;
}
if ((now - *idleTimeoutCheck_.lastTimeIdleTimeoutScheduled_) >=
idleTimeoutCheck_.idleTimeoutMs) {
// Call timer expiration async.
idleTimeoutCheck_.forcedIdleTimeoutScheduled_ = true;
runOnEvbAsync([](auto self) {
if (!self->good() || self->closeState_ == CloseState::CLOSED) {
// The connection was probably closed.
return;
}
self->idleTimeout_.timeoutExpired();
});
}
}
void QuicTransportBase::setIdleTimer() {
if (closeState_ == CloseState::CLOSED) {
return;
@@ -1975,6 +2010,10 @@ void QuicTransportBase::setIdleTimer() {
auto peerIdleTimeout =
conn_->peerIdleTimeout > 0ms ? conn_->peerIdleTimeout : localIdleTimeout;
auto idleTimeout = timeMin(localIdleTimeout, peerIdleTimeout);
idleTimeoutCheck_.idleTimeoutMs = idleTimeout;
idleTimeoutCheck_.lastTimeIdleTimeoutScheduled_ = Clock::now();
scheduleTimeout(&idleTimeout_, idleTimeout);
auto idleTimeoutCount = idleTimeout.count();
if (conn_->transportSettings.enableKeepalive) {

View File

@@ -1015,6 +1015,18 @@ class QuicTransportBase : public QuicSocket,
void onSocketWritable() noexcept override;
void maybeStopWriteLooperAndArmSocketWritableEvent();
/**
* Checks the idle timer on write events, and if it's past the idle timeout,
* calls the timer finctions.
*/
void checkIdleTimer(TimePoint now);
struct IdleTimeoutCheck {
std::chrono::milliseconds idleTimeoutMs{0};
Optional<TimePoint> lastTimeIdleTimeoutScheduled_;
bool forcedIdleTimeoutScheduled_{false};
};
IdleTimeoutCheck idleTimeoutCheck_;
private:
/**
* Helper functions to handle new streams.

View File

@@ -413,6 +413,14 @@ class TestQuicTransport
return readLooper_;
}
void runCheckIdleTimer(TimePoint now) {
checkIdleTimer(now);
}
const IdleTimeoutCheck& getIdleTimeoutCheck() {
return idleTimeoutCheck_;
}
void unbindConnection() {}
void onReadError(const folly::AsyncSocketException&) noexcept {}
@@ -4961,5 +4969,46 @@ TEST_P(
transport.reset();
}
TEST_P(QuicTransportImplTestBase, TestCheckIdleTimerTimerActiveConnNotExpired) {
auto transportSettings = transport->getTransportSettings();
transportSettings.checkIdleTimerOnWrite = true;
transport->setTransportSettings(transportSettings);
transport->getConnectionState().streamManager->refreshTransportSettings(
transportSettings);
transport->transportConn->oneRttWriteCipher = test::createNoOpAead();
EXPECT_FALSE(transport->isClosed());
transport->setIdleTimeout();
transport->runCheckIdleTimer(Clock::now());
qEvb->loopOnce();
EXPECT_FALSE(transport->isClosed());
transport.reset();
}
TEST_P(QuicTransportImplTestBase, TestCheckIdleTimerTimerActiveConnExpired) {
auto transportSettings = transport->getTransportSettings();
transportSettings.checkIdleTimerOnWrite = true;
transport->setTransportSettings(transportSettings);
transport->getConnectionState().streamManager->refreshTransportSettings(
transportSettings);
transport->transportConn->oneRttWriteCipher = test::createNoOpAead();
EXPECT_FALSE(transport->isClosed());
transport->setIdleTimeout();
const auto& idleTimerCheck = transport->getIdleTimeoutCheck();
TimePoint fakeFutureTs = Clock::now() +
std::chrono::milliseconds(idleTimerCheck.idleTimeoutMs.count() + 1000);
transport->runCheckIdleTimer(fakeFutureTs);
qEvb->loopOnce();
EXPECT_TRUE(transport->isClosed());
transport.reset();
}
} // namespace test
} // namespace quic

View File

@@ -395,6 +395,8 @@ struct TransportSettings {
// If flow control updates should be sent based on time passed since last
// update.
bool enableFlowControlTimeBasedUpdates{true};
// Check if idle timer needs to be triggered manually.
bool checkIdleTimerOnWrite{false};
};
} // namespace quic