• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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