From a9ca8b687b2882c32ceb94aa538117e709a564aa Mon Sep 17 00:00:00 2001 From: Paul-Louis Ageneau Date: Thu, 20 May 2021 14:06:44 +0200 Subject: [PATCH 1/3] Exposed SCTP RTO and RTX settings --- include/rtc/global.hpp | 5 +++++ include/rtc/rtc.h | 19 ++++++++++++------- src/capi.cpp | 15 +++++++++++++++ src/impl/sctptransport.cpp | 30 +++++++++++++++++++++--------- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/include/rtc/global.hpp b/include/rtc/global.hpp index d51b1c7..2332b0b 100644 --- a/include/rtc/global.hpp +++ b/include/rtc/global.hpp @@ -54,6 +54,11 @@ struct SctpSettings { optional maxBurst; // in MTUs optional congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC optional delayedSackTime; + optional minRetransmitTimeout; + optional maxRetransmitTimeout; + optional initialRetransmitTimeout; + optional maxRetransmitAttempts; + optional heartbeatInterval; }; RTC_EXPORT void SetSctpSettings(SctpSettings s); diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index ec53242..9d5c0eb 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -340,13 +340,18 @@ RTC_EXPORT void rtcCleanup(void); // SCTP global settings typedef struct { - int recvBufferSize; // in bytes, <= 0 means optimized default - int sendBufferSize; // in bytes, <= 0 means optimized default - int maxChunksOnQueue; // in chunks, <= 0 means optimized default - int initialCongestionWindow; // in MTUs, <= 0 means optimized default - int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled - int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC - int delayedSackTimeMs; // in msecs, <= 0 means optimized default + int recvBufferSize; // in bytes, <= 0 means optimized default + int sendBufferSize; // in bytes, <= 0 means optimized default + int maxChunksOnQueue; // in chunks, <= 0 means optimized default + int initialCongestionWindow; // in MTUs, <= 0 means optimized default + int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled + int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC + int delayedSackTimeMs; // in msecs, <= 0 means optimized default + int minRetransmitTimeoutMs; // in msecs, <= 0 means optimized default + int maxRetransmitTimeoutMs; // in msecs, <= 0 means optimized default + int initialRetransmitTimeoutMs; // in msecs, <= 0 means optimized default + int maxRetransmitAttempts; // number of retransmissions, <= 0 means optimized default + int heartbeatIntervalMs; // in msecs, <= 0 means optimized default } rtcSctpSettings; // Note: SCTP settings apply to newly-created PeerConnections only diff --git a/src/capi.cpp b/src/capi.cpp index 82edb3d..5363aad 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -1140,6 +1140,21 @@ int rtcSetSctpSettings(const rtcSctpSettings *settings) { if (settings->delayedSackTimeMs > 0) s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs); + if (settings->minRetransmitTimeoutMs > 0) + s.minRetransmitTimeout = std::chrono::milliseconds(settings->minRetransmitTimeoutMs); + + if (settings->maxRetransmitTimeoutMs > 0) + s.maxRetransmitTimeout = std::chrono::milliseconds(settings->maxRetransmitTimeoutMs); + + if (settings->initialRetransmitTimeoutMs > 0) + s.initialRetransmitTimeout = std::chrono::milliseconds(settings->initialRetransmitTimeoutMs); + + if (settings->maxRetransmitAttempts > 0) + s.maxRetransmitAttempts = settings->maxRetransmitAttempts; + + if (settings->heartbeatIntervalMs > 0) + s.heartbeatInterval = std::chrono::milliseconds(settings->heartbeatIntervalMs); + SetSctpSettings(std::move(s)); return RTC_ERR_SUCCESS; }); diff --git a/src/impl/sctptransport.cpp b/src/impl/sctptransport.cpp index c3d85a2..eb07430 100644 --- a/src/impl/sctptransport.cpp +++ b/src/impl/sctptransport.cpp @@ -92,14 +92,6 @@ void SctpTransport::Init() { usrsctp_init(0, &SctpTransport::WriteCallback, nullptr); usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758) usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification - usrsctp_sysctl_set_sctp_init_rtx_max_default(5); - usrsctp_sysctl_set_sctp_path_rtx_max_default(5); - usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path - usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000); // ms - usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000); // ms - usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms - usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms - usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms } void SctpTransport::SetSettings(const SctpSettings &s) { @@ -122,9 +114,29 @@ void SctpTransport::SetSettings(const SctpSettings &s) { // See https://github.com/paullouisageneau/libdatachannel/issues/354 usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0))); - // Reduce SACK delay to 20ms by default + // Reduce SACK delay to 20ms by default (the recommended default value from RFC 4960 is 200ms) usrsctp_sysctl_set_sctp_delayed_sack_time_default( to_uint32(s.delayedSackTime.value_or(20ms).count())); + + // RTO + usrsctp_sysctl_set_sctp_rto_min_default( + to_uint32(s.minRetransmitTimeout.value_or(1000ms).count())); + usrsctp_sysctl_set_sctp_rto_max_default( + to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); + usrsctp_sysctl_set_sctp_rto_initial_default( + to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); + usrsctp_sysctl_set_sctp_init_rto_max_default( + to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); + + // RTX + auto maxRtx = to_uint32(s.maxRetransmitAttempts.value_or(5)); + usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx); + usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx); + usrsctp_sysctl_set_sctp_path_rtx_max_default(maxRtx); // single path + + // Heartbeat interval + usrsctp_sysctl_set_sctp_heartbeat_interval_default( + to_uint32(s.heartbeatInterval.value_or(10000ms).count())); } void SctpTransport::Cleanup() { From 05a37c830681642e93d1156046782a97910241a5 Mon Sep 17 00:00:00 2001 From: Paul-Louis Ageneau Date: Thu, 20 May 2021 14:10:07 +0200 Subject: [PATCH 2/3] Allowed disabling delayed SACK from C API --- include/rtc/rtc.h | 2 +- src/capi.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index 9d5c0eb..c8b8856 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -346,7 +346,7 @@ typedef struct { int initialCongestionWindow; // in MTUs, <= 0 means optimized default int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC - int delayedSackTimeMs; // in msecs, <= 0 means optimized default + int delayedSackTimeMs; // in msecs, 0 means optimized default, < 0 means disabled int minRetransmitTimeoutMs; // in msecs, <= 0 means optimized default int maxRetransmitTimeoutMs; // in msecs, <= 0 means optimized default int initialRetransmitTimeoutMs; // in msecs, <= 0 means optimized default diff --git a/src/capi.cpp b/src/capi.cpp index 5363aad..194901f 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -1139,6 +1139,8 @@ int rtcSetSctpSettings(const rtcSctpSettings *settings) { if (settings->delayedSackTimeMs > 0) s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs); + else if (settings->delayedSackTimeMs < 0) + s.delayedSackTime = std::chrono::milliseconds(0); if (settings->minRetransmitTimeoutMs > 0) s.minRetransmitTimeout = std::chrono::milliseconds(settings->minRetransmitTimeoutMs); From ddbd963e7ef5f75122640323e39ab36ff98a000b Mon Sep 17 00:00:00 2001 From: Paul-Louis Ageneau Date: Thu, 20 May 2021 14:29:15 +0200 Subject: [PATCH 3/3] Reduced SCTP min RTO to 200ms --- src/impl/sctptransport.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/impl/sctptransport.cpp b/src/impl/sctptransport.cpp index eb07430..ddcaedf 100644 --- a/src/impl/sctptransport.cpp +++ b/src/impl/sctptransport.cpp @@ -118,17 +118,21 @@ void SctpTransport::SetSettings(const SctpSettings &s) { usrsctp_sysctl_set_sctp_delayed_sack_time_default( to_uint32(s.delayedSackTime.value_or(20ms).count())); - // RTO + // RTO settings + // RFC 2988 recommends a 1s min RTO, which is very high, but TCP on Linux has a 200ms min RTO usrsctp_sysctl_set_sctp_rto_min_default( - to_uint32(s.minRetransmitTimeout.value_or(1000ms).count())); + to_uint32(s.minRetransmitTimeout.value_or(200ms).count())); + // Set only 10s as max RTO instead of 60s for shorter connection timeout usrsctp_sysctl_set_sctp_rto_max_default( to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); - usrsctp_sysctl_set_sctp_rto_initial_default( - to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); usrsctp_sysctl_set_sctp_init_rto_max_default( to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count())); + // Still set 1s as initial RTO + usrsctp_sysctl_set_sctp_rto_initial_default( + to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count())); - // RTX + // RTX settings + // 5 retransmissions instead of 8 to shorten the backoff for shorter connection timeout auto maxRtx = to_uint32(s.maxRetransmitAttempts.value_or(5)); usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx); usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx);