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..c8b8856 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, < 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 + 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..194901f 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -1139,6 +1139,23 @@ 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); + + 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..ddcaedf 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,33 @@ 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 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(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_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 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); + 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() {