summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/p2p/base/port_allocator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/p2p/base/port_allocator.cc')
-rw-r--r--third_party/libwebrtc/p2p/base/port_allocator.cc349
1 files changed, 349 insertions, 0 deletions
diff --git a/third_party/libwebrtc/p2p/base/port_allocator.cc b/third_party/libwebrtc/p2p/base/port_allocator.cc
new file mode 100644
index 0000000000..522f0beb98
--- /dev/null
+++ b/third_party/libwebrtc/p2p/base/port_allocator.cc
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "p2p/base/port_allocator.h"
+
+#include <iterator>
+#include <set>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "p2p/base/ice_credentials_iterator.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace cricket {
+
+RelayServerConfig::RelayServerConfig() {}
+
+RelayServerConfig::RelayServerConfig(const rtc::SocketAddress& address,
+ absl::string_view username,
+ absl::string_view password,
+ ProtocolType proto)
+ : credentials(username, password) {
+ ports.push_back(ProtocolAddress(address, proto));
+}
+
+RelayServerConfig::RelayServerConfig(absl::string_view address,
+ int port,
+ absl::string_view username,
+ absl::string_view password,
+ ProtocolType proto)
+ : RelayServerConfig(rtc::SocketAddress(address, port),
+ username,
+ password,
+ proto) {}
+
+// Legacy constructor where "secure" and PROTO_TCP implies PROTO_TLS.
+RelayServerConfig::RelayServerConfig(absl::string_view address,
+ int port,
+ absl::string_view username,
+ absl::string_view password,
+ ProtocolType proto,
+ bool secure)
+ : RelayServerConfig(address,
+ port,
+ username,
+ password,
+ (proto == PROTO_TCP && secure ? PROTO_TLS : proto)) {}
+
+RelayServerConfig::RelayServerConfig(const RelayServerConfig&) = default;
+
+RelayServerConfig::~RelayServerConfig() = default;
+
+PortAllocatorSession::PortAllocatorSession(absl::string_view content_name,
+ int component,
+ absl::string_view ice_ufrag,
+ absl::string_view ice_pwd,
+ uint32_t flags)
+ : flags_(flags),
+ generation_(0),
+ content_name_(content_name),
+ component_(component),
+ ice_ufrag_(ice_ufrag),
+ ice_pwd_(ice_pwd),
+ tiebreaker_(0) {
+ // Pooled sessions are allowed to be created with empty content name,
+ // component, ufrag and password.
+ RTC_DCHECK(ice_ufrag.empty() == ice_pwd.empty());
+}
+
+PortAllocatorSession::~PortAllocatorSession() = default;
+
+bool PortAllocatorSession::IsCleared() const {
+ return false;
+}
+
+bool PortAllocatorSession::IsStopped() const {
+ return false;
+}
+
+uint32_t PortAllocatorSession::generation() {
+ return generation_;
+}
+
+void PortAllocatorSession::set_generation(uint32_t generation) {
+ generation_ = generation;
+}
+
+PortAllocator::PortAllocator()
+ : flags_(kDefaultPortAllocatorFlags),
+ min_port_(0),
+ max_port_(0),
+ max_ipv6_networks_(kDefaultMaxIPv6Networks),
+ step_delay_(kDefaultStepDelay),
+ allow_tcp_listen_(true),
+ candidate_filter_(CF_ALL),
+ tiebreaker_(0) {
+ // The allocator will be attached to a thread in Initialize.
+ thread_checker_.Detach();
+}
+
+void PortAllocator::Initialize() {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ initialized_ = true;
+}
+
+PortAllocator::~PortAllocator() {
+ CheckRunOnValidThreadIfInitialized();
+}
+
+void PortAllocator::set_restrict_ice_credentials_change(bool value) {
+ restrict_ice_credentials_change_ = value;
+}
+
+// Deprecated
+bool PortAllocator::SetConfiguration(
+ const ServerAddresses& stun_servers,
+ const std::vector<RelayServerConfig>& turn_servers,
+ int candidate_pool_size,
+ bool prune_turn_ports,
+ webrtc::TurnCustomizer* turn_customizer,
+ const absl::optional<int>& stun_candidate_keepalive_interval) {
+ webrtc::PortPrunePolicy turn_port_prune_policy =
+ prune_turn_ports ? webrtc::PRUNE_BASED_ON_PRIORITY : webrtc::NO_PRUNE;
+ return SetConfiguration(stun_servers, turn_servers, candidate_pool_size,
+ turn_port_prune_policy, turn_customizer,
+ stun_candidate_keepalive_interval);
+}
+
+bool PortAllocator::SetConfiguration(
+ const ServerAddresses& stun_servers,
+ const std::vector<RelayServerConfig>& turn_servers,
+ int candidate_pool_size,
+ webrtc::PortPrunePolicy turn_port_prune_policy,
+ webrtc::TurnCustomizer* turn_customizer,
+ const absl::optional<int>& stun_candidate_keepalive_interval) {
+ CheckRunOnValidThreadIfInitialized();
+ // A positive candidate pool size would lead to the creation of a pooled
+ // allocator session and starting getting ports, which we should only do on
+ // the network thread.
+ RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.IsCurrent());
+ bool ice_servers_changed =
+ (stun_servers != stun_servers_ || turn_servers != turn_servers_);
+ stun_servers_ = stun_servers;
+ turn_servers_ = turn_servers;
+ turn_port_prune_policy_ = turn_port_prune_policy;
+
+ if (candidate_pool_frozen_) {
+ if (candidate_pool_size != candidate_pool_size_) {
+ RTC_LOG(LS_ERROR)
+ << "Trying to change candidate pool size after pool was frozen.";
+ return false;
+ }
+ return true;
+ }
+
+ if (candidate_pool_size < 0) {
+ RTC_LOG(LS_ERROR) << "Can't set negative pool size.";
+ return false;
+ }
+
+ candidate_pool_size_ = candidate_pool_size;
+
+ // If ICE servers changed, throw away any existing pooled sessions and create
+ // new ones.
+ if (ice_servers_changed) {
+ pooled_sessions_.clear();
+ }
+
+ turn_customizer_ = turn_customizer;
+
+ // If `candidate_pool_size_` is less than the number of pooled sessions, get
+ // rid of the extras.
+ while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
+ pooled_sessions_.back().reset(nullptr);
+ pooled_sessions_.pop_back();
+ }
+
+ // `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<int>(pooled_sessions_.size()) < candidate_pool_size_) {
+ IceParameters iceCredentials =
+ IceCredentialsIterator::CreateRandomIceCredentials();
+ PortAllocatorSession* pooled_session =
+ CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
+ pooled_session->set_pooled(true);
+ pooled_session->set_ice_tiebreaker(tiebreaker_);
+ pooled_session->StartGettingPorts();
+ pooled_sessions_.push_back(
+ std::unique_ptr<PortAllocatorSession>(pooled_session));
+ }
+ return true;
+}
+
+void PortAllocator::SetIceTiebreaker(uint64_t tiebreaker) {
+ tiebreaker_ = tiebreaker;
+ for (auto& pooled_session : pooled_sessions_) {
+ pooled_session->set_ice_tiebreaker(tiebreaker_);
+ }
+}
+
+std::unique_ptr<PortAllocatorSession> PortAllocator::CreateSession(
+ absl::string_view content_name,
+ int component,
+ absl::string_view ice_ufrag,
+ absl::string_view ice_pwd) {
+ CheckRunOnValidThreadAndInitialized();
+ auto session = std::unique_ptr<PortAllocatorSession>(
+ CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd));
+ session->SetCandidateFilter(candidate_filter());
+ session->set_ice_tiebreaker(tiebreaker_);
+ return session;
+}
+
+std::unique_ptr<PortAllocatorSession> PortAllocator::TakePooledSession(
+ absl::string_view content_name,
+ int component,
+ absl::string_view ice_ufrag,
+ absl::string_view ice_pwd) {
+ CheckRunOnValidThreadAndInitialized();
+ RTC_DCHECK(!ice_ufrag.empty());
+ RTC_DCHECK(!ice_pwd.empty());
+ if (pooled_sessions_.empty()) {
+ return nullptr;
+ }
+
+ IceParameters credentials(ice_ufrag, ice_pwd, false);
+ // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
+ // with ice credentials. Otherwise call it with nullptr which means
+ // "find any" pooled session.
+ auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
+ : nullptr);
+ if (cit == pooled_sessions_.end()) {
+ return nullptr;
+ }
+
+ auto it =
+ pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
+ std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
+ ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
+ ret->set_pooled(false);
+ // According to JSEP, a pooled session should filter candidates only
+ // after it's taken out of the pool.
+ ret->SetCandidateFilter(candidate_filter());
+ pooled_sessions_.erase(it);
+ return ret;
+}
+
+const PortAllocatorSession* PortAllocator::GetPooledSession(
+ const IceParameters* ice_credentials) const {
+ CheckRunOnValidThreadAndInitialized();
+ auto it = FindPooledSession(ice_credentials);
+ if (it == pooled_sessions_.end()) {
+ return nullptr;
+ } else {
+ return it->get();
+ }
+}
+
+std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
+PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
+ for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
+ if (ice_credentials == nullptr ||
+ ((*it)->ice_ufrag() == ice_credentials->ufrag &&
+ (*it)->ice_pwd() == ice_credentials->pwd)) {
+ return it;
+ }
+ }
+ return pooled_sessions_.end();
+}
+
+void PortAllocator::FreezeCandidatePool() {
+ CheckRunOnValidThreadAndInitialized();
+ candidate_pool_frozen_ = true;
+}
+
+void PortAllocator::DiscardCandidatePool() {
+ CheckRunOnValidThreadIfInitialized();
+ pooled_sessions_.clear();
+}
+
+void PortAllocator::SetCandidateFilter(uint32_t filter) {
+ CheckRunOnValidThreadIfInitialized();
+ if (candidate_filter_ == filter) {
+ return;
+ }
+ uint32_t prev_filter = candidate_filter_;
+ candidate_filter_ = filter;
+ SignalCandidateFilterChanged(prev_filter, filter);
+}
+
+void PortAllocator::GetCandidateStatsFromPooledSessions(
+ CandidateStatsList* candidate_stats_list) {
+ CheckRunOnValidThreadAndInitialized();
+ for (const auto& session : pooled_sessions()) {
+ session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
+ }
+}
+
+std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
+ CheckRunOnValidThreadAndInitialized();
+ std::vector<IceParameters> list;
+ for (const auto& session : pooled_sessions_) {
+ list.push_back(
+ IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
+ }
+ return list;
+}
+
+Candidate PortAllocator::SanitizeCandidate(const Candidate& c) const {
+ CheckRunOnValidThreadAndInitialized();
+ // For a local host candidate, we need to conceal its IP address candidate if
+ // the mDNS obfuscation is enabled.
+ bool use_hostname_address =
+ (c.type() == LOCAL_PORT_TYPE || c.type() == PRFLX_PORT_TYPE) &&
+ MdnsObfuscationEnabled();
+ // If adapter enumeration is disabled or host candidates are disabled,
+ // clear the raddr of STUN candidates to avoid local address leakage.
+ bool filter_stun_related_address =
+ ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
+ (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
+ !(candidate_filter_ & CF_HOST) || MdnsObfuscationEnabled();
+ // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
+ // to avoid reflexive address leakage.
+ bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
+ bool filter_related_address =
+ ((c.type() == STUN_PORT_TYPE && filter_stun_related_address) ||
+ (c.type() == RELAY_PORT_TYPE && filter_turn_related_address));
+ return c.ToSanitizedCopy(use_hostname_address, filter_related_address);
+}
+
+} // namespace cricket