blob: 8338abed00a9c4cfa8be4f912bc47cf8802e2cb3 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
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 "talk/p2p/client/basicportallocator.h"
29
30#include <string>
31#include <vector>
32
33#include "talk/base/common.h"
34#include "talk/base/helpers.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035#include "talk/base/logging.h"
36#include "talk/p2p/base/basicpacketsocketfactory.h"
37#include "talk/p2p/base/common.h"
38#include "talk/p2p/base/port.h"
39#include "talk/p2p/base/relayport.h"
40#include "talk/p2p/base/stunport.h"
41#include "talk/p2p/base/tcpport.h"
42#include "talk/p2p/base/turnport.h"
43#include "talk/p2p/base/udpport.h"
44
45using talk_base::CreateRandomId;
46using talk_base::CreateRandomString;
47
48namespace {
49
50const uint32 MSG_CONFIG_START = 1;
51const uint32 MSG_CONFIG_READY = 2;
52const uint32 MSG_ALLOCATE = 3;
53const uint32 MSG_ALLOCATION_PHASE = 4;
54const uint32 MSG_SHAKE = 5;
55const uint32 MSG_SEQUENCEOBJECTS_CREATED = 6;
56const uint32 MSG_CONFIG_STOP = 7;
57
58const uint32 ALLOCATE_DELAY = 250;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60const int PHASE_UDP = 0;
61const int PHASE_RELAY = 1;
62const int PHASE_TCP = 2;
63const int PHASE_SSLTCP = 3;
64
65const int kNumPhases = 4;
66
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds
68const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds
69
70int ShakeDelay() {
71 int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
72 return SHAKE_MIN_DELAY + CreateRandomId() % range;
73}
74
75} // namespace
76
77namespace cricket {
78
79const uint32 DISABLE_ALL_PHASES =
80 PORTALLOCATOR_DISABLE_UDP
81 | PORTALLOCATOR_DISABLE_TCP
82 | PORTALLOCATOR_DISABLE_STUN
83 | PORTALLOCATOR_DISABLE_RELAY;
84
85// Performs the allocation of ports, in a sequenced (timed) manner, for a given
86// network and IP address.
87class AllocationSequence : public talk_base::MessageHandler,
88 public sigslot::has_slots<> {
89 public:
90 enum State {
91 kInit, // Initial state.
92 kRunning, // Started allocating ports.
93 kStopped, // Stopped from running.
94 kCompleted, // All ports are allocated.
95
96 // kInit --> kRunning --> {kCompleted|kStopped}
97 };
98
99 AllocationSequence(BasicPortAllocatorSession* session,
100 talk_base::Network* network,
101 PortConfiguration* config,
102 uint32 flags);
103 ~AllocationSequence();
104 bool Init();
105
106 State state() const { return state_; }
107
108 // Disables the phases for a new sequence that this one already covers for an
109 // equivalent network setup.
110 void DisableEquivalentPhases(talk_base::Network* network,
111 PortConfiguration* config, uint32* flags);
112
113 // Starts and stops the sequence. When started, it will continue allocating
114 // new ports on its own timed schedule.
115 void Start();
116 void Stop();
117
118 // MessageHandler
119 void OnMessage(talk_base::Message* msg);
120
121 void EnableProtocol(ProtocolType proto);
122 bool ProtocolEnabled(ProtocolType proto) const;
123
124 // Signal from AllocationSequence, when it's done with allocating ports.
125 // This signal is useful, when port allocation fails which doesn't result
126 // in any candidates. Using this signal BasicPortAllocatorSession can send
127 // its candidate discovery conclusion signal. Without this signal,
128 // BasicPortAllocatorSession doesn't have any event to trigger signal. This
129 // can also be achieved by starting timer in BPAS.
130 sigslot::signal1<AllocationSequence*> SignalPortAllocationComplete;
131
132 private:
133 typedef std::vector<ProtocolType> ProtocolList;
134
135 bool IsFlagSet(uint32 flag) {
136 return ((flags_ & flag) != 0);
137 }
138 void CreateUDPPorts();
139 void CreateTCPPorts();
140 void CreateStunPorts();
141 void CreateRelayPorts();
142 void CreateGturnPort(const RelayServerConfig& config);
143 void CreateTurnPort(const RelayServerConfig& config);
144
145 void OnReadPacket(talk_base::AsyncPacketSocket* socket,
146 const char* data, size_t size,
wu@webrtc.orga9890802013-12-13 00:21:03 +0000147 const talk_base::SocketAddress& remote_addr,
148 const talk_base::PacketTime& packet_time);
149
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150 void OnPortDestroyed(PortInterface* port);
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +0000151 void OnResolvedTurnServerAddress(
152 TurnPort* port, const talk_base::SocketAddress& server_address,
153 const talk_base::SocketAddress& resolved_server_address);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154
155 BasicPortAllocatorSession* session_;
156 talk_base::Network* network_;
157 talk_base::IPAddress ip_;
158 PortConfiguration* config_;
159 State state_;
160 uint32 flags_;
161 ProtocolList protocols_;
162 talk_base::scoped_ptr<talk_base::AsyncPacketSocket> udp_socket_;
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +0000163 // There will be only one udp port per AllocationSequence.
164 Port* udp_port_;
165 // Keeping a map for turn ports keyed with server addresses.
166 std::map<talk_base::SocketAddress, Port*> turn_ports_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000167 int phase_;
168};
169
170// BasicPortAllocator
171BasicPortAllocator::BasicPortAllocator(
172 talk_base::NetworkManager* network_manager,
173 talk_base::PacketSocketFactory* socket_factory)
174 : network_manager_(network_manager),
175 socket_factory_(socket_factory) {
176 ASSERT(socket_factory_ != NULL);
177 Construct();
178}
179
180BasicPortAllocator::BasicPortAllocator(
181 talk_base::NetworkManager* network_manager)
182 : network_manager_(network_manager),
183 socket_factory_(NULL) {
184 Construct();
185}
186
187BasicPortAllocator::BasicPortAllocator(
188 talk_base::NetworkManager* network_manager,
189 talk_base::PacketSocketFactory* socket_factory,
190 const talk_base::SocketAddress& stun_address)
191 : network_manager_(network_manager),
192 socket_factory_(socket_factory),
193 stun_address_(stun_address) {
194 ASSERT(socket_factory_ != NULL);
195 Construct();
196}
197
198BasicPortAllocator::BasicPortAllocator(
199 talk_base::NetworkManager* network_manager,
200 const talk_base::SocketAddress& stun_address,
201 const talk_base::SocketAddress& relay_address_udp,
202 const talk_base::SocketAddress& relay_address_tcp,
203 const talk_base::SocketAddress& relay_address_ssl)
204 : network_manager_(network_manager),
205 socket_factory_(NULL),
206 stun_address_(stun_address) {
207
208 RelayServerConfig config(RELAY_GTURN);
209 if (!relay_address_udp.IsAny())
210 config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
211 if (!relay_address_tcp.IsAny())
212 config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
213 if (!relay_address_ssl.IsAny())
214 config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
215 AddRelay(config);
216
217 Construct();
218}
219
220void BasicPortAllocator::Construct() {
221 allow_tcp_listen_ = true;
222}
223
224BasicPortAllocator::~BasicPortAllocator() {
225}
226
227PortAllocatorSession *BasicPortAllocator::CreateSessionInternal(
228 const std::string& content_name, int component,
229 const std::string& ice_ufrag, const std::string& ice_pwd) {
230 return new BasicPortAllocatorSession(this, content_name, component,
231 ice_ufrag, ice_pwd);
232}
233
234// BasicPortAllocatorSession
235BasicPortAllocatorSession::BasicPortAllocatorSession(
236 BasicPortAllocator *allocator,
237 const std::string& content_name,
238 int component,
239 const std::string& ice_ufrag,
240 const std::string& ice_pwd)
241 : PortAllocatorSession(content_name, component,
242 ice_ufrag, ice_pwd, allocator->flags()),
243 allocator_(allocator), network_thread_(NULL),
244 socket_factory_(allocator->socket_factory()),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245 allocation_started_(false),
246 network_manager_started_(false),
247 running_(false),
248 allocation_sequences_created_(false) {
249 allocator_->network_manager()->SignalNetworksChanged.connect(
250 this, &BasicPortAllocatorSession::OnNetworksChanged);
251 allocator_->network_manager()->StartUpdating();
252}
253
254BasicPortAllocatorSession::~BasicPortAllocatorSession() {
255 allocator_->network_manager()->StopUpdating();
256 if (network_thread_ != NULL)
257 network_thread_->Clear(this);
258
259 std::vector<PortData>::iterator it;
260 for (it = ports_.begin(); it != ports_.end(); it++)
261 delete it->port();
262
263 for (uint32 i = 0; i < configs_.size(); ++i)
264 delete configs_[i];
265
266 for (uint32 i = 0; i < sequences_.size(); ++i)
267 delete sequences_[i];
268}
269
270void BasicPortAllocatorSession::StartGettingPorts() {
271 network_thread_ = talk_base::Thread::Current();
272 if (!socket_factory_) {
273 owned_socket_factory_.reset(
274 new talk_base::BasicPacketSocketFactory(network_thread_));
275 socket_factory_ = owned_socket_factory_.get();
276 }
277
278 running_ = true;
279 network_thread_->Post(this, MSG_CONFIG_START);
280
281 if (flags() & PORTALLOCATOR_ENABLE_SHAKER)
282 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
283}
284
285void BasicPortAllocatorSession::StopGettingPorts() {
286 ASSERT(talk_base::Thread::Current() == network_thread_);
287 running_ = false;
288 network_thread_->Clear(this, MSG_ALLOCATE);
289 for (uint32 i = 0; i < sequences_.size(); ++i)
290 sequences_[i]->Stop();
291 network_thread_->Post(this, MSG_CONFIG_STOP);
292}
293
294void BasicPortAllocatorSession::OnMessage(talk_base::Message *message) {
295 switch (message->message_id) {
296 case MSG_CONFIG_START:
297 ASSERT(talk_base::Thread::Current() == network_thread_);
298 GetPortConfigurations();
299 break;
300
301 case MSG_CONFIG_READY:
302 ASSERT(talk_base::Thread::Current() == network_thread_);
303 OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
304 break;
305
306 case MSG_ALLOCATE:
307 ASSERT(talk_base::Thread::Current() == network_thread_);
308 OnAllocate();
309 break;
310
311 case MSG_SHAKE:
312 ASSERT(talk_base::Thread::Current() == network_thread_);
313 OnShake();
314 break;
315 case MSG_SEQUENCEOBJECTS_CREATED:
316 ASSERT(talk_base::Thread::Current() == network_thread_);
317 OnAllocationSequenceObjectsCreated();
318 break;
319 case MSG_CONFIG_STOP:
320 ASSERT(talk_base::Thread::Current() == network_thread_);
321 OnConfigStop();
322 break;
323 default:
324 ASSERT(false);
325 }
326}
327
328void BasicPortAllocatorSession::GetPortConfigurations() {
329 PortConfiguration* config = new PortConfiguration(allocator_->stun_address(),
330 username(),
331 password());
332
333 for (size_t i = 0; i < allocator_->relays().size(); ++i) {
334 config->AddRelay(allocator_->relays()[i]);
335 }
336 ConfigReady(config);
337}
338
339void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
340 network_thread_->Post(this, MSG_CONFIG_READY, config);
341}
342
343// Adds a configuration to the list.
344void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
345 if (config)
346 configs_.push_back(config);
347
348 AllocatePorts();
349}
350
351void BasicPortAllocatorSession::OnConfigStop() {
352 ASSERT(talk_base::Thread::Current() == network_thread_);
353
354 // If any of the allocated ports have not completed the candidates allocation,
355 // mark those as error. Since session doesn't need any new candidates
356 // at this stage of the allocation, it's safe to discard any new candidates.
357 bool send_signal = false;
358 for (std::vector<PortData>::iterator it = ports_.begin();
359 it != ports_.end(); ++it) {
360 if (!it->complete()) {
361 // Updating port state to error, which didn't finish allocating candidates
362 // yet.
363 it->set_error();
364 send_signal = true;
365 }
366 }
367
368 // Did we stop any running sequences?
369 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
370 it != sequences_.end() && !send_signal; ++it) {
371 if ((*it)->state() == AllocationSequence::kStopped) {
372 send_signal = true;
373 }
374 }
375
376 // If we stopped anything that was running, send a done signal now.
377 if (send_signal) {
378 MaybeSignalCandidatesAllocationDone();
379 }
380}
381
382void BasicPortAllocatorSession::AllocatePorts() {
383 ASSERT(talk_base::Thread::Current() == network_thread_);
384 network_thread_->Post(this, MSG_ALLOCATE);
385}
386
387void BasicPortAllocatorSession::OnAllocate() {
388 if (network_manager_started_)
389 DoAllocate();
390
391 allocation_started_ = true;
392 if (running_)
393 network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
394}
395
396// For each network, see if we have a sequence that covers it already. If not,
397// create a new sequence to create the appropriate ports.
398void BasicPortAllocatorSession::DoAllocate() {
399 bool done_signal_needed = false;
400 std::vector<talk_base::Network*> networks;
401 allocator_->network_manager()->GetNetworks(&networks);
402 if (networks.empty()) {
403 LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
404 done_signal_needed = true;
405 } else {
406 for (uint32 i = 0; i < networks.size(); ++i) {
407 PortConfiguration* config = NULL;
408 if (configs_.size() > 0)
409 config = configs_.back();
410
411 uint32 sequence_flags = flags();
412 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
413 // If all the ports are disabled we should just fire the allocation
414 // done event and return.
415 done_signal_needed = true;
416 break;
417 }
418
419 // Disables phases that are not specified in this config.
420 if (!config || config->stun_address.IsNil()) {
421 // No STUN ports specified in this config.
422 sequence_flags |= PORTALLOCATOR_DISABLE_STUN;
423 }
424 if (!config || config->relays.empty()) {
425 // No relay ports specified in this config.
426 sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
427 }
428
429 if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) &&
430 networks[i]->ip().family() == AF_INET6) {
431 // Skip IPv6 networks unless the flag's been set.
432 continue;
433 }
434
435 // Disable phases that would only create ports equivalent to
436 // ones that we have already made.
437 DisableEquivalentPhases(networks[i], config, &sequence_flags);
438
439 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
440 // New AllocationSequence would have nothing to do, so don't make it.
441 continue;
442 }
443
444 AllocationSequence* sequence =
445 new AllocationSequence(this, networks[i], config, sequence_flags);
446 if (!sequence->Init()) {
447 delete sequence;
448 continue;
449 }
450 done_signal_needed = true;
451 sequence->SignalPortAllocationComplete.connect(
452 this, &BasicPortAllocatorSession::OnPortAllocationComplete);
453 if (running_)
454 sequence->Start();
455 sequences_.push_back(sequence);
456 }
457 }
458 if (done_signal_needed) {
459 network_thread_->Post(this, MSG_SEQUENCEOBJECTS_CREATED);
460 }
461}
462
463void BasicPortAllocatorSession::OnNetworksChanged() {
464 network_manager_started_ = true;
465 if (allocation_started_)
466 DoAllocate();
467}
468
469void BasicPortAllocatorSession::DisableEquivalentPhases(
470 talk_base::Network* network, PortConfiguration* config, uint32* flags) {
471 for (uint32 i = 0; i < sequences_.size() &&
472 (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES; ++i) {
473 sequences_[i]->DisableEquivalentPhases(network, config, flags);
474 }
475}
476
477void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
478 AllocationSequence * seq,
479 bool prepare_address) {
480 if (!port)
481 return;
482
483 LOG(LS_INFO) << "Adding allocated port for " << content_name();
484 port->set_content_name(content_name());
485 port->set_component(component_);
486 port->set_generation(generation());
487 if (allocator_->proxy().type != talk_base::PROXY_NONE)
488 port->set_proxy(allocator_->user_agent(), allocator_->proxy());
489 port->set_send_retransmit_count_attribute((allocator_->flags() &
490 PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
491
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 PortData data(port, seq);
493 ports_.push_back(data);
494
495 port->SignalCandidateReady.connect(
496 this, &BasicPortAllocatorSession::OnCandidateReady);
497 port->SignalPortComplete.connect(this,
498 &BasicPortAllocatorSession::OnPortComplete);
499 port->SignalDestroyed.connect(this,
500 &BasicPortAllocatorSession::OnPortDestroyed);
501 port->SignalPortError.connect(
502 this, &BasicPortAllocatorSession::OnPortError);
503 LOG_J(LS_INFO, port) << "Added port to allocator";
504
505 if (prepare_address)
506 port->PrepareAddress();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507}
508
509void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
510 allocation_sequences_created_ = true;
511 // Send candidate allocation complete signal if we have no sequences.
512 MaybeSignalCandidatesAllocationDone();
513}
514
515void BasicPortAllocatorSession::OnCandidateReady(
516 Port* port, const Candidate& c) {
517 ASSERT(talk_base::Thread::Current() == network_thread_);
518 PortData* data = FindPort(port);
519 ASSERT(data != NULL);
520 // Discarding any candidate signal if port allocation status is
521 // already in completed state.
522 if (data->complete())
523 return;
524
525 // Send candidates whose protocol is enabled.
526 std::vector<Candidate> candidates;
527 ProtocolType pvalue;
528 if (StringToProto(c.protocol().c_str(), &pvalue) &&
529 data->sequence()->ProtocolEnabled(pvalue)) {
530 candidates.push_back(c);
531 }
532
533 if (!candidates.empty()) {
534 SignalCandidatesReady(this, candidates);
535 }
536
537 // Moving to READY state as we have atleast one candidate from the port.
538 // Since this port has atleast one candidate we should forward this port
539 // to listners, to allow connections from this port.
540 if (!data->ready()) {
541 data->set_ready();
542 SignalPortReady(this, port);
543 }
544}
545
546void BasicPortAllocatorSession::OnPortComplete(Port* port) {
547 ASSERT(talk_base::Thread::Current() == network_thread_);
548 PortData* data = FindPort(port);
549 ASSERT(data != NULL);
550
551 // Ignore any late signals.
552 if (data->complete())
553 return;
554
555 // Moving to COMPLETE state.
556 data->set_complete();
557 // Send candidate allocation complete signal if this was the last port.
558 MaybeSignalCandidatesAllocationDone();
559}
560
561void BasicPortAllocatorSession::OnPortError(Port* port) {
562 ASSERT(talk_base::Thread::Current() == network_thread_);
563 PortData* data = FindPort(port);
564 ASSERT(data != NULL);
565 // We might have already given up on this port and stopped it.
566 if (data->complete())
567 return;
568
569 // SignalAddressError is currently sent from StunPort/TurnPort.
570 // But this signal itself is generic.
571 data->set_error();
572 // Send candidate allocation complete signal if this was the last port.
573 MaybeSignalCandidatesAllocationDone();
574}
575
576void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
577 ProtocolType proto) {
578 std::vector<Candidate> candidates;
579 for (std::vector<PortData>::iterator it = ports_.begin();
580 it != ports_.end(); ++it) {
581 if (it->sequence() != seq)
582 continue;
583
584 const std::vector<Candidate>& potentials = it->port()->Candidates();
585 for (size_t i = 0; i < potentials.size(); ++i) {
586 ProtocolType pvalue;
587 if (!StringToProto(potentials[i].protocol().c_str(), &pvalue))
588 continue;
589 if (pvalue == proto) {
590 candidates.push_back(potentials[i]);
591 }
592 }
593 }
594
595 if (!candidates.empty()) {
596 SignalCandidatesReady(this, candidates);
597 }
598}
599
600void BasicPortAllocatorSession::OnPortAllocationComplete(
601 AllocationSequence* seq) {
602 // Send candidate allocation complete signal if all ports are done.
603 MaybeSignalCandidatesAllocationDone();
604}
605
606void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
607 // Send signal only if all required AllocationSequence objects
608 // are created.
609 if (!allocation_sequences_created_)
610 return;
611
612 // Check that all port allocation sequences are complete.
613 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
614 it != sequences_.end(); ++it) {
615 if ((*it)->state() == AllocationSequence::kRunning)
616 return;
617 }
618
619 // If all allocated ports are in complete state, session must have got all
620 // expected candidates. Session will trigger candidates allocation complete
621 // signal.
622 for (std::vector<PortData>::iterator it = ports_.begin();
623 it != ports_.end(); ++it) {
624 if (!it->complete())
625 return;
626 }
627 LOG(LS_INFO) << "All candidates gathered for " << content_name_ << ":"
628 << component_ << ":" << generation();
629 SignalCandidatesAllocationDone(this);
630}
631
632void BasicPortAllocatorSession::OnPortDestroyed(
633 PortInterface* port) {
634 ASSERT(talk_base::Thread::Current() == network_thread_);
635 for (std::vector<PortData>::iterator iter = ports_.begin();
636 iter != ports_.end(); ++iter) {
637 if (port == iter->port()) {
638 ports_.erase(iter);
639 LOG_J(LS_INFO, port) << "Removed port from allocator ("
640 << static_cast<int>(ports_.size()) << " remaining)";
641 return;
642 }
643 }
644 ASSERT(false);
645}
646
647void BasicPortAllocatorSession::OnShake() {
648 LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
649
650 std::vector<Port*> ports;
651 std::vector<Connection*> connections;
652
653 for (size_t i = 0; i < ports_.size(); ++i) {
654 if (ports_[i].ready())
655 ports.push_back(ports_[i].port());
656 }
657
658 for (size_t i = 0; i < ports.size(); ++i) {
659 Port::AddressMap::const_iterator iter;
660 for (iter = ports[i]->connections().begin();
661 iter != ports[i]->connections().end();
662 ++iter) {
663 connections.push_back(iter->second);
664 }
665 }
666
667 LOG(INFO) << ">>>>> Destroying " << ports.size() << " ports and "
668 << connections.size() << " connections";
669
670 for (size_t i = 0; i < connections.size(); ++i)
671 connections[i]->Destroy();
672
673 if (running_ || (ports.size() > 0) || (connections.size() > 0))
674 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
675}
676
677BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
678 Port* port) {
679 for (std::vector<PortData>::iterator it = ports_.begin();
680 it != ports_.end(); ++it) {
681 if (it->port() == port) {
682 return &*it;
683 }
684 }
685 return NULL;
686}
687
688// AllocationSequence
689
690AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
691 talk_base::Network* network,
692 PortConfiguration* config,
693 uint32 flags)
694 : session_(session),
695 network_(network),
696 ip_(network->ip()),
697 config_(config),
698 state_(kInit),
699 flags_(flags),
wu@webrtc.org97077a32013-10-25 21:18:33 +0000700 udp_socket_(),
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +0000701 udp_port_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 phase_(0) {
703}
704
705bool AllocationSequence::Init() {
706 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
707 !IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_UFRAG)) {
708 LOG(LS_ERROR) << "Shared socket option can't be set without "
709 << "shared ufrag.";
710 ASSERT(false);
711 return false;
712 }
713
714 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
715 udp_socket_.reset(session_->socket_factory()->CreateUdpSocket(
716 talk_base::SocketAddress(ip_, 0), session_->allocator()->min_port(),
717 session_->allocator()->max_port()));
718 if (udp_socket_) {
719 udp_socket_->SignalReadPacket.connect(
720 this, &AllocationSequence::OnReadPacket);
721 }
722 // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
723 // are next available options to setup a communication channel.
724 }
725 return true;
726}
727
728AllocationSequence::~AllocationSequence() {
729 session_->network_thread()->Clear(this);
730}
731
732void AllocationSequence::DisableEquivalentPhases(talk_base::Network* network,
733 PortConfiguration* config, uint32* flags) {
734 if (!((network == network_) && (ip_ == network->ip()))) {
735 // Different network setup; nothing is equivalent.
736 return;
737 }
738
739 // Else turn off the stuff that we've already got covered.
740
741 // Every config implicitly specifies local, so turn that off right away.
742 *flags |= PORTALLOCATOR_DISABLE_UDP;
743 *flags |= PORTALLOCATOR_DISABLE_TCP;
744
745 if (config_ && config) {
746 if (config_->stun_address == config->stun_address) {
747 // Already got this STUN server covered.
748 *flags |= PORTALLOCATOR_DISABLE_STUN;
749 }
750 if (!config_->relays.empty()) {
751 // Already got relays covered.
752 // NOTE: This will even skip a _different_ set of relay servers if we
753 // were to be given one, but that never happens in our codebase. Should
754 // probably get rid of the list in PortConfiguration and just keep a
755 // single relay server in each one.
756 *flags |= PORTALLOCATOR_DISABLE_RELAY;
757 }
758 }
759}
760
761void AllocationSequence::Start() {
762 state_ = kRunning;
763 session_->network_thread()->Post(this, MSG_ALLOCATION_PHASE);
764}
765
766void AllocationSequence::Stop() {
767 // If the port is completed, don't set it to stopped.
768 if (state_ == kRunning) {
769 state_ = kStopped;
770 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
771 }
772}
773
774void AllocationSequence::OnMessage(talk_base::Message* msg) {
775 ASSERT(talk_base::Thread::Current() == session_->network_thread());
776 ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
777
778 const char* const PHASE_NAMES[kNumPhases] = {
779 "Udp", "Relay", "Tcp", "SslTcp"
780 };
781
782 // Perform all of the phases in the current step.
783 LOG_J(LS_INFO, network_) << "Allocation Phase="
784 << PHASE_NAMES[phase_];
785
786 switch (phase_) {
787 case PHASE_UDP:
788 CreateUDPPorts();
789 CreateStunPorts();
790 EnableProtocol(PROTO_UDP);
791 break;
792
793 case PHASE_RELAY:
794 CreateRelayPorts();
795 break;
796
797 case PHASE_TCP:
798 CreateTCPPorts();
799 EnableProtocol(PROTO_TCP);
800 break;
801
802 case PHASE_SSLTCP:
803 state_ = kCompleted;
804 EnableProtocol(PROTO_SSLTCP);
805 break;
806
807 default:
808 ASSERT(false);
809 }
810
811 if (state() == kRunning) {
812 ++phase_;
813 session_->network_thread()->PostDelayed(
814 session_->allocator()->step_delay(),
815 this, MSG_ALLOCATION_PHASE);
816 } else {
817 // If all phases in AllocationSequence are completed, no allocation
818 // steps needed further. Canceling pending signal.
819 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
820 SignalPortAllocationComplete(this);
821 }
822}
823
824void AllocationSequence::EnableProtocol(ProtocolType proto) {
825 if (!ProtocolEnabled(proto)) {
826 protocols_.push_back(proto);
827 session_->OnProtocolEnabled(this, proto);
828 }
829}
830
831bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
832 for (ProtocolList::const_iterator it = protocols_.begin();
833 it != protocols_.end(); ++it) {
834 if (*it == proto)
835 return true;
836 }
837 return false;
838}
839
840void AllocationSequence::CreateUDPPorts() {
841 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) {
842 LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
843 return;
844 }
845
846 // TODO(mallinath) - Remove UDPPort creating socket after shared socket
847 // is enabled completely.
848 UDPPort* port = NULL;
849 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000850 port = UDPPort::Create(session_->network_thread(),
851 session_->socket_factory(), network_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 udp_socket_.get(),
853 session_->username(), session_->password());
854 } else {
855 port = UDPPort::Create(session_->network_thread(),
856 session_->socket_factory(),
857 network_, ip_,
858 session_->allocator()->min_port(),
859 session_->allocator()->max_port(),
860 session_->username(), session_->password());
861 }
862
863 if (port) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 // If shared socket is enabled, STUN candidate will be allocated by the
865 // UDPPort.
866 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
867 !IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
868 ASSERT(config_ && !config_->stun_address.IsNil());
869 if (!(config_ && !config_->stun_address.IsNil())) {
870 LOG(LS_WARNING)
871 << "AllocationSequence: No STUN server configured, skipping.";
872 return;
873 }
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +0000874 udp_port_ = port;
875 // If there is a TURN UDP server available, then we will use TURN port
876 // to get stun address, otherwise by UDP port.
877 // Shared socket mode is not used in GTURN mode.
878 if (config_ && !config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) {
879 port->set_server_addr(config_->stun_address);
880 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 }
882
883 session_->AddAllocatedPort(port, this, true);
884 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
885 }
886}
887
888void AllocationSequence::CreateTCPPorts() {
889 if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) {
890 LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
891 return;
892 }
893
894 Port* port = TCPPort::Create(session_->network_thread(),
895 session_->socket_factory(),
896 network_, ip_,
897 session_->allocator()->min_port(),
898 session_->allocator()->max_port(),
899 session_->username(), session_->password(),
900 session_->allocator()->allow_tcp_listen());
901 if (port) {
902 session_->AddAllocatedPort(port, this, true);
903 // Since TCPPort is not created using shared socket, |port| will not be
904 // added to the dequeue.
905 }
906}
907
908void AllocationSequence::CreateStunPorts() {
909 if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
910 LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
911 return;
912 }
913
914 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
915 LOG(LS_INFO) << "AllocationSequence: "
916 << "UDPPort will be handling the STUN candidate generation.";
917 return;
918 }
919
920 // If BasicPortAllocatorSession::OnAllocate left STUN ports enabled then we
921 // ought to have an address for them here.
922 ASSERT(config_ && !config_->stun_address.IsNil());
923 if (!(config_ && !config_->stun_address.IsNil())) {
924 LOG(LS_WARNING)
925 << "AllocationSequence: No STUN server configured, skipping.";
926 return;
927 }
928
929 StunPort* port = StunPort::Create(session_->network_thread(),
930 session_->socket_factory(),
931 network_, ip_,
932 session_->allocator()->min_port(),
933 session_->allocator()->max_port(),
934 session_->username(), session_->password(),
935 config_->stun_address);
936 if (port) {
937 session_->AddAllocatedPort(port, this, true);
938 // Since StunPort is not created using shared socket, |port| will not be
939 // added to the dequeue.
940 }
941}
942
943void AllocationSequence::CreateRelayPorts() {
944 if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
945 LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
946 return;
947 }
948
949 // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
950 // ought to have a relay list for them here.
951 ASSERT(config_ && !config_->relays.empty());
952 if (!(config_ && !config_->relays.empty())) {
953 LOG(LS_WARNING)
954 << "AllocationSequence: No relay server configured, skipping.";
955 return;
956 }
957
958 PortConfiguration::RelayList::const_iterator relay;
959 for (relay = config_->relays.begin();
960 relay != config_->relays.end(); ++relay) {
961 if (relay->type == RELAY_GTURN) {
962 CreateGturnPort(*relay);
963 } else if (relay->type == RELAY_TURN) {
964 CreateTurnPort(*relay);
965 } else {
966 ASSERT(false);
967 }
968 }
969}
970
971void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
972 // TODO(mallinath) - Rename RelayPort to GTurnPort.
973 RelayPort* port = RelayPort::Create(session_->network_thread(),
974 session_->socket_factory(),
975 network_, ip_,
976 session_->allocator()->min_port(),
977 session_->allocator()->max_port(),
978 config_->username, config_->password);
979 if (port) {
980 // Since RelayPort is not created using shared socket, |port| will not be
981 // added to the dequeue.
982 // Note: We must add the allocated port before we add addresses because
983 // the latter will create candidates that need name and preference
984 // settings. However, we also can't prepare the address (normally
985 // done by AddAllocatedPort) until we have these addresses. So we
986 // wait to do that until below.
987 session_->AddAllocatedPort(port, this, false);
988
989 // Add the addresses of this protocol.
990 PortList::const_iterator relay_port;
991 for (relay_port = config.ports.begin();
992 relay_port != config.ports.end();
993 ++relay_port) {
994 port->AddServerAddress(*relay_port);
995 port->AddExternalAddress(*relay_port);
996 }
997 // Start fetching an address for this port.
998 port->PrepareAddress();
999 }
1000}
1001
1002void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
1003 PortList::const_iterator relay_port;
1004 for (relay_port = config.ports.begin();
1005 relay_port != config.ports.end(); ++relay_port) {
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001006 TurnPort* port = NULL;
1007 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1008 port = TurnPort::Create(session_->network_thread(),
1009 session_->socket_factory(),
1010 network_, udp_socket_.get(),
1011 session_->username(), session_->password(),
1012 *relay_port, config.credentials);
1013 } else {
1014 port = TurnPort::Create(session_->network_thread(),
1015 session_->socket_factory(),
1016 network_, ip_,
1017 session_->allocator()->min_port(),
1018 session_->allocator()->max_port(),
1019 session_->username(),
1020 session_->password(),
1021 *relay_port, config.credentials);
1022 }
1023
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 if (port) {
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001025 // If we are using shared socket for TURN and udp ports, we need to
1026 // find a way to demux the packets to the correct port when received.
1027 // Mapping against server_address is one way of doing this. When packet
1028 // is received the remote_address will be checked against the map.
1029 // If server address is not resolved, a signal will be sent from the port
1030 // after the address is resolved. The map entry will updated with the
1031 // resolved address when the signal is received from the port.
1032 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
1033 // If server address is not resolved then listen for signal from port.
1034 if ((*relay_port).address.IsUnresolved()) {
1035 port->SignalResolvedServerAddress.connect(
1036 this, &AllocationSequence::OnResolvedTurnServerAddress);
1037 }
1038 turn_ports_[(*relay_port).address] = port;
1039 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 session_->AddAllocatedPort(port, this, true);
1041 }
1042 }
1043}
1044
1045void AllocationSequence::OnReadPacket(
1046 talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
wu@webrtc.orga9890802013-12-13 00:21:03 +00001047 const talk_base::SocketAddress& remote_addr,
1048 const talk_base::PacketTime& packet_time) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 ASSERT(socket == udp_socket_.get());
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001050 // If the packet is received from one of the TURN server in the config, then
1051 // pass down the packet to that port, otherwise it will be handed down to
1052 // the local udp port.
1053 Port* port = NULL;
1054 std::map<talk_base::SocketAddress, Port*>::iterator iter =
1055 turn_ports_.find(remote_addr);
1056 if (iter != turn_ports_.end()) {
1057 port = iter->second;
1058 } else if (udp_port_) {
1059 port = udp_port_;
1060 }
1061 ASSERT(port != NULL);
1062 port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
1063}
1064
1065void AllocationSequence::OnPortDestroyed(PortInterface* port) {
1066 if (udp_port_ == port) {
1067 udp_port_ = NULL;
1068 } else {
1069 std::map<talk_base::SocketAddress, Port*>::iterator iter;
1070 for (iter = turn_ports_.begin(); iter != turn_ports_.end(); ++iter) {
1071 if (iter->second == port) {
1072 turn_ports_.erase(iter);
1073 break;
1074 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 }
1076 }
1077}
1078
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001079void AllocationSequence::OnResolvedTurnServerAddress(
1080 TurnPort* port, const talk_base::SocketAddress& server_address,
1081 const talk_base::SocketAddress& resolved_server_address) {
1082 std::map<talk_base::SocketAddress, Port*>::iterator iter;
1083 iter = turn_ports_.find(server_address);
1084
1085 ASSERT(iter != turn_ports_.end());
1086 ASSERT(iter->second != port);
1087 // Remove old entry and then insert using the resolved address as key.
1088 turn_ports_.erase(iter);
1089 turn_ports_[resolved_server_address] = port;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090}
1091
1092// PortConfiguration
1093PortConfiguration::PortConfiguration(
1094 const talk_base::SocketAddress& stun_address,
1095 const std::string& username,
1096 const std::string& password)
1097 : stun_address(stun_address),
1098 username(username),
1099 password(password) {
1100}
1101
1102void PortConfiguration::AddRelay(const RelayServerConfig& config) {
1103 relays.push_back(config);
1104}
1105
1106bool PortConfiguration::SupportsProtocol(
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001107 const RelayServerConfig& relay, ProtocolType type) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108 PortList::const_iterator relay_port;
1109 for (relay_port = relay.ports.begin();
1110 relay_port != relay.ports.end();
1111 ++relay_port) {
1112 if (relay_port->proto == type)
1113 return true;
1114 }
1115 return false;
1116}
1117
buildbot@webrtc.orgf875f152014-04-14 16:06:21 +00001118bool PortConfiguration::SupportsProtocol(const RelayType turn_type,
1119 ProtocolType type) const {
1120 for (size_t i = 0; i < relays.size(); ++i) {
1121 if (relays[i].type == turn_type &&
1122 SupportsProtocol(relays[i], type))
1123 return true;
1124 }
1125 return false;
1126}
1127
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128} // namespace cricket