blob: 93a4a2b57d5b02c966f499bdd8d47f286225bd30 [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() {
33 for (ChannelMap::iterator iter = channels_.begin();
34 iter != channels_.end(); ++iter) {
35 iter->second->SignalDestroyed(iter->second);
36 delete iter->second;
37 }
38}
39
40const std::string& TransportProxy::type() const {
41 return transport_->get()->type();
42}
43
44TransportChannel* TransportProxy::GetChannel(int component) {
45 ASSERT(rtc::Thread::Current() == worker_thread_);
46 return GetChannelProxy(component);
47}
48
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000049TransportChannel* TransportProxy::CreateChannel(const std::string& name,
50 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000051 ASSERT(rtc::Thread::Current() == worker_thread_);
52 ASSERT(GetChannel(component) == NULL);
53 ASSERT(!transport_->get()->HasChannel(component));
54
55 // We always create a proxy in case we need to change out the transport later.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000056 TransportChannelProxy* channel_proxy =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000057 new TransportChannelProxy(content_name(), name, component);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000058 channels_[component] = channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059
60 // If we're already negotiated, create an impl and hook it up to the proxy
61 // channel. If we're connecting, create an impl but don't hook it up yet.
62 if (negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000063 CreateChannelImpl_w(component);
64 SetChannelImplFromTransport_w(channel_proxy, component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000065 } else if (connecting_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000066 CreateChannelImpl_w(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067 }
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000068 return channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000069}
70
71bool TransportProxy::HasChannel(int component) {
72 return transport_->get()->HasChannel(component);
73}
74
75void TransportProxy::DestroyChannel(int component) {
76 ASSERT(rtc::Thread::Current() == worker_thread_);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000077 TransportChannelProxy* channel_proxy = GetChannelProxy(component);
78 if (channel_proxy) {
79 // If the state of TransportProxy is not NEGOTIATED then
80 // TransportChannelProxy and its impl are not connected. Both must
81 // be connected before deletion.
82 //
83 // However, if we haven't entered the connecting state then there
84 // is no implementation to hook up.
85 if (connecting_ && !negotiated_) {
86 SetChannelImplFromTransport_w(channel_proxy, component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000087 }
88
89 channels_.erase(component);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000090 channel_proxy->SignalDestroyed(channel_proxy);
91 delete channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092 }
93}
94
95void TransportProxy::ConnectChannels() {
96 if (!connecting_) {
97 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000098 for (auto& iter : channels_) {
99 CreateChannelImpl(iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000100 }
101 }
102 connecting_ = true;
103 }
104 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
105 // don't have any channels yet, so we need to allow this method to be called
106 // multiple times. Once we fix Transport, we can move this call inside the
107 // if (!connecting_) block.
108 transport_->get()->ConnectChannels();
109}
110
111void TransportProxy::CompleteNegotiation() {
112 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000113 // Negotiating assumes connecting_ has happened and
114 // implementations exist. If not we need to create the
115 // implementations.
116 for (auto& iter : channels_) {
117 if (!connecting_) {
118 CreateChannelImpl(iter.first);
119 }
120 SetChannelImplFromTransport(iter.second, iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121 }
122 negotiated_ = true;
123 }
124}
125
126void TransportProxy::AddSentCandidates(const Candidates& candidates) {
127 for (Candidates::const_iterator cand = candidates.begin();
128 cand != candidates.end(); ++cand) {
129 sent_candidates_.push_back(*cand);
130 }
131}
132
133void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
134 for (Candidates::const_iterator cand = candidates.begin();
135 cand != candidates.end(); ++cand) {
136 unsent_candidates_.push_back(*cand);
137 }
138}
139
140bool TransportProxy::GetChannelNameFromComponent(
141 int component, std::string* channel_name) const {
142 const TransportChannelProxy* channel = GetChannelProxy(component);
143 if (channel == NULL) {
144 return false;
145 }
146
147 *channel_name = channel->name();
148 return true;
149}
150
151bool TransportProxy::GetComponentFromChannelName(
152 const std::string& channel_name, int* component) const {
153 const TransportChannelProxy* channel = GetChannelProxyByName(channel_name);
154 if (channel == NULL) {
155 return false;
156 }
157
158 *component = channel->component();
159 return true;
160}
161
162TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
163 ChannelMap::const_iterator iter = channels_.find(component);
164 return (iter != channels_.end()) ? iter->second : NULL;
165}
166
167TransportChannelProxy* TransportProxy::GetChannelProxyByName(
168 const std::string& name) const {
169 for (ChannelMap::const_iterator iter = channels_.begin();
170 iter != channels_.end();
171 ++iter) {
172 if (iter->second->name() == name) {
173 return iter->second;
174 }
175 }
176 return NULL;
177}
178
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000179void TransportProxy::CreateChannelImpl(int component) {
180 worker_thread_->Invoke<void>(Bind(
181 &TransportProxy::CreateChannelImpl_w, this, component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182}
183
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000184void TransportProxy::CreateChannelImpl_w(int component) {
185 ASSERT(rtc::Thread::Current() == worker_thread_);
186 transport_->get()->CreateChannel(component);
187}
188
189void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
190 int component) {
191 worker_thread_->Invoke<void>(Bind(
192 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
193}
194
195void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
196 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197 ASSERT(rtc::Thread::Current() == worker_thread_);
198 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000199 ASSERT(impl != NULL);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000200 ReplaceChannelImpl_w(proxy, impl);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201}
202
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000203void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
204 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000205 worker_thread_->Invoke<void>(Bind(
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000206 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207}
208
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000209void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
210 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211 ASSERT(rtc::Thread::Current() == worker_thread_);
212 ASSERT(proxy != NULL);
213 proxy->SetImplementation(impl);
214}
215
216// This function muxes |this| onto |target| by repointing |this| at
217// |target|'s transport and setting our TransportChannelProxies
218// to point to |target|'s underlying implementations.
219bool TransportProxy::SetupMux(TransportProxy* target) {
220 // Bail out if there's nothing to do.
221 if (transport_ == target->transport_) {
222 return true;
223 }
224
225 // Run through all channels and remove any non-rtp transport channels before
226 // setting target transport channels.
227 for (ChannelMap::const_iterator iter = channels_.begin();
228 iter != channels_.end(); ++iter) {
229 if (!target->transport_->get()->HasChannel(iter->first)) {
230 // Remove if channel doesn't exist in |transport_|.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000231 ReplaceChannelImpl(iter->second, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000232 } else {
233 // Replace the impl for all the TransportProxyChannels with the channels
234 // from |target|'s transport. Fail if there's not an exact match.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000235 ReplaceChannelImpl(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236 iter->second, target->transport_->get()->CreateChannel(iter->first));
237 }
238 }
239
240 // Now replace our transport. Must happen afterwards because
241 // it deletes all impls as a side effect.
242 transport_ = target->transport_;
243 transport_->get()->SignalCandidatesReady.connect(
244 this, &TransportProxy::OnTransportCandidatesReady);
245 set_candidates_allocated(target->candidates_allocated());
246 return true;
247}
248
249void TransportProxy::SetIceRole(IceRole role) {
250 transport_->get()->SetIceRole(role);
251}
252
253bool TransportProxy::SetLocalTransportDescription(
254 const TransportDescription& description,
255 ContentAction action,
256 std::string* error_desc) {
257 // If this is an answer, finalize the negotiation.
258 if (action == CA_ANSWER) {
259 CompleteNegotiation();
260 }
261 bool result = transport_->get()->SetLocalTransportDescription(description,
262 action,
263 error_desc);
264 if (result)
265 local_description_set_ = true;
266 return result;
267}
268
269bool TransportProxy::SetRemoteTransportDescription(
270 const TransportDescription& description,
271 ContentAction action,
272 std::string* error_desc) {
273 // If this is an answer, finalize the negotiation.
274 if (action == CA_ANSWER) {
275 CompleteNegotiation();
276 }
277 bool result = transport_->get()->SetRemoteTransportDescription(description,
278 action,
279 error_desc);
280 if (result)
281 remote_description_set_ = true;
282 return result;
283}
284
285void TransportProxy::OnSignalingReady() {
286 // If we're starting a new allocation sequence, reset our state.
287 set_candidates_allocated(false);
288 transport_->get()->OnSignalingReady();
289}
290
291bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
292 std::string* error) {
293 // Ensure the transport is negotiated before handling candidates.
294 // TODO(juberti): Remove this once everybody calls SetLocalTD.
295 CompleteNegotiation();
296
297 // Verify each candidate before passing down to transport layer.
298 for (Candidates::const_iterator cand = candidates.begin();
299 cand != candidates.end(); ++cand) {
300 if (!transport_->get()->VerifyCandidate(*cand, error))
301 return false;
302 if (!HasChannel(cand->component())) {
303 *error = "Candidate has unknown component: " + cand->ToString() +
304 " for content: " + content_name_;
305 return false;
306 }
307 }
308 transport_->get()->OnRemoteCandidates(candidates);
309 return true;
310}
311
312void TransportProxy::SetIdentity(
313 rtc::SSLIdentity* identity) {
314 transport_->get()->SetIdentity(identity);
315}
316
317std::string BaseSession::StateToString(State state) {
318 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000319 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000321 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000323 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000324 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000325 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000326 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000327 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000328 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000329 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000330 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000331 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000333 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000335 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000336 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000337 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000339 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000341 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000342 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000343 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000345 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000347 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000348 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000349 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000350 return "STATE_DEINIT";
351 default:
352 break;
353 }
354 return "STATE_" + rtc::ToString(state);
355}
356
357BaseSession::BaseSession(rtc::Thread* signaling_thread,
358 rtc::Thread* worker_thread,
359 PortAllocator* port_allocator,
360 const std::string& sid,
361 const std::string& content_type,
362 bool initiator)
363 : state_(STATE_INIT),
364 error_(ERROR_NONE),
365 signaling_thread_(signaling_thread),
366 worker_thread_(worker_thread),
367 port_allocator_(port_allocator),
368 sid_(sid),
369 content_type_(content_type),
370 transport_type_(NS_GINGLE_P2P),
371 initiator_(initiator),
372 identity_(NULL),
373 ice_tiebreaker_(rtc::CreateRandomId64()),
374 role_switch_(false) {
375 ASSERT(signaling_thread->IsCurrent());
376}
377
378BaseSession::~BaseSession() {
379 ASSERT(signaling_thread()->IsCurrent());
380
381 ASSERT(state_ != STATE_DEINIT);
382 LogState(state_, STATE_DEINIT);
383 state_ = STATE_DEINIT;
384 SignalState(this, state_);
385
386 for (TransportMap::iterator iter = transports_.begin();
387 iter != transports_.end(); ++iter) {
388 delete iter->second;
389 }
390}
391
392const SessionDescription* BaseSession::local_description() const {
393 // TODO(tommi): Assert on thread correctness.
394 return local_description_.get();
395}
396
397const SessionDescription* BaseSession::remote_description() const {
398 // TODO(tommi): Assert on thread correctness.
399 return remote_description_.get();
400}
401
402SessionDescription* BaseSession::remote_description() {
403 // TODO(tommi): Assert on thread correctness.
404 return remote_description_.get();
405}
406
407void BaseSession::set_local_description(const SessionDescription* sdesc) {
408 // TODO(tommi): Assert on thread correctness.
409 if (sdesc != local_description_.get())
410 local_description_.reset(sdesc);
411}
412
413void BaseSession::set_remote_description(SessionDescription* sdesc) {
414 // TODO(tommi): Assert on thread correctness.
415 if (sdesc != remote_description_)
416 remote_description_.reset(sdesc);
417}
418
419const SessionDescription* BaseSession::initiator_description() const {
420 // TODO(tommi): Assert on thread correctness.
421 return initiator_ ? local_description_.get() : remote_description_.get();
422}
423
424bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
425 if (identity_)
426 return false;
427 identity_ = identity;
428 for (TransportMap::iterator iter = transports_.begin();
429 iter != transports_.end(); ++iter) {
430 iter->second->SetIdentity(identity_);
431 }
432 return true;
433}
434
435bool BaseSession::PushdownTransportDescription(ContentSource source,
436 ContentAction action,
437 std::string* error_desc) {
438 if (source == CS_LOCAL) {
439 return PushdownLocalTransportDescription(local_description(),
440 action,
441 error_desc);
442 }
443 return PushdownRemoteTransportDescription(remote_description(),
444 action,
445 error_desc);
446}
447
448bool BaseSession::PushdownLocalTransportDescription(
449 const SessionDescription* sdesc,
450 ContentAction action,
451 std::string* error_desc) {
452 // Update the Transports with the right information, and trigger them to
453 // start connecting.
454 for (TransportMap::iterator iter = transports_.begin();
455 iter != transports_.end(); ++iter) {
456 // If no transport info was in this session description, ret == false
457 // and we just skip this one.
458 TransportDescription tdesc;
459 bool ret = GetTransportDescription(
460 sdesc, iter->second->content_name(), &tdesc);
461 if (ret) {
462 if (!iter->second->SetLocalTransportDescription(tdesc, action,
463 error_desc)) {
464 return false;
465 }
466
467 iter->second->ConnectChannels();
468 }
469 }
470
471 return true;
472}
473
474bool BaseSession::PushdownRemoteTransportDescription(
475 const SessionDescription* sdesc,
476 ContentAction action,
477 std::string* error_desc) {
478 // Update the Transports with the right information.
479 for (TransportMap::iterator iter = transports_.begin();
480 iter != transports_.end(); ++iter) {
481 TransportDescription tdesc;
482
483 // If no transport info was in this session description, ret == false
484 // and we just skip this one.
485 bool ret = GetTransportDescription(
486 sdesc, iter->second->content_name(), &tdesc);
487 if (ret) {
488 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
489 error_desc)) {
490 return false;
491 }
492 }
493 }
494
495 return true;
496}
497
498TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
499 const std::string& channel_name,
500 int component) {
501 // We create the proxy "on demand" here because we need to support
502 // creating channels at any time, even before we send or receive
503 // initiate messages, which is before we create the transports.
504 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
505 return transproxy->CreateChannel(channel_name, component);
506}
507
508TransportChannel* BaseSession::GetChannel(const std::string& content_name,
509 int component) {
510 TransportProxy* transproxy = GetTransportProxy(content_name);
511 if (transproxy == NULL)
512 return NULL;
513
514 return transproxy->GetChannel(component);
515}
516
517void BaseSession::DestroyChannel(const std::string& content_name,
518 int component) {
519 TransportProxy* transproxy = GetTransportProxy(content_name);
520 ASSERT(transproxy != NULL);
521 transproxy->DestroyChannel(component);
522}
523
524TransportProxy* BaseSession::GetOrCreateTransportProxy(
525 const std::string& content_name) {
526 TransportProxy* transproxy = GetTransportProxy(content_name);
527 if (transproxy)
528 return transproxy;
529
530 Transport* transport = CreateTransport(content_name);
531 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
532 transport->SetIceTiebreaker(ice_tiebreaker_);
533 // TODO: Connect all the Transport signals to TransportProxy
534 // then to the BaseSession.
535 transport->SignalConnecting.connect(
536 this, &BaseSession::OnTransportConnecting);
537 transport->SignalWritableState.connect(
538 this, &BaseSession::OnTransportWritable);
539 transport->SignalRequestSignaling.connect(
540 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000541 transport->SignalRouteChange.connect(
542 this, &BaseSession::OnTransportRouteChange);
543 transport->SignalCandidatesAllocationDone.connect(
544 this, &BaseSession::OnTransportCandidatesAllocationDone);
545 transport->SignalRoleConflict.connect(
546 this, &BaseSession::OnRoleConflict);
547 transport->SignalCompleted.connect(
548 this, &BaseSession::OnTransportCompleted);
549 transport->SignalFailed.connect(
550 this, &BaseSession::OnTransportFailed);
551
552 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
553 new TransportWrapper(transport));
554 transproxy->SignalCandidatesReady.connect(
555 this, &BaseSession::OnTransportProxyCandidatesReady);
556 if (identity_)
557 transproxy->SetIdentity(identity_);
558 transports_[content_name] = transproxy;
559
560 return transproxy;
561}
562
563Transport* BaseSession::GetTransport(const std::string& content_name) {
564 TransportProxy* transproxy = GetTransportProxy(content_name);
565 if (transproxy == NULL)
566 return NULL;
567 return transproxy->impl();
568}
569
570TransportProxy* BaseSession::GetTransportProxy(
571 const std::string& content_name) {
572 TransportMap::iterator iter = transports_.find(content_name);
573 return (iter != transports_.end()) ? iter->second : NULL;
574}
575
576TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
577 for (TransportMap::iterator iter = transports_.begin();
578 iter != transports_.end(); ++iter) {
579 TransportProxy* transproxy = iter->second;
580 if (transproxy->impl() == transport) {
581 return transproxy;
582 }
583 }
584 return NULL;
585}
586
587TransportProxy* BaseSession::GetFirstTransportProxy() {
588 if (transports_.empty())
589 return NULL;
590 return transports_.begin()->second;
591}
592
593void BaseSession::DestroyTransportProxy(
594 const std::string& content_name) {
595 TransportMap::iterator iter = transports_.find(content_name);
596 if (iter != transports_.end()) {
597 delete iter->second;
598 transports_.erase(content_name);
599 }
600}
601
602cricket::Transport* BaseSession::CreateTransport(
603 const std::string& content_name) {
604 ASSERT(transport_type_ == NS_GINGLE_P2P);
605 return new cricket::DtlsTransport<P2PTransport>(
606 signaling_thread(), worker_thread(), content_name,
607 port_allocator(), identity_);
608}
609
610bool BaseSession::GetStats(SessionStats* stats) {
611 for (TransportMap::iterator iter = transports_.begin();
612 iter != transports_.end(); ++iter) {
613 std::string proxy_id = iter->second->content_name();
614 // We are ignoring not-yet-instantiated transports.
615 if (iter->second->impl()) {
616 std::string transport_id = iter->second->impl()->content_name();
617 stats->proxy_to_transport[proxy_id] = transport_id;
618 if (stats->transport_stats.find(transport_id)
619 == stats->transport_stats.end()) {
620 TransportStats subinfos;
621 if (!iter->second->impl()->GetStats(&subinfos)) {
622 return false;
623 }
624 stats->transport_stats[transport_id] = subinfos;
625 }
626 }
627 }
628 return true;
629}
630
631void BaseSession::SetState(State state) {
632 ASSERT(signaling_thread_->IsCurrent());
633 if (state != state_) {
634 LogState(state_, state);
635 state_ = state;
636 SignalState(this, state_);
637 signaling_thread_->Post(this, MSG_STATE);
638 }
639 SignalNewDescription();
640}
641
642void BaseSession::SetError(Error error, const std::string& error_desc) {
643 ASSERT(signaling_thread_->IsCurrent());
644 if (error != error_) {
645 error_ = error;
646 error_desc_ = error_desc;
647 SignalError(this, error);
648 }
649}
650
651void BaseSession::OnSignalingReady() {
652 ASSERT(signaling_thread()->IsCurrent());
653 for (TransportMap::iterator iter = transports_.begin();
654 iter != transports_.end(); ++iter) {
655 iter->second->OnSignalingReady();
656 }
657}
658
659// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
660// start, remove this method once everyone calls PushdownLocalTD.
661void BaseSession::SpeculativelyConnectAllTransportChannels() {
662 // Put all transports into the connecting state.
663 for (TransportMap::iterator iter = transports_.begin();
664 iter != transports_.end(); ++iter) {
665 iter->second->ConnectChannels();
666 }
667}
668
669bool BaseSession::OnRemoteCandidates(const std::string& content_name,
670 const Candidates& candidates,
671 std::string* error) {
672 // Give candidates to the appropriate transport, and tell that transport
673 // to start connecting, if it's not already doing so.
674 TransportProxy* transproxy = GetTransportProxy(content_name);
675 if (!transproxy) {
676 *error = "Unknown content name " + content_name;
677 return false;
678 }
679 if (!transproxy->OnRemoteCandidates(candidates, error)) {
680 return false;
681 }
682 // TODO(juberti): Remove this call once we can be sure that we always have
683 // a local transport description (which will trigger the connection).
684 transproxy->ConnectChannels();
685 return true;
686}
687
688bool BaseSession::MaybeEnableMuxingSupport() {
689 // We need both a local and remote description to decide if we should mux.
690 if ((state_ == STATE_SENTINITIATE ||
691 state_ == STATE_RECEIVEDINITIATE) &&
692 ((local_description_ == NULL) ||
693 (remote_description_ == NULL))) {
694 return false;
695 }
696
697 // In order to perform the multiplexing, we need all proxies to be in the
698 // negotiated state, i.e. to have implementations underneath.
699 // Ensure that this is the case, regardless of whether we are going to mux.
700 for (TransportMap::iterator iter = transports_.begin();
701 iter != transports_.end(); ++iter) {
702 ASSERT(iter->second->negotiated());
703 if (!iter->second->negotiated())
704 return false;
705 }
706
707 // If both sides agree to BUNDLE, mux all the specified contents onto the
708 // transport belonging to the first content name in the BUNDLE group.
709 // If the contents are already muxed, this will be a no-op.
710 // TODO(juberti): Should this check that local and remote have configured
711 // BUNDLE the same way?
712 bool candidates_allocated = IsCandidateAllocationDone();
713 const ContentGroup* local_bundle_group =
714 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
715 const ContentGroup* remote_bundle_group =
716 remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
717 if (local_bundle_group && remote_bundle_group &&
718 local_bundle_group->FirstContentName()) {
719 const std::string* content_name = local_bundle_group->FirstContentName();
720 const ContentInfo* content =
721 local_description_->GetContentByName(*content_name);
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000722 if (!content) {
723 LOG(LS_WARNING) << "Content \"" << *content_name
724 << "\" referenced in BUNDLE group is not present";
725 return false;
726 }
727
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000728 if (!SetSelectedProxy(content->name, local_bundle_group)) {
729 LOG(LS_WARNING) << "Failed to set up BUNDLE";
730 return false;
731 }
732
733 // If we weren't done gathering before, we might be done now, as a result
734 // of enabling mux.
735 LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
736 << *content_name;
737 if (!candidates_allocated) {
738 MaybeCandidateAllocationDone();
739 }
740 } else {
741 LOG(LS_INFO) << "No BUNDLE information, not bundling.";
742 }
743 return true;
744}
745
746bool BaseSession::SetSelectedProxy(const std::string& content_name,
747 const ContentGroup* muxed_group) {
748 TransportProxy* selected_proxy = GetTransportProxy(content_name);
749 if (!selected_proxy) {
750 return false;
751 }
752
753 ASSERT(selected_proxy->negotiated());
754 for (TransportMap::iterator iter = transports_.begin();
755 iter != transports_.end(); ++iter) {
756 // If content is part of the mux group, then repoint its proxy at the
757 // transport object that we have chosen to mux onto. If the proxy
758 // is already pointing at the right object, it will be a no-op.
759 if (muxed_group->HasContentName(iter->first) &&
760 !iter->second->SetupMux(selected_proxy)) {
761 return false;
762 }
763 }
764 return true;
765}
766
767void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
768 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
769 // TransportProxy should receive the done signal directly, set its allocated
770 // flag internally, and then reissue the done signal to Session.
771 // Overall we should make TransportProxy receive *all* the signals from
772 // Transport, since this removes the need to manually iterate over all
773 // the transports, as is needed to make sure signals are handled properly
774 // when BUNDLEing.
775 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
776 // that make it prohibitively difficult to run dbg builds. Disabled for now.
777 //ASSERT(!IsCandidateAllocationDone());
778 for (TransportMap::iterator iter = transports_.begin();
779 iter != transports_.end(); ++iter) {
780 if (iter->second->impl() == transport) {
781 iter->second->set_candidates_allocated(true);
782 }
783 }
784 MaybeCandidateAllocationDone();
785}
786
787bool BaseSession::IsCandidateAllocationDone() const {
788 for (TransportMap::const_iterator iter = transports_.begin();
789 iter != transports_.end(); ++iter) {
pthatcher@webrtc.orgaf01d932015-02-03 23:13:37 +0000790 if (!iter->second->candidates_allocated()) {
791 LOG(LS_INFO) << "Candidate allocation not done for "
792 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793 return false;
pthatcher@webrtc.orgaf01d932015-02-03 23:13:37 +0000794 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000795 }
796 return true;
797}
798
799void BaseSession::MaybeCandidateAllocationDone() {
800 if (IsCandidateAllocationDone()) {
801 LOG(LS_INFO) << "Candidate gathering is complete.";
802 OnCandidatesAllocationDone();
803 }
804}
805
806void BaseSession::OnRoleConflict() {
807 if (role_switch_) {
808 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
809 return;
810 }
811
812 role_switch_ = true;
813 for (TransportMap::iterator iter = transports_.begin();
814 iter != transports_.end(); ++iter) {
815 // Role will be reverse of initial role setting.
816 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
817 iter->second->SetIceRole(role);
818 }
819}
820
821void BaseSession::LogState(State old_state, State new_state) {
822 LOG(LS_INFO) << "Session:" << id()
823 << " Old state:" << StateToString(old_state)
824 << " New state:" << StateToString(new_state)
825 << " Type:" << content_type()
826 << " Transport:" << transport_type();
827}
828
829// static
830bool BaseSession::GetTransportDescription(const SessionDescription* description,
831 const std::string& content_name,
832 TransportDescription* tdesc) {
833 if (!description || !tdesc) {
834 return false;
835 }
836 const TransportInfo* transport_info =
837 description->GetTransportInfoByName(content_name);
838 if (!transport_info) {
839 return false;
840 }
841 *tdesc = transport_info->description;
842 return true;
843}
844
845void BaseSession::SignalNewDescription() {
846 ContentAction action;
847 ContentSource source;
848 if (!GetContentAction(&action, &source)) {
849 return;
850 }
851 if (source == CS_LOCAL) {
852 SignalNewLocalDescription(this, action);
853 } else {
854 SignalNewRemoteDescription(this, action);
855 }
856}
857
858bool BaseSession::GetContentAction(ContentAction* action,
859 ContentSource* source) {
860 switch (state_) {
861 // new local description
862 case STATE_SENTINITIATE:
863 *action = CA_OFFER;
864 *source = CS_LOCAL;
865 break;
866 case STATE_SENTPRACCEPT:
867 *action = CA_PRANSWER;
868 *source = CS_LOCAL;
869 break;
870 case STATE_SENTACCEPT:
871 *action = CA_ANSWER;
872 *source = CS_LOCAL;
873 break;
874 // new remote description
875 case STATE_RECEIVEDINITIATE:
876 *action = CA_OFFER;
877 *source = CS_REMOTE;
878 break;
879 case STATE_RECEIVEDPRACCEPT:
880 *action = CA_PRANSWER;
881 *source = CS_REMOTE;
882 break;
883 case STATE_RECEIVEDACCEPT:
884 *action = CA_ANSWER;
885 *source = CS_REMOTE;
886 break;
887 default:
888 return false;
889 }
890 return true;
891}
892
893void BaseSession::OnMessage(rtc::Message *pmsg) {
894 switch (pmsg->message_id) {
895 case MSG_TIMEOUT:
896 // Session timeout has occured.
897 SetError(ERROR_TIME, "Session timeout has occured.");
898 break;
899
900 case MSG_STATE:
901 switch (state_) {
902 case STATE_SENTACCEPT:
903 case STATE_RECEIVEDACCEPT:
904 SetState(STATE_INPROGRESS);
905 break;
906
907 default:
908 // Explicitly ignoring some states here.
909 break;
910 }
911 break;
912 }
913}
914
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000915} // namespace cricket