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
43using talk_base::CreateRandomId;
44using talk_base::CreateRandomString;
45
46namespace {
47
48const uint32 MSG_CONFIG_START = 1;
49const uint32 MSG_CONFIG_READY = 2;
50const uint32 MSG_ALLOCATE = 3;
51const uint32 MSG_ALLOCATION_PHASE = 4;
52const uint32 MSG_SHAKE = 5;
53
54const uint32 ALLOCATE_DELAY = 250;
55const uint32 ALLOCATION_STEP_DELAY = 1 * 1000;
56
57const int PHASE_UDP = 0;
58const int PHASE_RELAY = 1;
59const int PHASE_TCP = 2;
60const int PHASE_SSLTCP = 3;
61const int kNumPhases = 4;
62
63const float PREF_LOCAL_UDP = 1.0f;
64const float PREF_LOCAL_STUN = 0.9f;
65const float PREF_LOCAL_TCP = 0.8f;
66const float PREF_RELAY = 0.5f;
67
68// Modifiers of the above constants
69const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f;
70const 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.
74int 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
102const int SHAKE_MIN_DELAY = 45 * 1000;  // 45 seconds
103const int SHAKE_MAX_DELAY = 90 * 1000;  // 90 seconds
104
105int ShakeDelay() {
106  int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
107  return SHAKE_MIN_DELAY + CreateRandomId() % range;
108}
109
110}  // namespace
111
112namespace cricket {
113
114const 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.
122class 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
168BasicPortAllocator::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
178BasicPortAllocator::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
195BasicPortAllocator::~BasicPortAllocator() {
196}
197
198int 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
208PortAllocatorSession *BasicPortAllocator::CreateSession(
209    const std::string &name, const std::string &session_type) {
210  return new BasicPortAllocatorSession(this, name, session_type);
211}
212
213void BasicPortAllocator::AddWritablePhase(int phase) {
214  if ((best_writable_phase_ == -1) || (phase < best_writable_phase_))
215    best_writable_phase_ = phase;
216}
217
218// BasicPortAllocatorSession
219BasicPortAllocatorSession::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
228BasicPortAllocatorSession::~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
243void 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
252void 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
263void 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
271void 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
298void 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
318void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
319  network_thread_->Post(this, MSG_CONFIG_READY, config);
320}
321
322// Adds a configuration to the list.
323void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
324  if (config)
325    configs_.push_back(config);
326
327  AllocatePorts();
328}
329
330void 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.
337void 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
385void 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
393void 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
426void 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
452void 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
475void 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
486void BasicPortAllocatorSession::OnConnectionCreated(Port* port,
487                                                    Connection* conn) {
488  conn->SignalStateChange.connect(this,
489    &BasicPortAllocatorSession::OnConnectionStateChange);
490}
491
492void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) {
493  if (conn->write_state() == Connection::STATE_WRITABLE)
494    allocator_->AddWritablePhase(
495      LocalCandidateToPhase(conn->local_candidate()));
496}
497
498void 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
530AllocationSequence::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
548AllocationSequence::~AllocationSequence() {
549  session_->network_thread()->Clear(this);
550}
551
552void 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
581void AllocationSequence::Start() {
582  running_ = true;
583  session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY,
584                                          this,
585                                          MSG_ALLOCATION_PHASE);
586}
587
588void AllocationSequence::Stop() {
589  running_ = false;
590  session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
591}
592
593void 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
644void AllocationSequence::EnableProtocol(ProtocolType proto) {
645  if (!ProtocolEnabled(proto)) {
646    protocols_.push_back(proto);
647    session_->OnProtocolEnabled(this, proto);
648  }
649}
650
651bool 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
660void 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
675void 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
691void 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
716void 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
766PortConfiguration::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
773void 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
780bool 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
790bool 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