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