blob: d3b3a56edd926c7c0a0314bc53c86a472974c22b [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/portallocator.h"
Steve Anton6c38cc72017-11-29 10:25:58 -080012
Jonas Oreland1cd39fa2018-10-11 07:47:12 +020013#include <iterator>
Steve Anton6c38cc72017-11-29 10:25:58 -080014#include <utility>
15
Jonas Oreland1cd39fa2018-10-11 07:47:12 +020016#include "p2p/base/icecredentialsiterator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000018
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000019namespace cricket {
20
Steve Anton7995d8c2017-10-30 16:23:38 -070021RelayServerConfig::RelayServerConfig(RelayType type) : type(type) {}
22
23RelayServerConfig::RelayServerConfig(const rtc::SocketAddress& address,
24 const std::string& username,
25 const std::string& password,
26 ProtocolType proto)
27 : type(RELAY_TURN), credentials(username, password) {
28 ports.push_back(ProtocolAddress(address, proto));
29}
30
31RelayServerConfig::RelayServerConfig(const std::string& address,
32 int port,
33 const std::string& username,
34 const std::string& password,
35 ProtocolType proto)
36 : RelayServerConfig(rtc::SocketAddress(address, port),
37 username,
38 password,
39 proto) {}
40
41// Legacy constructor where "secure" and PROTO_TCP implies PROTO_TLS.
42RelayServerConfig::RelayServerConfig(const std::string& address,
43 int port,
44 const std::string& username,
45 const std::string& password,
46 ProtocolType proto,
47 bool secure)
48 : RelayServerConfig(address,
49 port,
50 username,
51 password,
52 (proto == PROTO_TCP && secure ? PROTO_TLS : proto)) {}
53
54RelayServerConfig::RelayServerConfig(const RelayServerConfig&) = default;
55
56RelayServerConfig::~RelayServerConfig() = default;
57
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058PortAllocatorSession::PortAllocatorSession(const std::string& content_name,
59 int component,
60 const std::string& ice_ufrag,
61 const std::string& ice_pwd,
Peter Boström0c4e06b2015-10-07 12:23:21 +020062 uint32_t flags)
Taylor Brandstettera1c30352016-05-13 08:15:11 -070063 : flags_(flags),
deadbeefc55fb302016-05-12 12:51:38 -070064 generation_(0),
Taylor Brandstettera1c30352016-05-13 08:15:11 -070065 content_name_(content_name),
66 component_(component),
deadbeefcbecd352015-09-23 11:50:27 -070067 ice_ufrag_(ice_ufrag),
68 ice_pwd_(ice_pwd) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -070069 // Pooled sessions are allowed to be created with empty content name,
70 // component, ufrag and password.
71 RTC_DCHECK(ice_ufrag.empty() == ice_pwd.empty());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000072}
73
Steve Anton7995d8c2017-10-30 16:23:38 -070074PortAllocatorSession::~PortAllocatorSession() = default;
75
76bool PortAllocatorSession::IsCleared() const {
77 return false;
78}
79
80bool PortAllocatorSession::IsStopped() const {
81 return false;
82}
83
Qingsi Wang72a43a12018-02-20 16:03:18 -080084void PortAllocatorSession::GetCandidateStatsFromReadyPorts(
85 CandidateStatsList* candidate_stats_list) const {
86 auto ports = ReadyPorts();
87 for (auto* port : ports) {
88 auto candidates = port->Candidates();
89 for (const auto& candidate : candidates) {
90 CandidateStats candidate_stats(candidate);
91 port->GetStunStats(&candidate_stats.stun_stats);
92 candidate_stats_list->push_back(std::move(candidate_stats));
93 }
94 }
95}
96
Steve Anton7995d8c2017-10-30 16:23:38 -070097uint32_t PortAllocatorSession::generation() {
98 return generation_;
99}
100
101void PortAllocatorSession::set_generation(uint32_t generation) {
102 generation_ = generation;
103}
104
105PortAllocator::PortAllocator()
106 : flags_(kDefaultPortAllocatorFlags),
107 min_port_(0),
108 max_port_(0),
109 max_ipv6_networks_(kDefaultMaxIPv6Networks),
110 step_delay_(kDefaultStepDelay),
111 allow_tcp_listen_(true),
Qingsi Wanga2d60672018-04-11 16:57:45 -0700112 candidate_filter_(CF_ALL) {
113 // The allocator will be attached to a thread in Initialize.
114 thread_checker_.DetachFromThread();
115}
Steve Anton7995d8c2017-10-30 16:23:38 -0700116
Qingsi Wanga2d60672018-04-11 16:57:45 -0700117void PortAllocator::Initialize() {
118 RTC_DCHECK(thread_checker_.CalledOnValidThread());
119 initialized_ = true;
120}
121
122PortAllocator::~PortAllocator() {
123 CheckRunOnValidThreadIfInitialized();
124}
Steve Anton7995d8c2017-10-30 16:23:38 -0700125
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200126void PortAllocator::set_restrict_ice_credentials_change(bool value) {
127 restrict_ice_credentials_change_ = value;
128}
129
deadbeef6de92f92016-12-12 18:49:32 -0800130bool PortAllocator::SetConfiguration(
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700131 const ServerAddresses& stun_servers,
132 const std::vector<RelayServerConfig>& turn_servers,
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700133 int candidate_pool_size,
Jonas Orelandbdcee282017-10-10 14:01:40 +0200134 bool prune_turn_ports,
Qingsi Wangdb53f8e2018-02-20 14:45:49 -0800135 webrtc::TurnCustomizer* turn_customizer,
Danil Chapovalov00c71832018-06-15 15:58:38 +0200136 const absl::optional<int>& stun_candidate_keepalive_interval) {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700137 CheckRunOnValidThreadIfInitialized();
Qingsi Wange6ded162018-10-02 16:00:41 -0700138 // A positive candidate pool size would lead to the creation of a pooled
139 // allocator session and starting getting ports, which we should only do on
140 // the network thread.
141 RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.CalledOnValidThread());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700142 bool ice_servers_changed =
143 (stun_servers != stun_servers_ || turn_servers != turn_servers_);
144 stun_servers_ = stun_servers;
145 turn_servers_ = turn_servers;
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700146 prune_turn_ports_ = prune_turn_ports;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700147
deadbeef42a42632017-03-10 15:18:00 -0800148 if (candidate_pool_frozen_) {
149 if (candidate_pool_size != candidate_pool_size_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100150 RTC_LOG(LS_ERROR)
Jonas Olssond7d762d2018-03-28 09:47:51 +0200151 << "Trying to change candidate pool size after pool was frozen.";
deadbeef42a42632017-03-10 15:18:00 -0800152 return false;
153 }
154 return true;
deadbeef6de92f92016-12-12 18:49:32 -0800155 }
deadbeef42a42632017-03-10 15:18:00 -0800156
deadbeef6de92f92016-12-12 18:49:32 -0800157 if (candidate_pool_size < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100158 RTC_LOG(LS_ERROR) << "Can't set negative pool size.";
deadbeef6de92f92016-12-12 18:49:32 -0800159 return false;
160 }
deadbeef6de92f92016-12-12 18:49:32 -0800161
deadbeef42a42632017-03-10 15:18:00 -0800162 candidate_pool_size_ = candidate_pool_size;
deadbeef6de92f92016-12-12 18:49:32 -0800163
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700164 // If ICE servers changed, throw away any existing pooled sessions and create
165 // new ones.
166 if (ice_servers_changed) {
167 pooled_sessions_.clear();
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700168 }
169
Jonas Orelandbdcee282017-10-10 14:01:40 +0200170 turn_customizer_ = turn_customizer;
171
deadbeef42a42632017-03-10 15:18:00 -0800172 // If |candidate_pool_size_| is less than the number of pooled sessions, get
173 // rid of the extras.
174 while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200175 pooled_sessions_.back().reset(nullptr);
176 pooled_sessions_.pop_back();
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700177 }
deadbeef6de92f92016-12-12 18:49:32 -0800178
Qingsi Wangdb53f8e2018-02-20 14:45:49 -0800179 // |stun_candidate_keepalive_interval_| will be used in STUN port allocation
180 // in future sessions. We also update the ready ports in the pooled sessions.
181 // Ports in sessions that are taken and owned by P2PTransportChannel will be
182 // updated there via IceConfig.
183 stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval;
184 for (const auto& session : pooled_sessions_) {
185 session->SetStunKeepaliveIntervalForReadyPorts(
186 stun_candidate_keepalive_interval_);
187 }
188
deadbeef42a42632017-03-10 15:18:00 -0800189 // If |candidate_pool_size_| is greater than the number of pooled sessions,
deadbeef6de92f92016-12-12 18:49:32 -0800190 // create new sessions.
deadbeef42a42632017-03-10 15:18:00 -0800191 while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200192 IceParameters iceCredentials =
193 IceCredentialsIterator::CreateRandomIceCredentials();
194 PortAllocatorSession* pooled_session =
195 CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
196 pooled_session->set_pooled(true);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700197 pooled_session->StartGettingPorts();
198 pooled_sessions_.push_back(
199 std::unique_ptr<PortAllocatorSession>(pooled_session));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700200 }
deadbeef6de92f92016-12-12 18:49:32 -0800201 return true;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700202}
203
204std::unique_ptr<PortAllocatorSession> PortAllocator::CreateSession(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000205 const std::string& content_name,
206 int component,
207 const std::string& ice_ufrag,
208 const std::string& ice_pwd) {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700209 CheckRunOnValidThreadAndInitialized();
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700210 auto session = std::unique_ptr<PortAllocatorSession>(
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700211 CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd));
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700212 session->SetCandidateFilter(candidate_filter());
213 return session;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700214}
215
216std::unique_ptr<PortAllocatorSession> PortAllocator::TakePooledSession(
217 const std::string& content_name,
218 int component,
219 const std::string& ice_ufrag,
220 const std::string& ice_pwd) {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700221 CheckRunOnValidThreadAndInitialized();
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700222 RTC_DCHECK(!ice_ufrag.empty());
223 RTC_DCHECK(!ice_pwd.empty());
224 if (pooled_sessions_.empty()) {
225 return nullptr;
226 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200227
228 IceParameters credentials(ice_ufrag, ice_pwd, false);
229 // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
230 // with ice credentials. Otherwise call it with nullptr which means
231 // "find any" pooled session.
232 auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
233 : nullptr);
234 if (cit == pooled_sessions_.end()) {
235 return nullptr;
236 }
237
238 auto it =
239 pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
240 std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700241 ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200242 ret->set_pooled(false);
243 // According to JSEP, a pooled session should filter candidates only
244 // after it's taken out of the pool.
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700245 ret->SetCandidateFilter(candidate_filter());
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200246 pooled_sessions_.erase(it);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700247 return ret;
248}
249
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200250const PortAllocatorSession* PortAllocator::GetPooledSession(
251 const IceParameters* ice_credentials) const {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700252 CheckRunOnValidThreadAndInitialized();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200253 auto it = FindPooledSession(ice_credentials);
254 if (it == pooled_sessions_.end()) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700255 return nullptr;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200256 } else {
257 return it->get();
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700258 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200259}
260
261std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
262PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
263 for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
264 if (ice_credentials == nullptr ||
265 ((*it)->ice_ufrag() == ice_credentials->ufrag &&
266 (*it)->ice_pwd() == ice_credentials->pwd)) {
267 return it;
268 }
269 }
270 return pooled_sessions_.end();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000271}
272
deadbeef42a42632017-03-10 15:18:00 -0800273void PortAllocator::FreezeCandidatePool() {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700274 CheckRunOnValidThreadAndInitialized();
deadbeef42a42632017-03-10 15:18:00 -0800275 candidate_pool_frozen_ = true;
276}
277
278void PortAllocator::DiscardCandidatePool() {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700279 CheckRunOnValidThreadIfInitialized();
deadbeef42a42632017-03-10 15:18:00 -0800280 pooled_sessions_.clear();
281}
282
Qingsi Wang72a43a12018-02-20 16:03:18 -0800283void PortAllocator::GetCandidateStatsFromPooledSessions(
284 CandidateStatsList* candidate_stats_list) {
Qingsi Wanga2d60672018-04-11 16:57:45 -0700285 CheckRunOnValidThreadAndInitialized();
Qingsi Wang72a43a12018-02-20 16:03:18 -0800286 for (const auto& session : pooled_sessions()) {
287 session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
288 }
289}
290
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200291std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
292 CheckRunOnValidThreadAndInitialized();
293 std::vector<IceParameters> list;
294 for (const auto& session : pooled_sessions_) {
295 list.push_back(
296 IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
297 }
298 return list;
299}
300
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301} // namespace cricket