blob: 690cf13b0cc896d0e837f5ad633f1ea27b38725d [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() {
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000033 for (ChannelMap::iterator iter = channels_.begin();
34 iter != channels_.end(); ++iter) {
35 iter->second->SignalDestroyed(iter->second);
36 delete iter->second;
37 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000038}
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_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000052 ASSERT(GetChannel(component) == NULL);
53 ASSERT(!transport_->get()->HasChannel(component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000054
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000055 // We always create a proxy in case we need to change out the transport later.
56 TransportChannelProxy* channel_proxy =
57 new TransportChannelProxy(content_name(), name, component);
58 channels_[component] = channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000060 // 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_) {
63 CreateChannelImpl_w(component);
64 SetChannelImplFromTransport_w(channel_proxy, component);
65 } else if (connecting_) {
66 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_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +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);
87 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000089 channels_.erase(component);
90 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
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000140TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
141 ChannelMap::const_iterator iter = channels_.find(component);
142 return (iter != channels_.end()) ? iter->second : NULL;
143}
144
145TransportChannelProxy* TransportProxy::GetChannelProxyByName(
146 const std::string& name) const {
147 for (ChannelMap::const_iterator iter = channels_.begin();
148 iter != channels_.end();
149 ++iter) {
150 if (iter->second->name() == name) {
151 return iter->second;
152 }
153 }
154 return NULL;
155}
156
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000157void TransportProxy::CreateChannelImpl(int component) {
158 worker_thread_->Invoke<void>(Bind(
159 &TransportProxy::CreateChannelImpl_w, this, component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160}
161
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000162void TransportProxy::CreateChannelImpl_w(int component) {
163 ASSERT(rtc::Thread::Current() == worker_thread_);
164 transport_->get()->CreateChannel(component);
165}
166
167void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
168 int component) {
169 worker_thread_->Invoke<void>(Bind(
170 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
171}
172
173void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
174 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175 ASSERT(rtc::Thread::Current() == worker_thread_);
176 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000177 ASSERT(impl != NULL);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000178 ReplaceChannelImpl_w(proxy, impl);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179}
180
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000181void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
182 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000183 worker_thread_->Invoke<void>(Bind(
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000184 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000185}
186
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000187void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
188 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000189 ASSERT(rtc::Thread::Current() == worker_thread_);
190 ASSERT(proxy != NULL);
191 proxy->SetImplementation(impl);
192}
193
194// This function muxes |this| onto |target| by repointing |this| at
195// |target|'s transport and setting our TransportChannelProxies
196// to point to |target|'s underlying implementations.
197bool TransportProxy::SetupMux(TransportProxy* target) {
198 // Bail out if there's nothing to do.
199 if (transport_ == target->transport_) {
200 return true;
201 }
202
203 // Run through all channels and remove any non-rtp transport channels before
204 // setting target transport channels.
205 for (ChannelMap::const_iterator iter = channels_.begin();
206 iter != channels_.end(); ++iter) {
207 if (!target->transport_->get()->HasChannel(iter->first)) {
208 // Remove if channel doesn't exist in |transport_|.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000209 ReplaceChannelImpl(iter->second, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210 } else {
211 // Replace the impl for all the TransportProxyChannels with the channels
212 // from |target|'s transport. Fail if there's not an exact match.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000213 ReplaceChannelImpl(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000214 iter->second, target->transport_->get()->CreateChannel(iter->first));
215 }
216 }
217
218 // Now replace our transport. Must happen afterwards because
219 // it deletes all impls as a side effect.
220 transport_ = target->transport_;
221 transport_->get()->SignalCandidatesReady.connect(
222 this, &TransportProxy::OnTransportCandidatesReady);
223 set_candidates_allocated(target->candidates_allocated());
224 return true;
225}
226
227void TransportProxy::SetIceRole(IceRole role) {
228 transport_->get()->SetIceRole(role);
229}
230
231bool TransportProxy::SetLocalTransportDescription(
232 const TransportDescription& description,
233 ContentAction action,
234 std::string* error_desc) {
235 // If this is an answer, finalize the negotiation.
236 if (action == CA_ANSWER) {
237 CompleteNegotiation();
238 }
239 bool result = transport_->get()->SetLocalTransportDescription(description,
240 action,
241 error_desc);
242 if (result)
243 local_description_set_ = true;
244 return result;
245}
246
247bool TransportProxy::SetRemoteTransportDescription(
248 const TransportDescription& description,
249 ContentAction action,
250 std::string* error_desc) {
251 // If this is an answer, finalize the negotiation.
252 if (action == CA_ANSWER) {
253 CompleteNegotiation();
254 }
255 bool result = transport_->get()->SetRemoteTransportDescription(description,
256 action,
257 error_desc);
258 if (result)
259 remote_description_set_ = true;
260 return result;
261}
262
263void TransportProxy::OnSignalingReady() {
264 // If we're starting a new allocation sequence, reset our state.
265 set_candidates_allocated(false);
266 transport_->get()->OnSignalingReady();
267}
268
269bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
270 std::string* error) {
271 // Ensure the transport is negotiated before handling candidates.
272 // TODO(juberti): Remove this once everybody calls SetLocalTD.
273 CompleteNegotiation();
274
275 // Verify each candidate before passing down to transport layer.
276 for (Candidates::const_iterator cand = candidates.begin();
277 cand != candidates.end(); ++cand) {
278 if (!transport_->get()->VerifyCandidate(*cand, error))
279 return false;
280 if (!HasChannel(cand->component())) {
281 *error = "Candidate has unknown component: " + cand->ToString() +
282 " for content: " + content_name_;
283 return false;
284 }
285 }
286 transport_->get()->OnRemoteCandidates(candidates);
287 return true;
288}
289
290void TransportProxy::SetIdentity(
291 rtc::SSLIdentity* identity) {
292 transport_->get()->SetIdentity(identity);
293}
294
295std::string BaseSession::StateToString(State state) {
296 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000297 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000299 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000300 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000301 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000302 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000303 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000305 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000307 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000308 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000309 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000310 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000311 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000312 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000313 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000315 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000317 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000319 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000321 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000323 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000324 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000325 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000326 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000327 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000328 return "STATE_DEINIT";
329 default:
330 break;
331 }
332 return "STATE_" + rtc::ToString(state);
333}
334
335BaseSession::BaseSession(rtc::Thread* signaling_thread,
336 rtc::Thread* worker_thread,
337 PortAllocator* port_allocator,
338 const std::string& sid,
339 const std::string& content_type,
340 bool initiator)
341 : state_(STATE_INIT),
342 error_(ERROR_NONE),
343 signaling_thread_(signaling_thread),
344 worker_thread_(worker_thread),
345 port_allocator_(port_allocator),
346 sid_(sid),
347 content_type_(content_type),
348 transport_type_(NS_GINGLE_P2P),
349 initiator_(initiator),
350 identity_(NULL),
351 ice_tiebreaker_(rtc::CreateRandomId64()),
352 role_switch_(false) {
353 ASSERT(signaling_thread->IsCurrent());
354}
355
356BaseSession::~BaseSession() {
357 ASSERT(signaling_thread()->IsCurrent());
358
359 ASSERT(state_ != STATE_DEINIT);
360 LogState(state_, STATE_DEINIT);
361 state_ = STATE_DEINIT;
362 SignalState(this, state_);
363
364 for (TransportMap::iterator iter = transports_.begin();
365 iter != transports_.end(); ++iter) {
366 delete iter->second;
367 }
368}
369
370const SessionDescription* BaseSession::local_description() const {
371 // TODO(tommi): Assert on thread correctness.
372 return local_description_.get();
373}
374
375const SessionDescription* BaseSession::remote_description() const {
376 // TODO(tommi): Assert on thread correctness.
377 return remote_description_.get();
378}
379
380SessionDescription* BaseSession::remote_description() {
381 // TODO(tommi): Assert on thread correctness.
382 return remote_description_.get();
383}
384
385void BaseSession::set_local_description(const SessionDescription* sdesc) {
386 // TODO(tommi): Assert on thread correctness.
387 if (sdesc != local_description_.get())
388 local_description_.reset(sdesc);
389}
390
391void BaseSession::set_remote_description(SessionDescription* sdesc) {
392 // TODO(tommi): Assert on thread correctness.
393 if (sdesc != remote_description_)
394 remote_description_.reset(sdesc);
395}
396
397const SessionDescription* BaseSession::initiator_description() const {
398 // TODO(tommi): Assert on thread correctness.
399 return initiator_ ? local_description_.get() : remote_description_.get();
400}
401
402bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
403 if (identity_)
404 return false;
405 identity_ = identity;
406 for (TransportMap::iterator iter = transports_.begin();
407 iter != transports_.end(); ++iter) {
408 iter->second->SetIdentity(identity_);
409 }
410 return true;
411}
412
413bool BaseSession::PushdownTransportDescription(ContentSource source,
414 ContentAction action,
415 std::string* error_desc) {
416 if (source == CS_LOCAL) {
417 return PushdownLocalTransportDescription(local_description(),
418 action,
419 error_desc);
420 }
421 return PushdownRemoteTransportDescription(remote_description(),
422 action,
423 error_desc);
424}
425
426bool BaseSession::PushdownLocalTransportDescription(
427 const SessionDescription* sdesc,
428 ContentAction action,
429 std::string* error_desc) {
430 // Update the Transports with the right information, and trigger them to
431 // start connecting.
432 for (TransportMap::iterator iter = transports_.begin();
433 iter != transports_.end(); ++iter) {
434 // If no transport info was in this session description, ret == false
435 // and we just skip this one.
436 TransportDescription tdesc;
437 bool ret = GetTransportDescription(
438 sdesc, iter->second->content_name(), &tdesc);
439 if (ret) {
440 if (!iter->second->SetLocalTransportDescription(tdesc, action,
441 error_desc)) {
442 return false;
443 }
444
445 iter->second->ConnectChannels();
446 }
447 }
448
449 return true;
450}
451
452bool BaseSession::PushdownRemoteTransportDescription(
453 const SessionDescription* sdesc,
454 ContentAction action,
455 std::string* error_desc) {
456 // Update the Transports with the right information.
457 for (TransportMap::iterator iter = transports_.begin();
458 iter != transports_.end(); ++iter) {
459 TransportDescription tdesc;
460
461 // If no transport info was in this session description, ret == false
462 // and we just skip this one.
463 bool ret = GetTransportDescription(
464 sdesc, iter->second->content_name(), &tdesc);
465 if (ret) {
466 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
467 error_desc)) {
468 return false;
469 }
470 }
471 }
472
473 return true;
474}
475
476TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
477 const std::string& channel_name,
478 int component) {
479 // We create the proxy "on demand" here because we need to support
480 // creating channels at any time, even before we send or receive
481 // initiate messages, which is before we create the transports.
482 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
483 return transproxy->CreateChannel(channel_name, component);
484}
485
486TransportChannel* BaseSession::GetChannel(const std::string& content_name,
487 int component) {
488 TransportProxy* transproxy = GetTransportProxy(content_name);
489 if (transproxy == NULL)
490 return NULL;
491
492 return transproxy->GetChannel(component);
493}
494
495void BaseSession::DestroyChannel(const std::string& content_name,
496 int component) {
497 TransportProxy* transproxy = GetTransportProxy(content_name);
498 ASSERT(transproxy != NULL);
499 transproxy->DestroyChannel(component);
500}
501
502TransportProxy* BaseSession::GetOrCreateTransportProxy(
503 const std::string& content_name) {
504 TransportProxy* transproxy = GetTransportProxy(content_name);
505 if (transproxy)
506 return transproxy;
507
508 Transport* transport = CreateTransport(content_name);
509 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
510 transport->SetIceTiebreaker(ice_tiebreaker_);
511 // TODO: Connect all the Transport signals to TransportProxy
512 // then to the BaseSession.
513 transport->SignalConnecting.connect(
514 this, &BaseSession::OnTransportConnecting);
515 transport->SignalWritableState.connect(
516 this, &BaseSession::OnTransportWritable);
517 transport->SignalRequestSignaling.connect(
518 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000519 transport->SignalRouteChange.connect(
520 this, &BaseSession::OnTransportRouteChange);
521 transport->SignalCandidatesAllocationDone.connect(
522 this, &BaseSession::OnTransportCandidatesAllocationDone);
523 transport->SignalRoleConflict.connect(
524 this, &BaseSession::OnRoleConflict);
525 transport->SignalCompleted.connect(
526 this, &BaseSession::OnTransportCompleted);
527 transport->SignalFailed.connect(
528 this, &BaseSession::OnTransportFailed);
529
530 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
531 new TransportWrapper(transport));
532 transproxy->SignalCandidatesReady.connect(
533 this, &BaseSession::OnTransportProxyCandidatesReady);
534 if (identity_)
535 transproxy->SetIdentity(identity_);
536 transports_[content_name] = transproxy;
537
538 return transproxy;
539}
540
541Transport* BaseSession::GetTransport(const std::string& content_name) {
542 TransportProxy* transproxy = GetTransportProxy(content_name);
543 if (transproxy == NULL)
544 return NULL;
545 return transproxy->impl();
546}
547
548TransportProxy* BaseSession::GetTransportProxy(
549 const std::string& content_name) {
550 TransportMap::iterator iter = transports_.find(content_name);
551 return (iter != transports_.end()) ? iter->second : NULL;
552}
553
554TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
555 for (TransportMap::iterator iter = transports_.begin();
556 iter != transports_.end(); ++iter) {
557 TransportProxy* transproxy = iter->second;
558 if (transproxy->impl() == transport) {
559 return transproxy;
560 }
561 }
562 return NULL;
563}
564
565TransportProxy* BaseSession::GetFirstTransportProxy() {
566 if (transports_.empty())
567 return NULL;
568 return transports_.begin()->second;
569}
570
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000571void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000572 const std::string& content_name) {
573 TransportMap::iterator iter = transports_.find(content_name);
574 if (iter != transports_.end()) {
575 delete iter->second;
576 transports_.erase(content_name);
577 }
578}
579
580cricket::Transport* BaseSession::CreateTransport(
581 const std::string& content_name) {
582 ASSERT(transport_type_ == NS_GINGLE_P2P);
583 return new cricket::DtlsTransport<P2PTransport>(
584 signaling_thread(), worker_thread(), content_name,
585 port_allocator(), identity_);
586}
587
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000588void BaseSession::SetState(State state) {
589 ASSERT(signaling_thread_->IsCurrent());
590 if (state != state_) {
591 LogState(state_, state);
592 state_ = state;
593 SignalState(this, state_);
594 signaling_thread_->Post(this, MSG_STATE);
595 }
596 SignalNewDescription();
597}
598
599void BaseSession::SetError(Error error, const std::string& error_desc) {
600 ASSERT(signaling_thread_->IsCurrent());
601 if (error != error_) {
602 error_ = error;
603 error_desc_ = error_desc;
604 SignalError(this, error);
605 }
606}
607
608void BaseSession::OnSignalingReady() {
609 ASSERT(signaling_thread()->IsCurrent());
610 for (TransportMap::iterator iter = transports_.begin();
611 iter != transports_.end(); ++iter) {
612 iter->second->OnSignalingReady();
613 }
614}
615
616// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
617// start, remove this method once everyone calls PushdownLocalTD.
618void BaseSession::SpeculativelyConnectAllTransportChannels() {
619 // Put all transports into the connecting state.
620 for (TransportMap::iterator iter = transports_.begin();
621 iter != transports_.end(); ++iter) {
622 iter->second->ConnectChannels();
623 }
624}
625
626bool BaseSession::OnRemoteCandidates(const std::string& content_name,
627 const Candidates& candidates,
628 std::string* error) {
629 // Give candidates to the appropriate transport, and tell that transport
630 // to start connecting, if it's not already doing so.
631 TransportProxy* transproxy = GetTransportProxy(content_name);
632 if (!transproxy) {
633 *error = "Unknown content name " + content_name;
634 return false;
635 }
636 if (!transproxy->OnRemoteCandidates(candidates, error)) {
637 return false;
638 }
639 // TODO(juberti): Remove this call once we can be sure that we always have
640 // a local transport description (which will trigger the connection).
641 transproxy->ConnectChannels();
642 return true;
643}
644
645bool BaseSession::MaybeEnableMuxingSupport() {
646 // We need both a local and remote description to decide if we should mux.
647 if ((state_ == STATE_SENTINITIATE ||
648 state_ == STATE_RECEIVEDINITIATE) &&
649 ((local_description_ == NULL) ||
650 (remote_description_ == NULL))) {
651 return false;
652 }
653
654 // In order to perform the multiplexing, we need all proxies to be in the
655 // negotiated state, i.e. to have implementations underneath.
656 // Ensure that this is the case, regardless of whether we are going to mux.
657 for (TransportMap::iterator iter = transports_.begin();
658 iter != transports_.end(); ++iter) {
659 ASSERT(iter->second->negotiated());
660 if (!iter->second->negotiated())
661 return false;
662 }
663
664 // If both sides agree to BUNDLE, mux all the specified contents onto the
665 // transport belonging to the first content name in the BUNDLE group.
666 // If the contents are already muxed, this will be a no-op.
667 // TODO(juberti): Should this check that local and remote have configured
668 // BUNDLE the same way?
669 bool candidates_allocated = IsCandidateAllocationDone();
670 const ContentGroup* local_bundle_group =
671 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
672 const ContentGroup* remote_bundle_group =
673 remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
674 if (local_bundle_group && remote_bundle_group &&
675 local_bundle_group->FirstContentName()) {
676 const std::string* content_name = local_bundle_group->FirstContentName();
677 const ContentInfo* content =
678 local_description_->GetContentByName(*content_name);
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000679 if (!content) {
680 LOG(LS_WARNING) << "Content \"" << *content_name
681 << "\" referenced in BUNDLE group is not present";
682 return false;
683 }
684
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000685 if (!SetSelectedProxy(content->name, local_bundle_group)) {
686 LOG(LS_WARNING) << "Failed to set up BUNDLE";
687 return false;
688 }
689
690 // If we weren't done gathering before, we might be done now, as a result
691 // of enabling mux.
692 LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
693 << *content_name;
694 if (!candidates_allocated) {
695 MaybeCandidateAllocationDone();
696 }
697 } else {
698 LOG(LS_INFO) << "No BUNDLE information, not bundling.";
699 }
700 return true;
701}
702
703bool BaseSession::SetSelectedProxy(const std::string& content_name,
704 const ContentGroup* muxed_group) {
705 TransportProxy* selected_proxy = GetTransportProxy(content_name);
706 if (!selected_proxy) {
707 return false;
708 }
709
710 ASSERT(selected_proxy->negotiated());
711 for (TransportMap::iterator iter = transports_.begin();
712 iter != transports_.end(); ++iter) {
713 // If content is part of the mux group, then repoint its proxy at the
714 // transport object that we have chosen to mux onto. If the proxy
715 // is already pointing at the right object, it will be a no-op.
716 if (muxed_group->HasContentName(iter->first) &&
717 !iter->second->SetupMux(selected_proxy)) {
718 return false;
719 }
720 }
721 return true;
722}
723
724void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
725 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
726 // TransportProxy should receive the done signal directly, set its allocated
727 // flag internally, and then reissue the done signal to Session.
728 // Overall we should make TransportProxy receive *all* the signals from
729 // Transport, since this removes the need to manually iterate over all
730 // the transports, as is needed to make sure signals are handled properly
731 // when BUNDLEing.
732 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
733 // that make it prohibitively difficult to run dbg builds. Disabled for now.
734 //ASSERT(!IsCandidateAllocationDone());
735 for (TransportMap::iterator iter = transports_.begin();
736 iter != transports_.end(); ++iter) {
737 if (iter->second->impl() == transport) {
738 iter->second->set_candidates_allocated(true);
739 }
740 }
741 MaybeCandidateAllocationDone();
742}
743
744bool BaseSession::IsCandidateAllocationDone() const {
745 for (TransportMap::const_iterator iter = transports_.begin();
746 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000747 if (!iter->second->candidates_allocated()) {
748 LOG(LS_INFO) << "Candidate allocation not done for "
749 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000751 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752 }
753 return true;
754}
755
756void BaseSession::MaybeCandidateAllocationDone() {
757 if (IsCandidateAllocationDone()) {
758 LOG(LS_INFO) << "Candidate gathering is complete.";
759 OnCandidatesAllocationDone();
760 }
761}
762
763void BaseSession::OnRoleConflict() {
764 if (role_switch_) {
765 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
766 return;
767 }
768
769 role_switch_ = true;
770 for (TransportMap::iterator iter = transports_.begin();
771 iter != transports_.end(); ++iter) {
772 // Role will be reverse of initial role setting.
773 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
774 iter->second->SetIceRole(role);
775 }
776}
777
778void BaseSession::LogState(State old_state, State new_state) {
779 LOG(LS_INFO) << "Session:" << id()
780 << " Old state:" << StateToString(old_state)
781 << " New state:" << StateToString(new_state)
782 << " Type:" << content_type()
783 << " Transport:" << transport_type();
784}
785
786// static
787bool BaseSession::GetTransportDescription(const SessionDescription* description,
788 const std::string& content_name,
789 TransportDescription* tdesc) {
790 if (!description || !tdesc) {
791 return false;
792 }
793 const TransportInfo* transport_info =
794 description->GetTransportInfoByName(content_name);
795 if (!transport_info) {
796 return false;
797 }
798 *tdesc = transport_info->description;
799 return true;
800}
801
802void BaseSession::SignalNewDescription() {
803 ContentAction action;
804 ContentSource source;
805 if (!GetContentAction(&action, &source)) {
806 return;
807 }
808 if (source == CS_LOCAL) {
809 SignalNewLocalDescription(this, action);
810 } else {
811 SignalNewRemoteDescription(this, action);
812 }
813}
814
815bool BaseSession::GetContentAction(ContentAction* action,
816 ContentSource* source) {
817 switch (state_) {
818 // new local description
819 case STATE_SENTINITIATE:
820 *action = CA_OFFER;
821 *source = CS_LOCAL;
822 break;
823 case STATE_SENTPRACCEPT:
824 *action = CA_PRANSWER;
825 *source = CS_LOCAL;
826 break;
827 case STATE_SENTACCEPT:
828 *action = CA_ANSWER;
829 *source = CS_LOCAL;
830 break;
831 // new remote description
832 case STATE_RECEIVEDINITIATE:
833 *action = CA_OFFER;
834 *source = CS_REMOTE;
835 break;
836 case STATE_RECEIVEDPRACCEPT:
837 *action = CA_PRANSWER;
838 *source = CS_REMOTE;
839 break;
840 case STATE_RECEIVEDACCEPT:
841 *action = CA_ANSWER;
842 *source = CS_REMOTE;
843 break;
844 default:
845 return false;
846 }
847 return true;
848}
849
850void BaseSession::OnMessage(rtc::Message *pmsg) {
851 switch (pmsg->message_id) {
852 case MSG_TIMEOUT:
853 // Session timeout has occured.
854 SetError(ERROR_TIME, "Session timeout has occured.");
855 break;
856
857 case MSG_STATE:
858 switch (state_) {
859 case STATE_SENTACCEPT:
860 case STATE_RECEIVEDACCEPT:
861 SetState(STATE_INPROGRESS);
862 break;
863
864 default:
865 // Explicitly ignoring some states here.
866 break;
867 }
868 break;
869 }
870}
871
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000872} // namespace cricket