blob: edd5fed9cf55843c8e56a7d8089c6ec4a61c4dba [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
11#include "webrtc/p2p/client/basicportallocator.h"
12
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -080013#include <algorithm>
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000014#include <string>
15#include <vector>
16
17#include "webrtc/p2p/base/basicpacketsocketfactory.h"
18#include "webrtc/p2p/base/common.h"
19#include "webrtc/p2p/base/port.h"
20#include "webrtc/p2p/base/relayport.h"
21#include "webrtc/p2p/base/stunport.h"
22#include "webrtc/p2p/base/tcpport.h"
23#include "webrtc/p2p/base/turnport.h"
24#include "webrtc/p2p/base/udpport.h"
Guo-wei Shieh38f88932015-08-13 22:24:02 -070025#include "webrtc/base/checks.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026#include "webrtc/base/common.h"
27#include "webrtc/base/helpers.h"
28#include "webrtc/base/logging.h"
29
30using rtc::CreateRandomId;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000031
32namespace {
33
34enum {
35 MSG_CONFIG_START,
36 MSG_CONFIG_READY,
37 MSG_ALLOCATE,
38 MSG_ALLOCATION_PHASE,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000039 MSG_SEQUENCEOBJECTS_CREATED,
40 MSG_CONFIG_STOP,
41};
42
43const int PHASE_UDP = 0;
44const int PHASE_RELAY = 1;
45const int PHASE_TCP = 2;
46const int PHASE_SSLTCP = 3;
47
48const int kNumPhases = 4;
49
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -070050// Gets protocol priority: UDP > TCP > SSLTCP.
51int GetProtocolPriority(cricket::ProtocolType protocol) {
52 switch (protocol) {
53 case cricket::PROTO_UDP:
54 return 2;
55 case cricket::PROTO_TCP:
56 return 1;
57 case cricket::PROTO_SSLTCP:
58 return 0;
59 default:
60 RTC_DCHECK(false);
61 return 0;
62 }
63}
64// Gets address family priority: IPv6 > IPv4 > Unspecified.
65int GetAddressFamilyPriority(int ip_family) {
66 switch (ip_family) {
67 case AF_INET6:
68 return 2;
69 case AF_INET:
70 return 1;
71 default:
72 RTC_DCHECK(false);
73 return 0;
74 }
75}
76
77// Returns positive if a is better, negative if b is better, and 0 otherwise.
78int ComparePort(const cricket::Port* a, const cricket::Port* b) {
79 int a_protocol = GetProtocolPriority(a->GetProtocol());
80 int b_protocol = GetProtocolPriority(b->GetProtocol());
81 int cmp_protocol = a_protocol - b_protocol;
82 if (cmp_protocol != 0) {
83 return cmp_protocol;
84 }
85
86 int a_family = GetAddressFamilyPriority(a->Network()->GetBestIP().family());
87 int b_family = GetAddressFamilyPriority(b->Network()->GetBestIP().family());
88 return a_family - b_family;
89}
90
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091} // namespace
92
93namespace cricket {
Peter Boström0c4e06b2015-10-07 12:23:21 +020094const uint32_t DISABLE_ALL_PHASES =
honghaizf421bdc2015-07-17 16:21:55 -070095 PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP |
96 PORTALLOCATOR_DISABLE_STUN | PORTALLOCATOR_DISABLE_RELAY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000097
98// BasicPortAllocator
Taylor Brandstettera1c30352016-05-13 08:15:11 -070099BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
100 rtc::PacketSocketFactory* socket_factory)
101 : network_manager_(network_manager), socket_factory_(socket_factory) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800102 ASSERT(network_manager_ != nullptr);
103 ASSERT(socket_factory_ != nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000104 Construct();
105}
106
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800107BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager)
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700108 : network_manager_(network_manager), socket_factory_(nullptr) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800109 ASSERT(network_manager_ != nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110 Construct();
111}
112
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700113BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
114 rtc::PacketSocketFactory* socket_factory,
115 const ServerAddresses& stun_servers)
116 : network_manager_(network_manager), socket_factory_(socket_factory) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000117 ASSERT(socket_factory_ != NULL);
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700118 SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000119 Construct();
120}
121
122BasicPortAllocator::BasicPortAllocator(
123 rtc::NetworkManager* network_manager,
124 const ServerAddresses& stun_servers,
125 const rtc::SocketAddress& relay_address_udp,
126 const rtc::SocketAddress& relay_address_tcp,
127 const rtc::SocketAddress& relay_address_ssl)
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700128 : network_manager_(network_manager), socket_factory_(NULL) {
129 std::vector<RelayServerConfig> turn_servers;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130 RelayServerConfig config(RELAY_GTURN);
deadbeef653b8e02015-11-11 12:55:10 -0800131 if (!relay_address_udp.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000132 config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
deadbeef653b8e02015-11-11 12:55:10 -0800133 }
134 if (!relay_address_tcp.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135 config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
deadbeef653b8e02015-11-11 12:55:10 -0800136 }
137 if (!relay_address_ssl.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000138 config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
deadbeef653b8e02015-11-11 12:55:10 -0800139 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000140
deadbeef653b8e02015-11-11 12:55:10 -0800141 if (!config.ports.empty()) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700142 turn_servers.push_back(config);
deadbeef653b8e02015-11-11 12:55:10 -0800143 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000144
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700145 SetConfiguration(stun_servers, turn_servers, 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146 Construct();
147}
148
149void BasicPortAllocator::Construct() {
150 allow_tcp_listen_ = true;
151}
152
153BasicPortAllocator::~BasicPortAllocator() {
154}
155
deadbeefc5d0d952015-07-16 10:22:21 -0700156PortAllocatorSession* BasicPortAllocator::CreateSessionInternal(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157 const std::string& content_name, int component,
158 const std::string& ice_ufrag, const std::string& ice_pwd) {
159 return new BasicPortAllocatorSession(
160 this, content_name, component, ice_ufrag, ice_pwd);
161}
162
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700163void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) {
164 std::vector<RelayServerConfig> new_turn_servers = turn_servers();
165 new_turn_servers.push_back(turn_server);
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700166 SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size(),
167 prune_turn_ports());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700168}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169
170// BasicPortAllocatorSession
171BasicPortAllocatorSession::BasicPortAllocatorSession(
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700172 BasicPortAllocator* allocator,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 const std::string& content_name,
174 int component,
175 const std::string& ice_ufrag,
176 const std::string& ice_pwd)
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700177 : PortAllocatorSession(content_name,
178 component,
179 ice_ufrag,
180 ice_pwd,
181 allocator->flags()),
182 allocator_(allocator),
183 network_thread_(NULL),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000184 socket_factory_(allocator->socket_factory()),
185 allocation_started_(false),
186 network_manager_started_(false),
187 running_(false),
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700188 allocation_sequences_created_(false),
189 prune_turn_ports_(allocator->prune_turn_ports()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000190 allocator_->network_manager()->SignalNetworksChanged.connect(
191 this, &BasicPortAllocatorSession::OnNetworksChanged);
192 allocator_->network_manager()->StartUpdating();
193}
194
195BasicPortAllocatorSession::~BasicPortAllocatorSession() {
196 allocator_->network_manager()->StopUpdating();
197 if (network_thread_ != NULL)
198 network_thread_->Clear(this);
199
Peter Boström0c4e06b2015-10-07 12:23:21 +0200200 for (uint32_t i = 0; i < sequences_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201 // AllocationSequence should clear it's map entry for turn ports before
202 // ports are destroyed.
203 sequences_[i]->Clear();
204 }
205
206 std::vector<PortData>::iterator it;
207 for (it = ports_.begin(); it != ports_.end(); it++)
208 delete it->port();
209
Peter Boström0c4e06b2015-10-07 12:23:21 +0200210 for (uint32_t i = 0; i < configs_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211 delete configs_[i];
212
Peter Boström0c4e06b2015-10-07 12:23:21 +0200213 for (uint32_t i = 0; i < sequences_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000214 delete sequences_[i];
215}
216
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700217void BasicPortAllocatorSession::SetCandidateFilter(uint32_t filter) {
218 if (filter == candidate_filter_) {
219 return;
220 }
221 // We assume the filter will only change from "ALL" to something else.
222 RTC_DCHECK(candidate_filter_ == CF_ALL);
223 candidate_filter_ = filter;
224 for (PortData& port : ports_) {
225 if (!port.has_pairable_candidate()) {
226 continue;
227 }
228 const auto& candidates = port.port()->Candidates();
229 // Setting a filter may cause a ready port to become non-ready
230 // if it no longer has any pairable candidates.
231 if (!std::any_of(candidates.begin(), candidates.end(),
232 [this, &port](const Candidate& candidate) {
233 return CandidatePairable(candidate, port.port());
234 })) {
235 port.set_has_pairable_candidate(false);
236 }
237 }
238}
239
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000240void BasicPortAllocatorSession::StartGettingPorts() {
241 network_thread_ = rtc::Thread::Current();
242 if (!socket_factory_) {
243 owned_socket_factory_.reset(
244 new rtc::BasicPacketSocketFactory(network_thread_));
245 socket_factory_ = owned_socket_factory_.get();
246 }
247
248 running_ = true;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700249 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000250}
251
252void BasicPortAllocatorSession::StopGettingPorts() {
253 ASSERT(rtc::Thread::Current() == network_thread_);
254 running_ = false;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700255 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_STOP);
honghaiz98db68f2015-09-29 07:58:17 -0700256 ClearGettingPorts();
257}
258
259void BasicPortAllocatorSession::ClearGettingPorts() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000260 network_thread_->Clear(this, MSG_ALLOCATE);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200261 for (uint32_t i = 0; i < sequences_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000262 sequences_[i]->Stop();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263}
264
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700265std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const {
266 std::vector<PortInterface*> ret;
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700267 for (const PortData& data : ports_) {
268 if (data.ready()) {
269 ret.push_back(data.port());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700270 }
271 }
272 return ret;
273}
274
275std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const {
276 std::vector<Candidate> candidates;
277 for (const PortData& data : ports_) {
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700278 if (!data.ready()) {
279 continue;
280 }
281
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700282 for (const Candidate& candidate : data.port()->Candidates()) {
283 if (!CheckCandidateFilter(candidate)) {
284 continue;
285 }
286 ProtocolType pvalue;
287 if (!StringToProto(candidate.protocol().c_str(), &pvalue) ||
288 !data.sequence()->ProtocolEnabled(pvalue)) {
289 continue;
290 }
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700291 candidates.push_back(SanitizeRelatedAddress(candidate));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700292 }
293 }
294 return candidates;
295}
296
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700297Candidate BasicPortAllocatorSession::SanitizeRelatedAddress(
298 const Candidate& c) const {
299 Candidate copy = c;
300 // If adapter enumeration is disabled or host candidates are disabled,
301 // clear the raddr of STUN candidates to avoid local address leakage.
302 bool filter_stun_related_address =
303 ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
304 (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
305 !(candidate_filter_ & CF_HOST);
306 // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
307 // to avoid reflexive address leakage.
308 bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
309 if ((c.type() == STUN_PORT_TYPE && filter_stun_related_address) ||
310 (c.type() == RELAY_PORT_TYPE && filter_turn_related_address)) {
311 copy.set_related_address(
312 rtc::EmptySocketAddressWithFamily(copy.address().family()));
313 }
314 return copy;
315}
316
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700317bool BasicPortAllocatorSession::CandidatesAllocationDone() const {
318 // Done only if all required AllocationSequence objects
319 // are created.
320 if (!allocation_sequences_created_) {
321 return false;
322 }
323
324 // Check that all port allocation sequences are complete (not running).
325 if (std::any_of(sequences_.begin(), sequences_.end(),
326 [](const AllocationSequence* sequence) {
327 return sequence->state() == AllocationSequence::kRunning;
328 })) {
329 return false;
330 }
331
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700332 // If all allocated ports are no longer gathering, session must have got all
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700333 // expected candidates. Session will trigger candidates allocation complete
334 // signal.
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700335 return std::none_of(ports_.begin(), ports_.end(),
336 [](const PortData& port) { return port.inprogress(); });
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700337}
338
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000339void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
340 switch (message->message_id) {
341 case MSG_CONFIG_START:
342 ASSERT(rtc::Thread::Current() == network_thread_);
343 GetPortConfigurations();
344 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000345 case MSG_CONFIG_READY:
346 ASSERT(rtc::Thread::Current() == network_thread_);
347 OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
348 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000349 case MSG_ALLOCATE:
350 ASSERT(rtc::Thread::Current() == network_thread_);
351 OnAllocate();
352 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 case MSG_SEQUENCEOBJECTS_CREATED:
354 ASSERT(rtc::Thread::Current() == network_thread_);
355 OnAllocationSequenceObjectsCreated();
356 break;
357 case MSG_CONFIG_STOP:
358 ASSERT(rtc::Thread::Current() == network_thread_);
359 OnConfigStop();
360 break;
361 default:
362 ASSERT(false);
363 }
364}
365
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700366void BasicPortAllocatorSession::UpdateIceParametersInternal() {
367 for (PortData& port : ports_) {
368 port.port()->set_content_name(content_name());
369 port.port()->SetIceParameters(component(), ice_ufrag(), ice_pwd());
370 }
371}
372
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373void BasicPortAllocatorSession::GetPortConfigurations() {
374 PortConfiguration* config = new PortConfiguration(allocator_->stun_servers(),
375 username(),
376 password());
377
deadbeef653b8e02015-11-11 12:55:10 -0800378 for (const RelayServerConfig& turn_server : allocator_->turn_servers()) {
379 config->AddRelay(turn_server);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380 }
381 ConfigReady(config);
382}
383
384void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700385 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_READY, config);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000386}
387
388// Adds a configuration to the list.
389void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
deadbeef653b8e02015-11-11 12:55:10 -0800390 if (config) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000391 configs_.push_back(config);
deadbeef653b8e02015-11-11 12:55:10 -0800392 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000393
394 AllocatePorts();
395}
396
397void BasicPortAllocatorSession::OnConfigStop() {
398 ASSERT(rtc::Thread::Current() == network_thread_);
399
400 // If any of the allocated ports have not completed the candidates allocation,
401 // mark those as error. Since session doesn't need any new candidates
402 // at this stage of the allocation, it's safe to discard any new candidates.
403 bool send_signal = false;
404 for (std::vector<PortData>::iterator it = ports_.begin();
405 it != ports_.end(); ++it) {
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700406 if (it->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 // Updating port state to error, which didn't finish allocating candidates
408 // yet.
409 it->set_error();
410 send_signal = true;
411 }
412 }
413
414 // Did we stop any running sequences?
415 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
416 it != sequences_.end() && !send_signal; ++it) {
417 if ((*it)->state() == AllocationSequence::kStopped) {
418 send_signal = true;
419 }
420 }
421
422 // If we stopped anything that was running, send a done signal now.
423 if (send_signal) {
424 MaybeSignalCandidatesAllocationDone();
425 }
426}
427
428void BasicPortAllocatorSession::AllocatePorts() {
429 ASSERT(rtc::Thread::Current() == network_thread_);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700430 network_thread_->Post(RTC_FROM_HERE, this, MSG_ALLOCATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000431}
432
433void BasicPortAllocatorSession::OnAllocate() {
434 if (network_manager_started_)
435 DoAllocate();
436
437 allocation_started_ = true;
438}
439
honghaiz8c404fa2015-09-28 07:59:43 -0700440void BasicPortAllocatorSession::GetNetworks(
441 std::vector<rtc::Network*>* networks) {
442 networks->clear();
443 rtc::NetworkManager* network_manager = allocator_->network_manager();
444 ASSERT(network_manager != nullptr);
Guo-wei Shieh47872ec2015-08-19 10:32:46 -0700445 // If the network permission state is BLOCKED, we just act as if the flag has
446 // been passed in.
honghaiz8c404fa2015-09-28 07:59:43 -0700447 if (network_manager->enumeration_permission() ==
guoweisea1012b2015-08-21 09:06:28 -0700448 rtc::NetworkManager::ENUMERATION_BLOCKED) {
Guo-wei Shieh47872ec2015-08-19 10:32:46 -0700449 set_flags(flags() | PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION);
450 }
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000451 // If the adapter enumeration is disabled, we'll just bind to any address
452 // instead of specific NIC. This is to ensure the same routing for http
453 // traffic by OS is also used here to avoid any local or public IP leakage
454 // during stun process.
455 if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) {
honghaiz8c404fa2015-09-28 07:59:43 -0700456 network_manager->GetAnyAddressNetworks(networks);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000457 } else {
honghaiz8c404fa2015-09-28 07:59:43 -0700458 network_manager->GetNetworks(networks);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000459 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800460 networks->erase(std::remove_if(networks->begin(), networks->end(),
461 [this](rtc::Network* network) {
462 return allocator_->network_ignore_mask() &
463 network->type();
464 }),
465 networks->end());
honghaiz60347052016-05-31 18:29:12 -0700466
467 if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) {
468 uint16_t lowest_cost = rtc::kNetworkCostMax;
469 for (rtc::Network* network : *networks) {
470 lowest_cost = std::min<uint16_t>(lowest_cost, network->GetCost());
471 }
472 networks->erase(std::remove_if(networks->begin(), networks->end(),
473 [lowest_cost](rtc::Network* network) {
474 return network->GetCost() >
475 lowest_cost + rtc::kNetworkCostLow;
476 }),
477 networks->end());
478 }
honghaiz8c404fa2015-09-28 07:59:43 -0700479}
480
481// For each network, see if we have a sequence that covers it already. If not,
482// create a new sequence to create the appropriate ports.
483void BasicPortAllocatorSession::DoAllocate() {
484 bool done_signal_needed = false;
485 std::vector<rtc::Network*> networks;
486 GetNetworks(&networks);
487
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000488 if (networks.empty()) {
489 LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
490 done_signal_needed = true;
491 } else {
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700492 PortConfiguration* config = configs_.empty() ? nullptr : configs_.back();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200493 for (uint32_t i = 0; i < networks.size(); ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200494 uint32_t sequence_flags = flags();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
496 // If all the ports are disabled we should just fire the allocation
497 // done event and return.
498 done_signal_needed = true;
499 break;
500 }
501
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000502 if (!config || config->relays.empty()) {
503 // No relay ports specified in this config.
504 sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
505 }
506
507 if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000508 networks[i]->GetBestIP().family() == AF_INET6) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000509 // Skip IPv6 networks unless the flag's been set.
510 continue;
511 }
512
513 // Disable phases that would only create ports equivalent to
514 // ones that we have already made.
515 DisableEquivalentPhases(networks[i], config, &sequence_flags);
516
517 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
518 // New AllocationSequence would have nothing to do, so don't make it.
519 continue;
520 }
521
522 AllocationSequence* sequence =
523 new AllocationSequence(this, networks[i], config, sequence_flags);
524 if (!sequence->Init()) {
525 delete sequence;
526 continue;
527 }
528 done_signal_needed = true;
529 sequence->SignalPortAllocationComplete.connect(
530 this, &BasicPortAllocatorSession::OnPortAllocationComplete);
531 if (running_)
532 sequence->Start();
533 sequences_.push_back(sequence);
534 }
535 }
536 if (done_signal_needed) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700537 network_thread_->Post(RTC_FROM_HERE, this, MSG_SEQUENCEOBJECTS_CREATED);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000538 }
539}
540
541void BasicPortAllocatorSession::OnNetworksChanged() {
honghaiz8c404fa2015-09-28 07:59:43 -0700542 std::vector<rtc::Network*> networks;
543 GetNetworks(&networks);
544 for (AllocationSequence* sequence : sequences_) {
545 // Remove the network from the allocation sequence if it is not in
546 // |networks|.
547 if (!sequence->network_removed() &&
548 std::find(networks.begin(), networks.end(), sequence->network()) ==
549 networks.end()) {
550 sequence->OnNetworkRemoved();
551 }
552 }
553
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554 network_manager_started_ = true;
555 if (allocation_started_)
556 DoAllocate();
557}
558
559void BasicPortAllocatorSession::DisableEquivalentPhases(
Peter Boström0c4e06b2015-10-07 12:23:21 +0200560 rtc::Network* network,
561 PortConfiguration* config,
562 uint32_t* flags) {
563 for (uint32_t i = 0; i < sequences_.size() &&
564 (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES;
565 ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566 sequences_[i]->DisableEquivalentPhases(network, config, flags);
567 }
568}
569
570void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
571 AllocationSequence * seq,
572 bool prepare_address) {
573 if (!port)
574 return;
575
576 LOG(LS_INFO) << "Adding allocated port for " << content_name();
577 port->set_content_name(content_name());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700578 port->set_component(component());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 port->set_generation(generation());
580 if (allocator_->proxy().type != rtc::PROXY_NONE)
581 port->set_proxy(allocator_->user_agent(), allocator_->proxy());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700582 port->set_send_retransmit_count_attribute(
583 (flags() & PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000584
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000585 PortData data(port, seq);
586 ports_.push_back(data);
587
588 port->SignalCandidateReady.connect(
589 this, &BasicPortAllocatorSession::OnCandidateReady);
590 port->SignalPortComplete.connect(this,
591 &BasicPortAllocatorSession::OnPortComplete);
592 port->SignalDestroyed.connect(this,
593 &BasicPortAllocatorSession::OnPortDestroyed);
594 port->SignalPortError.connect(
595 this, &BasicPortAllocatorSession::OnPortError);
596 LOG_J(LS_INFO, port) << "Added port to allocator";
597
598 if (prepare_address)
599 port->PrepareAddress();
600}
601
602void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
603 allocation_sequences_created_ = true;
604 // Send candidate allocation complete signal if we have no sequences.
605 MaybeSignalCandidatesAllocationDone();
606}
607
608void BasicPortAllocatorSession::OnCandidateReady(
609 Port* port, const Candidate& c) {
610 ASSERT(rtc::Thread::Current() == network_thread_);
611 PortData* data = FindPort(port);
612 ASSERT(data != NULL);
613 // Discarding any candidate signal if port allocation status is
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700614 // already done with gathering.
615 if (!data->inprogress()) {
danilchapf4e8cf02016-06-30 01:55:03 -0700616 return;
Honghai Zhang17aac052016-06-29 21:41:53 -0700617 }
Honghai Zhang17aac052016-06-29 21:41:53 -0700618
danilchapf4e8cf02016-06-30 01:55:03 -0700619 // Mark that the port has a pairable candidate, either because we have a
620 // usable candidate from the port, or simply because the port is bound to the
621 // any address and therefore has no host candidate. This will trigger the port
622 // to start creating candidate pairs (connections) and issue connectivity
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700623 // checks. If port has already been marked as having a pairable candidate,
624 // do nothing here.
625 // Note: We should check whether any candidates may become ready after this
626 // because there we will check whether the candidate is generated by the ready
627 // ports, which may include this port.
628 bool pruned_port = false;
629 if (CandidatePairable(c, port) && !data->has_pairable_candidate()) {
danilchapf4e8cf02016-06-30 01:55:03 -0700630 data->set_has_pairable_candidate(true);
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700631
632 if (prune_turn_ports_ && port->Type() == RELAY_PORT_TYPE) {
633 pruned_port = PruneTurnPorts(port);
634 }
635 // If the current port is not pruned yet, SignalPortReady.
636 if (!data->pruned()) {
637 SignalPortReady(this, port);
638 }
Honghai Zhang17aac052016-06-29 21:41:53 -0700639 }
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700640
641 ProtocolType pvalue;
642 bool candidate_protocol_enabled =
643 StringToProto(c.protocol().c_str(), &pvalue) &&
644 data->sequence()->ProtocolEnabled(pvalue);
645
646 if (data->ready() && CheckCandidateFilter(c) && candidate_protocol_enabled) {
647 std::vector<Candidate> candidates;
648 candidates.push_back(SanitizeRelatedAddress(c));
649 SignalCandidatesReady(this, candidates);
650 }
651
652 // If we have pruned any port, maybe need to signal port allocation done.
653 if (pruned_port) {
654 MaybeSignalCandidatesAllocationDone();
655 }
656}
657
658Port* BasicPortAllocatorSession::GetBestTurnPortForNetwork(
659 const std::string& network_name) const {
660 Port* best_turn_port = nullptr;
661 for (const PortData& data : ports_) {
662 if (data.port()->Network()->name() == network_name &&
663 data.port()->Type() == RELAY_PORT_TYPE && data.ready() &&
664 (!best_turn_port || ComparePort(data.port(), best_turn_port) > 0)) {
665 best_turn_port = data.port();
666 }
667 }
668 return best_turn_port;
669}
670
671bool BasicPortAllocatorSession::PruneTurnPorts(Port* newly_pairable_turn_port) {
672 bool pruned_port = false;
673 // Note: We determine the same network based only on their network names. So
674 // if an IPv4 address and an IPv6 address have the same network name, they
675 // are considered the same network here.
676 const std::string& network_name = newly_pairable_turn_port->Network()->name();
677 Port* best_turn_port = GetBestTurnPortForNetwork(network_name);
678 // |port| is already in the list of ports, so the best port cannot be nullptr.
679 RTC_CHECK(best_turn_port != nullptr);
680
681 for (PortData& data : ports_) {
682 if (data.port()->Network()->name() == network_name &&
683 data.port()->Type() == RELAY_PORT_TYPE && !data.pruned() &&
684 ComparePort(data.port(), best_turn_port) < 0) {
685 data.set_pruned();
686 pruned_port = true;
687 if (data.port() != newly_pairable_turn_port) {
688 SignalPortPruned(this, data.port());
689 }
690 }
691 }
692 return pruned_port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693}
694
695void BasicPortAllocatorSession::OnPortComplete(Port* port) {
696 ASSERT(rtc::Thread::Current() == network_thread_);
697 PortData* data = FindPort(port);
698 ASSERT(data != NULL);
699
700 // Ignore any late signals.
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700701 if (!data->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000702 return;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700703 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704
705 // Moving to COMPLETE state.
706 data->set_complete();
707 // Send candidate allocation complete signal if this was the last port.
708 MaybeSignalCandidatesAllocationDone();
709}
710
711void BasicPortAllocatorSession::OnPortError(Port* port) {
712 ASSERT(rtc::Thread::Current() == network_thread_);
713 PortData* data = FindPort(port);
714 ASSERT(data != NULL);
715 // We might have already given up on this port and stopped it.
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -0700716 if (!data->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000717 return;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700718 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000719
720 // SignalAddressError is currently sent from StunPort/TurnPort.
721 // But this signal itself is generic.
722 data->set_error();
723 // Send candidate allocation complete signal if this was the last port.
724 MaybeSignalCandidatesAllocationDone();
725}
726
727void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
728 ProtocolType proto) {
729 std::vector<Candidate> candidates;
730 for (std::vector<PortData>::iterator it = ports_.begin();
731 it != ports_.end(); ++it) {
732 if (it->sequence() != seq)
733 continue;
734
735 const std::vector<Candidate>& potentials = it->port()->Candidates();
736 for (size_t i = 0; i < potentials.size(); ++i) {
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700737 if (!CheckCandidateFilter(potentials[i])) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000738 continue;
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700739 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 ProtocolType pvalue;
Guo-wei Shieh38f88932015-08-13 22:24:02 -0700741 bool candidate_protocol_enabled =
742 StringToProto(potentials[i].protocol().c_str(), &pvalue) &&
743 pvalue == proto;
744 if (candidate_protocol_enabled) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000745 candidates.push_back(potentials[i]);
746 }
747 }
748 }
749
750 if (!candidates.empty()) {
751 SignalCandidatesReady(this, candidates);
752 }
753}
754
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700755bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) const {
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700756 uint32_t filter = candidate_filter_;
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000757
758 // When binding to any address, before sending packets out, the getsockname
759 // returns all 0s, but after sending packets, it'll be the NIC used to
760 // send. All 0s is not a valid ICE candidate address and should be filtered
761 // out.
762 if (c.address().IsAnyIP()) {
763 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 }
765
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000766 if (c.type() == RELAY_PORT_TYPE) {
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000767 return ((filter & CF_RELAY) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000768 } else if (c.type() == STUN_PORT_TYPE) {
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000769 return ((filter & CF_REFLEXIVE) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000770 } else if (c.type() == LOCAL_PORT_TYPE) {
771 if ((filter & CF_REFLEXIVE) && !c.address().IsPrivateIP()) {
772 // We allow host candidates if the filter allows server-reflexive
773 // candidates and the candidate is a public IP. Because we don't generate
774 // server-reflexive candidates if they have the same IP as the host
775 // candidate (i.e. when the host candidate is a public IP), filtering to
776 // only server-reflexive candidates won't work right when the host
777 // candidates have public IPs.
778 return true;
779 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000780
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000781 return ((filter & CF_HOST) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000782 }
783 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000784}
785
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700786bool BasicPortAllocatorSession::CandidatePairable(const Candidate& c,
787 const Port* port) const {
788 bool candidate_signalable = CheckCandidateFilter(c);
789
790 // When device enumeration is disabled (to prevent non-default IP addresses
791 // from leaking), we ping from some local candidates even though we don't
792 // signal them. However, if host candidates are also disabled (for example, to
793 // prevent even default IP addresses from leaking), we still don't want to
794 // ping from them, even if device enumeration is disabled. Thus, we check for
795 // both device enumeration and host candidates being disabled.
796 bool network_enumeration_disabled = c.address().IsAnyIP();
797 bool can_ping_from_candidate =
798 (port->SharedSocket() || c.protocol() == TCP_PROTOCOL_NAME);
799 bool host_candidates_disabled = !(candidate_filter_ & CF_HOST);
800
801 return candidate_signalable ||
802 (network_enumeration_disabled && can_ping_from_candidate &&
803 !host_candidates_disabled);
804}
805
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000806void BasicPortAllocatorSession::OnPortAllocationComplete(
807 AllocationSequence* seq) {
808 // Send candidate allocation complete signal if all ports are done.
809 MaybeSignalCandidatesAllocationDone();
810}
811
812void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700813 if (CandidatesAllocationDone()) {
814 if (pooled()) {
815 LOG(LS_INFO) << "All candidates gathered for pooled session.";
816 } else {
817 LOG(LS_INFO) << "All candidates gathered for " << content_name() << ":"
818 << component() << ":" << generation();
819 }
820 SignalCandidatesAllocationDone(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000821 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000822}
823
824void BasicPortAllocatorSession::OnPortDestroyed(
825 PortInterface* port) {
826 ASSERT(rtc::Thread::Current() == network_thread_);
827 for (std::vector<PortData>::iterator iter = ports_.begin();
828 iter != ports_.end(); ++iter) {
829 if (port == iter->port()) {
830 ports_.erase(iter);
831 LOG_J(LS_INFO, port) << "Removed port from allocator ("
832 << static_cast<int>(ports_.size()) << " remaining)";
833 return;
834 }
835 }
836 ASSERT(false);
837}
838
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000839BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
840 Port* port) {
841 for (std::vector<PortData>::iterator it = ports_.begin();
842 it != ports_.end(); ++it) {
843 if (it->port() == port) {
844 return &*it;
845 }
846 }
847 return NULL;
848}
849
850// AllocationSequence
851
852AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
853 rtc::Network* network,
854 PortConfiguration* config,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200855 uint32_t flags)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000856 : session_(session),
857 network_(network),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000858 ip_(network->GetBestIP()),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000859 config_(config),
860 state_(kInit),
861 flags_(flags),
862 udp_socket_(),
863 udp_port_(NULL),
864 phase_(0) {
865}
866
867bool AllocationSequence::Init() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
869 udp_socket_.reset(session_->socket_factory()->CreateUdpSocket(
870 rtc::SocketAddress(ip_, 0), session_->allocator()->min_port(),
871 session_->allocator()->max_port()));
872 if (udp_socket_) {
873 udp_socket_->SignalReadPacket.connect(
874 this, &AllocationSequence::OnReadPacket);
875 }
876 // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
877 // are next available options to setup a communication channel.
878 }
879 return true;
880}
881
882void AllocationSequence::Clear() {
883 udp_port_ = NULL;
884 turn_ports_.clear();
885}
886
honghaiz8c404fa2015-09-28 07:59:43 -0700887void AllocationSequence::OnNetworkRemoved() {
888 // Stop the allocation sequence if its network is gone.
889 Stop();
890 network_removed_ = true;
891}
892
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000893AllocationSequence::~AllocationSequence() {
894 session_->network_thread()->Clear(this);
895}
896
897void AllocationSequence::DisableEquivalentPhases(rtc::Network* network,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200898 PortConfiguration* config, uint32_t* flags) {
honghaiz8c404fa2015-09-28 07:59:43 -0700899 if (network_removed_) {
900 // If the network of this allocation sequence has ever gone away,
901 // it won't be equivalent to the new network.
902 return;
903 }
904
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000905 if (!((network == network_) && (ip_ == network->GetBestIP()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000906 // Different network setup; nothing is equivalent.
907 return;
908 }
909
910 // Else turn off the stuff that we've already got covered.
911
912 // Every config implicitly specifies local, so turn that off right away.
913 *flags |= PORTALLOCATOR_DISABLE_UDP;
914 *flags |= PORTALLOCATOR_DISABLE_TCP;
915
916 if (config_ && config) {
917 if (config_->StunServers() == config->StunServers()) {
918 // Already got this STUN servers covered.
919 *flags |= PORTALLOCATOR_DISABLE_STUN;
920 }
921 if (!config_->relays.empty()) {
922 // Already got relays covered.
923 // NOTE: This will even skip a _different_ set of relay servers if we
924 // were to be given one, but that never happens in our codebase. Should
925 // probably get rid of the list in PortConfiguration and just keep a
926 // single relay server in each one.
927 *flags |= PORTALLOCATOR_DISABLE_RELAY;
928 }
929 }
930}
931
932void AllocationSequence::Start() {
933 state_ = kRunning;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700934 session_->network_thread()->Post(RTC_FROM_HERE, this, MSG_ALLOCATION_PHASE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000935}
936
937void AllocationSequence::Stop() {
938 // If the port is completed, don't set it to stopped.
939 if (state_ == kRunning) {
940 state_ = kStopped;
941 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
942 }
943}
944
945void AllocationSequence::OnMessage(rtc::Message* msg) {
946 ASSERT(rtc::Thread::Current() == session_->network_thread());
947 ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
948
949 const char* const PHASE_NAMES[kNumPhases] = {
950 "Udp", "Relay", "Tcp", "SslTcp"
951 };
952
953 // Perform all of the phases in the current step.
954 LOG_J(LS_INFO, network_) << "Allocation Phase="
955 << PHASE_NAMES[phase_];
956
957 switch (phase_) {
958 case PHASE_UDP:
959 CreateUDPPorts();
960 CreateStunPorts();
961 EnableProtocol(PROTO_UDP);
962 break;
963
964 case PHASE_RELAY:
965 CreateRelayPorts();
966 break;
967
968 case PHASE_TCP:
969 CreateTCPPorts();
970 EnableProtocol(PROTO_TCP);
971 break;
972
973 case PHASE_SSLTCP:
974 state_ = kCompleted;
975 EnableProtocol(PROTO_SSLTCP);
976 break;
977
978 default:
979 ASSERT(false);
980 }
981
982 if (state() == kRunning) {
983 ++phase_;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700984 session_->network_thread()->PostDelayed(RTC_FROM_HERE,
985 session_->allocator()->step_delay(),
986 this, MSG_ALLOCATION_PHASE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000987 } else {
988 // If all phases in AllocationSequence are completed, no allocation
989 // steps needed further. Canceling pending signal.
990 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
991 SignalPortAllocationComplete(this);
992 }
993}
994
995void AllocationSequence::EnableProtocol(ProtocolType proto) {
996 if (!ProtocolEnabled(proto)) {
997 protocols_.push_back(proto);
998 session_->OnProtocolEnabled(this, proto);
999 }
1000}
1001
1002bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
1003 for (ProtocolList::const_iterator it = protocols_.begin();
1004 it != protocols_.end(); ++it) {
1005 if (*it == proto)
1006 return true;
1007 }
1008 return false;
1009}
1010
1011void AllocationSequence::CreateUDPPorts() {
1012 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) {
1013 LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
1014 return;
1015 }
1016
1017 // TODO(mallinath) - Remove UDPPort creating socket after shared socket
1018 // is enabled completely.
1019 UDPPort* port = NULL;
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001020 bool emit_local_candidate_for_anyaddress =
1021 !IsFlagSet(PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001022 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -07001023 port = UDPPort::Create(
1024 session_->network_thread(), session_->socket_factory(), network_,
1025 udp_socket_.get(), session_->username(), session_->password(),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001026 session_->allocator()->origin(), emit_local_candidate_for_anyaddress);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001027 } else {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -07001028 port = UDPPort::Create(
1029 session_->network_thread(), session_->socket_factory(), network_, ip_,
1030 session_->allocator()->min_port(), session_->allocator()->max_port(),
1031 session_->username(), session_->password(),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001032 session_->allocator()->origin(), emit_local_candidate_for_anyaddress);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001033 }
1034
1035 if (port) {
1036 // If shared socket is enabled, STUN candidate will be allocated by the
1037 // UDPPort.
1038 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1039 udp_port_ = port;
jiayl@webrtc.org7e5b3802015-01-22 21:28:39 +00001040 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001041
1042 // If STUN is not disabled, setting stun server address to port.
1043 if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001044 if (config_ && !config_->StunServers().empty()) {
1045 LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the "
1046 << "STUN candidate generation.";
1047 port->set_server_addresses(config_->StunServers());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001048 }
1049 }
1050 }
1051
1052 session_->AddAllocatedPort(port, this, true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001053 }
1054}
1055
1056void AllocationSequence::CreateTCPPorts() {
1057 if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) {
1058 LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
1059 return;
1060 }
1061
1062 Port* port = TCPPort::Create(session_->network_thread(),
1063 session_->socket_factory(),
1064 network_, ip_,
1065 session_->allocator()->min_port(),
1066 session_->allocator()->max_port(),
1067 session_->username(), session_->password(),
1068 session_->allocator()->allow_tcp_listen());
1069 if (port) {
1070 session_->AddAllocatedPort(port, this, true);
1071 // Since TCPPort is not created using shared socket, |port| will not be
1072 // added to the dequeue.
1073 }
1074}
1075
1076void AllocationSequence::CreateStunPorts() {
1077 if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
1078 LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
1079 return;
1080 }
1081
1082 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1083 return;
1084 }
1085
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001086 if (!(config_ && !config_->StunServers().empty())) {
1087 LOG(LS_WARNING)
1088 << "AllocationSequence: No STUN server configured, skipping.";
1089 return;
1090 }
1091
1092 StunPort* port = StunPort::Create(session_->network_thread(),
1093 session_->socket_factory(),
1094 network_, ip_,
1095 session_->allocator()->min_port(),
1096 session_->allocator()->max_port(),
1097 session_->username(), session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001098 config_->StunServers(),
1099 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001100 if (port) {
1101 session_->AddAllocatedPort(port, this, true);
1102 // Since StunPort is not created using shared socket, |port| will not be
1103 // added to the dequeue.
1104 }
1105}
1106
1107void AllocationSequence::CreateRelayPorts() {
1108 if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
1109 LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
1110 return;
1111 }
1112
1113 // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
1114 // ought to have a relay list for them here.
1115 ASSERT(config_ && !config_->relays.empty());
1116 if (!(config_ && !config_->relays.empty())) {
1117 LOG(LS_WARNING)
1118 << "AllocationSequence: No relay server configured, skipping.";
1119 return;
1120 }
1121
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07001122 for (RelayServerConfig& relay : config_->relays) {
1123 if (relay.type == RELAY_GTURN) {
1124 CreateGturnPort(relay);
1125 } else if (relay.type == RELAY_TURN) {
1126 CreateTurnPort(relay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001127 } else {
1128 ASSERT(false);
1129 }
1130 }
1131}
1132
1133void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
1134 // TODO(mallinath) - Rename RelayPort to GTurnPort.
1135 RelayPort* port = RelayPort::Create(session_->network_thread(),
1136 session_->socket_factory(),
1137 network_, ip_,
1138 session_->allocator()->min_port(),
1139 session_->allocator()->max_port(),
1140 config_->username, config_->password);
1141 if (port) {
1142 // Since RelayPort is not created using shared socket, |port| will not be
1143 // added to the dequeue.
1144 // Note: We must add the allocated port before we add addresses because
1145 // the latter will create candidates that need name and preference
1146 // settings. However, we also can't prepare the address (normally
1147 // done by AddAllocatedPort) until we have these addresses. So we
1148 // wait to do that until below.
1149 session_->AddAllocatedPort(port, this, false);
1150
1151 // Add the addresses of this protocol.
1152 PortList::const_iterator relay_port;
1153 for (relay_port = config.ports.begin();
1154 relay_port != config.ports.end();
1155 ++relay_port) {
1156 port->AddServerAddress(*relay_port);
1157 port->AddExternalAddress(*relay_port);
1158 }
1159 // Start fetching an address for this port.
1160 port->PrepareAddress();
1161 }
1162}
1163
1164void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
1165 PortList::const_iterator relay_port;
1166 for (relay_port = config.ports.begin();
1167 relay_port != config.ports.end(); ++relay_port) {
1168 TurnPort* port = NULL;
Guo-wei Shieh13d35f62015-08-26 15:32:56 -07001169
1170 // Skip UDP connections to relay servers if it's disallowed.
1171 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP_RELAY) &&
1172 relay_port->proto == PROTO_UDP) {
1173 continue;
1174 }
1175
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001176 // Shared socket mode must be enabled only for UDP based ports. Hence
1177 // don't pass shared socket for ports which will create TCP sockets.
1178 // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
1179 // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537
1180 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
honghaizf421bdc2015-07-17 16:21:55 -07001181 relay_port->proto == PROTO_UDP && udp_socket_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001182 port = TurnPort::Create(session_->network_thread(),
1183 session_->socket_factory(),
1184 network_, udp_socket_.get(),
1185 session_->username(), session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001186 *relay_port, config.credentials, config.priority,
1187 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001188 turn_ports_.push_back(port);
1189 // Listen to the port destroyed signal, to allow AllocationSequence to
1190 // remove entrt from it's map.
1191 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
1192 } else {
1193 port = TurnPort::Create(session_->network_thread(),
1194 session_->socket_factory(),
1195 network_, ip_,
1196 session_->allocator()->min_port(),
1197 session_->allocator()->max_port(),
1198 session_->username(),
1199 session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001200 *relay_port, config.credentials, config.priority,
1201 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001202 }
1203 ASSERT(port != NULL);
1204 session_->AddAllocatedPort(port, this, true);
1205 }
1206}
1207
1208void AllocationSequence::OnReadPacket(
1209 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
1210 const rtc::SocketAddress& remote_addr,
1211 const rtc::PacketTime& packet_time) {
1212 ASSERT(socket == udp_socket_.get());
1213
1214 bool turn_port_found = false;
1215
1216 // Try to find the TurnPort that matches the remote address. Note that the
1217 // message could be a STUN binding response if the TURN server is also used as
1218 // a STUN server. We don't want to parse every message here to check if it is
1219 // a STUN binding response, so we pass the message to TurnPort regardless of
1220 // the message type. The TurnPort will just ignore the message since it will
1221 // not find any request by transaction ID.
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001222 for (TurnPort* port : turn_ports_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001223 if (port->server_address().address == remote_addr) {
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001224 if (port->HandleIncomingPacket(socket, data, size, remote_addr,
1225 packet_time)) {
1226 return;
1227 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001228 turn_port_found = true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001229 }
1230 }
1231
1232 if (udp_port_) {
1233 const ServerAddresses& stun_servers = udp_port_->server_addresses();
1234
1235 // Pass the packet to the UdpPort if there is no matching TurnPort, or if
1236 // the TURN server is also a STUN server.
1237 if (!turn_port_found ||
1238 stun_servers.find(remote_addr) != stun_servers.end()) {
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001239 RTC_DCHECK(udp_port_->SharedSocket());
1240 udp_port_->HandleIncomingPacket(socket, data, size, remote_addr,
1241 packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001242 }
1243 }
1244}
1245
1246void AllocationSequence::OnPortDestroyed(PortInterface* port) {
1247 if (udp_port_ == port) {
1248 udp_port_ = NULL;
1249 return;
1250 }
1251
jiayl@webrtc.org7e5b3802015-01-22 21:28:39 +00001252 auto it = std::find(turn_ports_.begin(), turn_ports_.end(), port);
1253 if (it != turn_ports_.end()) {
1254 turn_ports_.erase(it);
1255 } else {
1256 LOG(LS_ERROR) << "Unexpected OnPortDestroyed for nonexistent port.";
1257 ASSERT(false);
1258 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001259}
1260
1261// PortConfiguration
1262PortConfiguration::PortConfiguration(
1263 const rtc::SocketAddress& stun_address,
1264 const std::string& username,
1265 const std::string& password)
1266 : stun_address(stun_address), username(username), password(password) {
1267 if (!stun_address.IsNil())
1268 stun_servers.insert(stun_address);
1269}
1270
1271PortConfiguration::PortConfiguration(const ServerAddresses& stun_servers,
1272 const std::string& username,
1273 const std::string& password)
1274 : stun_servers(stun_servers),
1275 username(username),
1276 password(password) {
1277 if (!stun_servers.empty())
1278 stun_address = *(stun_servers.begin());
1279}
1280
1281ServerAddresses PortConfiguration::StunServers() {
1282 if (!stun_address.IsNil() &&
1283 stun_servers.find(stun_address) == stun_servers.end()) {
1284 stun_servers.insert(stun_address);
1285 }
deadbeefc5d0d952015-07-16 10:22:21 -07001286 // Every UDP TURN server should also be used as a STUN server.
1287 ServerAddresses turn_servers = GetRelayServerAddresses(RELAY_TURN, PROTO_UDP);
1288 for (const rtc::SocketAddress& turn_server : turn_servers) {
1289 if (stun_servers.find(turn_server) == stun_servers.end()) {
1290 stun_servers.insert(turn_server);
1291 }
1292 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001293 return stun_servers;
1294}
1295
1296void PortConfiguration::AddRelay(const RelayServerConfig& config) {
1297 relays.push_back(config);
1298}
1299
1300bool PortConfiguration::SupportsProtocol(
1301 const RelayServerConfig& relay, ProtocolType type) const {
1302 PortList::const_iterator relay_port;
1303 for (relay_port = relay.ports.begin();
1304 relay_port != relay.ports.end();
1305 ++relay_port) {
1306 if (relay_port->proto == type)
1307 return true;
1308 }
1309 return false;
1310}
1311
1312bool PortConfiguration::SupportsProtocol(RelayType turn_type,
1313 ProtocolType type) const {
1314 for (size_t i = 0; i < relays.size(); ++i) {
1315 if (relays[i].type == turn_type &&
1316 SupportsProtocol(relays[i], type))
1317 return true;
1318 }
1319 return false;
1320}
1321
1322ServerAddresses PortConfiguration::GetRelayServerAddresses(
1323 RelayType turn_type, ProtocolType type) const {
1324 ServerAddresses servers;
1325 for (size_t i = 0; i < relays.size(); ++i) {
1326 if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) {
1327 servers.insert(relays[i].ports.front().address);
1328 }
1329 }
1330 return servers;
1331}
1332
1333} // namespace cricket