Home | History | Annotate | Download | only in client
      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.
     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 
    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 
    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 
    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 
    195 BasicPortAllocator::~BasicPortAllocator() {
    196 }
    197 
    198 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 
    208 PortAllocatorSession *BasicPortAllocator::CreateSession(
    209     const std::string &name, const std::string &session_type) {
    210   return new BasicPortAllocatorSession(this, name, session_type);
    211 }
    212 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    318 void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
    319   network_thread_->Post(this, MSG_CONFIG_READY, config);
    320 }
    321 
    322 // Adds a configuration to the list.
    323 void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
    324   if (config)
    325     configs_.push_back(config);
    326 
    327   AllocatePorts();
    328 }
    329 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    486 void BasicPortAllocatorSession::OnConnectionCreated(Port* port,
    487                                                     Connection* conn) {
    488   conn->SignalStateChange.connect(this,
    489     &BasicPortAllocatorSession::OnConnectionStateChange);
    490 }
    491 
    492 void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) {
    493   if (conn->write_state() == Connection::STATE_WRITABLE)
    494     allocator_->AddWritablePhase(
    495       LocalCandidateToPhase(conn->local_candidate()));
    496 }
    497 
    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 
    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 
    548 AllocationSequence::~AllocationSequence() {
    549   session_->network_thread()->Clear(this);
    550 }
    551 
    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 
    581 void AllocationSequence::Start() {
    582   running_ = true;
    583   session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
    584                                           this,
    585                                           MSG_ALLOCATION_PHASE);
    586 }
    587 
    588 void AllocationSequence::Stop() {
    589   running_ = false;
    590   session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
    591 }
    592 
    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 
    644 void AllocationSequence::EnableProtocol(ProtocolType proto) {
    645   if (!ProtocolEnabled(proto)) {
    646     protocols_.push_back(proto);
    647     session_->OnProtocolEnabled(this, proto);
    648   }
    649 }
    650 
    651 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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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