blob: 7c285d1c383ed8e224ac51a8182d6639254c0652 [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);
151
152 BasicPortAllocatorSession* session_;
153 talk_base::Network* network_;
154 talk_base::IPAddress ip_;
155 PortConfiguration* config_;
156 State state_;
157 uint32 flags_;
158 ProtocolList protocols_;
159 talk_base::scoped_ptr<talk_base::AsyncPacketSocket> udp_socket_;
160 // Keeping a list of all UDP based ports.
161 std::deque<Port*> ports;
162 int phase_;
163};
164
165// BasicPortAllocator
166BasicPortAllocator::BasicPortAllocator(
167 talk_base::NetworkManager* network_manager,
168 talk_base::PacketSocketFactory* socket_factory)
169 : network_manager_(network_manager),
170 socket_factory_(socket_factory) {
171 ASSERT(socket_factory_ != NULL);
172 Construct();
173}
174
175BasicPortAllocator::BasicPortAllocator(
176 talk_base::NetworkManager* network_manager)
177 : network_manager_(network_manager),
178 socket_factory_(NULL) {
179 Construct();
180}
181
182BasicPortAllocator::BasicPortAllocator(
183 talk_base::NetworkManager* network_manager,
184 talk_base::PacketSocketFactory* socket_factory,
185 const talk_base::SocketAddress& stun_address)
186 : network_manager_(network_manager),
187 socket_factory_(socket_factory),
188 stun_address_(stun_address) {
189 ASSERT(socket_factory_ != NULL);
190 Construct();
191}
192
193BasicPortAllocator::BasicPortAllocator(
194 talk_base::NetworkManager* network_manager,
195 const talk_base::SocketAddress& stun_address,
196 const talk_base::SocketAddress& relay_address_udp,
197 const talk_base::SocketAddress& relay_address_tcp,
198 const talk_base::SocketAddress& relay_address_ssl)
199 : network_manager_(network_manager),
200 socket_factory_(NULL),
201 stun_address_(stun_address) {
202
203 RelayServerConfig config(RELAY_GTURN);
204 if (!relay_address_udp.IsAny())
205 config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
206 if (!relay_address_tcp.IsAny())
207 config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
208 if (!relay_address_ssl.IsAny())
209 config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
210 AddRelay(config);
211
212 Construct();
213}
214
215void BasicPortAllocator::Construct() {
216 allow_tcp_listen_ = true;
217}
218
219BasicPortAllocator::~BasicPortAllocator() {
220}
221
222PortAllocatorSession *BasicPortAllocator::CreateSessionInternal(
223 const std::string& content_name, int component,
224 const std::string& ice_ufrag, const std::string& ice_pwd) {
225 return new BasicPortAllocatorSession(this, content_name, component,
226 ice_ufrag, ice_pwd);
227}
228
229// BasicPortAllocatorSession
230BasicPortAllocatorSession::BasicPortAllocatorSession(
231 BasicPortAllocator *allocator,
232 const std::string& content_name,
233 int component,
234 const std::string& ice_ufrag,
235 const std::string& ice_pwd)
236 : PortAllocatorSession(content_name, component,
237 ice_ufrag, ice_pwd, allocator->flags()),
238 allocator_(allocator), network_thread_(NULL),
239 socket_factory_(allocator->socket_factory()),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240 allocation_started_(false),
241 network_manager_started_(false),
242 running_(false),
243 allocation_sequences_created_(false) {
244 allocator_->network_manager()->SignalNetworksChanged.connect(
245 this, &BasicPortAllocatorSession::OnNetworksChanged);
246 allocator_->network_manager()->StartUpdating();
247}
248
249BasicPortAllocatorSession::~BasicPortAllocatorSession() {
250 allocator_->network_manager()->StopUpdating();
251 if (network_thread_ != NULL)
252 network_thread_->Clear(this);
253
254 std::vector<PortData>::iterator it;
255 for (it = ports_.begin(); it != ports_.end(); it++)
256 delete it->port();
257
258 for (uint32 i = 0; i < configs_.size(); ++i)
259 delete configs_[i];
260
261 for (uint32 i = 0; i < sequences_.size(); ++i)
262 delete sequences_[i];
263}
264
265void BasicPortAllocatorSession::StartGettingPorts() {
266 network_thread_ = talk_base::Thread::Current();
267 if (!socket_factory_) {
268 owned_socket_factory_.reset(
269 new talk_base::BasicPacketSocketFactory(network_thread_));
270 socket_factory_ = owned_socket_factory_.get();
271 }
272
273 running_ = true;
274 network_thread_->Post(this, MSG_CONFIG_START);
275
276 if (flags() & PORTALLOCATOR_ENABLE_SHAKER)
277 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
278}
279
280void BasicPortAllocatorSession::StopGettingPorts() {
281 ASSERT(talk_base::Thread::Current() == network_thread_);
282 running_ = false;
283 network_thread_->Clear(this, MSG_ALLOCATE);
284 for (uint32 i = 0; i < sequences_.size(); ++i)
285 sequences_[i]->Stop();
286 network_thread_->Post(this, MSG_CONFIG_STOP);
287}
288
289void BasicPortAllocatorSession::OnMessage(talk_base::Message *message) {
290 switch (message->message_id) {
291 case MSG_CONFIG_START:
292 ASSERT(talk_base::Thread::Current() == network_thread_);
293 GetPortConfigurations();
294 break;
295
296 case MSG_CONFIG_READY:
297 ASSERT(talk_base::Thread::Current() == network_thread_);
298 OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
299 break;
300
301 case MSG_ALLOCATE:
302 ASSERT(talk_base::Thread::Current() == network_thread_);
303 OnAllocate();
304 break;
305
306 case MSG_SHAKE:
307 ASSERT(talk_base::Thread::Current() == network_thread_);
308 OnShake();
309 break;
310 case MSG_SEQUENCEOBJECTS_CREATED:
311 ASSERT(talk_base::Thread::Current() == network_thread_);
312 OnAllocationSequenceObjectsCreated();
313 break;
314 case MSG_CONFIG_STOP:
315 ASSERT(talk_base::Thread::Current() == network_thread_);
316 OnConfigStop();
317 break;
318 default:
319 ASSERT(false);
320 }
321}
322
323void BasicPortAllocatorSession::GetPortConfigurations() {
324 PortConfiguration* config = new PortConfiguration(allocator_->stun_address(),
325 username(),
326 password());
327
328 for (size_t i = 0; i < allocator_->relays().size(); ++i) {
329 config->AddRelay(allocator_->relays()[i]);
330 }
331 ConfigReady(config);
332}
333
334void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
335 network_thread_->Post(this, MSG_CONFIG_READY, config);
336}
337
338// Adds a configuration to the list.
339void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
340 if (config)
341 configs_.push_back(config);
342
343 AllocatePorts();
344}
345
346void BasicPortAllocatorSession::OnConfigStop() {
347 ASSERT(talk_base::Thread::Current() == network_thread_);
348
349 // If any of the allocated ports have not completed the candidates allocation,
350 // mark those as error. Since session doesn't need any new candidates
351 // at this stage of the allocation, it's safe to discard any new candidates.
352 bool send_signal = false;
353 for (std::vector<PortData>::iterator it = ports_.begin();
354 it != ports_.end(); ++it) {
355 if (!it->complete()) {
356 // Updating port state to error, which didn't finish allocating candidates
357 // yet.
358 it->set_error();
359 send_signal = true;
360 }
361 }
362
363 // Did we stop any running sequences?
364 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
365 it != sequences_.end() && !send_signal; ++it) {
366 if ((*it)->state() == AllocationSequence::kStopped) {
367 send_signal = true;
368 }
369 }
370
371 // If we stopped anything that was running, send a done signal now.
372 if (send_signal) {
373 MaybeSignalCandidatesAllocationDone();
374 }
375}
376
377void BasicPortAllocatorSession::AllocatePorts() {
378 ASSERT(talk_base::Thread::Current() == network_thread_);
379 network_thread_->Post(this, MSG_ALLOCATE);
380}
381
382void BasicPortAllocatorSession::OnAllocate() {
383 if (network_manager_started_)
384 DoAllocate();
385
386 allocation_started_ = true;
387 if (running_)
388 network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE);
389}
390
391// For each network, see if we have a sequence that covers it already. If not,
392// create a new sequence to create the appropriate ports.
393void BasicPortAllocatorSession::DoAllocate() {
394 bool done_signal_needed = false;
395 std::vector<talk_base::Network*> networks;
396 allocator_->network_manager()->GetNetworks(&networks);
397 if (networks.empty()) {
398 LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
399 done_signal_needed = true;
400 } else {
401 for (uint32 i = 0; i < networks.size(); ++i) {
402 PortConfiguration* config = NULL;
403 if (configs_.size() > 0)
404 config = configs_.back();
405
406 uint32 sequence_flags = flags();
407 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
408 // If all the ports are disabled we should just fire the allocation
409 // done event and return.
410 done_signal_needed = true;
411 break;
412 }
413
414 // Disables phases that are not specified in this config.
415 if (!config || config->stun_address.IsNil()) {
416 // No STUN ports specified in this config.
417 sequence_flags |= PORTALLOCATOR_DISABLE_STUN;
418 }
419 if (!config || config->relays.empty()) {
420 // No relay ports specified in this config.
421 sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
422 }
423
424 if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) &&
425 networks[i]->ip().family() == AF_INET6) {
426 // Skip IPv6 networks unless the flag's been set.
427 continue;
428 }
429
430 // Disable phases that would only create ports equivalent to
431 // ones that we have already made.
432 DisableEquivalentPhases(networks[i], config, &sequence_flags);
433
434 if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
435 // New AllocationSequence would have nothing to do, so don't make it.
436 continue;
437 }
438
439 AllocationSequence* sequence =
440 new AllocationSequence(this, networks[i], config, sequence_flags);
441 if (!sequence->Init()) {
442 delete sequence;
443 continue;
444 }
445 done_signal_needed = true;
446 sequence->SignalPortAllocationComplete.connect(
447 this, &BasicPortAllocatorSession::OnPortAllocationComplete);
448 if (running_)
449 sequence->Start();
450 sequences_.push_back(sequence);
451 }
452 }
453 if (done_signal_needed) {
454 network_thread_->Post(this, MSG_SEQUENCEOBJECTS_CREATED);
455 }
456}
457
458void BasicPortAllocatorSession::OnNetworksChanged() {
459 network_manager_started_ = true;
460 if (allocation_started_)
461 DoAllocate();
462}
463
464void BasicPortAllocatorSession::DisableEquivalentPhases(
465 talk_base::Network* network, PortConfiguration* config, uint32* flags) {
466 for (uint32 i = 0; i < sequences_.size() &&
467 (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES; ++i) {
468 sequences_[i]->DisableEquivalentPhases(network, config, flags);
469 }
470}
471
472void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
473 AllocationSequence * seq,
474 bool prepare_address) {
475 if (!port)
476 return;
477
478 LOG(LS_INFO) << "Adding allocated port for " << content_name();
479 port->set_content_name(content_name());
480 port->set_component(component_);
481 port->set_generation(generation());
482 if (allocator_->proxy().type != talk_base::PROXY_NONE)
483 port->set_proxy(allocator_->user_agent(), allocator_->proxy());
484 port->set_send_retransmit_count_attribute((allocator_->flags() &
485 PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
486
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 PortData data(port, seq);
488 ports_.push_back(data);
489
490 port->SignalCandidateReady.connect(
491 this, &BasicPortAllocatorSession::OnCandidateReady);
492 port->SignalPortComplete.connect(this,
493 &BasicPortAllocatorSession::OnPortComplete);
494 port->SignalDestroyed.connect(this,
495 &BasicPortAllocatorSession::OnPortDestroyed);
496 port->SignalPortError.connect(
497 this, &BasicPortAllocatorSession::OnPortError);
498 LOG_J(LS_INFO, port) << "Added port to allocator";
499
500 if (prepare_address)
501 port->PrepareAddress();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502}
503
504void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
505 allocation_sequences_created_ = true;
506 // Send candidate allocation complete signal if we have no sequences.
507 MaybeSignalCandidatesAllocationDone();
508}
509
510void BasicPortAllocatorSession::OnCandidateReady(
511 Port* port, const Candidate& c) {
512 ASSERT(talk_base::Thread::Current() == network_thread_);
513 PortData* data = FindPort(port);
514 ASSERT(data != NULL);
515 // Discarding any candidate signal if port allocation status is
516 // already in completed state.
517 if (data->complete())
518 return;
519
520 // Send candidates whose protocol is enabled.
521 std::vector<Candidate> candidates;
522 ProtocolType pvalue;
523 if (StringToProto(c.protocol().c_str(), &pvalue) &&
524 data->sequence()->ProtocolEnabled(pvalue)) {
525 candidates.push_back(c);
526 }
527
528 if (!candidates.empty()) {
529 SignalCandidatesReady(this, candidates);
530 }
531
532 // Moving to READY state as we have atleast one candidate from the port.
533 // Since this port has atleast one candidate we should forward this port
534 // to listners, to allow connections from this port.
535 if (!data->ready()) {
536 data->set_ready();
537 SignalPortReady(this, port);
538 }
539}
540
541void BasicPortAllocatorSession::OnPortComplete(Port* port) {
542 ASSERT(talk_base::Thread::Current() == network_thread_);
543 PortData* data = FindPort(port);
544 ASSERT(data != NULL);
545
546 // Ignore any late signals.
547 if (data->complete())
548 return;
549
550 // Moving to COMPLETE state.
551 data->set_complete();
552 // Send candidate allocation complete signal if this was the last port.
553 MaybeSignalCandidatesAllocationDone();
554}
555
556void BasicPortAllocatorSession::OnPortError(Port* port) {
557 ASSERT(talk_base::Thread::Current() == network_thread_);
558 PortData* data = FindPort(port);
559 ASSERT(data != NULL);
560 // We might have already given up on this port and stopped it.
561 if (data->complete())
562 return;
563
564 // SignalAddressError is currently sent from StunPort/TurnPort.
565 // But this signal itself is generic.
566 data->set_error();
567 // Send candidate allocation complete signal if this was the last port.
568 MaybeSignalCandidatesAllocationDone();
569}
570
571void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
572 ProtocolType proto) {
573 std::vector<Candidate> candidates;
574 for (std::vector<PortData>::iterator it = ports_.begin();
575 it != ports_.end(); ++it) {
576 if (it->sequence() != seq)
577 continue;
578
579 const std::vector<Candidate>& potentials = it->port()->Candidates();
580 for (size_t i = 0; i < potentials.size(); ++i) {
581 ProtocolType pvalue;
582 if (!StringToProto(potentials[i].protocol().c_str(), &pvalue))
583 continue;
584 if (pvalue == proto) {
585 candidates.push_back(potentials[i]);
586 }
587 }
588 }
589
590 if (!candidates.empty()) {
591 SignalCandidatesReady(this, candidates);
592 }
593}
594
595void BasicPortAllocatorSession::OnPortAllocationComplete(
596 AllocationSequence* seq) {
597 // Send candidate allocation complete signal if all ports are done.
598 MaybeSignalCandidatesAllocationDone();
599}
600
601void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
602 // Send signal only if all required AllocationSequence objects
603 // are created.
604 if (!allocation_sequences_created_)
605 return;
606
607 // Check that all port allocation sequences are complete.
608 for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
609 it != sequences_.end(); ++it) {
610 if ((*it)->state() == AllocationSequence::kRunning)
611 return;
612 }
613
614 // If all allocated ports are in complete state, session must have got all
615 // expected candidates. Session will trigger candidates allocation complete
616 // signal.
617 for (std::vector<PortData>::iterator it = ports_.begin();
618 it != ports_.end(); ++it) {
619 if (!it->complete())
620 return;
621 }
622 LOG(LS_INFO) << "All candidates gathered for " << content_name_ << ":"
623 << component_ << ":" << generation();
624 SignalCandidatesAllocationDone(this);
625}
626
627void BasicPortAllocatorSession::OnPortDestroyed(
628 PortInterface* port) {
629 ASSERT(talk_base::Thread::Current() == network_thread_);
630 for (std::vector<PortData>::iterator iter = ports_.begin();
631 iter != ports_.end(); ++iter) {
632 if (port == iter->port()) {
633 ports_.erase(iter);
634 LOG_J(LS_INFO, port) << "Removed port from allocator ("
635 << static_cast<int>(ports_.size()) << " remaining)";
636 return;
637 }
638 }
639 ASSERT(false);
640}
641
642void BasicPortAllocatorSession::OnShake() {
643 LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
644
645 std::vector<Port*> ports;
646 std::vector<Connection*> connections;
647
648 for (size_t i = 0; i < ports_.size(); ++i) {
649 if (ports_[i].ready())
650 ports.push_back(ports_[i].port());
651 }
652
653 for (size_t i = 0; i < ports.size(); ++i) {
654 Port::AddressMap::const_iterator iter;
655 for (iter = ports[i]->connections().begin();
656 iter != ports[i]->connections().end();
657 ++iter) {
658 connections.push_back(iter->second);
659 }
660 }
661
662 LOG(INFO) << ">>>>> Destroying " << ports.size() << " ports and "
663 << connections.size() << " connections";
664
665 for (size_t i = 0; i < connections.size(); ++i)
666 connections[i]->Destroy();
667
668 if (running_ || (ports.size() > 0) || (connections.size() > 0))
669 network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
670}
671
672BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
673 Port* port) {
674 for (std::vector<PortData>::iterator it = ports_.begin();
675 it != ports_.end(); ++it) {
676 if (it->port() == port) {
677 return &*it;
678 }
679 }
680 return NULL;
681}
682
683// AllocationSequence
684
685AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
686 talk_base::Network* network,
687 PortConfiguration* config,
688 uint32 flags)
689 : session_(session),
690 network_(network),
691 ip_(network->ip()),
692 config_(config),
693 state_(kInit),
694 flags_(flags),
wu@webrtc.org97077a32013-10-25 21:18:33 +0000695 udp_socket_(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 phase_(0) {
697}
698
699bool AllocationSequence::Init() {
700 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
701 !IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_UFRAG)) {
702 LOG(LS_ERROR) << "Shared socket option can't be set without "
703 << "shared ufrag.";
704 ASSERT(false);
705 return false;
706 }
707
708 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
709 udp_socket_.reset(session_->socket_factory()->CreateUdpSocket(
710 talk_base::SocketAddress(ip_, 0), session_->allocator()->min_port(),
711 session_->allocator()->max_port()));
712 if (udp_socket_) {
713 udp_socket_->SignalReadPacket.connect(
714 this, &AllocationSequence::OnReadPacket);
715 }
716 // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
717 // are next available options to setup a communication channel.
718 }
719 return true;
720}
721
722AllocationSequence::~AllocationSequence() {
723 session_->network_thread()->Clear(this);
724}
725
726void AllocationSequence::DisableEquivalentPhases(talk_base::Network* network,
727 PortConfiguration* config, uint32* flags) {
728 if (!((network == network_) && (ip_ == network->ip()))) {
729 // Different network setup; nothing is equivalent.
730 return;
731 }
732
733 // Else turn off the stuff that we've already got covered.
734
735 // Every config implicitly specifies local, so turn that off right away.
736 *flags |= PORTALLOCATOR_DISABLE_UDP;
737 *flags |= PORTALLOCATOR_DISABLE_TCP;
738
739 if (config_ && config) {
740 if (config_->stun_address == config->stun_address) {
741 // Already got this STUN server covered.
742 *flags |= PORTALLOCATOR_DISABLE_STUN;
743 }
744 if (!config_->relays.empty()) {
745 // Already got relays covered.
746 // NOTE: This will even skip a _different_ set of relay servers if we
747 // were to be given one, but that never happens in our codebase. Should
748 // probably get rid of the list in PortConfiguration and just keep a
749 // single relay server in each one.
750 *flags |= PORTALLOCATOR_DISABLE_RELAY;
751 }
752 }
753}
754
755void AllocationSequence::Start() {
756 state_ = kRunning;
757 session_->network_thread()->Post(this, MSG_ALLOCATION_PHASE);
758}
759
760void AllocationSequence::Stop() {
761 // If the port is completed, don't set it to stopped.
762 if (state_ == kRunning) {
763 state_ = kStopped;
764 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
765 }
766}
767
768void AllocationSequence::OnMessage(talk_base::Message* msg) {
769 ASSERT(talk_base::Thread::Current() == session_->network_thread());
770 ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
771
772 const char* const PHASE_NAMES[kNumPhases] = {
773 "Udp", "Relay", "Tcp", "SslTcp"
774 };
775
776 // Perform all of the phases in the current step.
777 LOG_J(LS_INFO, network_) << "Allocation Phase="
778 << PHASE_NAMES[phase_];
779
780 switch (phase_) {
781 case PHASE_UDP:
782 CreateUDPPorts();
783 CreateStunPorts();
784 EnableProtocol(PROTO_UDP);
785 break;
786
787 case PHASE_RELAY:
788 CreateRelayPorts();
789 break;
790
791 case PHASE_TCP:
792 CreateTCPPorts();
793 EnableProtocol(PROTO_TCP);
794 break;
795
796 case PHASE_SSLTCP:
797 state_ = kCompleted;
798 EnableProtocol(PROTO_SSLTCP);
799 break;
800
801 default:
802 ASSERT(false);
803 }
804
805 if (state() == kRunning) {
806 ++phase_;
807 session_->network_thread()->PostDelayed(
808 session_->allocator()->step_delay(),
809 this, MSG_ALLOCATION_PHASE);
810 } else {
811 // If all phases in AllocationSequence are completed, no allocation
812 // steps needed further. Canceling pending signal.
813 session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
814 SignalPortAllocationComplete(this);
815 }
816}
817
818void AllocationSequence::EnableProtocol(ProtocolType proto) {
819 if (!ProtocolEnabled(proto)) {
820 protocols_.push_back(proto);
821 session_->OnProtocolEnabled(this, proto);
822 }
823}
824
825bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
826 for (ProtocolList::const_iterator it = protocols_.begin();
827 it != protocols_.end(); ++it) {
828 if (*it == proto)
829 return true;
830 }
831 return false;
832}
833
834void AllocationSequence::CreateUDPPorts() {
835 if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) {
836 LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
837 return;
838 }
839
840 // TODO(mallinath) - Remove UDPPort creating socket after shared socket
841 // is enabled completely.
842 UDPPort* port = NULL;
843 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000844 port = UDPPort::Create(session_->network_thread(),
845 session_->socket_factory(), network_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 udp_socket_.get(),
847 session_->username(), session_->password());
848 } else {
849 port = UDPPort::Create(session_->network_thread(),
850 session_->socket_factory(),
851 network_, ip_,
852 session_->allocator()->min_port(),
853 session_->allocator()->max_port(),
854 session_->username(), session_->password());
855 }
856
857 if (port) {
858 ports.push_back(port);
859 // If shared socket is enabled, STUN candidate will be allocated by the
860 // UDPPort.
861 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
862 !IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
863 ASSERT(config_ && !config_->stun_address.IsNil());
864 if (!(config_ && !config_->stun_address.IsNil())) {
865 LOG(LS_WARNING)
866 << "AllocationSequence: No STUN server configured, skipping.";
867 return;
868 }
869 port->set_server_addr(config_->stun_address);
870 }
871
872 session_->AddAllocatedPort(port, this, true);
873 port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
874 }
875}
876
877void AllocationSequence::CreateTCPPorts() {
878 if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) {
879 LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
880 return;
881 }
882
883 Port* port = TCPPort::Create(session_->network_thread(),
884 session_->socket_factory(),
885 network_, ip_,
886 session_->allocator()->min_port(),
887 session_->allocator()->max_port(),
888 session_->username(), session_->password(),
889 session_->allocator()->allow_tcp_listen());
890 if (port) {
891 session_->AddAllocatedPort(port, this, true);
892 // Since TCPPort is not created using shared socket, |port| will not be
893 // added to the dequeue.
894 }
895}
896
897void AllocationSequence::CreateStunPorts() {
898 if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
899 LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
900 return;
901 }
902
903 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
904 LOG(LS_INFO) << "AllocationSequence: "
905 << "UDPPort will be handling the STUN candidate generation.";
906 return;
907 }
908
909 // If BasicPortAllocatorSession::OnAllocate left STUN ports enabled then we
910 // ought to have an address for them here.
911 ASSERT(config_ && !config_->stun_address.IsNil());
912 if (!(config_ && !config_->stun_address.IsNil())) {
913 LOG(LS_WARNING)
914 << "AllocationSequence: No STUN server configured, skipping.";
915 return;
916 }
917
918 StunPort* port = StunPort::Create(session_->network_thread(),
919 session_->socket_factory(),
920 network_, ip_,
921 session_->allocator()->min_port(),
922 session_->allocator()->max_port(),
923 session_->username(), session_->password(),
924 config_->stun_address);
925 if (port) {
926 session_->AddAllocatedPort(port, this, true);
927 // Since StunPort is not created using shared socket, |port| will not be
928 // added to the dequeue.
929 }
930}
931
932void AllocationSequence::CreateRelayPorts() {
933 if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
934 LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
935 return;
936 }
937
938 // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
939 // ought to have a relay list for them here.
940 ASSERT(config_ && !config_->relays.empty());
941 if (!(config_ && !config_->relays.empty())) {
942 LOG(LS_WARNING)
943 << "AllocationSequence: No relay server configured, skipping.";
944 return;
945 }
946
947 PortConfiguration::RelayList::const_iterator relay;
948 for (relay = config_->relays.begin();
949 relay != config_->relays.end(); ++relay) {
950 if (relay->type == RELAY_GTURN) {
951 CreateGturnPort(*relay);
952 } else if (relay->type == RELAY_TURN) {
953 CreateTurnPort(*relay);
954 } else {
955 ASSERT(false);
956 }
957 }
958}
959
960void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
961 // TODO(mallinath) - Rename RelayPort to GTurnPort.
962 RelayPort* port = RelayPort::Create(session_->network_thread(),
963 session_->socket_factory(),
964 network_, ip_,
965 session_->allocator()->min_port(),
966 session_->allocator()->max_port(),
967 config_->username, config_->password);
968 if (port) {
969 // Since RelayPort is not created using shared socket, |port| will not be
970 // added to the dequeue.
971 // Note: We must add the allocated port before we add addresses because
972 // the latter will create candidates that need name and preference
973 // settings. However, we also can't prepare the address (normally
974 // done by AddAllocatedPort) until we have these addresses. So we
975 // wait to do that until below.
976 session_->AddAllocatedPort(port, this, false);
977
978 // Add the addresses of this protocol.
979 PortList::const_iterator relay_port;
980 for (relay_port = config.ports.begin();
981 relay_port != config.ports.end();
982 ++relay_port) {
983 port->AddServerAddress(*relay_port);
984 port->AddExternalAddress(*relay_port);
985 }
986 // Start fetching an address for this port.
987 port->PrepareAddress();
988 }
989}
990
991void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
992 PortList::const_iterator relay_port;
993 for (relay_port = config.ports.begin();
994 relay_port != config.ports.end(); ++relay_port) {
995 TurnPort* port = TurnPort::Create(session_->network_thread(),
996 session_->socket_factory(),
997 network_, ip_,
998 session_->allocator()->min_port(),
999 session_->allocator()->max_port(),
1000 session_->username(),
1001 session_->password(),
1002 *relay_port, config.credentials);
1003 if (port) {
1004 session_->AddAllocatedPort(port, this, true);
1005 }
1006 }
1007}
1008
1009void AllocationSequence::OnReadPacket(
1010 talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
wu@webrtc.orga9890802013-12-13 00:21:03 +00001011 const talk_base::SocketAddress& remote_addr,
1012 const talk_base::PacketTime& packet_time) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 ASSERT(socket == udp_socket_.get());
1014 for (std::deque<Port*>::iterator iter = ports.begin();
1015 iter != ports.end(); ++iter) {
1016 // We have only one port in the queue.
1017 // TODO(mallinath) - Add shared socket support to Relay and Turn ports.
wu@webrtc.orga9890802013-12-13 00:21:03 +00001018 if ((*iter)->HandleIncomingPacket(
1019 socket, data, size, remote_addr, packet_time)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 break;
1021 }
1022 }
1023}
1024
1025void AllocationSequence::OnPortDestroyed(PortInterface* port) {
1026 std::deque<Port*>::iterator iter =
1027 std::find(ports.begin(), ports.end(), port);
1028 ASSERT(iter != ports.end());
1029 ports.erase(iter);
1030}
1031
1032// PortConfiguration
1033PortConfiguration::PortConfiguration(
1034 const talk_base::SocketAddress& stun_address,
1035 const std::string& username,
1036 const std::string& password)
1037 : stun_address(stun_address),
1038 username(username),
1039 password(password) {
1040}
1041
1042void PortConfiguration::AddRelay(const RelayServerConfig& config) {
1043 relays.push_back(config);
1044}
1045
1046bool PortConfiguration::SupportsProtocol(
1047 const RelayServerConfig& relay, ProtocolType type) {
1048 PortList::const_iterator relay_port;
1049 for (relay_port = relay.ports.begin();
1050 relay_port != relay.ports.end();
1051 ++relay_port) {
1052 if (relay_port->proto == type)
1053 return true;
1054 }
1055 return false;
1056}
1057
1058} // namespace cricket