blob: 19f23b3f004d13cc7de0e6f283d0169602c5e35f [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 Zhang17aac052016-06-29 21:41:53 -070050// Gets address family priority: IPv6 > IPv4 > Unspecified.
51int GetAddressFamilyPriority(int ip_family) {
52 switch (ip_family) {
53 case AF_INET6:
54 return 2;
55 case AF_INET:
56 return 1;
57 default:
58 RTC_DCHECK(false);
59 return 0;
60 }
61}
62
63// Returns positive if a is better, negative if b is better, and 0 otherwise.
64int ComparePort(const cricket::Port* a, const cricket::Port* b) {
65 static constexpr int a_is_better = 1;
66 static constexpr int b_is_better = -1;
67 // Protocol type is defined as UDP = 0, TCP = 1, SSLTCP = 2.
68 if (a->GetProtocol() < b->GetProtocol()) {
69 return a_is_better;
70 }
71 if (a->GetProtocol() > b->GetProtocol()) {
72 return b_is_better;
73 }
74
75 int a_family = GetAddressFamilyPriority(a->Network()->GetBestIP().family());
76 int b_family = GetAddressFamilyPriority(b->Network()->GetBestIP().family());
77 return a_family - b_family;
78}
79
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000080} // namespace
81
82namespace cricket {
Peter Boström0c4e06b2015-10-07 12:23:21 +020083const uint32_t DISABLE_ALL_PHASES =
honghaizf421bdc2015-07-17 16:21:55 -070084 PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP |
85 PORTALLOCATOR_DISABLE_STUN | PORTALLOCATOR_DISABLE_RELAY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086
87// BasicPortAllocator
Taylor Brandstettera1c30352016-05-13 08:15:11 -070088BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
89 rtc::PacketSocketFactory* socket_factory)
90 : network_manager_(network_manager), socket_factory_(socket_factory) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -080091 ASSERT(network_manager_ != nullptr);
92 ASSERT(socket_factory_ != nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000093 Construct();
94}
95
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -080096BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager)
Taylor Brandstettera1c30352016-05-13 08:15:11 -070097 : network_manager_(network_manager), socket_factory_(nullptr) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -080098 ASSERT(network_manager_ != nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000099 Construct();
100}
101
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700102BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
103 rtc::PacketSocketFactory* socket_factory,
104 const ServerAddresses& stun_servers)
105 : network_manager_(network_manager), socket_factory_(socket_factory) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000106 ASSERT(socket_factory_ != NULL);
Honghai Zhang17aac052016-06-29 21:41:53 -0700107 SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000108 Construct();
109}
110
111BasicPortAllocator::BasicPortAllocator(
112 rtc::NetworkManager* network_manager,
113 const ServerAddresses& stun_servers,
114 const rtc::SocketAddress& relay_address_udp,
115 const rtc::SocketAddress& relay_address_tcp,
116 const rtc::SocketAddress& relay_address_ssl)
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700117 : network_manager_(network_manager), socket_factory_(NULL) {
118 std::vector<RelayServerConfig> turn_servers;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000119 RelayServerConfig config(RELAY_GTURN);
deadbeef653b8e02015-11-11 12:55:10 -0800120 if (!relay_address_udp.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121 config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
deadbeef653b8e02015-11-11 12:55:10 -0800122 }
123 if (!relay_address_tcp.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000124 config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
deadbeef653b8e02015-11-11 12:55:10 -0800125 }
126 if (!relay_address_ssl.IsNil()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000127 config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
deadbeef653b8e02015-11-11 12:55:10 -0800128 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000129
deadbeef653b8e02015-11-11 12:55:10 -0800130 if (!config.ports.empty()) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700131 turn_servers.push_back(config);
deadbeef653b8e02015-11-11 12:55:10 -0800132 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000133
Honghai Zhang17aac052016-06-29 21:41:53 -0700134 SetConfiguration(stun_servers, turn_servers, 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135 Construct();
136}
137
138void BasicPortAllocator::Construct() {
139 allow_tcp_listen_ = true;
140}
141
142BasicPortAllocator::~BasicPortAllocator() {
143}
144
deadbeefc5d0d952015-07-16 10:22:21 -0700145PortAllocatorSession* BasicPortAllocator::CreateSessionInternal(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000146 const std::string& content_name, int component,
147 const std::string& ice_ufrag, const std::string& ice_pwd) {
148 return new BasicPortAllocatorSession(
149 this, content_name, component, ice_ufrag, ice_pwd);
150}
151
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700152void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) {
153 std::vector<RelayServerConfig> new_turn_servers = turn_servers();
154 new_turn_servers.push_back(turn_server);
Honghai Zhang17aac052016-06-29 21:41:53 -0700155 SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size(),
156 prune_turn_ports());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700157}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158
159// BasicPortAllocatorSession
160BasicPortAllocatorSession::BasicPortAllocatorSession(
Honghai Zhang17aac052016-06-29 21:41:53 -0700161 BasicPortAllocator* allocator,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162 const std::string& content_name,
163 int component,
164 const std::string& ice_ufrag,
165 const std::string& ice_pwd)
Honghai Zhang17aac052016-06-29 21:41:53 -0700166 : PortAllocatorSession(content_name,
167 component,
168 ice_ufrag,
169 ice_pwd,
170 allocator->flags()),
171 allocator_(allocator),
172 network_thread_(NULL),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 socket_factory_(allocator->socket_factory()),
174 allocation_started_(false),
175 network_manager_started_(false),
176 running_(false),
Honghai Zhang17aac052016-06-29 21:41:53 -0700177 allocation_sequences_created_(false),
178 prune_turn_ports_(allocator->prune_turn_ports()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179 allocator_->network_manager()->SignalNetworksChanged.connect(
180 this, &BasicPortAllocatorSession::OnNetworksChanged);
181 allocator_->network_manager()->StartUpdating();
182}
183
184BasicPortAllocatorSession::~BasicPortAllocatorSession() {
185 allocator_->network_manager()->StopUpdating();
186 if (network_thread_ != NULL)
187 network_thread_->Clear(this);
188
Peter Boström0c4e06b2015-10-07 12:23:21 +0200189 for (uint32_t i = 0; i < sequences_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000190 // AllocationSequence should clear it's map entry for turn ports before
191 // ports are destroyed.
192 sequences_[i]->Clear();
193 }
194
195 std::vector<PortData>::iterator it;
196 for (it = ports_.begin(); it != ports_.end(); it++)
197 delete it->port();
198
Peter Boström0c4e06b2015-10-07 12:23:21 +0200199 for (uint32_t i = 0; i < configs_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 delete configs_[i];
201
Peter Boström0c4e06b2015-10-07 12:23:21 +0200202 for (uint32_t i = 0; i < sequences_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203 delete sequences_[i];
204}
205
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700206void BasicPortAllocatorSession::SetCandidateFilter(uint32_t filter) {
207 if (filter == candidate_filter_) {
208 return;
209 }
210 // We assume the filter will only change from "ALL" to something else.
211 RTC_DCHECK(candidate_filter_ == CF_ALL);
212 candidate_filter_ = filter;
213 for (PortData& port : ports_) {
214 if (!port.has_pairable_candidate()) {
215 continue;
216 }
217 const auto& candidates = port.port()->Candidates();
218 // Setting a filter may cause a ready port to become non-ready
219 // if it no longer has any pairable candidates.
220 if (!std::any_of(candidates.begin(), candidates.end(),
221 [this, &port](const Candidate& candidate) {
222 return CandidatePairable(candidate, port.port());
223 })) {
224 port.set_has_pairable_candidate(false);
225 }
226 }
227}
228
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000229void BasicPortAllocatorSession::StartGettingPorts() {
230 network_thread_ = rtc::Thread::Current();
231 if (!socket_factory_) {
232 owned_socket_factory_.reset(
233 new rtc::BasicPacketSocketFactory(network_thread_));
234 socket_factory_ = owned_socket_factory_.get();
235 }
236
237 running_ = true;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700238 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000239}
240
241void BasicPortAllocatorSession::StopGettingPorts() {
242 ASSERT(rtc::Thread::Current() == network_thread_);
243 running_ = false;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700244 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_STOP);
honghaiz98db68f2015-09-29 07:58:17 -0700245 ClearGettingPorts();
246}
247
248void BasicPortAllocatorSession::ClearGettingPorts() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000249 network_thread_->Clear(this, MSG_ALLOCATE);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200250 for (uint32_t i = 0; i < sequences_.size(); ++i)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 sequences_[i]->Stop();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252}
253
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700254std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const {
255 std::vector<PortInterface*> ret;
Honghai Zhang17aac052016-06-29 21:41:53 -0700256 for (const PortData& data : ports_) {
257 if (data.ready()) {
258 ret.push_back(data.port());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700259 }
260 }
261 return ret;
262}
263
264std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const {
265 std::vector<Candidate> candidates;
266 for (const PortData& data : ports_) {
Honghai Zhang17aac052016-06-29 21:41:53 -0700267 if (!data.ready()) {
268 continue;
269 }
270
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700271 for (const Candidate& candidate : data.port()->Candidates()) {
272 if (!CheckCandidateFilter(candidate)) {
273 continue;
274 }
275 ProtocolType pvalue;
276 if (!StringToProto(candidate.protocol().c_str(), &pvalue) ||
277 !data.sequence()->ProtocolEnabled(pvalue)) {
278 continue;
279 }
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700280 candidates.push_back(SanitizeRelatedAddress(candidate));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700281 }
282 }
283 return candidates;
284}
285
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700286Candidate BasicPortAllocatorSession::SanitizeRelatedAddress(
287 const Candidate& c) const {
288 Candidate copy = c;
289 // If adapter enumeration is disabled or host candidates are disabled,
290 // clear the raddr of STUN candidates to avoid local address leakage.
291 bool filter_stun_related_address =
292 ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
293 (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
294 !(candidate_filter_ & CF_HOST);
295 // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
296 // to avoid reflexive address leakage.
297 bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
298 if ((c.type() == STUN_PORT_TYPE && filter_stun_related_address) ||
299 (c.type() == RELAY_PORT_TYPE && filter_turn_related_address)) {
300 copy.set_related_address(
301 rtc::EmptySocketAddressWithFamily(copy.address().family()));
302 }
303 return copy;
304}
305
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700306bool BasicPortAllocatorSession::CandidatesAllocationDone() const {
307 // Done only if all required AllocationSequence objects
308 // are created.
309 if (!allocation_sequences_created_) {
310 return false;
311 }
312
313 // Check that all port allocation sequences are complete (not running).
314 if (std::any_of(sequences_.begin(), sequences_.end(),
315 [](const AllocationSequence* sequence) {
316 return sequence->state() == AllocationSequence::kRunning;
317 })) {
318 return false;
319 }
320
Honghai Zhang17aac052016-06-29 21:41:53 -0700321 // If all allocated ports are no longer gathering, session must have got all
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700322 // expected candidates. Session will trigger candidates allocation complete
323 // signal.
Honghai Zhang17aac052016-06-29 21:41:53 -0700324 return std::none_of(ports_.begin(), ports_.end(),
325 [](const PortData& port) { return port.inprogress(); });
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700326}
327
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000328void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
329 switch (message->message_id) {
330 case MSG_CONFIG_START:
331 ASSERT(rtc::Thread::Current() == network_thread_);
332 GetPortConfigurations();
333 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334 case MSG_CONFIG_READY:
335 ASSERT(rtc::Thread::Current() == network_thread_);
336 OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
337 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 case MSG_ALLOCATE:
339 ASSERT(rtc::Thread::Current() == network_thread_);
340 OnAllocate();
341 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000342 case MSG_SEQUENCEOBJECTS_CREATED:
343 ASSERT(rtc::Thread::Current() == network_thread_);
344 OnAllocationSequenceObjectsCreated();
345 break;
346 case MSG_CONFIG_STOP:
347 ASSERT(rtc::Thread::Current() == network_thread_);
348 OnConfigStop();
349 break;
350 default:
351 ASSERT(false);
352 }
353}
354
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700355void BasicPortAllocatorSession::UpdateIceParametersInternal() {
356 for (PortData& port : ports_) {
357 port.port()->set_content_name(content_name());
358 port.port()->SetIceParameters(component(), ice_ufrag(), ice_pwd());
359 }
360}
361
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000362void BasicPortAllocatorSession::GetPortConfigurations() {
363 PortConfiguration* config = new PortConfiguration(allocator_->stun_servers(),
364 username(),
365 password());
366
deadbeef653b8e02015-11-11 12:55:10 -0800367 for (const RelayServerConfig& turn_server : allocator_->turn_servers()) {
368 config->AddRelay(turn_server);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369 }
370 ConfigReady(config);
371}
372
373void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700374 network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_READY, config);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375}
376
377// Adds a configuration to the list.
378void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
deadbeef653b8e02015-11-11 12:55:10 -0800379 if (config) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380 configs_.push_back(config);
deadbeef653b8e02015-11-11 12:55:10 -0800381 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000382
383 AllocatePorts();
384}
385
386void BasicPortAllocatorSession::OnConfigStop() {
387 ASSERT(rtc::Thread::Current() == network_thread_);
388
389 // If any of the allocated ports have not completed the candidates allocation,
390 // mark those as error. Since session doesn't need any new candidates
391 // at this stage of the allocation, it's safe to discard any new candidates.
392 bool send_signal = false;
393 for (std::vector<PortData>::iterator it = ports_.begin();
394 it != ports_.end(); ++it) {
Honghai Zhang17aac052016-06-29 21:41:53 -0700395 if (it->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000396 // Updating port state to error, which didn't finish allocating candidates
397 // yet.
398 it->set_error();
399 send_signal = true;
400 }
401 }
402
403 // Did we stop any running sequences?
404 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
405 it != sequences_.end() && !send_signal; ++it) {
406 if ((*it)->state() == AllocationSequence::kStopped) {
407 send_signal = true;
408 }
409 }
410
411 // If we stopped anything that was running, send a done signal now.
412 if (send_signal) {
413 MaybeSignalCandidatesAllocationDone();
414 }
415}
416
417void BasicPortAllocatorSession::AllocatePorts() {
418 ASSERT(rtc::Thread::Current() == network_thread_);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700419 network_thread_->Post(RTC_FROM_HERE, this, MSG_ALLOCATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420}
421
422void BasicPortAllocatorSession::OnAllocate() {
423 if (network_manager_started_)
424 DoAllocate();
425
426 allocation_started_ = true;
427}
428
honghaiz8c404fa2015-09-28 07:59:43 -0700429void BasicPortAllocatorSession::GetNetworks(
430 std::vector<rtc::Network*>* networks) {
431 networks->clear();
432 rtc::NetworkManager* network_manager = allocator_->network_manager();
433 ASSERT(network_manager != nullptr);
Guo-wei Shieh47872ec2015-08-19 10:32:46 -0700434 // If the network permission state is BLOCKED, we just act as if the flag has
435 // been passed in.
honghaiz8c404fa2015-09-28 07:59:43 -0700436 if (network_manager->enumeration_permission() ==
guoweisea1012b2015-08-21 09:06:28 -0700437 rtc::NetworkManager::ENUMERATION_BLOCKED) {
Guo-wei Shieh47872ec2015-08-19 10:32:46 -0700438 set_flags(flags() | PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION);
439 }
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000440 // If the adapter enumeration is disabled, we'll just bind to any address
441 // instead of specific NIC. This is to ensure the same routing for http
442 // traffic by OS is also used here to avoid any local or public IP leakage
443 // during stun process.
444 if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) {
honghaiz8c404fa2015-09-28 07:59:43 -0700445 network_manager->GetAnyAddressNetworks(networks);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000446 } else {
honghaiz8c404fa2015-09-28 07:59:43 -0700447 network_manager->GetNetworks(networks);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000448 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800449 networks->erase(std::remove_if(networks->begin(), networks->end(),
450 [this](rtc::Network* network) {
451 return allocator_->network_ignore_mask() &
452 network->type();
453 }),
454 networks->end());
honghaiz60347052016-05-31 18:29:12 -0700455
456 if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) {
457 uint16_t lowest_cost = rtc::kNetworkCostMax;
458 for (rtc::Network* network : *networks) {
459 lowest_cost = std::min<uint16_t>(lowest_cost, network->GetCost());
460 }
461 networks->erase(std::remove_if(networks->begin(), networks->end(),
462 [lowest_cost](rtc::Network* network) {
463 return network->GetCost() >
464 lowest_cost + rtc::kNetworkCostLow;
465 }),
466 networks->end());
467 }
honghaiz8c404fa2015-09-28 07:59:43 -0700468}
469
470// For each network, see if we have a sequence that covers it already. If not,
471// create a new sequence to create the appropriate ports.
472void BasicPortAllocatorSession::DoAllocate() {
473 bool done_signal_needed = false;
474 std::vector<rtc::Network*> networks;
475 GetNetworks(&networks);
476
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477 if (networks.empty()) {
478 LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
479 done_signal_needed = true;
480 } else {
Honghai Zhang17aac052016-06-29 21:41:53 -0700481 PortConfiguration* config = configs_.empty() ? nullptr : configs_.back();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200482 for (uint32_t i = 0; i < networks.size(); ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200483 uint32_t sequence_flags = flags();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
485 // If all the ports are disabled we should just fire the allocation
486 // done event and return.
487 done_signal_needed = true;
488 break;
489 }
490
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491 if (!config || config->relays.empty()) {
492 // No relay ports specified in this config.
493 sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
494 }
495
496 if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000497 networks[i]->GetBestIP().family() == AF_INET6) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000498 // Skip IPv6 networks unless the flag's been set.
499 continue;
500 }
501
502 // Disable phases that would only create ports equivalent to
503 // ones that we have already made.
504 DisableEquivalentPhases(networks[i], config, &sequence_flags);
505
506 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
507 // New AllocationSequence would have nothing to do, so don't make it.
508 continue;
509 }
510
511 AllocationSequence* sequence =
512 new AllocationSequence(this, networks[i], config, sequence_flags);
513 if (!sequence->Init()) {
514 delete sequence;
515 continue;
516 }
517 done_signal_needed = true;
518 sequence->SignalPortAllocationComplete.connect(
519 this, &BasicPortAllocatorSession::OnPortAllocationComplete);
520 if (running_)
521 sequence->Start();
522 sequences_.push_back(sequence);
523 }
524 }
525 if (done_signal_needed) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700526 network_thread_->Post(RTC_FROM_HERE, this, MSG_SEQUENCEOBJECTS_CREATED);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000527 }
528}
529
530void BasicPortAllocatorSession::OnNetworksChanged() {
honghaiz8c404fa2015-09-28 07:59:43 -0700531 std::vector<rtc::Network*> networks;
532 GetNetworks(&networks);
533 for (AllocationSequence* sequence : sequences_) {
534 // Remove the network from the allocation sequence if it is not in
535 // |networks|.
536 if (!sequence->network_removed() &&
537 std::find(networks.begin(), networks.end(), sequence->network()) ==
538 networks.end()) {
539 sequence->OnNetworkRemoved();
540 }
541 }
542
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000543 network_manager_started_ = true;
544 if (allocation_started_)
545 DoAllocate();
546}
547
548void BasicPortAllocatorSession::DisableEquivalentPhases(
Peter Boström0c4e06b2015-10-07 12:23:21 +0200549 rtc::Network* network,
550 PortConfiguration* config,
551 uint32_t* flags) {
552 for (uint32_t i = 0; i < sequences_.size() &&
553 (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES;
554 ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000555 sequences_[i]->DisableEquivalentPhases(network, config, flags);
556 }
557}
558
559void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
560 AllocationSequence * seq,
561 bool prepare_address) {
562 if (!port)
563 return;
564
565 LOG(LS_INFO) << "Adding allocated port for " << content_name();
566 port->set_content_name(content_name());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700567 port->set_component(component());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000568 port->set_generation(generation());
569 if (allocator_->proxy().type != rtc::PROXY_NONE)
570 port->set_proxy(allocator_->user_agent(), allocator_->proxy());
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700571 port->set_send_retransmit_count_attribute(
572 (flags() & PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000573
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 PortData data(port, seq);
575 ports_.push_back(data);
576
577 port->SignalCandidateReady.connect(
578 this, &BasicPortAllocatorSession::OnCandidateReady);
579 port->SignalPortComplete.connect(this,
580 &BasicPortAllocatorSession::OnPortComplete);
581 port->SignalDestroyed.connect(this,
582 &BasicPortAllocatorSession::OnPortDestroyed);
583 port->SignalPortError.connect(
584 this, &BasicPortAllocatorSession::OnPortError);
585 LOG_J(LS_INFO, port) << "Added port to allocator";
586
587 if (prepare_address)
588 port->PrepareAddress();
589}
590
591void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
592 allocation_sequences_created_ = true;
593 // Send candidate allocation complete signal if we have no sequences.
594 MaybeSignalCandidatesAllocationDone();
595}
596
597void BasicPortAllocatorSession::OnCandidateReady(
598 Port* port, const Candidate& c) {
599 ASSERT(rtc::Thread::Current() == network_thread_);
600 PortData* data = FindPort(port);
601 ASSERT(data != NULL);
602 // Discarding any candidate signal if port allocation status is
Honghai Zhang17aac052016-06-29 21:41:53 -0700603 // already done with gathering.
604 if (!data->inprogress()) {
Guo-wei Shieh38f88932015-08-13 22:24:02 -0700605 return;
606 }
607
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700608 // Mark that the port has a pairable candidate, either because we have a
609 // usable candidate from the port, or simply because the port is bound to the
610 // any address and therefore has no host candidate. This will trigger the port
611 // to start creating candidate pairs (connections) and issue connectivity
Honghai Zhang17aac052016-06-29 21:41:53 -0700612 // checks. If port has already been marked as having a pairable candidate,
613 // do nothing here.
614 // Note: We should check whether any candidates may become ready after this
615 // because there we will check whether the candidate is generated by the ready
616 // ports, which may include this port.
617 bool pruned_port = false;
618 if (CandidatePairable(c, port) && !data->has_pairable_candidate()) {
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700619 data->set_has_pairable_candidate(true);
Honghai Zhang17aac052016-06-29 21:41:53 -0700620
621 if (prune_turn_ports_ && port->Type() == RELAY_PORT_TYPE) {
622 pruned_port = PruneTurnPorts(port);
623 }
624 // If the current port is not pruned yet, SignalPortReady.
625 if (!data->pruned()) {
626 SignalPortReady(this, port);
627 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000628 }
Honghai Zhang17aac052016-06-29 21:41:53 -0700629
630 ProtocolType pvalue;
631 bool candidate_protocol_enabled =
632 StringToProto(c.protocol().c_str(), &pvalue) &&
633 data->sequence()->ProtocolEnabled(pvalue);
634
635 if (data->ready() && CheckCandidateFilter(c) && candidate_protocol_enabled) {
636 std::vector<Candidate> candidates;
637 candidates.push_back(SanitizeRelatedAddress(c));
638 SignalCandidatesReady(this, candidates);
639 }
640
641 // If we have pruned any port, maybe need to signal port allocation done.
642 if (pruned_port) {
643 MaybeSignalCandidatesAllocationDone();
644 }
645}
646
647Port* BasicPortAllocatorSession::GetBestTurnPortForNetwork(
648 const std::string& network_name) const {
649 Port* best_turn_port = nullptr;
650 for (const PortData& data : ports_) {
651 if (data.port()->Network()->name() == network_name &&
652 data.port()->Type() == RELAY_PORT_TYPE && data.ready() &&
653 (!best_turn_port || ComparePort(data.port(), best_turn_port) > 0)) {
654 best_turn_port = data.port();
655 }
656 }
657 return best_turn_port;
658}
659
660bool BasicPortAllocatorSession::PruneTurnPorts(Port* newly_pairable_turn_port) {
661 bool pruned_port = false;
662 // Note: We determine the same network based only on their network names. So
663 // if an IPv4 address and an IPv6 address have the same network name, they
664 // are considered the same network here.
665 const std::string& network_name = newly_pairable_turn_port->Network()->name();
666 Port* best_turn_port = GetBestTurnPortForNetwork(network_name);
667 // |port| is already in the list of ports, so the best port cannot be nullptr.
668 RTC_CHECK(best_turn_port != nullptr);
669
670 for (PortData& data : ports_) {
671 if (data.port()->Network()->name() == network_name &&
672 data.port()->Type() == RELAY_PORT_TYPE && !data.pruned() &&
673 ComparePort(data.port(), best_turn_port) < 0) {
674 data.set_pruned();
675 pruned_port = true;
676 if (data.port() != newly_pairable_turn_port) {
677 SignalPortPruned(this, data.port());
678 }
679 }
680 }
681 return pruned_port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682}
683
684void BasicPortAllocatorSession::OnPortComplete(Port* port) {
685 ASSERT(rtc::Thread::Current() == network_thread_);
686 PortData* data = FindPort(port);
687 ASSERT(data != NULL);
688
689 // Ignore any late signals.
Honghai Zhang17aac052016-06-29 21:41:53 -0700690 if (!data->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 return;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700692 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693
694 // Moving to COMPLETE state.
695 data->set_complete();
696 // Send candidate allocation complete signal if this was the last port.
697 MaybeSignalCandidatesAllocationDone();
698}
699
700void BasicPortAllocatorSession::OnPortError(Port* port) {
701 ASSERT(rtc::Thread::Current() == network_thread_);
702 PortData* data = FindPort(port);
703 ASSERT(data != NULL);
704 // We might have already given up on this port and stopped it.
Honghai Zhang17aac052016-06-29 21:41:53 -0700705 if (!data->inprogress()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 return;
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700707 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000708
709 // SignalAddressError is currently sent from StunPort/TurnPort.
710 // But this signal itself is generic.
711 data->set_error();
712 // Send candidate allocation complete signal if this was the last port.
713 MaybeSignalCandidatesAllocationDone();
714}
715
716void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
717 ProtocolType proto) {
718 std::vector<Candidate> candidates;
719 for (std::vector<PortData>::iterator it = ports_.begin();
720 it != ports_.end(); ++it) {
721 if (it->sequence() != seq)
722 continue;
723
724 const std::vector<Candidate>& potentials = it->port()->Candidates();
725 for (size_t i = 0; i < potentials.size(); ++i) {
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700726 if (!CheckCandidateFilter(potentials[i])) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000727 continue;
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700728 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000729 ProtocolType pvalue;
Guo-wei Shieh38f88932015-08-13 22:24:02 -0700730 bool candidate_protocol_enabled =
731 StringToProto(potentials[i].protocol().c_str(), &pvalue) &&
732 pvalue == proto;
733 if (candidate_protocol_enabled) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000734 candidates.push_back(potentials[i]);
735 }
736 }
737 }
738
739 if (!candidates.empty()) {
740 SignalCandidatesReady(this, candidates);
741 }
742}
743
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700744bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) const {
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700745 uint32_t filter = candidate_filter_;
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000746
747 // When binding to any address, before sending packets out, the getsockname
748 // returns all 0s, but after sending packets, it'll be the NIC used to
749 // send. All 0s is not a valid ICE candidate address and should be filtered
750 // out.
751 if (c.address().IsAnyIP()) {
752 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 }
754
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000755 if (c.type() == RELAY_PORT_TYPE) {
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000756 return ((filter & CF_RELAY) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000757 } else if (c.type() == STUN_PORT_TYPE) {
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000758 return ((filter & CF_REFLEXIVE) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000759 } else if (c.type() == LOCAL_PORT_TYPE) {
760 if ((filter & CF_REFLEXIVE) && !c.address().IsPrivateIP()) {
761 // We allow host candidates if the filter allows server-reflexive
762 // candidates and the candidate is a public IP. Because we don't generate
763 // server-reflexive candidates if they have the same IP as the host
764 // candidate (i.e. when the host candidate is a public IP), filtering to
765 // only server-reflexive candidates won't work right when the host
766 // candidates have public IPs.
767 return true;
768 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769
guoweis@webrtc.org931e0cf2015-02-18 19:09:42 +0000770 return ((filter & CF_HOST) != 0);
guoweis@webrtc.orgf358aea2015-02-18 18:44:01 +0000771 }
772 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000773}
774
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700775bool BasicPortAllocatorSession::CandidatePairable(const Candidate& c,
776 const Port* port) const {
777 bool candidate_signalable = CheckCandidateFilter(c);
778
779 // When device enumeration is disabled (to prevent non-default IP addresses
780 // from leaking), we ping from some local candidates even though we don't
781 // signal them. However, if host candidates are also disabled (for example, to
782 // prevent even default IP addresses from leaking), we still don't want to
783 // ping from them, even if device enumeration is disabled. Thus, we check for
784 // both device enumeration and host candidates being disabled.
785 bool network_enumeration_disabled = c.address().IsAnyIP();
786 bool can_ping_from_candidate =
787 (port->SharedSocket() || c.protocol() == TCP_PROTOCOL_NAME);
788 bool host_candidates_disabled = !(candidate_filter_ & CF_HOST);
789
790 return candidate_signalable ||
791 (network_enumeration_disabled && can_ping_from_candidate &&
792 !host_candidates_disabled);
793}
794
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000795void BasicPortAllocatorSession::OnPortAllocationComplete(
796 AllocationSequence* seq) {
797 // Send candidate allocation complete signal if all ports are done.
798 MaybeSignalCandidatesAllocationDone();
799}
800
801void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700802 if (CandidatesAllocationDone()) {
803 if (pooled()) {
804 LOG(LS_INFO) << "All candidates gathered for pooled session.";
805 } else {
806 LOG(LS_INFO) << "All candidates gathered for " << content_name() << ":"
807 << component() << ":" << generation();
808 }
809 SignalCandidatesAllocationDone(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000810 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000811}
812
813void BasicPortAllocatorSession::OnPortDestroyed(
814 PortInterface* port) {
815 ASSERT(rtc::Thread::Current() == network_thread_);
816 for (std::vector<PortData>::iterator iter = ports_.begin();
817 iter != ports_.end(); ++iter) {
818 if (port == iter->port()) {
819 ports_.erase(iter);
820 LOG_J(LS_INFO, port) << "Removed port from allocator ("
821 << static_cast<int>(ports_.size()) << " remaining)";
822 return;
823 }
824 }
825 ASSERT(false);
826}
827
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000828BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
829 Port* port) {
830 for (std::vector<PortData>::iterator it = ports_.begin();
831 it != ports_.end(); ++it) {
832 if (it->port() == port) {
833 return &*it;
834 }
835 }
836 return NULL;
837}
838
839// AllocationSequence
840
841AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
842 rtc::Network* network,
843 PortConfiguration* config,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200844 uint32_t flags)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000845 : session_(session),
846 network_(network),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000847 ip_(network->GetBestIP()),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848 config_(config),
849 state_(kInit),
850 flags_(flags),
851 udp_socket_(),
852 udp_port_(NULL),
853 phase_(0) {
854}
855
856bool AllocationSequence::Init() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
858 udp_socket_.reset(session_->socket_factory()->CreateUdpSocket(
859 rtc::SocketAddress(ip_, 0), session_->allocator()->min_port(),
860 session_->allocator()->max_port()));
861 if (udp_socket_) {
862 udp_socket_->SignalReadPacket.connect(
863 this, &AllocationSequence::OnReadPacket);
864 }
865 // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
866 // are next available options to setup a communication channel.
867 }
868 return true;
869}
870
871void AllocationSequence::Clear() {
872 udp_port_ = NULL;
873 turn_ports_.clear();
874}
875
honghaiz8c404fa2015-09-28 07:59:43 -0700876void AllocationSequence::OnNetworkRemoved() {
877 // Stop the allocation sequence if its network is gone.
878 Stop();
879 network_removed_ = true;
880}
881
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882AllocationSequence::~AllocationSequence() {
883 session_->network_thread()->Clear(this);
884}
885
886void AllocationSequence::DisableEquivalentPhases(rtc::Network* network,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200887 PortConfiguration* config, uint32_t* flags) {
honghaiz8c404fa2015-09-28 07:59:43 -0700888 if (network_removed_) {
889 // If the network of this allocation sequence has ever gone away,
890 // it won't be equivalent to the new network.
891 return;
892 }
893
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000894 if (!((network == network_) && (ip_ == network->GetBestIP()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000895 // Different network setup; nothing is equivalent.
896 return;
897 }
898
899 // Else turn off the stuff that we've already got covered.
900
901 // Every config implicitly specifies local, so turn that off right away.
902 *flags |= PORTALLOCATOR_DISABLE_UDP;
903 *flags |= PORTALLOCATOR_DISABLE_TCP;
904
905 if (config_ && config) {
906 if (config_->StunServers() == config->StunServers()) {
907 // Already got this STUN servers covered.
908 *flags |= PORTALLOCATOR_DISABLE_STUN;
909 }
910 if (!config_->relays.empty()) {
911 // Already got relays covered.
912 // NOTE: This will even skip a _different_ set of relay servers if we
913 // were to be given one, but that never happens in our codebase. Should
914 // probably get rid of the list in PortConfiguration and just keep a
915 // single relay server in each one.
916 *flags |= PORTALLOCATOR_DISABLE_RELAY;
917 }
918 }
919}
920
921void AllocationSequence::Start() {
922 state_ = kRunning;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700923 session_->network_thread()->Post(RTC_FROM_HERE, this, MSG_ALLOCATION_PHASE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000924}
925
926void AllocationSequence::Stop() {
927 // If the port is completed, don't set it to stopped.
928 if (state_ == kRunning) {
929 state_ = kStopped;
930 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
931 }
932}
933
934void AllocationSequence::OnMessage(rtc::Message* msg) {
935 ASSERT(rtc::Thread::Current() == session_->network_thread());
936 ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
937
938 const char* const PHASE_NAMES[kNumPhases] = {
939 "Udp", "Relay", "Tcp", "SslTcp"
940 };
941
942 // Perform all of the phases in the current step.
943 LOG_J(LS_INFO, network_) << "Allocation Phase="
944 << PHASE_NAMES[phase_];
945
946 switch (phase_) {
947 case PHASE_UDP:
948 CreateUDPPorts();
949 CreateStunPorts();
950 EnableProtocol(PROTO_UDP);
951 break;
952
953 case PHASE_RELAY:
954 CreateRelayPorts();
955 break;
956
957 case PHASE_TCP:
958 CreateTCPPorts();
959 EnableProtocol(PROTO_TCP);
960 break;
961
962 case PHASE_SSLTCP:
963 state_ = kCompleted;
964 EnableProtocol(PROTO_SSLTCP);
965 break;
966
967 default:
968 ASSERT(false);
969 }
970
971 if (state() == kRunning) {
972 ++phase_;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700973 session_->network_thread()->PostDelayed(RTC_FROM_HERE,
974 session_->allocator()->step_delay(),
975 this, MSG_ALLOCATION_PHASE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000976 } else {
977 // If all phases in AllocationSequence are completed, no allocation
978 // steps needed further. Canceling pending signal.
979 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
980 SignalPortAllocationComplete(this);
981 }
982}
983
984void AllocationSequence::EnableProtocol(ProtocolType proto) {
985 if (!ProtocolEnabled(proto)) {
986 protocols_.push_back(proto);
987 session_->OnProtocolEnabled(this, proto);
988 }
989}
990
991bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
992 for (ProtocolList::const_iterator it = protocols_.begin();
993 it != protocols_.end(); ++it) {
994 if (*it == proto)
995 return true;
996 }
997 return false;
998}
999
1000void AllocationSequence::CreateUDPPorts() {
1001 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) {
1002 LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
1003 return;
1004 }
1005
1006 // TODO(mallinath) - Remove UDPPort creating socket after shared socket
1007 // is enabled completely.
1008 UDPPort* port = NULL;
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001009 bool emit_local_candidate_for_anyaddress =
1010 !IsFlagSet(PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001011 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -07001012 port = UDPPort::Create(
1013 session_->network_thread(), session_->socket_factory(), network_,
1014 udp_socket_.get(), session_->username(), session_->password(),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001015 session_->allocator()->origin(), emit_local_candidate_for_anyaddress);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001016 } else {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -07001017 port = UDPPort::Create(
1018 session_->network_thread(), session_->socket_factory(), network_, ip_,
1019 session_->allocator()->min_port(), session_->allocator()->max_port(),
1020 session_->username(), session_->password(),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -08001021 session_->allocator()->origin(), emit_local_candidate_for_anyaddress);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001022 }
1023
1024 if (port) {
1025 // If shared socket is enabled, STUN candidate will be allocated by the
1026 // UDPPort.
1027 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1028 udp_port_ = port;
jiayl@webrtc.org7e5b3802015-01-22 21:28:39 +00001029 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001030
1031 // If STUN is not disabled, setting stun server address to port.
1032 if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001033 if (config_ && !config_->StunServers().empty()) {
1034 LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the "
1035 << "STUN candidate generation.";
1036 port->set_server_addresses(config_->StunServers());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001037 }
1038 }
1039 }
1040
1041 session_->AddAllocatedPort(port, this, true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001042 }
1043}
1044
1045void AllocationSequence::CreateTCPPorts() {
1046 if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) {
1047 LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
1048 return;
1049 }
1050
1051 Port* port = TCPPort::Create(session_->network_thread(),
1052 session_->socket_factory(),
1053 network_, ip_,
1054 session_->allocator()->min_port(),
1055 session_->allocator()->max_port(),
1056 session_->username(), session_->password(),
1057 session_->allocator()->allow_tcp_listen());
1058 if (port) {
1059 session_->AddAllocatedPort(port, this, true);
1060 // Since TCPPort is not created using shared socket, |port| will not be
1061 // added to the dequeue.
1062 }
1063}
1064
1065void AllocationSequence::CreateStunPorts() {
1066 if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
1067 LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
1068 return;
1069 }
1070
1071 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1072 return;
1073 }
1074
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001075 if (!(config_ && !config_->StunServers().empty())) {
1076 LOG(LS_WARNING)
1077 << "AllocationSequence: No STUN server configured, skipping.";
1078 return;
1079 }
1080
1081 StunPort* port = StunPort::Create(session_->network_thread(),
1082 session_->socket_factory(),
1083 network_, ip_,
1084 session_->allocator()->min_port(),
1085 session_->allocator()->max_port(),
1086 session_->username(), session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001087 config_->StunServers(),
1088 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001089 if (port) {
1090 session_->AddAllocatedPort(port, this, true);
1091 // Since StunPort is not created using shared socket, |port| will not be
1092 // added to the dequeue.
1093 }
1094}
1095
1096void AllocationSequence::CreateRelayPorts() {
1097 if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
1098 LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
1099 return;
1100 }
1101
1102 // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
1103 // ought to have a relay list for them here.
1104 ASSERT(config_ && !config_->relays.empty());
1105 if (!(config_ && !config_->relays.empty())) {
1106 LOG(LS_WARNING)
1107 << "AllocationSequence: No relay server configured, skipping.";
1108 return;
1109 }
1110
Honghai Zhang17aac052016-06-29 21:41:53 -07001111 for (RelayServerConfig& relay : config_->relays) {
1112 if (relay.type == RELAY_GTURN) {
1113 CreateGturnPort(relay);
1114 } else if (relay.type == RELAY_TURN) {
1115 CreateTurnPort(relay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001116 } else {
1117 ASSERT(false);
1118 }
1119 }
1120}
1121
1122void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
1123 // TODO(mallinath) - Rename RelayPort to GTurnPort.
1124 RelayPort* port = RelayPort::Create(session_->network_thread(),
1125 session_->socket_factory(),
1126 network_, ip_,
1127 session_->allocator()->min_port(),
1128 session_->allocator()->max_port(),
1129 config_->username, config_->password);
1130 if (port) {
1131 // Since RelayPort is not created using shared socket, |port| will not be
1132 // added to the dequeue.
1133 // Note: We must add the allocated port before we add addresses because
1134 // the latter will create candidates that need name and preference
1135 // settings. However, we also can't prepare the address (normally
1136 // done by AddAllocatedPort) until we have these addresses. So we
1137 // wait to do that until below.
1138 session_->AddAllocatedPort(port, this, false);
1139
1140 // Add the addresses of this protocol.
1141 PortList::const_iterator relay_port;
1142 for (relay_port = config.ports.begin();
1143 relay_port != config.ports.end();
1144 ++relay_port) {
1145 port->AddServerAddress(*relay_port);
1146 port->AddExternalAddress(*relay_port);
1147 }
1148 // Start fetching an address for this port.
1149 port->PrepareAddress();
1150 }
1151}
1152
1153void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
1154 PortList::const_iterator relay_port;
1155 for (relay_port = config.ports.begin();
1156 relay_port != config.ports.end(); ++relay_port) {
1157 TurnPort* port = NULL;
Guo-wei Shieh13d35f62015-08-26 15:32:56 -07001158
1159 // Skip UDP connections to relay servers if it's disallowed.
1160 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP_RELAY) &&
1161 relay_port->proto == PROTO_UDP) {
1162 continue;
1163 }
1164
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001165 // Shared socket mode must be enabled only for UDP based ports. Hence
1166 // don't pass shared socket for ports which will create TCP sockets.
1167 // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
1168 // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537
1169 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
honghaizf421bdc2015-07-17 16:21:55 -07001170 relay_port->proto == PROTO_UDP && udp_socket_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001171 port = TurnPort::Create(session_->network_thread(),
1172 session_->socket_factory(),
1173 network_, udp_socket_.get(),
1174 session_->username(), session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001175 *relay_port, config.credentials, config.priority,
1176 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001177 turn_ports_.push_back(port);
1178 // Listen to the port destroyed signal, to allow AllocationSequence to
1179 // remove entrt from it's map.
1180 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
1181 } else {
1182 port = TurnPort::Create(session_->network_thread(),
1183 session_->socket_factory(),
1184 network_, ip_,
1185 session_->allocator()->min_port(),
1186 session_->allocator()->max_port(),
1187 session_->username(),
1188 session_->password(),
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +00001189 *relay_port, config.credentials, config.priority,
1190 session_->allocator()->origin());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001191 }
1192 ASSERT(port != NULL);
1193 session_->AddAllocatedPort(port, this, true);
1194 }
1195}
1196
1197void AllocationSequence::OnReadPacket(
1198 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
1199 const rtc::SocketAddress& remote_addr,
1200 const rtc::PacketTime& packet_time) {
1201 ASSERT(socket == udp_socket_.get());
1202
1203 bool turn_port_found = false;
1204
1205 // Try to find the TurnPort that matches the remote address. Note that the
1206 // message could be a STUN binding response if the TURN server is also used as
1207 // a STUN server. We don't want to parse every message here to check if it is
1208 // a STUN binding response, so we pass the message to TurnPort regardless of
1209 // the message type. The TurnPort will just ignore the message since it will
1210 // not find any request by transaction ID.
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001211 for (TurnPort* port : turn_ports_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001212 if (port->server_address().address == remote_addr) {
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001213 if (port->HandleIncomingPacket(socket, data, size, remote_addr,
1214 packet_time)) {
1215 return;
1216 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001217 turn_port_found = true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001218 }
1219 }
1220
1221 if (udp_port_) {
1222 const ServerAddresses& stun_servers = udp_port_->server_addresses();
1223
1224 // Pass the packet to the UdpPort if there is no matching TurnPort, or if
1225 // the TURN server is also a STUN server.
1226 if (!turn_port_found ||
1227 stun_servers.find(remote_addr) != stun_servers.end()) {
Sergey Ulanov17fa6722016-05-10 10:20:47 -07001228 RTC_DCHECK(udp_port_->SharedSocket());
1229 udp_port_->HandleIncomingPacket(socket, data, size, remote_addr,
1230 packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001231 }
1232 }
1233}
1234
1235void AllocationSequence::OnPortDestroyed(PortInterface* port) {
1236 if (udp_port_ == port) {
1237 udp_port_ = NULL;
1238 return;
1239 }
1240
jiayl@webrtc.org7e5b3802015-01-22 21:28:39 +00001241 auto it = std::find(turn_ports_.begin(), turn_ports_.end(), port);
1242 if (it != turn_ports_.end()) {
1243 turn_ports_.erase(it);
1244 } else {
1245 LOG(LS_ERROR) << "Unexpected OnPortDestroyed for nonexistent port.";
1246 ASSERT(false);
1247 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001248}
1249
1250// PortConfiguration
1251PortConfiguration::PortConfiguration(
1252 const rtc::SocketAddress& stun_address,
1253 const std::string& username,
1254 const std::string& password)
1255 : stun_address(stun_address), username(username), password(password) {
1256 if (!stun_address.IsNil())
1257 stun_servers.insert(stun_address);
1258}
1259
1260PortConfiguration::PortConfiguration(const ServerAddresses& stun_servers,
1261 const std::string& username,
1262 const std::string& password)
1263 : stun_servers(stun_servers),
1264 username(username),
1265 password(password) {
1266 if (!stun_servers.empty())
1267 stun_address = *(stun_servers.begin());
1268}
1269
1270ServerAddresses PortConfiguration::StunServers() {
1271 if (!stun_address.IsNil() &&
1272 stun_servers.find(stun_address) == stun_servers.end()) {
1273 stun_servers.insert(stun_address);
1274 }
deadbeefc5d0d952015-07-16 10:22:21 -07001275 // Every UDP TURN server should also be used as a STUN server.
1276 ServerAddresses turn_servers = GetRelayServerAddresses(RELAY_TURN, PROTO_UDP);
1277 for (const rtc::SocketAddress& turn_server : turn_servers) {
1278 if (stun_servers.find(turn_server) == stun_servers.end()) {
1279 stun_servers.insert(turn_server);
1280 }
1281 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001282 return stun_servers;
1283}
1284
1285void PortConfiguration::AddRelay(const RelayServerConfig& config) {
1286 relays.push_back(config);
1287}
1288
1289bool PortConfiguration::SupportsProtocol(
1290 const RelayServerConfig& relay, ProtocolType type) const {
1291 PortList::const_iterator relay_port;
1292 for (relay_port = relay.ports.begin();
1293 relay_port != relay.ports.end();
1294 ++relay_port) {
1295 if (relay_port->proto == type)
1296 return true;
1297 }
1298 return false;
1299}
1300
1301bool PortConfiguration::SupportsProtocol(RelayType turn_type,
1302 ProtocolType type) const {
1303 for (size_t i = 0; i < relays.size(); ++i) {
1304 if (relays[i].type == turn_type &&
1305 SupportsProtocol(relays[i], type))
1306 return true;
1307 }
1308 return false;
1309}
1310
1311ServerAddresses PortConfiguration::GetRelayServerAddresses(
1312 RelayType turn_type, ProtocolType type) const {
1313 ServerAddresses servers;
1314 for (size_t i = 0; i < relays.size(); ++i) {
1315 if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) {
1316 servers.insert(relays[i].ports.front().address);
1317 }
1318 }
1319 return servers;
1320}
1321
1322} // namespace cricket