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