blob: 8cbe128a707bcc89bb9b534358ee29c52340054e [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
Donald Curtisd4f769d2015-05-28 09:48:21 -0700262 // Ignore candidates for if the proxy content_name doesn't match the content
263 // name of the actual transport. This stops video candidates from being sent
264 // down to the audio transport when BUNDLE is enabled.
265 if (content_name_ != transport_->get()->content_name()) {
266 return true;
267 }
268
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000269 // Verify each candidate before passing down to transport layer.
270 for (Candidates::const_iterator cand = candidates.begin();
271 cand != candidates.end(); ++cand) {
272 if (!transport_->get()->VerifyCandidate(*cand, error))
273 return false;
274 if (!HasChannel(cand->component())) {
275 *error = "Candidate has unknown component: " + cand->ToString() +
276 " for content: " + content_name_;
277 return false;
278 }
279 }
280 transport_->get()->OnRemoteCandidates(candidates);
281 return true;
282}
283
284void TransportProxy::SetIdentity(
285 rtc::SSLIdentity* identity) {
286 transport_->get()->SetIdentity(identity);
287}
288
289std::string BaseSession::StateToString(State state) {
290 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000291 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000293 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000294 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000295 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000297 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000299 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000300 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000301 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000302 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000303 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000305 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000307 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000308 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000309 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000310 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000311 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000312 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000313 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000315 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000317 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000319 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000321 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322 return "STATE_DEINIT";
323 default:
324 break;
325 }
326 return "STATE_" + rtc::ToString(state);
327}
328
329BaseSession::BaseSession(rtc::Thread* signaling_thread,
330 rtc::Thread* worker_thread,
331 PortAllocator* port_allocator,
332 const std::string& sid,
333 const std::string& content_type,
334 bool initiator)
335 : state_(STATE_INIT),
336 error_(ERROR_NONE),
337 signaling_thread_(signaling_thread),
338 worker_thread_(worker_thread),
339 port_allocator_(port_allocator),
340 sid_(sid),
341 content_type_(content_type),
342 transport_type_(NS_GINGLE_P2P),
343 initiator_(initiator),
344 identity_(NULL),
345 ice_tiebreaker_(rtc::CreateRandomId64()),
346 role_switch_(false) {
347 ASSERT(signaling_thread->IsCurrent());
348}
349
350BaseSession::~BaseSession() {
351 ASSERT(signaling_thread()->IsCurrent());
352
353 ASSERT(state_ != STATE_DEINIT);
354 LogState(state_, STATE_DEINIT);
355 state_ = STATE_DEINIT;
356 SignalState(this, state_);
357
358 for (TransportMap::iterator iter = transports_.begin();
359 iter != transports_.end(); ++iter) {
360 delete iter->second;
361 }
362}
363
364const SessionDescription* BaseSession::local_description() const {
365 // TODO(tommi): Assert on thread correctness.
366 return local_description_.get();
367}
368
369const SessionDescription* BaseSession::remote_description() const {
370 // TODO(tommi): Assert on thread correctness.
371 return remote_description_.get();
372}
373
374SessionDescription* BaseSession::remote_description() {
375 // TODO(tommi): Assert on thread correctness.
376 return remote_description_.get();
377}
378
379void BaseSession::set_local_description(const SessionDescription* sdesc) {
380 // TODO(tommi): Assert on thread correctness.
381 if (sdesc != local_description_.get())
382 local_description_.reset(sdesc);
383}
384
385void BaseSession::set_remote_description(SessionDescription* sdesc) {
386 // TODO(tommi): Assert on thread correctness.
387 if (sdesc != remote_description_)
388 remote_description_.reset(sdesc);
389}
390
391const SessionDescription* BaseSession::initiator_description() const {
392 // TODO(tommi): Assert on thread correctness.
393 return initiator_ ? local_description_.get() : remote_description_.get();
394}
395
396bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
397 if (identity_)
398 return false;
399 identity_ = identity;
400 for (TransportMap::iterator iter = transports_.begin();
401 iter != transports_.end(); ++iter) {
402 iter->second->SetIdentity(identity_);
403 }
404 return true;
405}
406
407bool BaseSession::PushdownTransportDescription(ContentSource source,
408 ContentAction action,
409 std::string* error_desc) {
410 if (source == CS_LOCAL) {
411 return PushdownLocalTransportDescription(local_description(),
412 action,
413 error_desc);
414 }
415 return PushdownRemoteTransportDescription(remote_description(),
416 action,
417 error_desc);
418}
419
420bool BaseSession::PushdownLocalTransportDescription(
421 const SessionDescription* sdesc,
422 ContentAction action,
423 std::string* error_desc) {
424 // Update the Transports with the right information, and trigger them to
425 // start connecting.
426 for (TransportMap::iterator iter = transports_.begin();
427 iter != transports_.end(); ++iter) {
428 // If no transport info was in this session description, ret == false
429 // and we just skip this one.
430 TransportDescription tdesc;
431 bool ret = GetTransportDescription(
432 sdesc, iter->second->content_name(), &tdesc);
433 if (ret) {
434 if (!iter->second->SetLocalTransportDescription(tdesc, action,
435 error_desc)) {
436 return false;
437 }
438
439 iter->second->ConnectChannels();
440 }
441 }
442
443 return true;
444}
445
446bool BaseSession::PushdownRemoteTransportDescription(
447 const SessionDescription* sdesc,
448 ContentAction action,
449 std::string* error_desc) {
450 // Update the Transports with the right information.
451 for (TransportMap::iterator iter = transports_.begin();
452 iter != transports_.end(); ++iter) {
453 TransportDescription tdesc;
454
455 // If no transport info was in this session description, ret == false
456 // and we just skip this one.
457 bool ret = GetTransportDescription(
458 sdesc, iter->second->content_name(), &tdesc);
459 if (ret) {
460 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
461 error_desc)) {
462 return false;
463 }
464 }
465 }
466
467 return true;
468}
469
470TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471 int component) {
472 // We create the proxy "on demand" here because we need to support
473 // creating channels at any time, even before we send or receive
474 // initiate messages, which is before we create the transports.
475 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000476 return transproxy->CreateChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477}
478
479TransportChannel* BaseSession::GetChannel(const std::string& content_name,
480 int component) {
481 TransportProxy* transproxy = GetTransportProxy(content_name);
482 if (transproxy == NULL)
483 return NULL;
484
485 return transproxy->GetChannel(component);
486}
487
488void BaseSession::DestroyChannel(const std::string& content_name,
489 int component) {
490 TransportProxy* transproxy = GetTransportProxy(content_name);
491 ASSERT(transproxy != NULL);
492 transproxy->DestroyChannel(component);
493}
494
495TransportProxy* BaseSession::GetOrCreateTransportProxy(
496 const std::string& content_name) {
497 TransportProxy* transproxy = GetTransportProxy(content_name);
498 if (transproxy)
499 return transproxy;
500
501 Transport* transport = CreateTransport(content_name);
502 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
503 transport->SetIceTiebreaker(ice_tiebreaker_);
504 // TODO: Connect all the Transport signals to TransportProxy
505 // then to the BaseSession.
506 transport->SignalConnecting.connect(
507 this, &BaseSession::OnTransportConnecting);
508 transport->SignalWritableState.connect(
509 this, &BaseSession::OnTransportWritable);
510 transport->SignalRequestSignaling.connect(
511 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512 transport->SignalRouteChange.connect(
513 this, &BaseSession::OnTransportRouteChange);
514 transport->SignalCandidatesAllocationDone.connect(
515 this, &BaseSession::OnTransportCandidatesAllocationDone);
516 transport->SignalRoleConflict.connect(
517 this, &BaseSession::OnRoleConflict);
518 transport->SignalCompleted.connect(
519 this, &BaseSession::OnTransportCompleted);
520 transport->SignalFailed.connect(
521 this, &BaseSession::OnTransportFailed);
522
523 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
524 new TransportWrapper(transport));
525 transproxy->SignalCandidatesReady.connect(
526 this, &BaseSession::OnTransportProxyCandidatesReady);
527 if (identity_)
528 transproxy->SetIdentity(identity_);
529 transports_[content_name] = transproxy;
530
531 return transproxy;
532}
533
534Transport* BaseSession::GetTransport(const std::string& content_name) {
535 TransportProxy* transproxy = GetTransportProxy(content_name);
536 if (transproxy == NULL)
537 return NULL;
538 return transproxy->impl();
539}
540
541TransportProxy* BaseSession::GetTransportProxy(
542 const std::string& content_name) {
543 TransportMap::iterator iter = transports_.find(content_name);
544 return (iter != transports_.end()) ? iter->second : NULL;
545}
546
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000547void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000548 const std::string& content_name) {
549 TransportMap::iterator iter = transports_.find(content_name);
550 if (iter != transports_.end()) {
551 delete iter->second;
552 transports_.erase(content_name);
553 }
554}
555
556cricket::Transport* BaseSession::CreateTransport(
557 const std::string& content_name) {
558 ASSERT(transport_type_ == NS_GINGLE_P2P);
559 return new cricket::DtlsTransport<P2PTransport>(
560 signaling_thread(), worker_thread(), content_name,
561 port_allocator(), identity_);
562}
563
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564void BaseSession::SetState(State state) {
565 ASSERT(signaling_thread_->IsCurrent());
566 if (state != state_) {
567 LogState(state_, state);
568 state_ = state;
569 SignalState(this, state_);
570 signaling_thread_->Post(this, MSG_STATE);
571 }
572 SignalNewDescription();
573}
574
575void BaseSession::SetError(Error error, const std::string& error_desc) {
576 ASSERT(signaling_thread_->IsCurrent());
577 if (error != error_) {
578 error_ = error;
579 error_desc_ = error_desc;
580 SignalError(this, error);
581 }
582}
583
584void BaseSession::OnSignalingReady() {
585 ASSERT(signaling_thread()->IsCurrent());
586 for (TransportMap::iterator iter = transports_.begin();
587 iter != transports_.end(); ++iter) {
588 iter->second->OnSignalingReady();
589 }
590}
591
592// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
593// start, remove this method once everyone calls PushdownLocalTD.
594void BaseSession::SpeculativelyConnectAllTransportChannels() {
595 // Put all transports into the connecting state.
596 for (TransportMap::iterator iter = transports_.begin();
597 iter != transports_.end(); ++iter) {
598 iter->second->ConnectChannels();
599 }
600}
601
602bool BaseSession::OnRemoteCandidates(const std::string& content_name,
603 const Candidates& candidates,
604 std::string* error) {
605 // Give candidates to the appropriate transport, and tell that transport
606 // to start connecting, if it's not already doing so.
607 TransportProxy* transproxy = GetTransportProxy(content_name);
608 if (!transproxy) {
609 *error = "Unknown content name " + content_name;
610 return false;
611 }
612 if (!transproxy->OnRemoteCandidates(candidates, error)) {
613 return false;
614 }
615 // TODO(juberti): Remove this call once we can be sure that we always have
616 // a local transport description (which will trigger the connection).
617 transproxy->ConnectChannels();
618 return true;
619}
620
621bool BaseSession::MaybeEnableMuxingSupport() {
622 // We need both a local and remote description to decide if we should mux.
623 if ((state_ == STATE_SENTINITIATE ||
624 state_ == STATE_RECEIVEDINITIATE) &&
625 ((local_description_ == NULL) ||
626 (remote_description_ == NULL))) {
627 return false;
628 }
629
630 // In order to perform the multiplexing, we need all proxies to be in the
631 // negotiated state, i.e. to have implementations underneath.
632 // Ensure that this is the case, regardless of whether we are going to mux.
633 for (TransportMap::iterator iter = transports_.begin();
634 iter != transports_.end(); ++iter) {
635 ASSERT(iter->second->negotiated());
Donald Curtis0e209b02015-03-24 09:29:54 -0700636 if (!iter->second->negotiated()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637 return false;
Donald Curtis0e209b02015-03-24 09:29:54 -0700638 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000639 }
640
641 // If both sides agree to BUNDLE, mux all the specified contents onto the
642 // transport belonging to the first content name in the BUNDLE group.
643 // If the contents are already muxed, this will be a no-op.
644 // TODO(juberti): Should this check that local and remote have configured
645 // BUNDLE the same way?
646 bool candidates_allocated = IsCandidateAllocationDone();
647 const ContentGroup* local_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700648 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000649 const ContentGroup* remote_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700650 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
651 if (local_bundle_group && remote_bundle_group) {
652 if (!BundleContentGroup(local_bundle_group)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653 LOG(LS_WARNING) << "Failed to set up BUNDLE";
654 return false;
655 }
656
657 // If we weren't done gathering before, we might be done now, as a result
658 // of enabling mux.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000659 if (!candidates_allocated) {
660 MaybeCandidateAllocationDone();
661 }
662 } else {
Donald Curtis0e209b02015-03-24 09:29:54 -0700663 LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 }
665 return true;
666}
667
Donald Curtis0e209b02015-03-24 09:29:54 -0700668bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
669 const std::string* content_name = bundle_group->FirstContentName();
670 if (!content_name) {
671 LOG(LS_INFO) << "No content names specified in BUNDLE group.";
672 return true;
673 }
674
Donald Curtis0e209b02015-03-24 09:29:54 -0700675 TransportProxy* selected_proxy = GetTransportProxy(*content_name);
676 if (!selected_proxy) {
677 LOG(LS_WARNING) << "No transport found for content \""
678 << *content_name << "\".";
679 return false;
680 }
681
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682 for (TransportMap::iterator iter = transports_.begin();
683 iter != transports_.end(); ++iter) {
684 // If content is part of the mux group, then repoint its proxy at the
685 // transport object that we have chosen to mux onto. If the proxy
686 // is already pointing at the right object, it will be a no-op.
Donald Curtis0e209b02015-03-24 09:29:54 -0700687 if (bundle_group->HasContentName(iter->first) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000688 !iter->second->SetupMux(selected_proxy)) {
Donald Curtis0e209b02015-03-24 09:29:54 -0700689 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
690 << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 return false;
692 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700693 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000694 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700695
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000696 return true;
697}
698
699void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
700 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
701 // TransportProxy should receive the done signal directly, set its allocated
702 // flag internally, and then reissue the done signal to Session.
703 // Overall we should make TransportProxy receive *all* the signals from
704 // Transport, since this removes the need to manually iterate over all
705 // the transports, as is needed to make sure signals are handled properly
706 // when BUNDLEing.
707 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
708 // that make it prohibitively difficult to run dbg builds. Disabled for now.
709 //ASSERT(!IsCandidateAllocationDone());
710 for (TransportMap::iterator iter = transports_.begin();
711 iter != transports_.end(); ++iter) {
712 if (iter->second->impl() == transport) {
713 iter->second->set_candidates_allocated(true);
714 }
715 }
716 MaybeCandidateAllocationDone();
717}
718
719bool BaseSession::IsCandidateAllocationDone() const {
720 for (TransportMap::const_iterator iter = transports_.begin();
721 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000722 if (!iter->second->candidates_allocated()) {
723 LOG(LS_INFO) << "Candidate allocation not done for "
724 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000725 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000726 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000727 }
728 return true;
729}
730
731void BaseSession::MaybeCandidateAllocationDone() {
732 if (IsCandidateAllocationDone()) {
733 LOG(LS_INFO) << "Candidate gathering is complete.";
734 OnCandidatesAllocationDone();
735 }
736}
737
738void BaseSession::OnRoleConflict() {
739 if (role_switch_) {
740 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
741 return;
742 }
743
744 role_switch_ = true;
745 for (TransportMap::iterator iter = transports_.begin();
746 iter != transports_.end(); ++iter) {
747 // Role will be reverse of initial role setting.
748 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
749 iter->second->SetIceRole(role);
750 }
751}
752
753void BaseSession::LogState(State old_state, State new_state) {
754 LOG(LS_INFO) << "Session:" << id()
755 << " Old state:" << StateToString(old_state)
756 << " New state:" << StateToString(new_state)
757 << " Type:" << content_type()
758 << " Transport:" << transport_type();
759}
760
761// static
762bool BaseSession::GetTransportDescription(const SessionDescription* description,
763 const std::string& content_name,
764 TransportDescription* tdesc) {
765 if (!description || !tdesc) {
766 return false;
767 }
768 const TransportInfo* transport_info =
769 description->GetTransportInfoByName(content_name);
770 if (!transport_info) {
771 return false;
772 }
773 *tdesc = transport_info->description;
774 return true;
775}
776
777void BaseSession::SignalNewDescription() {
778 ContentAction action;
779 ContentSource source;
780 if (!GetContentAction(&action, &source)) {
781 return;
782 }
783 if (source == CS_LOCAL) {
784 SignalNewLocalDescription(this, action);
785 } else {
786 SignalNewRemoteDescription(this, action);
787 }
788}
789
790bool BaseSession::GetContentAction(ContentAction* action,
791 ContentSource* source) {
792 switch (state_) {
793 // new local description
794 case STATE_SENTINITIATE:
795 *action = CA_OFFER;
796 *source = CS_LOCAL;
797 break;
798 case STATE_SENTPRACCEPT:
799 *action = CA_PRANSWER;
800 *source = CS_LOCAL;
801 break;
802 case STATE_SENTACCEPT:
803 *action = CA_ANSWER;
804 *source = CS_LOCAL;
805 break;
806 // new remote description
807 case STATE_RECEIVEDINITIATE:
808 *action = CA_OFFER;
809 *source = CS_REMOTE;
810 break;
811 case STATE_RECEIVEDPRACCEPT:
812 *action = CA_PRANSWER;
813 *source = CS_REMOTE;
814 break;
815 case STATE_RECEIVEDACCEPT:
816 *action = CA_ANSWER;
817 *source = CS_REMOTE;
818 break;
819 default:
820 return false;
821 }
822 return true;
823}
824
825void BaseSession::OnMessage(rtc::Message *pmsg) {
826 switch (pmsg->message_id) {
827 case MSG_TIMEOUT:
828 // Session timeout has occured.
829 SetError(ERROR_TIME, "Session timeout has occured.");
830 break;
831
832 case MSG_STATE:
833 switch (state_) {
834 case STATE_SENTACCEPT:
835 case STATE_RECEIVEDACCEPT:
836 SetState(STATE_INPROGRESS);
837 break;
838
839 default:
840 // Explicitly ignoring some states here.
841 break;
842 }
843 break;
844 }
845}
846
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000847} // namespace cricket