blob: 4da65192e4e2c72c9b6da07370c81a54ade83154 [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
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +000049TransportChannel* TransportProxy::CreateChannel(int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000050 ASSERT(rtc::Thread::Current() == worker_thread_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000051 ASSERT(GetChannel(component) == NULL);
52 ASSERT(!transport_->get()->HasChannel(component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000053
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000054 // We always create a proxy in case we need to change out the transport later.
55 TransportChannelProxy* channel_proxy =
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +000056 new TransportChannelProxy(content_name(), component);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000057 channels_[component] = channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000059 // If we're already negotiated, create an impl and hook it up to the proxy
60 // channel. If we're connecting, create an impl but don't hook it up yet.
61 if (negotiated_) {
62 CreateChannelImpl_w(component);
63 SetChannelImplFromTransport_w(channel_proxy, component);
64 } else if (connecting_) {
65 CreateChannelImpl_w(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000066 }
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000067 return channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000068}
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_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000076 TransportChannelProxy* channel_proxy = GetChannelProxy(component);
77 if (channel_proxy) {
78 // If the state of TransportProxy is not NEGOTIATED then
79 // TransportChannelProxy and its impl are not connected. Both must
80 // be connected before deletion.
81 //
82 // However, if we haven't entered the connecting state then there
83 // is no implementation to hook up.
84 if (connecting_ && !negotiated_) {
85 SetChannelImplFromTransport_w(channel_proxy, component);
86 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000087
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000088 channels_.erase(component);
89 channel_proxy->SignalDestroyed(channel_proxy);
90 delete channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091 }
92}
93
94void TransportProxy::ConnectChannels() {
95 if (!connecting_) {
96 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000097 for (auto& iter : channels_) {
98 CreateChannelImpl(iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000099 }
100 }
101 connecting_ = true;
102 }
103 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
104 // don't have any channels yet, so we need to allow this method to be called
105 // multiple times. Once we fix Transport, we can move this call inside the
106 // if (!connecting_) block.
107 transport_->get()->ConnectChannels();
108}
109
110void TransportProxy::CompleteNegotiation() {
111 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000112 // Negotiating assumes connecting_ has happened and
113 // implementations exist. If not we need to create the
114 // implementations.
115 for (auto& iter : channels_) {
116 if (!connecting_) {
117 CreateChannelImpl(iter.first);
118 }
119 SetChannelImplFromTransport(iter.second, iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000120 }
121 negotiated_ = true;
122 }
123}
124
125void TransportProxy::AddSentCandidates(const Candidates& candidates) {
126 for (Candidates::const_iterator cand = candidates.begin();
127 cand != candidates.end(); ++cand) {
128 sent_candidates_.push_back(*cand);
129 }
130}
131
132void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
133 for (Candidates::const_iterator cand = candidates.begin();
134 cand != candidates.end(); ++cand) {
135 unsent_candidates_.push_back(*cand);
136 }
137}
138
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000139TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
140 ChannelMap::const_iterator iter = channels_.find(component);
141 return (iter != channels_.end()) ? iter->second : NULL;
142}
143
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000144void TransportProxy::CreateChannelImpl(int component) {
145 worker_thread_->Invoke<void>(Bind(
146 &TransportProxy::CreateChannelImpl_w, this, component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000147}
148
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000149void TransportProxy::CreateChannelImpl_w(int component) {
150 ASSERT(rtc::Thread::Current() == worker_thread_);
151 transport_->get()->CreateChannel(component);
152}
153
154void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
155 int component) {
156 worker_thread_->Invoke<void>(Bind(
157 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
158}
159
160void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
161 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162 ASSERT(rtc::Thread::Current() == worker_thread_);
163 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000164 ASSERT(impl != NULL);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000165 ReplaceChannelImpl_w(proxy, impl);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166}
167
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000168void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
169 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000170 worker_thread_->Invoke<void>(Bind(
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000171 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172}
173
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000174void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
175 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176 ASSERT(rtc::Thread::Current() == worker_thread_);
177 ASSERT(proxy != NULL);
178 proxy->SetImplementation(impl);
179}
180
181// This function muxes |this| onto |target| by repointing |this| at
182// |target|'s transport and setting our TransportChannelProxies
183// to point to |target|'s underlying implementations.
184bool TransportProxy::SetupMux(TransportProxy* target) {
185 // Bail out if there's nothing to do.
186 if (transport_ == target->transport_) {
187 return true;
188 }
189
190 // Run through all channels and remove any non-rtp transport channels before
191 // setting target transport channels.
192 for (ChannelMap::const_iterator iter = channels_.begin();
193 iter != channels_.end(); ++iter) {
194 if (!target->transport_->get()->HasChannel(iter->first)) {
195 // Remove if channel doesn't exist in |transport_|.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000196 ReplaceChannelImpl(iter->second, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197 } else {
198 // Replace the impl for all the TransportProxyChannels with the channels
199 // from |target|'s transport. Fail if there's not an exact match.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000200 ReplaceChannelImpl(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201 iter->second, target->transport_->get()->CreateChannel(iter->first));
202 }
203 }
204
205 // Now replace our transport. Must happen afterwards because
206 // it deletes all impls as a side effect.
207 transport_ = target->transport_;
208 transport_->get()->SignalCandidatesReady.connect(
209 this, &TransportProxy::OnTransportCandidatesReady);
210 set_candidates_allocated(target->candidates_allocated());
211 return true;
212}
213
214void TransportProxy::SetIceRole(IceRole role) {
215 transport_->get()->SetIceRole(role);
216}
217
218bool TransportProxy::SetLocalTransportDescription(
219 const TransportDescription& description,
220 ContentAction action,
221 std::string* error_desc) {
222 // If this is an answer, finalize the negotiation.
223 if (action == CA_ANSWER) {
224 CompleteNegotiation();
225 }
226 bool result = transport_->get()->SetLocalTransportDescription(description,
227 action,
228 error_desc);
229 if (result)
230 local_description_set_ = true;
231 return result;
232}
233
234bool TransportProxy::SetRemoteTransportDescription(
235 const TransportDescription& description,
236 ContentAction action,
237 std::string* error_desc) {
238 // If this is an answer, finalize the negotiation.
239 if (action == CA_ANSWER) {
240 CompleteNegotiation();
241 }
242 bool result = transport_->get()->SetRemoteTransportDescription(description,
243 action,
244 error_desc);
245 if (result)
246 remote_description_set_ = true;
247 return result;
248}
249
250void TransportProxy::OnSignalingReady() {
251 // If we're starting a new allocation sequence, reset our state.
252 set_candidates_allocated(false);
253 transport_->get()->OnSignalingReady();
254}
255
256bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
257 std::string* error) {
258 // Ensure the transport is negotiated before handling candidates.
259 // TODO(juberti): Remove this once everybody calls SetLocalTD.
260 CompleteNegotiation();
261
262 // Verify each candidate before passing down to transport layer.
263 for (Candidates::const_iterator cand = candidates.begin();
264 cand != candidates.end(); ++cand) {
265 if (!transport_->get()->VerifyCandidate(*cand, error))
266 return false;
267 if (!HasChannel(cand->component())) {
268 *error = "Candidate has unknown component: " + cand->ToString() +
269 " for content: " + content_name_;
270 return false;
271 }
272 }
273 transport_->get()->OnRemoteCandidates(candidates);
274 return true;
275}
276
277void TransportProxy::SetIdentity(
278 rtc::SSLIdentity* identity) {
279 transport_->get()->SetIdentity(identity);
280}
281
282std::string BaseSession::StateToString(State state) {
283 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000284 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000285 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000286 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000287 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000288 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000289 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000290 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000291 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000292 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000293 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000294 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000296 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000297 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000298 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000299 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000300 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000302 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000303 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000304 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000305 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000306 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000307 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000308 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000309 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000310 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000311 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000312 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000313 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000314 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000315 return "STATE_DEINIT";
316 default:
317 break;
318 }
319 return "STATE_" + rtc::ToString(state);
320}
321
322BaseSession::BaseSession(rtc::Thread* signaling_thread,
323 rtc::Thread* worker_thread,
324 PortAllocator* port_allocator,
325 const std::string& sid,
326 const std::string& content_type,
327 bool initiator)
328 : state_(STATE_INIT),
329 error_(ERROR_NONE),
330 signaling_thread_(signaling_thread),
331 worker_thread_(worker_thread),
332 port_allocator_(port_allocator),
333 sid_(sid),
334 content_type_(content_type),
335 transport_type_(NS_GINGLE_P2P),
336 initiator_(initiator),
337 identity_(NULL),
338 ice_tiebreaker_(rtc::CreateRandomId64()),
339 role_switch_(false) {
340 ASSERT(signaling_thread->IsCurrent());
341}
342
343BaseSession::~BaseSession() {
344 ASSERT(signaling_thread()->IsCurrent());
345
346 ASSERT(state_ != STATE_DEINIT);
347 LogState(state_, STATE_DEINIT);
348 state_ = STATE_DEINIT;
349 SignalState(this, state_);
350
351 for (TransportMap::iterator iter = transports_.begin();
352 iter != transports_.end(); ++iter) {
353 delete iter->second;
354 }
355}
356
357const SessionDescription* BaseSession::local_description() const {
358 // TODO(tommi): Assert on thread correctness.
359 return local_description_.get();
360}
361
362const SessionDescription* BaseSession::remote_description() const {
363 // TODO(tommi): Assert on thread correctness.
364 return remote_description_.get();
365}
366
367SessionDescription* BaseSession::remote_description() {
368 // TODO(tommi): Assert on thread correctness.
369 return remote_description_.get();
370}
371
372void BaseSession::set_local_description(const SessionDescription* sdesc) {
373 // TODO(tommi): Assert on thread correctness.
374 if (sdesc != local_description_.get())
375 local_description_.reset(sdesc);
376}
377
378void BaseSession::set_remote_description(SessionDescription* sdesc) {
379 // TODO(tommi): Assert on thread correctness.
380 if (sdesc != remote_description_)
381 remote_description_.reset(sdesc);
382}
383
384const SessionDescription* BaseSession::initiator_description() const {
385 // TODO(tommi): Assert on thread correctness.
386 return initiator_ ? local_description_.get() : remote_description_.get();
387}
388
389bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
390 if (identity_)
391 return false;
392 identity_ = identity;
393 for (TransportMap::iterator iter = transports_.begin();
394 iter != transports_.end(); ++iter) {
395 iter->second->SetIdentity(identity_);
396 }
397 return true;
398}
399
400bool BaseSession::PushdownTransportDescription(ContentSource source,
401 ContentAction action,
402 std::string* error_desc) {
403 if (source == CS_LOCAL) {
404 return PushdownLocalTransportDescription(local_description(),
405 action,
406 error_desc);
407 }
408 return PushdownRemoteTransportDescription(remote_description(),
409 action,
410 error_desc);
411}
412
413bool BaseSession::PushdownLocalTransportDescription(
414 const SessionDescription* sdesc,
415 ContentAction action,
416 std::string* error_desc) {
417 // Update the Transports with the right information, and trigger them to
418 // start connecting.
419 for (TransportMap::iterator iter = transports_.begin();
420 iter != transports_.end(); ++iter) {
421 // If no transport info was in this session description, ret == false
422 // and we just skip this one.
423 TransportDescription tdesc;
424 bool ret = GetTransportDescription(
425 sdesc, iter->second->content_name(), &tdesc);
426 if (ret) {
427 if (!iter->second->SetLocalTransportDescription(tdesc, action,
428 error_desc)) {
429 return false;
430 }
431
432 iter->second->ConnectChannels();
433 }
434 }
435
436 return true;
437}
438
439bool BaseSession::PushdownRemoteTransportDescription(
440 const SessionDescription* sdesc,
441 ContentAction action,
442 std::string* error_desc) {
443 // Update the Transports with the right information.
444 for (TransportMap::iterator iter = transports_.begin();
445 iter != transports_.end(); ++iter) {
446 TransportDescription tdesc;
447
448 // If no transport info was in this session description, ret == false
449 // and we just skip this one.
450 bool ret = GetTransportDescription(
451 sdesc, iter->second->content_name(), &tdesc);
452 if (ret) {
453 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
454 error_desc)) {
455 return false;
456 }
457 }
458 }
459
460 return true;
461}
462
463TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000464 int component) {
465 // We create the proxy "on demand" here because we need to support
466 // creating channels at any time, even before we send or receive
467 // initiate messages, which is before we create the transports.
468 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000469 return transproxy->CreateChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000470}
471
472TransportChannel* BaseSession::GetChannel(const std::string& content_name,
473 int component) {
474 TransportProxy* transproxy = GetTransportProxy(content_name);
475 if (transproxy == NULL)
476 return NULL;
477
478 return transproxy->GetChannel(component);
479}
480
481void BaseSession::DestroyChannel(const std::string& content_name,
482 int component) {
483 TransportProxy* transproxy = GetTransportProxy(content_name);
484 ASSERT(transproxy != NULL);
485 transproxy->DestroyChannel(component);
486}
487
488TransportProxy* BaseSession::GetOrCreateTransportProxy(
489 const std::string& content_name) {
490 TransportProxy* transproxy = GetTransportProxy(content_name);
491 if (transproxy)
492 return transproxy;
493
494 Transport* transport = CreateTransport(content_name);
495 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
496 transport->SetIceTiebreaker(ice_tiebreaker_);
497 // TODO: Connect all the Transport signals to TransportProxy
498 // then to the BaseSession.
499 transport->SignalConnecting.connect(
500 this, &BaseSession::OnTransportConnecting);
501 transport->SignalWritableState.connect(
502 this, &BaseSession::OnTransportWritable);
503 transport->SignalRequestSignaling.connect(
504 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000505 transport->SignalRouteChange.connect(
506 this, &BaseSession::OnTransportRouteChange);
507 transport->SignalCandidatesAllocationDone.connect(
508 this, &BaseSession::OnTransportCandidatesAllocationDone);
509 transport->SignalRoleConflict.connect(
510 this, &BaseSession::OnRoleConflict);
511 transport->SignalCompleted.connect(
512 this, &BaseSession::OnTransportCompleted);
513 transport->SignalFailed.connect(
514 this, &BaseSession::OnTransportFailed);
515
516 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
517 new TransportWrapper(transport));
518 transproxy->SignalCandidatesReady.connect(
519 this, &BaseSession::OnTransportProxyCandidatesReady);
520 if (identity_)
521 transproxy->SetIdentity(identity_);
522 transports_[content_name] = transproxy;
523
524 return transproxy;
525}
526
527Transport* BaseSession::GetTransport(const std::string& content_name) {
528 TransportProxy* transproxy = GetTransportProxy(content_name);
529 if (transproxy == NULL)
530 return NULL;
531 return transproxy->impl();
532}
533
534TransportProxy* BaseSession::GetTransportProxy(
535 const std::string& content_name) {
536 TransportMap::iterator iter = transports_.find(content_name);
537 return (iter != transports_.end()) ? iter->second : NULL;
538}
539
540TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
541 for (TransportMap::iterator iter = transports_.begin();
542 iter != transports_.end(); ++iter) {
543 TransportProxy* transproxy = iter->second;
544 if (transproxy->impl() == transport) {
545 return transproxy;
546 }
547 }
548 return NULL;
549}
550
551TransportProxy* BaseSession::GetFirstTransportProxy() {
552 if (transports_.empty())
553 return NULL;
554 return transports_.begin()->second;
555}
556
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000557void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000558 const std::string& content_name) {
559 TransportMap::iterator iter = transports_.find(content_name);
560 if (iter != transports_.end()) {
561 delete iter->second;
562 transports_.erase(content_name);
563 }
564}
565
566cricket::Transport* BaseSession::CreateTransport(
567 const std::string& content_name) {
568 ASSERT(transport_type_ == NS_GINGLE_P2P);
569 return new cricket::DtlsTransport<P2PTransport>(
570 signaling_thread(), worker_thread(), content_name,
571 port_allocator(), identity_);
572}
573
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574void BaseSession::SetState(State state) {
575 ASSERT(signaling_thread_->IsCurrent());
576 if (state != state_) {
577 LogState(state_, state);
578 state_ = state;
579 SignalState(this, state_);
580 signaling_thread_->Post(this, MSG_STATE);
581 }
582 SignalNewDescription();
583}
584
585void BaseSession::SetError(Error error, const std::string& error_desc) {
586 ASSERT(signaling_thread_->IsCurrent());
587 if (error != error_) {
588 error_ = error;
589 error_desc_ = error_desc;
590 SignalError(this, error);
591 }
592}
593
594void BaseSession::OnSignalingReady() {
595 ASSERT(signaling_thread()->IsCurrent());
596 for (TransportMap::iterator iter = transports_.begin();
597 iter != transports_.end(); ++iter) {
598 iter->second->OnSignalingReady();
599 }
600}
601
602// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
603// start, remove this method once everyone calls PushdownLocalTD.
604void BaseSession::SpeculativelyConnectAllTransportChannels() {
605 // Put all transports into the connecting state.
606 for (TransportMap::iterator iter = transports_.begin();
607 iter != transports_.end(); ++iter) {
608 iter->second->ConnectChannels();
609 }
610}
611
612bool BaseSession::OnRemoteCandidates(const std::string& content_name,
613 const Candidates& candidates,
614 std::string* error) {
615 // Give candidates to the appropriate transport, and tell that transport
616 // to start connecting, if it's not already doing so.
617 TransportProxy* transproxy = GetTransportProxy(content_name);
618 if (!transproxy) {
619 *error = "Unknown content name " + content_name;
620 return false;
621 }
622 if (!transproxy->OnRemoteCandidates(candidates, error)) {
623 return false;
624 }
625 // TODO(juberti): Remove this call once we can be sure that we always have
626 // a local transport description (which will trigger the connection).
627 transproxy->ConnectChannels();
628 return true;
629}
630
631bool BaseSession::MaybeEnableMuxingSupport() {
632 // We need both a local and remote description to decide if we should mux.
633 if ((state_ == STATE_SENTINITIATE ||
634 state_ == STATE_RECEIVEDINITIATE) &&
635 ((local_description_ == NULL) ||
636 (remote_description_ == NULL))) {
637 return false;
638 }
639
640 // In order to perform the multiplexing, we need all proxies to be in the
641 // negotiated state, i.e. to have implementations underneath.
642 // Ensure that this is the case, regardless of whether we are going to mux.
643 for (TransportMap::iterator iter = transports_.begin();
644 iter != transports_.end(); ++iter) {
645 ASSERT(iter->second->negotiated());
646 if (!iter->second->negotiated())
647 return false;
648 }
649
650 // If both sides agree to BUNDLE, mux all the specified contents onto the
651 // transport belonging to the first content name in the BUNDLE group.
652 // If the contents are already muxed, this will be a no-op.
653 // TODO(juberti): Should this check that local and remote have configured
654 // BUNDLE the same way?
655 bool candidates_allocated = IsCandidateAllocationDone();
656 const ContentGroup* local_bundle_group =
657 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
658 const ContentGroup* remote_bundle_group =
659 remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
660 if (local_bundle_group && remote_bundle_group &&
661 local_bundle_group->FirstContentName()) {
662 const std::string* content_name = local_bundle_group->FirstContentName();
663 const ContentInfo* content =
664 local_description_->GetContentByName(*content_name);
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000665 if (!content) {
pthatcher@webrtc.org63a10972015-03-17 21:48:39 +0000666 LOG(LS_WARNING) << "Content \"" << *content_name
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000667 << "\" referenced in BUNDLE group is not present";
668 return false;
669 }
670
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000671 if (!SetSelectedProxy(content->name, local_bundle_group)) {
672 LOG(LS_WARNING) << "Failed to set up BUNDLE";
673 return false;
674 }
675
676 // If we weren't done gathering before, we might be done now, as a result
677 // of enabling mux.
678 LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
679 << *content_name;
680 if (!candidates_allocated) {
681 MaybeCandidateAllocationDone();
682 }
683 } else {
684 LOG(LS_INFO) << "No BUNDLE information, not bundling.";
685 }
686 return true;
687}
688
689bool BaseSession::SetSelectedProxy(const std::string& content_name,
690 const ContentGroup* muxed_group) {
691 TransportProxy* selected_proxy = GetTransportProxy(content_name);
692 if (!selected_proxy) {
693 return false;
694 }
695
696 ASSERT(selected_proxy->negotiated());
697 for (TransportMap::iterator iter = transports_.begin();
698 iter != transports_.end(); ++iter) {
699 // If content is part of the mux group, then repoint its proxy at the
700 // transport object that we have chosen to mux onto. If the proxy
701 // is already pointing at the right object, it will be a no-op.
702 if (muxed_group->HasContentName(iter->first) &&
703 !iter->second->SetupMux(selected_proxy)) {
704 return false;
705 }
706 }
707 return true;
708}
709
710void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
711 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
712 // TransportProxy should receive the done signal directly, set its allocated
713 // flag internally, and then reissue the done signal to Session.
714 // Overall we should make TransportProxy receive *all* the signals from
715 // Transport, since this removes the need to manually iterate over all
716 // the transports, as is needed to make sure signals are handled properly
717 // when BUNDLEing.
718 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
719 // that make it prohibitively difficult to run dbg builds. Disabled for now.
720 //ASSERT(!IsCandidateAllocationDone());
721 for (TransportMap::iterator iter = transports_.begin();
722 iter != transports_.end(); ++iter) {
723 if (iter->second->impl() == transport) {
724 iter->second->set_candidates_allocated(true);
725 }
726 }
727 MaybeCandidateAllocationDone();
728}
729
730bool BaseSession::IsCandidateAllocationDone() const {
731 for (TransportMap::const_iterator iter = transports_.begin();
732 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000733 if (!iter->second->candidates_allocated()) {
734 LOG(LS_INFO) << "Candidate allocation not done for "
735 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000736 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000737 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000738 }
739 return true;
740}
741
742void BaseSession::MaybeCandidateAllocationDone() {
743 if (IsCandidateAllocationDone()) {
744 LOG(LS_INFO) << "Candidate gathering is complete.";
745 OnCandidatesAllocationDone();
746 }
747}
748
749void BaseSession::OnRoleConflict() {
750 if (role_switch_) {
751 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
752 return;
753 }
754
755 role_switch_ = true;
756 for (TransportMap::iterator iter = transports_.begin();
757 iter != transports_.end(); ++iter) {
758 // Role will be reverse of initial role setting.
759 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
760 iter->second->SetIceRole(role);
761 }
762}
763
764void BaseSession::LogState(State old_state, State new_state) {
765 LOG(LS_INFO) << "Session:" << id()
766 << " Old state:" << StateToString(old_state)
767 << " New state:" << StateToString(new_state)
768 << " Type:" << content_type()
769 << " Transport:" << transport_type();
770}
771
772// static
773bool BaseSession::GetTransportDescription(const SessionDescription* description,
774 const std::string& content_name,
775 TransportDescription* tdesc) {
776 if (!description || !tdesc) {
777 return false;
778 }
779 const TransportInfo* transport_info =
780 description->GetTransportInfoByName(content_name);
781 if (!transport_info) {
782 return false;
783 }
784 *tdesc = transport_info->description;
785 return true;
786}
787
788void BaseSession::SignalNewDescription() {
789 ContentAction action;
790 ContentSource source;
791 if (!GetContentAction(&action, &source)) {
792 return;
793 }
794 if (source == CS_LOCAL) {
795 SignalNewLocalDescription(this, action);
796 } else {
797 SignalNewRemoteDescription(this, action);
798 }
799}
800
801bool BaseSession::GetContentAction(ContentAction* action,
802 ContentSource* source) {
803 switch (state_) {
804 // new local description
805 case STATE_SENTINITIATE:
806 *action = CA_OFFER;
807 *source = CS_LOCAL;
808 break;
809 case STATE_SENTPRACCEPT:
810 *action = CA_PRANSWER;
811 *source = CS_LOCAL;
812 break;
813 case STATE_SENTACCEPT:
814 *action = CA_ANSWER;
815 *source = CS_LOCAL;
816 break;
817 // new remote description
818 case STATE_RECEIVEDINITIATE:
819 *action = CA_OFFER;
820 *source = CS_REMOTE;
821 break;
822 case STATE_RECEIVEDPRACCEPT:
823 *action = CA_PRANSWER;
824 *source = CS_REMOTE;
825 break;
826 case STATE_RECEIVEDACCEPT:
827 *action = CA_ANSWER;
828 *source = CS_REMOTE;
829 break;
830 default:
831 return false;
832 }
833 return true;
834}
835
836void BaseSession::OnMessage(rtc::Message *pmsg) {
837 switch (pmsg->message_id) {
838 case MSG_TIMEOUT:
839 // Session timeout has occured.
840 SetError(ERROR_TIME, "Session timeout has occured.");
841 break;
842
843 case MSG_STATE:
844 switch (state_) {
845 case STATE_SENTACCEPT:
846 case STATE_RECEIVEDACCEPT:
847 SetState(STATE_INPROGRESS);
848 break;
849
850 default:
851 // Explicitly ignoring some states here.
852 break;
853 }
854 break;
855 }
856}
857
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000858} // namespace cricket