blob: 1a126a69836f9b0c67bf5267e85aaf51030699a6 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/p2p/base/session.h"
12
13#include "webrtc/p2p/base/dtlstransport.h"
14#include "webrtc/p2p/base/p2ptransport.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000015#include "webrtc/p2p/base/transport.h"
16#include "webrtc/p2p/base/transportchannelproxy.h"
17#include "webrtc/p2p/base/transportinfo.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000018#include "webrtc/base/bind.h"
19#include "webrtc/base/common.h"
20#include "webrtc/base/helpers.h"
21#include "webrtc/base/logging.h"
22#include "webrtc/base/scoped_ptr.h"
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +000023#include "webrtc/base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024#include "webrtc/base/sslstreamadapter.h"
25
26#include "webrtc/p2p/base/constants.h"
27
28namespace cricket {
29
30using rtc::Bind;
31
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000032TransportProxy::~TransportProxy() {
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000033 ASSERT(channels_.empty());
34}
35
36bool TransportProxy::HasChannels() const {
37 ASSERT(rtc::Thread::Current() == worker_thread_);
38 return !channels_.empty();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000039}
40
41const std::string& TransportProxy::type() const {
42 return transport_->get()->type();
43}
44
45TransportChannel* TransportProxy::GetChannel(int component) {
46 ASSERT(rtc::Thread::Current() == worker_thread_);
47 return GetChannelProxy(component);
48}
49
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000050TransportChannel* TransportProxy::CreateChannel(const std::string& name,
51 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052 ASSERT(rtc::Thread::Current() == worker_thread_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000053
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000054 TransportChannelProxyRef* channel_proxy;
55 if (channels_.find(component) == channels_.end()) {
56 channel_proxy =
57 new TransportChannelProxyRef(content_name(), name, component);
58 channels_[component] = channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000060 // TransportProxy maintains its own reference
61 // here. RefCountedObject automatically deletes the pointer when
62 // the refcount hits 0. This prevents RefCountedObject from
63 // deleting the object when all *external* references are
64 // gone. Things need to be done in DestroyChannel prior to the
65 // proxy being deleted.
66 channel_proxy->AddRef();
67
68 // If we're already negotiated, create an impl and hook it up to the proxy
69 // channel. If we're connecting, create an impl but don't hook it up yet.
70 if (negotiated_) {
71 CreateChannelImpl_w(component);
72 SetChannelImplFromTransport_w(channel_proxy, component);
73 } else if (connecting_) {
74 CreateChannelImpl_w(component);
75 }
76 } else {
77 channel_proxy = channels_[component];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000078 }
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000079
80 channel_proxy->AddRef();
81
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000082 return channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000083}
84
85bool TransportProxy::HasChannel(int component) {
86 return transport_->get()->HasChannel(component);
87}
88
89void TransportProxy::DestroyChannel(int component) {
90 ASSERT(rtc::Thread::Current() == worker_thread_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000092 ChannelMap::const_iterator iter = channels_.find(component);
93 if (iter == channels_.end()) {
94 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000095 }
decurtis@webrtc.orge2506672015-02-03 23:18:39 +000096
97 TransportChannelProxyRef* channel_proxy = iter->second;
98 int ref_count = channel_proxy->Release();
99 if (ref_count > 1) {
100 return;
101 }
102 // TransportProxy owns the last reference on the TransportChannelProxy.
103 // It should *never* be the case that ref_count is less than one
104 // here but this makes me sleep better at night.
105 ASSERT(ref_count == 1);
106
107 // If the state of TransportProxy is not NEGOTIATED then
108 // TransportChannelProxy and its impl are not connected. Both must
109 // be connected before deletion.
110 //
111 // However, if we haven't entered the connecting state then there
112 // is no implementation to hook up.
113 if (connecting_ && !negotiated_) {
114 SetChannelImplFromTransport_w(channel_proxy, component);
115 }
116
117 channels_.erase(component);
118 channel_proxy->SignalDestroyed(channel_proxy);
119
120 // Implicitly deletes the object since ref_count is now 0.
121 channel_proxy->Release();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000122}
123
124void TransportProxy::ConnectChannels() {
125 if (!connecting_) {
126 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000127 for (auto& iter : channels_) {
128 CreateChannelImpl(iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000129 }
130 }
131 connecting_ = true;
132 }
133 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
134 // don't have any channels yet, so we need to allow this method to be called
135 // multiple times. Once we fix Transport, we can move this call inside the
136 // if (!connecting_) block.
137 transport_->get()->ConnectChannels();
138}
139
140void TransportProxy::CompleteNegotiation() {
141 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000142 // Negotiating assumes connecting_ has happened and
143 // implementations exist. If not we need to create the
144 // implementations.
145 for (auto& iter : channels_) {
146 if (!connecting_) {
147 CreateChannelImpl(iter.first);
148 }
149 SetChannelImplFromTransport(iter.second, iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150 }
151 negotiated_ = true;
152 }
153}
154
155void TransportProxy::AddSentCandidates(const Candidates& candidates) {
156 for (Candidates::const_iterator cand = candidates.begin();
157 cand != candidates.end(); ++cand) {
158 sent_candidates_.push_back(*cand);
159 }
160}
161
162void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
163 for (Candidates::const_iterator cand = candidates.begin();
164 cand != candidates.end(); ++cand) {
165 unsent_candidates_.push_back(*cand);
166 }
167}
168
169bool TransportProxy::GetChannelNameFromComponent(
170 int component, std::string* channel_name) const {
171 const TransportChannelProxy* channel = GetChannelProxy(component);
172 if (channel == NULL) {
173 return false;
174 }
175
176 *channel_name = channel->name();
177 return true;
178}
179
180bool TransportProxy::GetComponentFromChannelName(
181 const std::string& channel_name, int* component) const {
182 const TransportChannelProxy* channel = GetChannelProxyByName(channel_name);
183 if (channel == NULL) {
184 return false;
185 }
186
187 *component = channel->component();
188 return true;
189}
190
191TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
192 ChannelMap::const_iterator iter = channels_.find(component);
193 return (iter != channels_.end()) ? iter->second : NULL;
194}
195
196TransportChannelProxy* TransportProxy::GetChannelProxyByName(
197 const std::string& name) const {
198 for (ChannelMap::const_iterator iter = channels_.begin();
199 iter != channels_.end();
200 ++iter) {
201 if (iter->second->name() == name) {
202 return iter->second;
203 }
204 }
205 return NULL;
206}
207
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000208void TransportProxy::CreateChannelImpl(int component) {
209 worker_thread_->Invoke<void>(Bind(
210 &TransportProxy::CreateChannelImpl_w, this, component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211}
212
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000213void TransportProxy::CreateChannelImpl_w(int component) {
214 ASSERT(rtc::Thread::Current() == worker_thread_);
215 transport_->get()->CreateChannel(component);
216}
217
218void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
219 int component) {
220 worker_thread_->Invoke<void>(Bind(
221 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
222}
223
224void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
225 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000226 ASSERT(rtc::Thread::Current() == worker_thread_);
227 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000228 ASSERT(impl != NULL);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000229 ReplaceChannelImpl_w(proxy, impl);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230}
231
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000232void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
233 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234 worker_thread_->Invoke<void>(Bind(
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000235 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236}
237
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000238void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
239 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000240 ASSERT(rtc::Thread::Current() == worker_thread_);
241 ASSERT(proxy != NULL);
242 proxy->SetImplementation(impl);
243}
244
245// This function muxes |this| onto |target| by repointing |this| at
246// |target|'s transport and setting our TransportChannelProxies
247// to point to |target|'s underlying implementations.
248bool TransportProxy::SetupMux(TransportProxy* target) {
249 // Bail out if there's nothing to do.
250 if (transport_ == target->transport_) {
251 return true;
252 }
253
254 // Run through all channels and remove any non-rtp transport channels before
255 // setting target transport channels.
256 for (ChannelMap::const_iterator iter = channels_.begin();
257 iter != channels_.end(); ++iter) {
258 if (!target->transport_->get()->HasChannel(iter->first)) {
259 // Remove if channel doesn't exist in |transport_|.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000260 ReplaceChannelImpl(iter->second, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 } else {
262 // Replace the impl for all the TransportProxyChannels with the channels
263 // from |target|'s transport. Fail if there's not an exact match.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000264 ReplaceChannelImpl(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000265 iter->second, target->transport_->get()->CreateChannel(iter->first));
266 }
267 }
268
269 // Now replace our transport. Must happen afterwards because
270 // it deletes all impls as a side effect.
271 transport_ = target->transport_;
272 transport_->get()->SignalCandidatesReady.connect(
273 this, &TransportProxy::OnTransportCandidatesReady);
274 set_candidates_allocated(target->candidates_allocated());
275 return true;
276}
277
278void TransportProxy::SetIceRole(IceRole role) {
279 transport_->get()->SetIceRole(role);
280}
281
282bool TransportProxy::SetLocalTransportDescription(
283 const TransportDescription& description,
284 ContentAction action,
285 std::string* error_desc) {
286 // If this is an answer, finalize the negotiation.
287 if (action == CA_ANSWER) {
288 CompleteNegotiation();
289 }
290 bool result = transport_->get()->SetLocalTransportDescription(description,
291 action,
292 error_desc);
293 if (result)
294 local_description_set_ = true;
295 return result;
296}
297
298bool TransportProxy::SetRemoteTransportDescription(
299 const TransportDescription& description,
300 ContentAction action,
301 std::string* error_desc) {
302 // If this is an answer, finalize the negotiation.
303 if (action == CA_ANSWER) {
304 CompleteNegotiation();
305 }
306 bool result = transport_->get()->SetRemoteTransportDescription(description,
307 action,
308 error_desc);
309 if (result)
310 remote_description_set_ = true;
311 return result;
312}
313
314void TransportProxy::OnSignalingReady() {
315 // If we're starting a new allocation sequence, reset our state.
316 set_candidates_allocated(false);
317 transport_->get()->OnSignalingReady();
318}
319
320bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
321 std::string* error) {
322 // Ensure the transport is negotiated before handling candidates.
323 // TODO(juberti): Remove this once everybody calls SetLocalTD.
324 CompleteNegotiation();
325
326 // Verify each candidate before passing down to transport layer.
327 for (Candidates::const_iterator cand = candidates.begin();
328 cand != candidates.end(); ++cand) {
329 if (!transport_->get()->VerifyCandidate(*cand, error))
330 return false;
331 if (!HasChannel(cand->component())) {
332 *error = "Candidate has unknown component: " + cand->ToString() +
333 " for content: " + content_name_;
334 return false;
335 }
336 }
337 transport_->get()->OnRemoteCandidates(candidates);
338 return true;
339}
340
341void TransportProxy::SetIdentity(
342 rtc::SSLIdentity* identity) {
343 transport_->get()->SetIdentity(identity);
344}
345
346std::string BaseSession::StateToString(State state) {
347 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000348 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000349 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000350 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000352 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000354 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000355 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000356 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000357 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000358 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000360 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000362 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000364 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000365 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000366 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000368 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000370 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000372 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000374 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000376 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000377 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000378 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379 return "STATE_DEINIT";
380 default:
381 break;
382 }
383 return "STATE_" + rtc::ToString(state);
384}
385
386BaseSession::BaseSession(rtc::Thread* signaling_thread,
387 rtc::Thread* worker_thread,
388 PortAllocator* port_allocator,
389 const std::string& sid,
390 const std::string& content_type,
391 bool initiator)
392 : state_(STATE_INIT),
393 error_(ERROR_NONE),
394 signaling_thread_(signaling_thread),
395 worker_thread_(worker_thread),
396 port_allocator_(port_allocator),
397 sid_(sid),
398 content_type_(content_type),
399 transport_type_(NS_GINGLE_P2P),
400 initiator_(initiator),
401 identity_(NULL),
402 ice_tiebreaker_(rtc::CreateRandomId64()),
403 role_switch_(false) {
404 ASSERT(signaling_thread->IsCurrent());
405}
406
407BaseSession::~BaseSession() {
408 ASSERT(signaling_thread()->IsCurrent());
409
410 ASSERT(state_ != STATE_DEINIT);
411 LogState(state_, STATE_DEINIT);
412 state_ = STATE_DEINIT;
413 SignalState(this, state_);
414
415 for (TransportMap::iterator iter = transports_.begin();
416 iter != transports_.end(); ++iter) {
417 delete iter->second;
418 }
419}
420
421const SessionDescription* BaseSession::local_description() const {
422 // TODO(tommi): Assert on thread correctness.
423 return local_description_.get();
424}
425
426const SessionDescription* BaseSession::remote_description() const {
427 // TODO(tommi): Assert on thread correctness.
428 return remote_description_.get();
429}
430
431SessionDescription* BaseSession::remote_description() {
432 // TODO(tommi): Assert on thread correctness.
433 return remote_description_.get();
434}
435
436void BaseSession::set_local_description(const SessionDescription* sdesc) {
437 // TODO(tommi): Assert on thread correctness.
438 if (sdesc != local_description_.get())
439 local_description_.reset(sdesc);
440}
441
442void BaseSession::set_remote_description(SessionDescription* sdesc) {
443 // TODO(tommi): Assert on thread correctness.
444 if (sdesc != remote_description_)
445 remote_description_.reset(sdesc);
446}
447
448const SessionDescription* BaseSession::initiator_description() const {
449 // TODO(tommi): Assert on thread correctness.
450 return initiator_ ? local_description_.get() : remote_description_.get();
451}
452
453bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
454 if (identity_)
455 return false;
456 identity_ = identity;
457 for (TransportMap::iterator iter = transports_.begin();
458 iter != transports_.end(); ++iter) {
459 iter->second->SetIdentity(identity_);
460 }
461 return true;
462}
463
464bool BaseSession::PushdownTransportDescription(ContentSource source,
465 ContentAction action,
466 std::string* error_desc) {
467 if (source == CS_LOCAL) {
468 return PushdownLocalTransportDescription(local_description(),
469 action,
470 error_desc);
471 }
472 return PushdownRemoteTransportDescription(remote_description(),
473 action,
474 error_desc);
475}
476
477bool BaseSession::PushdownLocalTransportDescription(
478 const SessionDescription* sdesc,
479 ContentAction action,
480 std::string* error_desc) {
481 // Update the Transports with the right information, and trigger them to
482 // start connecting.
483 for (TransportMap::iterator iter = transports_.begin();
484 iter != transports_.end(); ++iter) {
485 // If no transport info was in this session description, ret == false
486 // and we just skip this one.
487 TransportDescription tdesc;
488 bool ret = GetTransportDescription(
489 sdesc, iter->second->content_name(), &tdesc);
490 if (ret) {
491 if (!iter->second->SetLocalTransportDescription(tdesc, action,
492 error_desc)) {
493 return false;
494 }
495
496 iter->second->ConnectChannels();
497 }
498 }
499
500 return true;
501}
502
503bool BaseSession::PushdownRemoteTransportDescription(
504 const SessionDescription* sdesc,
505 ContentAction action,
506 std::string* error_desc) {
507 // Update the Transports with the right information.
508 for (TransportMap::iterator iter = transports_.begin();
509 iter != transports_.end(); ++iter) {
510 TransportDescription tdesc;
511
512 // If no transport info was in this session description, ret == false
513 // and we just skip this one.
514 bool ret = GetTransportDescription(
515 sdesc, iter->second->content_name(), &tdesc);
516 if (ret) {
517 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
518 error_desc)) {
519 return false;
520 }
521 }
522 }
523
524 return true;
525}
526
527TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
528 const std::string& channel_name,
529 int component) {
530 // We create the proxy "on demand" here because we need to support
531 // creating channels at any time, even before we send or receive
532 // initiate messages, which is before we create the transports.
533 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
534 return transproxy->CreateChannel(channel_name, component);
535}
536
537TransportChannel* BaseSession::GetChannel(const std::string& content_name,
538 int component) {
539 TransportProxy* transproxy = GetTransportProxy(content_name);
540 if (transproxy == NULL)
541 return NULL;
542
543 return transproxy->GetChannel(component);
544}
545
546void BaseSession::DestroyChannel(const std::string& content_name,
547 int component) {
548 TransportProxy* transproxy = GetTransportProxy(content_name);
549 ASSERT(transproxy != NULL);
550 transproxy->DestroyChannel(component);
551}
552
553TransportProxy* BaseSession::GetOrCreateTransportProxy(
554 const std::string& content_name) {
555 TransportProxy* transproxy = GetTransportProxy(content_name);
556 if (transproxy)
557 return transproxy;
558
559 Transport* transport = CreateTransport(content_name);
560 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
561 transport->SetIceTiebreaker(ice_tiebreaker_);
562 // TODO: Connect all the Transport signals to TransportProxy
563 // then to the BaseSession.
564 transport->SignalConnecting.connect(
565 this, &BaseSession::OnTransportConnecting);
566 transport->SignalWritableState.connect(
567 this, &BaseSession::OnTransportWritable);
568 transport->SignalRequestSignaling.connect(
569 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570 transport->SignalRouteChange.connect(
571 this, &BaseSession::OnTransportRouteChange);
572 transport->SignalCandidatesAllocationDone.connect(
573 this, &BaseSession::OnTransportCandidatesAllocationDone);
574 transport->SignalRoleConflict.connect(
575 this, &BaseSession::OnRoleConflict);
576 transport->SignalCompleted.connect(
577 this, &BaseSession::OnTransportCompleted);
578 transport->SignalFailed.connect(
579 this, &BaseSession::OnTransportFailed);
580
581 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
582 new TransportWrapper(transport));
583 transproxy->SignalCandidatesReady.connect(
584 this, &BaseSession::OnTransportProxyCandidatesReady);
585 if (identity_)
586 transproxy->SetIdentity(identity_);
587 transports_[content_name] = transproxy;
588
589 return transproxy;
590}
591
592Transport* BaseSession::GetTransport(const std::string& content_name) {
593 TransportProxy* transproxy = GetTransportProxy(content_name);
594 if (transproxy == NULL)
595 return NULL;
596 return transproxy->impl();
597}
598
599TransportProxy* BaseSession::GetTransportProxy(
600 const std::string& content_name) {
601 TransportMap::iterator iter = transports_.find(content_name);
602 return (iter != transports_.end()) ? iter->second : NULL;
603}
604
605TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
606 for (TransportMap::iterator iter = transports_.begin();
607 iter != transports_.end(); ++iter) {
608 TransportProxy* transproxy = iter->second;
609 if (transproxy->impl() == transport) {
610 return transproxy;
611 }
612 }
613 return NULL;
614}
615
616TransportProxy* BaseSession::GetFirstTransportProxy() {
617 if (transports_.empty())
618 return NULL;
619 return transports_.begin()->second;
620}
621
decurtis@webrtc.orge2506672015-02-03 23:18:39 +0000622void BaseSession::DestroyTransportProxyWhenUnused(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000623 const std::string& content_name) {
decurtis@webrtc.orge2506672015-02-03 23:18:39 +0000624 TransportProxy *tp = GetTransportProxy(content_name);
625 if(tp && !tp->HasChannels()) {
626 DestroyTransportProxy(content_name);
627 }
628}
629
630void BaseSession::DestroyTransportProxy(const std::string& content_name) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000631 TransportMap::iterator iter = transports_.find(content_name);
632 if (iter != transports_.end()) {
633 delete iter->second;
634 transports_.erase(content_name);
635 }
636}
637
638cricket::Transport* BaseSession::CreateTransport(
639 const std::string& content_name) {
640 ASSERT(transport_type_ == NS_GINGLE_P2P);
641 return new cricket::DtlsTransport<P2PTransport>(
642 signaling_thread(), worker_thread(), content_name,
643 port_allocator(), identity_);
644}
645
646bool BaseSession::GetStats(SessionStats* stats) {
647 for (TransportMap::iterator iter = transports_.begin();
648 iter != transports_.end(); ++iter) {
649 std::string proxy_id = iter->second->content_name();
650 // We are ignoring not-yet-instantiated transports.
651 if (iter->second->impl()) {
652 std::string transport_id = iter->second->impl()->content_name();
653 stats->proxy_to_transport[proxy_id] = transport_id;
654 if (stats->transport_stats.find(transport_id)
655 == stats->transport_stats.end()) {
656 TransportStats subinfos;
657 if (!iter->second->impl()->GetStats(&subinfos)) {
658 return false;
659 }
660 stats->transport_stats[transport_id] = subinfos;
661 }
662 }
663 }
664 return true;
665}
666
667void BaseSession::SetState(State state) {
668 ASSERT(signaling_thread_->IsCurrent());
669 if (state != state_) {
670 LogState(state_, state);
671 state_ = state;
672 SignalState(this, state_);
673 signaling_thread_->Post(this, MSG_STATE);
674 }
675 SignalNewDescription();
676}
677
678void BaseSession::SetError(Error error, const std::string& error_desc) {
679 ASSERT(signaling_thread_->IsCurrent());
680 if (error != error_) {
681 error_ = error;
682 error_desc_ = error_desc;
683 SignalError(this, error);
684 }
685}
686
687void BaseSession::OnSignalingReady() {
688 ASSERT(signaling_thread()->IsCurrent());
689 for (TransportMap::iterator iter = transports_.begin();
690 iter != transports_.end(); ++iter) {
691 iter->second->OnSignalingReady();
692 }
693}
694
695// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
696// start, remove this method once everyone calls PushdownLocalTD.
697void BaseSession::SpeculativelyConnectAllTransportChannels() {
698 // Put all transports into the connecting state.
699 for (TransportMap::iterator iter = transports_.begin();
700 iter != transports_.end(); ++iter) {
701 iter->second->ConnectChannels();
702 }
703}
704
705bool BaseSession::OnRemoteCandidates(const std::string& content_name,
706 const Candidates& candidates,
707 std::string* error) {
708 // Give candidates to the appropriate transport, and tell that transport
709 // to start connecting, if it's not already doing so.
710 TransportProxy* transproxy = GetTransportProxy(content_name);
711 if (!transproxy) {
712 *error = "Unknown content name " + content_name;
713 return false;
714 }
715 if (!transproxy->OnRemoteCandidates(candidates, error)) {
716 return false;
717 }
718 // TODO(juberti): Remove this call once we can be sure that we always have
719 // a local transport description (which will trigger the connection).
720 transproxy->ConnectChannels();
721 return true;
722}
723
724bool BaseSession::MaybeEnableMuxingSupport() {
725 // We need both a local and remote description to decide if we should mux.
726 if ((state_ == STATE_SENTINITIATE ||
727 state_ == STATE_RECEIVEDINITIATE) &&
728 ((local_description_ == NULL) ||
729 (remote_description_ == NULL))) {
730 return false;
731 }
732
733 // In order to perform the multiplexing, we need all proxies to be in the
734 // negotiated state, i.e. to have implementations underneath.
735 // Ensure that this is the case, regardless of whether we are going to mux.
736 for (TransportMap::iterator iter = transports_.begin();
737 iter != transports_.end(); ++iter) {
738 ASSERT(iter->second->negotiated());
739 if (!iter->second->negotiated())
740 return false;
741 }
742
743 // If both sides agree to BUNDLE, mux all the specified contents onto the
744 // transport belonging to the first content name in the BUNDLE group.
745 // If the contents are already muxed, this will be a no-op.
746 // TODO(juberti): Should this check that local and remote have configured
747 // BUNDLE the same way?
748 bool candidates_allocated = IsCandidateAllocationDone();
749 const ContentGroup* local_bundle_group =
750 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
751 const ContentGroup* remote_bundle_group =
752 remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
753 if (local_bundle_group && remote_bundle_group &&
754 local_bundle_group->FirstContentName()) {
755 const std::string* content_name = local_bundle_group->FirstContentName();
756 const ContentInfo* content =
757 local_description_->GetContentByName(*content_name);
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000758 if (!content) {
759 LOG(LS_WARNING) << "Content \"" << *content_name
760 << "\" referenced in BUNDLE group is not present";
761 return false;
762 }
763
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 if (!SetSelectedProxy(content->name, local_bundle_group)) {
765 LOG(LS_WARNING) << "Failed to set up BUNDLE";
766 return false;
767 }
768
769 // If we weren't done gathering before, we might be done now, as a result
770 // of enabling mux.
771 LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
772 << *content_name;
773 if (!candidates_allocated) {
774 MaybeCandidateAllocationDone();
775 }
776 } else {
777 LOG(LS_INFO) << "No BUNDLE information, not bundling.";
778 }
779 return true;
780}
781
782bool BaseSession::SetSelectedProxy(const std::string& content_name,
783 const ContentGroup* muxed_group) {
784 TransportProxy* selected_proxy = GetTransportProxy(content_name);
785 if (!selected_proxy) {
786 return false;
787 }
788
789 ASSERT(selected_proxy->negotiated());
790 for (TransportMap::iterator iter = transports_.begin();
791 iter != transports_.end(); ++iter) {
792 // If content is part of the mux group, then repoint its proxy at the
793 // transport object that we have chosen to mux onto. If the proxy
794 // is already pointing at the right object, it will be a no-op.
795 if (muxed_group->HasContentName(iter->first) &&
796 !iter->second->SetupMux(selected_proxy)) {
797 return false;
798 }
799 }
800 return true;
801}
802
803void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
804 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
805 // TransportProxy should receive the done signal directly, set its allocated
806 // flag internally, and then reissue the done signal to Session.
807 // Overall we should make TransportProxy receive *all* the signals from
808 // Transport, since this removes the need to manually iterate over all
809 // the transports, as is needed to make sure signals are handled properly
810 // when BUNDLEing.
811 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
812 // that make it prohibitively difficult to run dbg builds. Disabled for now.
813 //ASSERT(!IsCandidateAllocationDone());
814 for (TransportMap::iterator iter = transports_.begin();
815 iter != transports_.end(); ++iter) {
816 if (iter->second->impl() == transport) {
817 iter->second->set_candidates_allocated(true);
818 }
819 }
820 MaybeCandidateAllocationDone();
821}
822
823bool BaseSession::IsCandidateAllocationDone() const {
824 for (TransportMap::const_iterator iter = transports_.begin();
825 iter != transports_.end(); ++iter) {
bjornv@webrtc.orgc5f69712015-02-04 10:22:14 +0000826 if (!iter->second->candidates_allocated())
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 return false;
828 }
829 return true;
830}
831
832void BaseSession::MaybeCandidateAllocationDone() {
833 if (IsCandidateAllocationDone()) {
834 LOG(LS_INFO) << "Candidate gathering is complete.";
835 OnCandidatesAllocationDone();
836 }
837}
838
839void BaseSession::OnRoleConflict() {
840 if (role_switch_) {
841 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
842 return;
843 }
844
845 role_switch_ = true;
846 for (TransportMap::iterator iter = transports_.begin();
847 iter != transports_.end(); ++iter) {
848 // Role will be reverse of initial role setting.
849 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
850 iter->second->SetIceRole(role);
851 }
852}
853
854void BaseSession::LogState(State old_state, State new_state) {
855 LOG(LS_INFO) << "Session:" << id()
856 << " Old state:" << StateToString(old_state)
857 << " New state:" << StateToString(new_state)
858 << " Type:" << content_type()
859 << " Transport:" << transport_type();
860}
861
862// static
863bool BaseSession::GetTransportDescription(const SessionDescription* description,
864 const std::string& content_name,
865 TransportDescription* tdesc) {
866 if (!description || !tdesc) {
867 return false;
868 }
869 const TransportInfo* transport_info =
870 description->GetTransportInfoByName(content_name);
871 if (!transport_info) {
872 return false;
873 }
874 *tdesc = transport_info->description;
875 return true;
876}
877
878void BaseSession::SignalNewDescription() {
879 ContentAction action;
880 ContentSource source;
881 if (!GetContentAction(&action, &source)) {
882 return;
883 }
884 if (source == CS_LOCAL) {
885 SignalNewLocalDescription(this, action);
886 } else {
887 SignalNewRemoteDescription(this, action);
888 }
889}
890
891bool BaseSession::GetContentAction(ContentAction* action,
892 ContentSource* source) {
893 switch (state_) {
894 // new local description
895 case STATE_SENTINITIATE:
896 *action = CA_OFFER;
897 *source = CS_LOCAL;
898 break;
899 case STATE_SENTPRACCEPT:
900 *action = CA_PRANSWER;
901 *source = CS_LOCAL;
902 break;
903 case STATE_SENTACCEPT:
904 *action = CA_ANSWER;
905 *source = CS_LOCAL;
906 break;
907 // new remote description
908 case STATE_RECEIVEDINITIATE:
909 *action = CA_OFFER;
910 *source = CS_REMOTE;
911 break;
912 case STATE_RECEIVEDPRACCEPT:
913 *action = CA_PRANSWER;
914 *source = CS_REMOTE;
915 break;
916 case STATE_RECEIVEDACCEPT:
917 *action = CA_ANSWER;
918 *source = CS_REMOTE;
919 break;
920 default:
921 return false;
922 }
923 return true;
924}
925
926void BaseSession::OnMessage(rtc::Message *pmsg) {
927 switch (pmsg->message_id) {
928 case MSG_TIMEOUT:
929 // Session timeout has occured.
930 SetError(ERROR_TIME, "Session timeout has occured.");
931 break;
932
933 case MSG_STATE:
934 switch (state_) {
935 case STATE_SENTACCEPT:
936 case STATE_RECEIVEDACCEPT:
937 SetState(STATE_INPROGRESS);
938 break;
939
940 default:
941 // Explicitly ignoring some states here.
942 break;
943 }
944 break;
945 }
946}
947
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000948} // namespace cricket