1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <string>
29 #include <vector>
30
31 #include "talk/base/common.h"
32 #include "talk/base/helpers.h"
33 #include "talk/base/host.h"
34 #include "talk/base/logging.h"
35 #include "talk/p2p/client/basicportallocator.h"
36 #include "talk/p2p/base/common.h"
37 #include "talk/p2p/base/port.h"
38 #include "talk/p2p/base/relayport.h"
39 #include "talk/p2p/base/stunport.h"
40 #include "talk/p2p/base/tcpport.h"
41 #include "talk/p2p/base/udpport.h"
42
43 using talk_base::CreateRandomId;
44 using talk_base::CreateRandomString;
45
46 namespace {
47
48 const uint32 MSG_CONFIG_START = 1;
49 const uint32 MSG_CONFIG_READY = 2;
50 const uint32 MSG_ALLOCATE = 3;
51 const uint32 MSG_ALLOCATION_PHASE = 4;
52 const uint32 MSG_SHAKE = 5;
53
54 const uint32 ALLOCATE_DELAY = 250;
55 const uint32 ALLOCATION_STEP_DELAY = 1 * 1000;
56
57 const int PHASE_UDP = 0;
58 const int PHASE_RELAY = 1;
59 const int PHASE_TCP = 2;
60 const int PHASE_SSLTCP = 3;
61 const int kNumPhases = 4;
62
63 const float PREF_LOCAL_UDP = 1.0f;
64 const float PREF_LOCAL_STUN = 0.9f;
65 const float PREF_LOCAL_TCP = 0.8f;
66 const float PREF_RELAY = 0.5f;
67
68 // Modifiers of the above constants
69 const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f;
70 const float RELAY_BACKUP_PREF_MODIFIER = -0.2f;
71
72 // Returns the phase in which a given local candidate (or rather, the port that
73 // gave rise to that local candidate) would have been created.
LocalCandidateToPhase(const cricket::Candidate & candidate)74 int LocalCandidateToPhase(const cricket::Candidate& candidate) {
75 cricket::ProtocolType proto;
76 bool result = cricket::StringToProto(candidate.protocol().c_str(), &proto);
77 if (result) {
78 if (candidate.type() == cricket::LOCAL_PORT_TYPE) {
79 switch (proto) {
80 case cricket::PROTO_UDP: return PHASE_UDP;
81 case cricket::PROTO_TCP: return PHASE_TCP;
82 default: ASSERT(false);
83 }
84 } else if (candidate.type() == cricket::STUN_PORT_TYPE) {
85 return PHASE_UDP;
86 } else if (candidate.type() == cricket::RELAY_PORT_TYPE) {
87 switch (proto) {
88 case cricket::PROTO_UDP: return PHASE_RELAY;
89 case cricket::PROTO_TCP: return PHASE_TCP;
90 case cricket::PROTO_SSLTCP: return PHASE_SSLTCP;
91 default: ASSERT(false);
92 }
93 } else {
94 ASSERT(false);
95 }
96 } else {
97 ASSERT(false);
98 }
99 return PHASE_UDP; // reached only with assert failure
100 }
101
102 const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds
103 const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds
104
ShakeDelay()105 int ShakeDelay() {
106 int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
107 return SHAKE_MIN_DELAY + CreateRandomId() % range;
108 }
109
110 } // namespace
111
112 namespace cricket {
113
114 const uint32 DISABLE_ALL_PHASES =
115 PORTALLOCATOR_DISABLE_UDP
116 | PORTALLOCATOR_DISABLE_TCP
117 | PORTALLOCATOR_DISABLE_STUN
118 | PORTALLOCATOR_DISABLE_RELAY;
119
120 // Performs the allocation of ports, in a sequenced (timed) manner, for a given
121 // network and IP address.
122 class AllocationSequence : public talk_base::MessageHandler {
123 public:
124 AllocationSequence(BasicPortAllocatorSession* session,
125 talk_base::Network* network,
126 PortConfiguration* config,
127 uint32 flags);
128 ~AllocationSequence();
129
130 // Disables the phases for a new sequence that this one already covers for an
131 // equivalent network setup.
132 void DisableEquivalentPhases(talk_base::Network* network,
133 PortConfiguration* config, uint32* flags);
134
135 // Starts and stops the sequence. When started, it will continue allocating
136 // new ports on its own timed schedule.
137 void Start();
138 void Stop();
139
140 // MessageHandler
141 void OnMessage(talk_base::Message* msg);
142
143 void EnableProtocol(ProtocolType proto);
144 bool ProtocolEnabled(ProtocolType proto) const;
145
146 private:
147 typedef std::vector<ProtocolType> ProtocolList;
148
149 void CreateUDPPorts();
150 void CreateTCPPorts();
151 void CreateStunPorts();
152 void CreateRelayPorts();
153
154 BasicPortAllocatorSession* session_;
155 talk_base::Network* network_;
156 uint32 ip_;
157 PortConfiguration* config_;
158 bool running_;
159 int step_;
160 int step_of_phase_[kNumPhases];
161 uint32 flags_;
162 ProtocolList protocols_;
163 };
164
165
166 // BasicPortAllocator
167
BasicPortAllocator(talk_base::NetworkManager * network_manager,talk_base::PacketSocketFactory * socket_factory)168 BasicPortAllocator::BasicPortAllocator(
169 talk_base::NetworkManager* network_manager,
170 talk_base::PacketSocketFactory* socket_factory)
171 : network_manager_(network_manager),
172 socket_factory_(socket_factory),
173 best_writable_phase_(-1),
174 allow_tcp_listen_(true) {
175 ASSERT(socket_factory_ != NULL);
176 }
177
BasicPortAllocator(talk_base::NetworkManager * network_manager,talk_base::PacketSocketFactory * socket_factory,const talk_base::SocketAddress & stun_address,const talk_base::SocketAddress & relay_address_udp,const talk_base::SocketAddress & relay_address_tcp,const talk_base::SocketAddress & relay_address_ssl)178 BasicPortAllocator::BasicPortAllocator(
179 talk_base::NetworkManager* network_manager,
180 talk_base::PacketSocketFactory* socket_factory,
181 const talk_base::SocketAddress& stun_address,
182 const talk_base::SocketAddress& relay_address_udp,
183 const talk_base::SocketAddress& relay_address_tcp,
184 const talk_base::SocketAddress& relay_address_ssl)
185 : network_manager_(network_manager),
186 socket_factory_(socket_factory),
187 stun_address_(stun_address),
188 relay_address_udp_(relay_address_udp),
189 relay_address_tcp_(relay_address_tcp),
190 relay_address_ssl_(relay_address_ssl),
191 best_writable_phase_(-1),
192 allow_tcp_listen_(true) {
193 }
194
~BasicPortAllocator()195 BasicPortAllocator::~BasicPortAllocator() {
196 }
197
best_writable_phase() const198 int BasicPortAllocator::best_writable_phase() const {
199 // If we are configured with an HTTP proxy, the best bet is to use the relay
200 if ((best_writable_phase_ == -1)
201 && ((proxy().type == talk_base::PROXY_HTTPS)
202 || (proxy().type == talk_base::PROXY_UNKNOWN))) {
203 return PHASE_RELAY;
204 }
205 return best_writable_phase_;
206 }
207
CreateSession(const std::string & name,const std::string & session_type)208 PortAllocatorSession *BasicPortAllocator::CreateSession(
209 const std::string &name, const std::string &session_type) {
210 return new BasicPortAllocatorSession(this, name, session_type);
211 }
212
AddWritablePhase(int phase)213 void BasicPortAllocator::AddWritablePhase(int phase) {
214 if ((best_writable_phase_ == -1) || (phase < best_writable_phase_))
215 best_writable_phase_ = phase;
216 }
217
218 // BasicPortAllocatorSession
BasicPortAllocatorSession(BasicPortAllocator * allocator,const std::string & name,const std::string & session_type)219 BasicPortAllocatorSession::BasicPortAllocatorSession(
220 BasicPortAllocator *allocator,
221 const std::string &name,
222 const std::string &session_type)
223 : PortAllocatorSession(allocator->flags()), allocator_(allocator),
224 name_(name), session_type_(session_type), network_thread_(NULL),
225 allocation_started_(false), running_(false) {
226 }
227
~BasicPortAllocatorSession()228 BasicPortAllocatorSession::~BasicPortAllocatorSession() {
229 if (network_thread_ != NULL)
230 network_thread_->Clear(this);
231
232 std::vector<PortData>::iterator it;
233 for (it = ports_.begin(); it != ports_.end(); it++)
234 delete it->port;
235
236 for (uint32 i = 0; i < configs_.size(); ++i)
237 delete configs_[i];
238
239 for (uint32 i = 0; i < sequences_.size(); ++i)
240 delete sequences_[i];
241 }
242
GetInitialPorts()243 void BasicPortAllocatorSession::GetInitialPorts() {
244 network_thread_ = talk_base::Thread::Current();
245
246 network_thread_->Post(this, MSG_CONFIG_START);
247
248 if (flags() & PORTALLOCATOR_ENABLE_SHAKER)
249 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
250 }
251
StartGetAllPorts()252 void BasicPortAllocatorSession::StartGetAllPorts() {
253 ASSERT(talk_base::Thread::Current() == network_thread_);
254 running_ = true;
255 if (allocation_started_)
256 network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
257 for (uint32 i = 0; i < sequences_.size(); ++i)
258 sequences_[i]->Start();
259 for (size_t i = 0; i < ports_.size(); ++i)
260 ports_[i].port->Start();
261 }
262
StopGetAllPorts()263 void BasicPortAllocatorSession::StopGetAllPorts() {
264 ASSERT(talk_base::Thread::Current() == network_thread_);
265 running_ = false;
266 network_thread_->Clear(this, MSG_ALLOCATE);
267 for (uint32 i = 0; i < sequences_.size(); ++i)
268 sequences_[i]->Stop();
269 }
270
OnMessage(talk_base::Message * message)271 void BasicPortAllocatorSession::OnMessage(talk_base::Message *message) {
272 switch (message->message_id) {
273 case MSG_CONFIG_START:
274 ASSERT(talk_base::Thread::Current() == network_thread_);
275 GetPortConfigurations();
276 break;
277
278 case MSG_CONFIG_READY:
279 ASSERT(talk_base::Thread::Current() == network_thread_);
280 OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
281 break;
282
283 case MSG_ALLOCATE:
284 ASSERT(talk_base::Thread::Current() == network_thread_);
285 OnAllocate();
286 break;
287
288 case MSG_SHAKE:
289 ASSERT(talk_base::Thread::Current() == network_thread_);
290 OnShake();
291 break;
292
293 default:
294 ASSERT(false);
295 }
296 }
297
GetPortConfigurations()298 void BasicPortAllocatorSession::GetPortConfigurations() {
299 PortConfiguration* config = new PortConfiguration(allocator_->stun_address(),
300 CreateRandomString(16),
301 CreateRandomString(16),
302 "");
303 PortConfiguration::PortList ports;
304 if (!allocator_->relay_address_udp().IsAny())
305 ports.push_back(ProtocolAddress(
306 allocator_->relay_address_udp(), PROTO_UDP));
307 if (!allocator_->relay_address_tcp().IsAny())
308 ports.push_back(ProtocolAddress(
309 allocator_->relay_address_tcp(), PROTO_TCP));
310 if (!allocator_->relay_address_ssl().IsAny())
311 ports.push_back(ProtocolAddress(
312 allocator_->relay_address_ssl(), PROTO_SSLTCP));
313 config->AddRelay(ports, RELAY_PRIMARY_PREF_MODIFIER);
314
315 ConfigReady(config);
316 }
317
ConfigReady(PortConfiguration * config)318 void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
319 network_thread_->Post(this, MSG_CONFIG_READY, config);
320 }
321
322 // Adds a configuration to the list.
OnConfigReady(PortConfiguration * config)323 void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
324 if (config)
325 configs_.push_back(config);
326
327 AllocatePorts();
328 }
329
AllocatePorts()330 void BasicPortAllocatorSession::AllocatePorts() {
331 ASSERT(talk_base::Thread::Current() == network_thread_);
332 network_thread_->Post(this, MSG_ALLOCATE);
333 }
334
335 // For each network, see if we have a sequence that covers it already. If not,
336 // create a new sequence to create the appropriate ports.
OnAllocate()337 void BasicPortAllocatorSession::OnAllocate() {
338 std::vector<talk_base::Network*> networks;
339
340 if (!allocator_->network_manager()->GetNetworks(&networks)) {
341 LOG(LS_ERROR) << "Failed to enumerate networks";
342 } else if (networks.empty()) {
343 LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
344 } else {
345 for (uint32 i = 0; i < networks.size(); ++i) {
346 PortConfiguration* config = NULL;
347 if (configs_.size() > 0)
348 config = configs_.back();
349
350 uint32 sequence_flags = flags();
351
352 // Disables phases that are not specified in this config.
353 if (!config || config->stun_address.IsNil()) {
354 // No STUN ports specified in this config.
355 sequence_flags |= PORTALLOCATOR_DISABLE_STUN;
356 }
357 if (!config || config->relays.empty()) {
358 // No relay ports specified in this config.
359 sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
360 }
361
362 // Disable phases that would only create ports equivalent to ones that we
363 // have already made.
364 DisableEquivalentPhases(networks[i], config, &sequence_flags);
365
366 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
367 // New AllocationSequence would have nothing to do, so don't make it.
368 continue;
369 }
370
371 AllocationSequence* sequence =
372 new AllocationSequence(this, networks[i], config, sequence_flags);
373 if (running_)
374 sequence->Start();
375
376 sequences_.push_back(sequence);
377 }
378 }
379
380 allocation_started_ = true;
381 if (running_)
382 network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
383 }
384
DisableEquivalentPhases(talk_base::Network * network,PortConfiguration * config,uint32 * flags)385 void BasicPortAllocatorSession::DisableEquivalentPhases(
386 talk_base::Network* network, PortConfiguration* config, uint32* flags) {
387 for (uint32 i = 0; i < sequences_.size() &&
388 (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES; ++i) {
389 sequences_[i]->DisableEquivalentPhases(network, config, flags);
390 }
391 }
392
AddAllocatedPort(Port * port,AllocationSequence * seq,float pref,bool prepare_address)393 void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
394 AllocationSequence * seq,
395 float pref,
396 bool prepare_address) {
397 if (!port)
398 return;
399
400 port->set_name(name_);
401 port->set_preference(pref);
402 port->set_generation(generation());
403 if (allocator_->proxy().type != talk_base::PROXY_NONE)
404 port->set_proxy(allocator_->user_agent(), allocator_->proxy());
405
406 PortData data;
407 data.port = port;
408 data.sequence = seq;
409 data.ready = false;
410 ports_.push_back(data);
411
412 port->SignalAddressReady.connect(this,
413 &BasicPortAllocatorSession::OnAddressReady);
414 port->SignalConnectionCreated.connect(this,
415 &BasicPortAllocatorSession::OnConnectionCreated);
416 port->SignalDestroyed.connect(this,
417 &BasicPortAllocatorSession::OnPortDestroyed);
418 LOG_J(LS_INFO, port) << "Added port to allocator";
419
420 if (prepare_address)
421 port->PrepareAddress();
422 if (running_)
423 port->Start();
424 }
425
OnAddressReady(Port * port)426 void BasicPortAllocatorSession::OnAddressReady(Port *port) {
427 ASSERT(talk_base::Thread::Current() == network_thread_);
428 std::vector<PortData>::iterator it
429 = std::find(ports_.begin(), ports_.end(), port);
430 ASSERT(it != ports_.end());
431 if (it->ready)
432 return;
433 it->ready = true;
434 SignalPortReady(this, port);
435
436 // Only accumulate the candidates whose protocol has been enabled
437 std::vector<Candidate> candidates;
438 const std::vector<Candidate>& potentials = port->candidates();
439 for (size_t i = 0; i < potentials.size(); ++i) {
440 ProtocolType pvalue;
441 if (!StringToProto(potentials[i].protocol().c_str(), &pvalue))
442 continue;
443 if (it->sequence->ProtocolEnabled(pvalue)) {
444 candidates.push_back(potentials[i]);
445 }
446 }
447 if (!candidates.empty()) {
448 SignalCandidatesReady(this, candidates);
449 }
450 }
451
OnProtocolEnabled(AllocationSequence * seq,ProtocolType proto)452 void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence * seq,
453 ProtocolType proto) {
454 std::vector<Candidate> candidates;
455 for (std::vector<PortData>::iterator it = ports_.begin();
456 it != ports_.end(); ++it) {
457 if (!it->ready || (it->sequence != seq))
458 continue;
459
460 const std::vector<Candidate>& potentials = it->port->candidates();
461 for (size_t i = 0; i < potentials.size(); ++i) {
462 ProtocolType pvalue;
463 if (!StringToProto(potentials[i].protocol().c_str(), &pvalue))
464 continue;
465 if (pvalue == proto) {
466 candidates.push_back(potentials[i]);
467 }
468 }
469 }
470 if (!candidates.empty()) {
471 SignalCandidatesReady(this, candidates);
472 }
473 }
474
OnPortDestroyed(Port * port)475 void BasicPortAllocatorSession::OnPortDestroyed(Port* port) {
476 ASSERT(talk_base::Thread::Current() == network_thread_);
477 std::vector<PortData>::iterator iter =
478 std::find(ports_.begin(), ports_.end(), port);
479 ASSERT(iter != ports_.end());
480 ports_.erase(iter);
481
482 LOG_J(LS_INFO, port) << "Removed port from allocator ("
483 << static_cast<int>(ports_.size()) << " remaining)";
484 }
485
OnConnectionCreated(Port * port,Connection * conn)486 void BasicPortAllocatorSession::OnConnectionCreated(Port* port,
487 Connection* conn) {
488 conn->SignalStateChange.connect(this,
489 &BasicPortAllocatorSession::OnConnectionStateChange);
490 }
491
OnConnectionStateChange(Connection * conn)492 void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) {
493 if (conn->write_state() == Connection::STATE_WRITABLE)
494 allocator_->AddWritablePhase(
495 LocalCandidateToPhase(conn->local_candidate()));
496 }
497
OnShake()498 void BasicPortAllocatorSession::OnShake() {
499 LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
500
501 std::vector<Port*> ports;
502 std::vector<Connection*> connections;
503
504 for (size_t i = 0; i < ports_.size(); ++i) {
505 if (ports_[i].ready)
506 ports.push_back(ports_[i].port);
507 }
508
509 for (size_t i = 0; i < ports.size(); ++i) {
510 Port::AddressMap::const_iterator iter;
511 for (iter = ports[i]->connections().begin();
512 iter != ports[i]->connections().end();
513 ++iter) {
514 connections.push_back(iter->second);
515 }
516 }
517
518 LOG(INFO) << ">>>>> Destroying " << ports.size() << " ports and "
519 << connections.size() << " connections";
520
521 for (size_t i = 0; i < connections.size(); ++i)
522 connections[i]->Destroy();
523
524 if (running_ || (ports.size() > 0) || (connections.size() > 0))
525 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
526 }
527
528 // AllocationSequence
529
AllocationSequence(BasicPortAllocatorSession * session,talk_base::Network * network,PortConfiguration * config,uint32 flags)530 AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
531 talk_base::Network* network,
532 PortConfiguration* config,
533 uint32 flags)
534 : session_(session), network_(network), ip_(network->ip()), config_(config),
535 running_(false), step_(0), flags_(flags) {
536 // All of the phases up until the best-writable phase so far run in step 0.
537 // The other phases follow sequentially in the steps after that. If there is
538 // no best-writable so far, then only phase 0 occurs in step 0.
539 int last_phase_in_step_zero =
540 talk_base::_max(0, session->allocator()->best_writable_phase());
541 for (int phase = 0; phase < kNumPhases; ++phase)
542 step_of_phase_[phase] = talk_base::_max(0, phase - last_phase_in_step_zero);
543
544 // Immediately perform phase 0.
545 OnMessage(NULL);
546 }
547
~AllocationSequence()548 AllocationSequence::~AllocationSequence() {
549 session_->network_thread()->Clear(this);
550 }
551
DisableEquivalentPhases(talk_base::Network * network,PortConfiguration * config,uint32 * flags)552 void AllocationSequence::DisableEquivalentPhases(talk_base::Network* network,
553 PortConfiguration* config, uint32* flags) {
554 if (!((network == network_) && (ip_ == network->ip()))) {
555 // Different network setup; nothing is equivalent.
556 return;
557 }
558
559 // Else turn off the stuff that we've already got covered.
560
561 // Every config implicitly specifies local, so turn that off right away.
562 *flags |= PORTALLOCATOR_DISABLE_UDP;
563 *flags |= PORTALLOCATOR_DISABLE_TCP;
564
565 if (config_ && config) {
566 if (config_->stun_address == config->stun_address) {
567 // Already got this STUN server covered.
568 *flags |= PORTALLOCATOR_DISABLE_STUN;
569 }
570 if (!config_->relays.empty()) {
571 // Already got relays covered.
572 // NOTE: This will even skip a _different_ set of relay servers if we
573 // were to be given one, but that never happens in our codebase. Should
574 // probably get rid of the list in PortConfiguration and just keep a
575 // single relay server in each one.
576 *flags |= PORTALLOCATOR_DISABLE_RELAY;
577 }
578 }
579 }
580
Start()581 void AllocationSequence::Start() {
582 running_ = true;
583 session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
584 this,
585 MSG_ALLOCATION_PHASE);
586 }
587
Stop()588 void AllocationSequence::Stop() {
589 running_ = false;
590 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
591 }
592
OnMessage(talk_base::Message * msg)593 void AllocationSequence::OnMessage(talk_base::Message* msg) {
594 ASSERT(talk_base::Thread::Current() == session_->network_thread());
595 if (msg)
596 ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
597
598 const char* const PHASE_NAMES[kNumPhases] = {
599 "Udp", "Relay", "Tcp", "SslTcp"
600 };
601
602 // Perform all of the phases in the current step.
603 for (int phase = 0; phase < kNumPhases; phase++) {
604 if (step_of_phase_[phase] != step_)
605 continue;
606
607 LOG_J(LS_INFO, network_) << "Allocation Phase=" << PHASE_NAMES[phase]
608 << " (Step=" << step_ << ")";
609
610 switch (phase) {
611 case PHASE_UDP:
612 CreateUDPPorts();
613 CreateStunPorts();
614 EnableProtocol(PROTO_UDP);
615 break;
616
617 case PHASE_RELAY:
618 CreateRelayPorts();
619 break;
620
621 case PHASE_TCP:
622 CreateTCPPorts();
623 EnableProtocol(PROTO_TCP);
624 break;
625
626 case PHASE_SSLTCP:
627 EnableProtocol(PROTO_SSLTCP);
628 break;
629
630 default:
631 ASSERT(false);
632 }
633 }
634
635 // TODO: use different delays for each stage
636 step_ += 1;
637 if (running_) {
638 session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
639 this,
640 MSG_ALLOCATION_PHASE);
641 }
642 }
643
EnableProtocol(ProtocolType proto)644 void AllocationSequence::EnableProtocol(ProtocolType proto) {
645 if (!ProtocolEnabled(proto)) {
646 protocols_.push_back(proto);
647 session_->OnProtocolEnabled(this, proto);
648 }
649 }
650
ProtocolEnabled(ProtocolType proto) const651 bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
652 for (ProtocolList::const_iterator it = protocols_.begin();
653 it != protocols_.end(); ++it) {
654 if (*it == proto)
655 return true;
656 }
657 return false;
658 }
659
CreateUDPPorts()660 void AllocationSequence::CreateUDPPorts() {
661 if (flags_ & PORTALLOCATOR_DISABLE_UDP) {
662 LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
663 return;
664 }
665
666 Port* port = UDPPort::Create(session_->network_thread(),
667 session_->allocator()->socket_factory(),
668 network_, ip_,
669 session_->allocator()->min_port(),
670 session_->allocator()->max_port());
671 if (port)
672 session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP);
673 }
674
CreateTCPPorts()675 void AllocationSequence::CreateTCPPorts() {
676 if (flags_ & PORTALLOCATOR_DISABLE_TCP) {
677 LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
678 return;
679 }
680
681 Port* port = TCPPort::Create(session_->network_thread(),
682 session_->allocator()->socket_factory(),
683 network_, ip_,
684 session_->allocator()->min_port(),
685 session_->allocator()->max_port(),
686 session_->allocator()->allow_tcp_listen());
687 if (port)
688 session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP);
689 }
690
CreateStunPorts()691 void AllocationSequence::CreateStunPorts() {
692 if (flags_ & PORTALLOCATOR_DISABLE_STUN) {
693 LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
694 return;
695 }
696
697 // If BasicPortAllocatorSession::OnAllocate left STUN ports enabled then we
698 // ought to have an address for them here.
699 ASSERT(config_ && !config_->stun_address.IsNil());
700 if (!(config_ && !config_->stun_address.IsNil())) {
701 LOG(LS_WARNING)
702 << "AllocationSequence: No STUN server configured, skipping.";
703 return;
704 }
705
706 Port* port = StunPort::Create(session_->network_thread(),
707 session_->allocator()->socket_factory(),
708 network_, ip_,
709 session_->allocator()->min_port(),
710 session_->allocator()->max_port(),
711 config_->stun_address);
712 if (port)
713 session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN);
714 }
715
CreateRelayPorts()716 void AllocationSequence::CreateRelayPorts() {
717 if (flags_ & PORTALLOCATOR_DISABLE_RELAY) {
718 LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
719 return;
720 }
721
722 // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
723 // ought to have a relay list for them here.
724 ASSERT(config_ && !config_->relays.empty());
725 if (!(config_ && !config_->relays.empty())) {
726 LOG(LS_WARNING)
727 << "AllocationSequence: No relay server configured, skipping.";
728 return;
729 }
730
731 PortConfiguration::RelayList::const_iterator relay;
732 for (relay = config_->relays.begin();
733 relay != config_->relays.end(); ++relay) {
734 RelayPort* port = RelayPort::Create(session_->network_thread(),
735 session_->allocator()->socket_factory(),
736 network_, ip_,
737 session_->allocator()->min_port(),
738 session_->allocator()->max_port(),
739 config_->username, config_->password,
740 config_->magic_cookie);
741 if (port) {
742 // Note: We must add the allocated port before we add addresses because
743 // the latter will create candidates that need name and preference
744 // settings. However, we also can't prepare the address (normally
745 // done by AddAllocatedPort) until we have these addresses. So we
746 // wait to do that until below.
747 session_->AddAllocatedPort(port, this, PREF_RELAY + relay->pref_modifier,
748 false);
749
750 // Add the addresses of this protocol.
751 PortConfiguration::PortList::const_iterator relay_port;
752 for (relay_port = relay->ports.begin();
753 relay_port != relay->ports.end();
754 ++relay_port) {
755 port->AddServerAddress(*relay_port);
756 port->AddExternalAddress(*relay_port);
757 }
758
759 // Start fetching an address for this port.
760 port->PrepareAddress();
761 }
762 }
763 }
764
765 // PortConfiguration
PortConfiguration(const talk_base::SocketAddress & sa,const std::string & un,const std::string & pw,const std::string & mc)766 PortConfiguration::PortConfiguration(const talk_base::SocketAddress& sa,
767 const std::string& un,
768 const std::string& pw,
769 const std::string& mc)
770 : stun_address(sa), username(un), password(pw), magic_cookie(mc) {
771 }
772
AddRelay(const PortList & ports,float pref_modifier)773 void PortConfiguration::AddRelay(const PortList& ports, float pref_modifier) {
774 RelayServer relay;
775 relay.ports = ports;
776 relay.pref_modifier = pref_modifier;
777 relays.push_back(relay);
778 }
779
ResolveStunAddress()780 bool PortConfiguration::ResolveStunAddress() {
781 int err = 0;
782 if (!stun_address.ResolveIP(true, &err)) {
783 LOG(LS_ERROR) << "Unable to resolve STUN host "
784 << stun_address.hostname() << ". Error " << err;
785 return false;
786 }
787 return true;
788 }
789
SupportsProtocol(const PortConfiguration::RelayServer & relay,ProtocolType type)790 bool PortConfiguration::SupportsProtocol(
791 const PortConfiguration::RelayServer& relay, ProtocolType type) {
792 PortConfiguration::PortList::const_iterator relay_port;
793 for (relay_port = relay.ports.begin();
794 relay_port != relay.ports.end();
795 ++relay_port) {
796 if (relay_port->proto == type)
797 return true;
798 }
799 return false;
800 }
801
802 } // namespace cricket
803