dcsctp: Allow heartbeats to be disabled
This is useful in tests and in scenarios where the connection is
monitored externally and the heartbeat monitoring would be of no use.
Bug: webrtc:12614
Change-Id: Ida4f4e2e40fc4d2aa0c27ae9431f434da4cc8313
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220766
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34164}
diff --git a/net/dcsctp/public/dcsctp_options.h b/net/dcsctp/public/dcsctp_options.h
index 1c4e328..caefcff 100644
--- a/net/dcsctp/public/dcsctp_options.h
+++ b/net/dcsctp/public/dcsctp_options.h
@@ -112,7 +112,7 @@
// T2-shutdown timeout.
DurationMs t2_shutdown_timeout = DurationMs(1000);
- // Hearbeat interval (on idle connections only).
+ // Hearbeat interval (on idle connections only). Set to zero to disable.
DurationMs heartbeat_interval = DurationMs(30000);
// The maximum time when a SACK will be sent from the arrival of an
diff --git a/net/dcsctp/socket/heartbeat_handler.cc b/net/dcsctp/socket/heartbeat_handler.cc
index 30a0001..78616d1 100644
--- a/net/dcsctp/socket/heartbeat_handler.cc
+++ b/net/dcsctp/socket/heartbeat_handler.cc
@@ -104,10 +104,15 @@
TimerBackoffAlgorithm::kExponential,
/*max_restarts=*/0))) {
// The interval timer must always be running as long as the association is up.
- interval_timer_->Start();
+ RestartTimer();
}
void HeartbeatHandler::RestartTimer() {
+ if (interval_duration_ == DurationMs(0)) {
+ // Heartbeating has been disabled.
+ return;
+ }
+
if (interval_duration_should_include_rtt_) {
// The RTT should be used, but it's not easy accessible. The RTO will
// suffice.
diff --git a/net/dcsctp/socket/heartbeat_handler_test.cc b/net/dcsctp/socket/heartbeat_handler_test.cc
index 20c1d46..2c5df9f 100644
--- a/net/dcsctp/socket/heartbeat_handler_test.cc
+++ b/net/dcsctp/socket/heartbeat_handler_test.cc
@@ -30,17 +30,19 @@
using ::testing::Return;
using ::testing::SizeIs;
-DcSctpOptions MakeOptions() {
+constexpr DurationMs kHeartbeatInterval = DurationMs(30'000);
+
+DcSctpOptions MakeOptions(DurationMs heartbeat_interval) {
DcSctpOptions options;
options.heartbeat_interval_include_rtt = false;
- options.heartbeat_interval = DurationMs(30'000);
+ options.heartbeat_interval = heartbeat_interval;
return options;
}
-class HeartbeatHandlerTest : public testing::Test {
+class HeartbeatHandlerTestBase : public testing::Test {
protected:
- HeartbeatHandlerTest()
- : options_(MakeOptions()),
+ explicit HeartbeatHandlerTestBase(DurationMs heartbeat_interval)
+ : options_(MakeOptions(heartbeat_interval)),
context_(&callbacks_),
timer_manager_([this]() { return callbacks_.CreateTimeout(); }),
handler_("log: ", options_, &context_, &timer_manager_) {}
@@ -63,6 +65,31 @@
HeartbeatHandler handler_;
};
+class HeartbeatHandlerTest : public HeartbeatHandlerTestBase {
+ protected:
+ HeartbeatHandlerTest() : HeartbeatHandlerTestBase(kHeartbeatInterval) {}
+};
+
+class DisabledHeartbeatHandlerTest : public HeartbeatHandlerTestBase {
+ protected:
+ DisabledHeartbeatHandlerTest() : HeartbeatHandlerTestBase(DurationMs(0)) {}
+};
+
+TEST_F(HeartbeatHandlerTest, HasRunningHeartbeatIntervalTimer) {
+ AdvanceTime(options_.heartbeat_interval);
+
+ // Validate that a heartbeat request was sent.
+ std::vector<uint8_t> payload = callbacks_.ConsumeSentPacket();
+ ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, SctpPacket::Parse(payload));
+ ASSERT_THAT(packet.descriptors(), SizeIs(1));
+
+ ASSERT_HAS_VALUE_AND_ASSIGN(
+ HeartbeatRequestChunk request,
+ HeartbeatRequestChunk::Parse(packet.descriptors()[0].data));
+
+ EXPECT_TRUE(request.info().has_value());
+}
+
TEST_F(HeartbeatHandlerTest, RepliesToHeartbeatRequests) {
uint8_t info_data[] = {1, 2, 3, 4, 5};
HeartbeatRequestChunk request(
@@ -120,5 +147,12 @@
AdvanceTime(rto);
}
+TEST_F(DisabledHeartbeatHandlerTest, IsReallyDisabled) {
+ AdvanceTime(options_.heartbeat_interval);
+
+ // Validate that a request was NOT sent.
+ EXPECT_THAT(callbacks_.ConsumeSentPacket(), IsEmpty());
+}
+
} // namespace
} // namespace dcsctp