From db53f8e604db9050dd1b860c185558474d601a46 Mon Sep 17 00:00:00 2001 From: Qingsi Wang Date: Tue, 20 Feb 2018 14:45:49 -0800 Subject: [PATCH] Add configurable STUN binding request interval. STUN candidates use STUN binding requests to keep NAT bindings open. The interval at which the STUN keepalive pings are sent is configurable now via RTCConfiguration. TBR=sakal@webrtc.org Bug: None Change-Id: I5f99ea3fe1e9042fa2bf7dcab0aace78f57739e6 Reviewed-on: https://webrtc-review.googlesource.com/54180 Commit-Queue: Qingsi Wang Reviewed-by: Taylor Brandstetter Cr-Commit-Position: refs/heads/master@{#22109} --- api/peerconnectioninterface.h | 4 ++++ p2p/base/icetransportinternal.h | 3 +++ p2p/base/p2ptransportchannel.cc | 12 ++++++++++ p2p/base/portallocator.cc | 13 ++++++++++- p2p/base/portallocator.h | 16 ++++++++++++-- p2p/base/stunport.cc | 4 ++++ p2p/base/stunport.h | 4 +--- p2p/client/basicportallocator.cc | 13 +++++++++++ p2p/client/basicportallocator.h | 2 ++ pc/peerconnection.cc | 22 +++++++++++++------ pc/peerconnection.h | 3 ++- .../api/org/webrtc/PeerConnection.java | 11 ++++++++++ sdk/android/src/jni/pc/peerconnection.cc | 5 +++++ 13 files changed, 98 insertions(+), 14 deletions(-) diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h index 63912b22e7..9463c34c63 100644 --- a/api/peerconnectioninterface.h +++ b/api/peerconnectioninterface.h @@ -493,6 +493,10 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // (STUN pings), in milliseconds. rtc::Optional ice_check_min_interval; + // The interval in milliseconds at which STUN candidates will resend STUN + // binding requests to keep NAT bindings open. + rtc::Optional stun_candidate_keepalive_interval; + // ICE Periodic Regathering // If set, WebRTC will periodically create and propose candidates without // starting a new ICE generation. The regathering happens continuously with diff --git a/p2p/base/icetransportinternal.h b/p2p/base/icetransportinternal.h index 6888992618..13ba3316d9 100644 --- a/p2p/base/icetransportinternal.h +++ b/p2p/base/icetransportinternal.h @@ -114,6 +114,9 @@ struct IceConfig { // than this, no matter what other settings there are. // Measure in milliseconds. rtc::Optional ice_check_min_interval; + // The interval in milliseconds at which STUN candidates will resend STUN + // binding requests to keep NAT bindings open. + rtc::Optional stun_keepalive_interval; rtc::Optional network_preference; diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc index 71af657c3b..2ad4114c27 100644 --- a/p2p/base/p2ptransportchannel.cc +++ b/p2p/base/p2ptransportchannel.cc @@ -541,6 +541,18 @@ void P2PTransportChannel::SetIceConfig(const IceConfig& config) { ? config_.network_preference.value() : 0); } + + // TODO(qingsi): Resolve the naming conflict of stun_keepalive_delay in + // UDPPort and stun_keepalive_interval. + if (config_.stun_keepalive_interval != config.stun_keepalive_interval) { + config_.stun_keepalive_interval = config.stun_keepalive_interval; + allocator_session()->SetStunKeepaliveIntervalForReadyPorts( + config_.stun_keepalive_interval); + RTC_LOG(LS_INFO) << "Set STUN keepalive interval to " + << (config.stun_keepalive_interval.has_value() + ? config_.stun_keepalive_interval.value() + : -1); + } } const IceConfig& P2PTransportChannel::config() const { diff --git a/p2p/base/portallocator.cc b/p2p/base/portallocator.cc index 84c1df24da..6ef084ca63 100644 --- a/p2p/base/portallocator.cc +++ b/p2p/base/portallocator.cc @@ -103,7 +103,8 @@ bool PortAllocator::SetConfiguration( const std::vector& turn_servers, int candidate_pool_size, bool prune_turn_ports, - webrtc::TurnCustomizer* turn_customizer) { + webrtc::TurnCustomizer* turn_customizer, + const rtc::Optional& stun_candidate_keepalive_interval) { bool ice_servers_changed = (stun_servers != stun_servers_ || turn_servers != turn_servers_); stun_servers_ = stun_servers; @@ -142,6 +143,16 @@ bool PortAllocator::SetConfiguration( pooled_sessions_.pop_front(); } + // |stun_candidate_keepalive_interval_| will be used in STUN port allocation + // in future sessions. We also update the ready ports in the pooled sessions. + // Ports in sessions that are taken and owned by P2PTransportChannel will be + // updated there via IceConfig. + stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval; + for (const auto& session : pooled_sessions_) { + session->SetStunKeepaliveIntervalForReadyPorts( + stun_candidate_keepalive_interval_); + } + // If |candidate_pool_size_| is greater than the number of pooled sessions, // create new sessions. while (static_cast(pooled_sessions_.size()) < candidate_pool_size_) { diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h index 1081448918..f32fa07476 100644 --- a/p2p/base/portallocator.h +++ b/p2p/base/portallocator.h @@ -244,7 +244,12 @@ class PortAllocatorSession : public sigslot::has_slots<> { virtual void RegatherOnFailedNetworks() {} // Re-gathers candidates on all networks. virtual void RegatherOnAllNetworks() {} - + // Set the interval at which STUN candidates will resend STUN binding requests + // on the underlying ports to keep NAT bindings open. + // The default value of the interval in implementation is restored if a null + // optional value is passed. + virtual void SetStunKeepaliveIntervalForReadyPorts( + const rtc::Optional& stun_keepalive_interval) {} // Another way of getting the information provided by the signals below. // // Ports and candidates are not guaranteed to be in the same order as the @@ -347,7 +352,9 @@ class PortAllocator : public sigslot::has_slots<> { const std::vector& turn_servers, int candidate_pool_size, bool prune_turn_ports, - webrtc::TurnCustomizer* turn_customizer = nullptr); + webrtc::TurnCustomizer* turn_customizer = nullptr, + const rtc::Optional& + stun_candidate_keepalive_interval = rtc::nullopt); const ServerAddresses& stun_servers() const { return stun_servers_; } @@ -356,6 +363,9 @@ class PortAllocator : public sigslot::has_slots<> { } int candidate_pool_size() const { return candidate_pool_size_; } + const rtc::Optional& stun_candidate_keepalive_interval() const { + return stun_candidate_keepalive_interval_; + } // Sets the network types to ignore. // Values are defined by the AdapterType enum. @@ -506,6 +516,8 @@ class PortAllocator : public sigslot::has_slots<> { // The instance is owned by application and will be shared among // all TurnPort(s) created. webrtc::TurnCustomizer* turn_customizer_ = nullptr; + + rtc::Optional stun_candidate_keepalive_interval_; }; } // namespace cricket diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc index 69196cf130..2df14b7c62 100644 --- a/p2p/base/stunport.cc +++ b/p2p/base/stunport.cc @@ -317,6 +317,10 @@ ProtocolType UDPPort::GetProtocol() const { return PROTO_UDP; } +void UDPPort::set_stun_keepalive_delay(const rtc::Optional& delay) { + stun_keepalive_delay_ = (delay.has_value() ? delay.value() : KEEPALIVE_DELAY); +} + void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& address) { // When adapter enumeration is disabled and binding to the any address, the diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h index cf45d1df59..eaeea3ae91 100644 --- a/p2p/base/stunport.h +++ b/p2p/base/stunport.h @@ -101,9 +101,7 @@ class UDPPort : public Port { bool SupportsProtocol(const std::string& protocol) const override; ProtocolType GetProtocol() const override; - void set_stun_keepalive_delay(int delay) { - stun_keepalive_delay_ = delay; - } + void set_stun_keepalive_delay(const rtc::Optional& delay); int stun_keepalive_delay() const { return stun_keepalive_delay_; } diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc index 86cec8fb34..712d5959a4 100644 --- a/p2p/client/basicportallocator.cc +++ b/p2p/client/basicportallocator.cc @@ -429,6 +429,17 @@ void BasicPortAllocatorSession::Regather( } } +void BasicPortAllocatorSession::SetStunKeepaliveIntervalForReadyPorts( + const rtc::Optional& stun_keepalive_interval) { + auto ports = ReadyPorts(); + for (PortInterface* port : ports) { + if (port->Type() == STUN_PORT_TYPE) { + static_cast(port)->set_stun_keepalive_delay( + stun_keepalive_interval); + } + } +} + std::vector BasicPortAllocatorSession::ReadyPorts() const { std::vector ret; for (const PortData& data : ports_) { @@ -1357,6 +1368,8 @@ void AllocationSequence::CreateStunPorts() { session_->username(), session_->password(), config_->StunServers(), session_->allocator()->origin()); if (port) { + port->set_stun_keepalive_delay( + session_->allocator()->stun_candidate_keepalive_interval()); session_->AddAllocatedPort(port, this, true); // Since StunPort is not created using shared socket, |port| will not be // added to the dequeue. diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h index 23faff1cba..fb74ba5d74 100644 --- a/p2p/client/basicportallocator.h +++ b/p2p/client/basicportallocator.h @@ -127,6 +127,8 @@ class BasicPortAllocatorSession : public PortAllocatorSession, bool CandidatesAllocationDone() const override; void RegatherOnFailedNetworks() override; void RegatherOnAllNetworks() override; + void SetStunKeepaliveIntervalForReadyPorts( + const rtc::Optional& stun_keepalive_interval) override; void PruneAllPorts() override; protected: diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index 73f79c8a11..f32b478cc3 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -636,6 +636,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( bool enable_ice_renomination; bool redetermine_role_on_ice_restart; rtc::Optional ice_check_min_interval; + rtc::Optional stun_candidate_keepalive_interval; rtc::Optional ice_regather_interval_range; webrtc::TurnCustomizer* turn_customizer; SdpSemantics sdp_semantics; @@ -675,6 +676,8 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( enable_ice_renomination == o.enable_ice_renomination && redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart && ice_check_min_interval == o.ice_check_min_interval && + stun_candidate_keepalive_interval == + o.stun_candidate_keepalive_interval && ice_regather_interval_range == o.ice_regather_interval_range && turn_customizer == o.turn_customizer && sdp_semantics == o.sdp_semantics && @@ -2654,6 +2657,8 @@ bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration, configuration.ice_candidate_pool_size; modified_config.prune_turn_ports = configuration.prune_turn_ports; modified_config.ice_check_min_interval = configuration.ice_check_min_interval; + modified_config.stun_candidate_keepalive_interval = + configuration.stun_candidate_keepalive_interval; modified_config.turn_customizer = configuration.turn_customizer; modified_config.network_preference = configuration.network_preference; if (configuration != modified_config) { @@ -2690,7 +2695,8 @@ bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration, stun_servers, turn_servers, modified_config.type, modified_config.ice_candidate_pool_size, modified_config.prune_turn_ports, - modified_config.turn_customizer))) { + modified_config.turn_customizer, + modified_config.stun_candidate_keepalive_interval))) { RTC_LOG(LS_ERROR) << "Failed to apply configuration to PortAllocator."; return SafeSetError(RTCErrorType::INTERNAL_ERROR, error); } @@ -4394,10 +4400,10 @@ bool PeerConnection::InitializePortAllocator_n( // Call this last since it may create pooled allocator sessions using the // properties set above. - port_allocator_->SetConfiguration(stun_servers, turn_servers, - configuration.ice_candidate_pool_size, - configuration.prune_turn_ports, - configuration.turn_customizer); + port_allocator_->SetConfiguration( + stun_servers, turn_servers, configuration.ice_candidate_pool_size, + configuration.prune_turn_ports, configuration.turn_customizer, + configuration.stun_candidate_keepalive_interval); return true; } @@ -4407,14 +4413,15 @@ bool PeerConnection::ReconfigurePortAllocator_n( IceTransportsType type, int candidate_pool_size, bool prune_turn_ports, - webrtc::TurnCustomizer* turn_customizer) { + webrtc::TurnCustomizer* turn_customizer, + rtc::Optional stun_candidate_keepalive_interval) { port_allocator_->set_candidate_filter( ConvertIceTransportTypeToCandidateFilter(type)); // Call this last since it may create pooled allocator sessions using the // candidate filter set above. return port_allocator_->SetConfiguration( stun_servers, turn_servers, candidate_pool_size, prune_turn_ports, - turn_customizer); + turn_customizer, stun_candidate_keepalive_interval); } cricket::ChannelManager* PeerConnection::channel_manager() const { @@ -4778,6 +4785,7 @@ cricket::IceConfig PeerConnection::ParseIceConfig( ice_config.presume_writable_when_fully_relayed = config.presume_writable_when_fully_relayed; ice_config.ice_check_min_interval = config.ice_check_min_interval; + ice_config.stun_keepalive_interval = config.stun_candidate_keepalive_interval; ice_config.regather_all_networks_interval_range = config.ice_regather_interval_range; ice_config.network_preference = config.network_preference; diff --git a/pc/peerconnection.h b/pc/peerconnection.h index 3eccb96b96..d788b1e76d 100644 --- a/pc/peerconnection.h +++ b/pc/peerconnection.h @@ -661,7 +661,8 @@ class PeerConnection : public PeerConnectionInternal, IceTransportsType type, int candidate_pool_size, bool prune_turn_ports, - webrtc::TurnCustomizer* turn_customizer); + webrtc::TurnCustomizer* turn_customizer, + rtc::Optional stun_candidate_keepalive_interval); // Starts output of an RTC event log to the given output object. // This function should only be called from the worker thread. diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index c6598b76d1..de1e57d787 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -342,6 +342,7 @@ public class PeerConnection { } /** Java version of PeerConnectionInterface.RTCConfiguration */ + // TODO(qingsi): Resolve the naming inconsistency of fields with/without units. public static class RTCConfiguration { public IceTransportsType iceTransportsType; public List iceServers; @@ -359,6 +360,10 @@ public class PeerConnection { public boolean pruneTurnPorts; public boolean presumeWritableWhenFullyRelayed; public Integer iceCheckMinInterval; + // The interval in milliseconds at which STUN candidates will resend STUN binding requests + // to keep NAT bindings open. + // The default value in the implementation is used if this field is null. + public Integer stunCandidateKeepaliveIntervalMs; public boolean disableIPv6OnWifi; // By default, PeerConnection will use a limited number of IPv6 network // interfaces, in order to avoid too many ICE candidate pairs being created @@ -405,6 +410,7 @@ public class PeerConnection { pruneTurnPorts = false; presumeWritableWhenFullyRelayed = false; iceCheckMinInterval = null; + stunCandidateKeepaliveIntervalMs = null; disableIPv6OnWifi = false; maxIPv6Networks = 5; iceRegatherIntervalRange = null; @@ -499,6 +505,11 @@ public class PeerConnection { return iceCheckMinInterval; } + @CalledByNative("RTCConfiguration") + Integer getStunCandidateKeepaliveInterval() { + return stunCandidateKeepaliveIntervalMs; + } + @CalledByNative("RTCConfiguration") boolean getDisableIPv6OnWifi() { return disableIPv6OnWifi; diff --git a/sdk/android/src/jni/pc/peerconnection.cc b/sdk/android/src/jni/pc/peerconnection.cc index f6f3932fa5..f954a4330c 100644 --- a/sdk/android/src/jni/pc/peerconnection.cc +++ b/sdk/android/src/jni/pc/peerconnection.cc @@ -156,6 +156,11 @@ void JavaToNativeRTCConfiguration( Java_RTCConfiguration_getIceCheckMinInterval(jni, j_rtc_config); rtc_config->ice_check_min_interval = JavaToNativeOptionalInt(jni, j_ice_check_min_interval); + ScopedJavaLocalRef j_stun_candidate_keepalive_interval = + Java_RTCConfiguration_getStunCandidateKeepaliveInterval(jni, + j_rtc_config); + rtc_config->stun_candidate_keepalive_interval = + JavaToNativeOptionalInt(jni, j_stun_candidate_keepalive_interval); rtc_config->disable_ipv6_on_wifi = Java_RTCConfiguration_getDisableIPv6OnWifi(jni, j_rtc_config); rtc_config->max_ipv6_networks =