blob: 6c185113f9226e0d5bc9b4e48832fe7cc2805aa4 [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
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000040TransportChannel* TransportProxy::GetChannel(int component) {
41 ASSERT(rtc::Thread::Current() == worker_thread_);
42 return GetChannelProxy(component);
43}
44
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +000045TransportChannel* TransportProxy::CreateChannel(int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000046 ASSERT(rtc::Thread::Current() == worker_thread_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000047 ASSERT(GetChannel(component) == NULL);
48 ASSERT(!transport_->get()->HasChannel(component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000049
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000050 // We always create a proxy in case we need to change out the transport later.
51 TransportChannelProxy* channel_proxy =
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +000052 new TransportChannelProxy(content_name(), component);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000053 channels_[component] = channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000054
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000055 // If we're already negotiated, create an impl and hook it up to the proxy
56 // channel. If we're connecting, create an impl but don't hook it up yet.
57 if (negotiated_) {
58 CreateChannelImpl_w(component);
59 SetChannelImplFromTransport_w(channel_proxy, component);
60 } else if (connecting_) {
61 CreateChannelImpl_w(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000062 }
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000063 return channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064}
65
66bool TransportProxy::HasChannel(int component) {
67 return transport_->get()->HasChannel(component);
68}
69
70void TransportProxy::DestroyChannel(int component) {
71 ASSERT(rtc::Thread::Current() == worker_thread_);
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000072 TransportChannelProxy* channel_proxy = GetChannelProxy(component);
73 if (channel_proxy) {
74 // If the state of TransportProxy is not NEGOTIATED then
75 // TransportChannelProxy and its impl are not connected. Both must
76 // be connected before deletion.
77 //
78 // However, if we haven't entered the connecting state then there
79 // is no implementation to hook up.
80 if (connecting_ && !negotiated_) {
81 SetChannelImplFromTransport_w(channel_proxy, component);
82 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000083
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +000084 channels_.erase(component);
85 channel_proxy->SignalDestroyed(channel_proxy);
86 delete channel_proxy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000087 }
88}
89
90void TransportProxy::ConnectChannels() {
91 if (!connecting_) {
92 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +000093 for (auto& iter : channels_) {
94 CreateChannelImpl(iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000095 }
96 }
97 connecting_ = true;
98 }
99 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
100 // don't have any channels yet, so we need to allow this method to be called
101 // multiple times. Once we fix Transport, we can move this call inside the
102 // if (!connecting_) block.
103 transport_->get()->ConnectChannels();
104}
105
106void TransportProxy::CompleteNegotiation() {
107 if (!negotiated_) {
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000108 // Negotiating assumes connecting_ has happened and
109 // implementations exist. If not we need to create the
110 // implementations.
111 for (auto& iter : channels_) {
112 if (!connecting_) {
113 CreateChannelImpl(iter.first);
114 }
115 SetChannelImplFromTransport(iter.second, iter.first);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000116 }
117 negotiated_ = true;
118 }
119}
120
121void TransportProxy::AddSentCandidates(const Candidates& candidates) {
122 for (Candidates::const_iterator cand = candidates.begin();
123 cand != candidates.end(); ++cand) {
124 sent_candidates_.push_back(*cand);
125 }
126}
127
128void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
129 for (Candidates::const_iterator cand = candidates.begin();
130 cand != candidates.end(); ++cand) {
131 unsent_candidates_.push_back(*cand);
132 }
133}
134
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
136 ChannelMap::const_iterator iter = channels_.find(component);
137 return (iter != channels_.end()) ? iter->second : NULL;
138}
139
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000140void TransportProxy::CreateChannelImpl(int component) {
141 worker_thread_->Invoke<void>(Bind(
142 &TransportProxy::CreateChannelImpl_w, this, component));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143}
144
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000145void TransportProxy::CreateChannelImpl_w(int component) {
146 ASSERT(rtc::Thread::Current() == worker_thread_);
147 transport_->get()->CreateChannel(component);
148}
149
150void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
151 int component) {
152 worker_thread_->Invoke<void>(Bind(
153 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
154}
155
156void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
157 int component) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000158 ASSERT(rtc::Thread::Current() == worker_thread_);
159 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 ASSERT(impl != NULL);
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000161 ReplaceChannelImpl_w(proxy, impl);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162}
163
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000164void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
165 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 worker_thread_->Invoke<void>(Bind(
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000167 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168}
169
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000170void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
171 TransportChannelImpl* impl) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172 ASSERT(rtc::Thread::Current() == worker_thread_);
173 ASSERT(proxy != NULL);
174 proxy->SetImplementation(impl);
175}
176
177// This function muxes |this| onto |target| by repointing |this| at
178// |target|'s transport and setting our TransportChannelProxies
179// to point to |target|'s underlying implementations.
180bool TransportProxy::SetupMux(TransportProxy* target) {
181 // Bail out if there's nothing to do.
182 if (transport_ == target->transport_) {
183 return true;
184 }
185
186 // Run through all channels and remove any non-rtp transport channels before
187 // setting target transport channels.
188 for (ChannelMap::const_iterator iter = channels_.begin();
189 iter != channels_.end(); ++iter) {
190 if (!target->transport_->get()->HasChannel(iter->first)) {
191 // Remove if channel doesn't exist in |transport_|.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000192 ReplaceChannelImpl(iter->second, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 } else {
194 // Replace the impl for all the TransportProxyChannels with the channels
195 // from |target|'s transport. Fail if there's not an exact match.
decurtis@webrtc.org357469d2015-01-15 22:53:49 +0000196 ReplaceChannelImpl(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197 iter->second, target->transport_->get()->CreateChannel(iter->first));
198 }
199 }
200
201 // Now replace our transport. Must happen afterwards because
202 // it deletes all impls as a side effect.
203 transport_ = target->transport_;
204 transport_->get()->SignalCandidatesReady.connect(
205 this, &TransportProxy::OnTransportCandidatesReady);
206 set_candidates_allocated(target->candidates_allocated());
207 return true;
208}
209
210void TransportProxy::SetIceRole(IceRole role) {
211 transport_->get()->SetIceRole(role);
212}
213
214bool TransportProxy::SetLocalTransportDescription(
215 const TransportDescription& description,
216 ContentAction action,
217 std::string* error_desc) {
218 // If this is an answer, finalize the negotiation.
219 if (action == CA_ANSWER) {
220 CompleteNegotiation();
221 }
222 bool result = transport_->get()->SetLocalTransportDescription(description,
223 action,
224 error_desc);
225 if (result)
226 local_description_set_ = true;
227 return result;
228}
229
230bool TransportProxy::SetRemoteTransportDescription(
231 const TransportDescription& description,
232 ContentAction action,
233 std::string* error_desc) {
234 // If this is an answer, finalize the negotiation.
235 if (action == CA_ANSWER) {
236 CompleteNegotiation();
237 }
238 bool result = transport_->get()->SetRemoteTransportDescription(description,
239 action,
240 error_desc);
241 if (result)
242 remote_description_set_ = true;
243 return result;
244}
245
246void TransportProxy::OnSignalingReady() {
247 // If we're starting a new allocation sequence, reset our state.
248 set_candidates_allocated(false);
249 transport_->get()->OnSignalingReady();
250}
251
252bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
253 std::string* error) {
254 // Ensure the transport is negotiated before handling candidates.
255 // TODO(juberti): Remove this once everybody calls SetLocalTD.
256 CompleteNegotiation();
257
Donald Curtisd4f769d2015-05-28 09:48:21 -0700258 // Ignore candidates for if the proxy content_name doesn't match the content
259 // name of the actual transport. This stops video candidates from being sent
260 // down to the audio transport when BUNDLE is enabled.
261 if (content_name_ != transport_->get()->content_name()) {
262 return true;
263 }
264
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000265 // Verify each candidate before passing down to transport layer.
266 for (Candidates::const_iterator cand = candidates.begin();
267 cand != candidates.end(); ++cand) {
268 if (!transport_->get()->VerifyCandidate(*cand, error))
269 return false;
270 if (!HasChannel(cand->component())) {
271 *error = "Candidate has unknown component: " + cand->ToString() +
272 " for content: " + content_name_;
273 return false;
274 }
275 }
276 transport_->get()->OnRemoteCandidates(candidates);
277 return true;
278}
279
280void TransportProxy::SetIdentity(
281 rtc::SSLIdentity* identity) {
282 transport_->get()->SetIdentity(identity);
283}
284
285std::string BaseSession::StateToString(State state) {
286 switch (state) {
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000287 case STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000288 return "STATE_INIT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000289 case STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000290 return "STATE_SENTINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000291 case STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000293 case STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000294 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000295 case STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296 return "STATE_SENTACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000297 case STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000299 case STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000300 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000301 case STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000302 return "STATE_SENTMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000303 case STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000305 case STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 return "STATE_SENTREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000307 case STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000308 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000309 case STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000310 return "STATE_SENTREDIRECT";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000311 case STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000312 return "STATE_SENTTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000313 case STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000315 case STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 return "STATE_INPROGRESS";
pthatcher@webrtc.orgaacc2342014-12-18 20:31:29 +0000317 case STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 return "STATE_DEINIT";
319 default:
320 break;
321 }
322 return "STATE_" + rtc::ToString(state);
323}
324
325BaseSession::BaseSession(rtc::Thread* signaling_thread,
326 rtc::Thread* worker_thread,
327 PortAllocator* port_allocator,
328 const std::string& sid,
329 const std::string& content_type,
330 bool initiator)
331 : state_(STATE_INIT),
332 error_(ERROR_NONE),
333 signaling_thread_(signaling_thread),
334 worker_thread_(worker_thread),
335 port_allocator_(port_allocator),
336 sid_(sid),
337 content_type_(content_type),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 initiator_(initiator),
339 identity_(NULL),
Joachim Bauch04e5b492015-05-29 09:40:39 +0200340 ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000341 ice_tiebreaker_(rtc::CreateRandomId64()),
honghaiz90099622015-07-13 12:19:33 -0700342 role_switch_(false),
343 ice_receiving_timeout_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 ASSERT(signaling_thread->IsCurrent());
345}
346
347BaseSession::~BaseSession() {
348 ASSERT(signaling_thread()->IsCurrent());
349
350 ASSERT(state_ != STATE_DEINIT);
351 LogState(state_, STATE_DEINIT);
352 state_ = STATE_DEINIT;
353 SignalState(this, state_);
354
355 for (TransportMap::iterator iter = transports_.begin();
356 iter != transports_.end(); ++iter) {
357 delete iter->second;
358 }
359}
360
361const SessionDescription* BaseSession::local_description() const {
362 // TODO(tommi): Assert on thread correctness.
363 return local_description_.get();
364}
365
366const SessionDescription* BaseSession::remote_description() const {
367 // TODO(tommi): Assert on thread correctness.
368 return remote_description_.get();
369}
370
371SessionDescription* BaseSession::remote_description() {
372 // TODO(tommi): Assert on thread correctness.
373 return remote_description_.get();
374}
375
376void BaseSession::set_local_description(const SessionDescription* sdesc) {
377 // TODO(tommi): Assert on thread correctness.
378 if (sdesc != local_description_.get())
379 local_description_.reset(sdesc);
380}
381
382void BaseSession::set_remote_description(SessionDescription* sdesc) {
383 // TODO(tommi): Assert on thread correctness.
384 if (sdesc != remote_description_)
385 remote_description_.reset(sdesc);
386}
387
388const SessionDescription* BaseSession::initiator_description() const {
389 // TODO(tommi): Assert on thread correctness.
390 return initiator_ ? local_description_.get() : remote_description_.get();
391}
392
393bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
394 if (identity_)
395 return false;
396 identity_ = identity;
397 for (TransportMap::iterator iter = transports_.begin();
398 iter != transports_.end(); ++iter) {
399 iter->second->SetIdentity(identity_);
400 }
401 return true;
402}
403
Joachim Bauch04e5b492015-05-29 09:40:39 +0200404bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
405 if (state_ != STATE_INIT) {
406 return false;
407 }
408
409 ssl_max_version_ = version;
410 return true;
411}
412
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413bool BaseSession::PushdownTransportDescription(ContentSource source,
414 ContentAction action,
415 std::string* error_desc) {
416 if (source == CS_LOCAL) {
417 return PushdownLocalTransportDescription(local_description(),
418 action,
419 error_desc);
420 }
421 return PushdownRemoteTransportDescription(remote_description(),
422 action,
423 error_desc);
424}
425
426bool BaseSession::PushdownLocalTransportDescription(
427 const SessionDescription* sdesc,
428 ContentAction action,
429 std::string* error_desc) {
430 // Update the Transports with the right information, and trigger them to
431 // start connecting.
432 for (TransportMap::iterator iter = transports_.begin();
433 iter != transports_.end(); ++iter) {
434 // If no transport info was in this session description, ret == false
435 // and we just skip this one.
436 TransportDescription tdesc;
437 bool ret = GetTransportDescription(
438 sdesc, iter->second->content_name(), &tdesc);
439 if (ret) {
440 if (!iter->second->SetLocalTransportDescription(tdesc, action,
441 error_desc)) {
442 return false;
443 }
444
445 iter->second->ConnectChannels();
446 }
447 }
448
449 return true;
450}
451
452bool BaseSession::PushdownRemoteTransportDescription(
453 const SessionDescription* sdesc,
454 ContentAction action,
455 std::string* error_desc) {
456 // Update the Transports with the right information.
457 for (TransportMap::iterator iter = transports_.begin();
458 iter != transports_.end(); ++iter) {
459 TransportDescription tdesc;
460
461 // If no transport info was in this session description, ret == false
462 // and we just skip this one.
463 bool ret = GetTransportDescription(
464 sdesc, iter->second->content_name(), &tdesc);
465 if (ret) {
466 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
467 error_desc)) {
468 return false;
469 }
470 }
471 }
472
473 return true;
474}
475
honghaiz90099622015-07-13 12:19:33 -0700476void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) {
477 ice_receiving_timeout_ = timeout_ms;
478 for (const auto& kv : transport_proxies()) {
479 Transport* transport = kv.second->impl();
480 if (transport) {
481 transport->SetChannelReceivingTimeout(timeout_ms);
482 }
483 }
484}
485
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000486TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487 int component) {
488 // We create the proxy "on demand" here because we need to support
489 // creating channels at any time, even before we send or receive
490 // initiate messages, which is before we create the transports.
491 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000492 return transproxy->CreateChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493}
494
495TransportChannel* BaseSession::GetChannel(const std::string& content_name,
496 int component) {
497 TransportProxy* transproxy = GetTransportProxy(content_name);
498 if (transproxy == NULL)
499 return NULL;
500
501 return transproxy->GetChannel(component);
502}
503
504void BaseSession::DestroyChannel(const std::string& content_name,
505 int component) {
506 TransportProxy* transproxy = GetTransportProxy(content_name);
507 ASSERT(transproxy != NULL);
508 transproxy->DestroyChannel(component);
509}
510
511TransportProxy* BaseSession::GetOrCreateTransportProxy(
512 const std::string& content_name) {
513 TransportProxy* transproxy = GetTransportProxy(content_name);
514 if (transproxy)
515 return transproxy;
516
517 Transport* transport = CreateTransport(content_name);
518 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
519 transport->SetIceTiebreaker(ice_tiebreaker_);
Joachim Bauch04e5b492015-05-29 09:40:39 +0200520 transport->SetSslMaxProtocolVersion(ssl_max_version_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000521 // TODO: Connect all the Transport signals to TransportProxy
522 // then to the BaseSession.
523 transport->SignalConnecting.connect(
524 this, &BaseSession::OnTransportConnecting);
525 transport->SignalWritableState.connect(
526 this, &BaseSession::OnTransportWritable);
Peter Thatcher54360512015-07-08 11:08:35 -0700527 transport->SignalReceivingState.connect(
528 this, &BaseSession::OnTransportReceiving);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000529 transport->SignalRequestSignaling.connect(
530 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000531 transport->SignalRouteChange.connect(
532 this, &BaseSession::OnTransportRouteChange);
533 transport->SignalCandidatesAllocationDone.connect(
534 this, &BaseSession::OnTransportCandidatesAllocationDone);
535 transport->SignalRoleConflict.connect(
536 this, &BaseSession::OnRoleConflict);
537 transport->SignalCompleted.connect(
538 this, &BaseSession::OnTransportCompleted);
539 transport->SignalFailed.connect(
540 this, &BaseSession::OnTransportFailed);
541
542 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
543 new TransportWrapper(transport));
544 transproxy->SignalCandidatesReady.connect(
545 this, &BaseSession::OnTransportProxyCandidatesReady);
546 if (identity_)
547 transproxy->SetIdentity(identity_);
548 transports_[content_name] = transproxy;
549
550 return transproxy;
551}
552
553Transport* BaseSession::GetTransport(const std::string& content_name) {
554 TransportProxy* transproxy = GetTransportProxy(content_name);
555 if (transproxy == NULL)
556 return NULL;
557 return transproxy->impl();
558}
559
560TransportProxy* BaseSession::GetTransportProxy(
561 const std::string& content_name) {
562 TransportMap::iterator iter = transports_.find(content_name);
563 return (iter != transports_.end()) ? iter->second : NULL;
564}
565
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000566void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 const std::string& content_name) {
568 TransportMap::iterator iter = transports_.find(content_name);
569 if (iter != transports_.end()) {
570 delete iter->second;
571 transports_.erase(content_name);
572 }
573}
574
honghaiz90099622015-07-13 12:19:33 -0700575Transport* BaseSession::CreateTransport(const std::string& content_name) {
honghaiz90099622015-07-13 12:19:33 -0700576 Transport* transport = new DtlsTransport<P2PTransport>(
577 signaling_thread(), worker_thread(), content_name, port_allocator(),
578 identity_);
579 transport->SetChannelReceivingTimeout(ice_receiving_timeout_);
580 return transport;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581}
582
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000583void BaseSession::SetState(State state) {
584 ASSERT(signaling_thread_->IsCurrent());
585 if (state != state_) {
586 LogState(state_, state);
587 state_ = state;
588 SignalState(this, state_);
589 signaling_thread_->Post(this, MSG_STATE);
590 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591}
592
593void BaseSession::SetError(Error error, const std::string& error_desc) {
594 ASSERT(signaling_thread_->IsCurrent());
595 if (error != error_) {
596 error_ = error;
597 error_desc_ = error_desc;
598 SignalError(this, error);
599 }
600}
601
602void BaseSession::OnSignalingReady() {
603 ASSERT(signaling_thread()->IsCurrent());
604 for (TransportMap::iterator iter = transports_.begin();
605 iter != transports_.end(); ++iter) {
606 iter->second->OnSignalingReady();
607 }
608}
609
610// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
611// start, remove this method once everyone calls PushdownLocalTD.
612void BaseSession::SpeculativelyConnectAllTransportChannels() {
613 // Put all transports into the connecting state.
614 for (TransportMap::iterator iter = transports_.begin();
615 iter != transports_.end(); ++iter) {
616 iter->second->ConnectChannels();
617 }
618}
619
620bool BaseSession::OnRemoteCandidates(const std::string& content_name,
621 const Candidates& candidates,
622 std::string* error) {
623 // Give candidates to the appropriate transport, and tell that transport
624 // to start connecting, if it's not already doing so.
625 TransportProxy* transproxy = GetTransportProxy(content_name);
626 if (!transproxy) {
627 *error = "Unknown content name " + content_name;
628 return false;
629 }
630 if (!transproxy->OnRemoteCandidates(candidates, error)) {
631 return false;
632 }
633 // TODO(juberti): Remove this call once we can be sure that we always have
634 // a local transport description (which will trigger the connection).
635 transproxy->ConnectChannels();
636 return true;
637}
638
639bool BaseSession::MaybeEnableMuxingSupport() {
640 // We need both a local and remote description to decide if we should mux.
641 if ((state_ == STATE_SENTINITIATE ||
642 state_ == STATE_RECEIVEDINITIATE) &&
643 ((local_description_ == NULL) ||
644 (remote_description_ == NULL))) {
645 return false;
646 }
647
648 // In order to perform the multiplexing, we need all proxies to be in the
649 // negotiated state, i.e. to have implementations underneath.
650 // Ensure that this is the case, regardless of whether we are going to mux.
651 for (TransportMap::iterator iter = transports_.begin();
652 iter != transports_.end(); ++iter) {
653 ASSERT(iter->second->negotiated());
Donald Curtis0e209b02015-03-24 09:29:54 -0700654 if (!iter->second->negotiated()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000655 return false;
Donald Curtis0e209b02015-03-24 09:29:54 -0700656 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000657 }
658
659 // If both sides agree to BUNDLE, mux all the specified contents onto the
660 // transport belonging to the first content name in the BUNDLE group.
661 // If the contents are already muxed, this will be a no-op.
662 // TODO(juberti): Should this check that local and remote have configured
663 // BUNDLE the same way?
664 bool candidates_allocated = IsCandidateAllocationDone();
665 const ContentGroup* local_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700666 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000667 const ContentGroup* remote_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700668 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
669 if (local_bundle_group && remote_bundle_group) {
670 if (!BundleContentGroup(local_bundle_group)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000671 LOG(LS_WARNING) << "Failed to set up BUNDLE";
672 return false;
673 }
674
675 // If we weren't done gathering before, we might be done now, as a result
676 // of enabling mux.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677 if (!candidates_allocated) {
678 MaybeCandidateAllocationDone();
679 }
680 } else {
Donald Curtis0e209b02015-03-24 09:29:54 -0700681 LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682 }
683 return true;
684}
685
Donald Curtis0e209b02015-03-24 09:29:54 -0700686bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
687 const std::string* content_name = bundle_group->FirstContentName();
688 if (!content_name) {
689 LOG(LS_INFO) << "No content names specified in BUNDLE group.";
690 return true;
691 }
692
Donald Curtis0e209b02015-03-24 09:29:54 -0700693 TransportProxy* selected_proxy = GetTransportProxy(*content_name);
694 if (!selected_proxy) {
695 LOG(LS_WARNING) << "No transport found for content \""
696 << *content_name << "\".";
697 return false;
698 }
699
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000700 for (TransportMap::iterator iter = transports_.begin();
701 iter != transports_.end(); ++iter) {
702 // If content is part of the mux group, then repoint its proxy at the
703 // transport object that we have chosen to mux onto. If the proxy
704 // is already pointing at the right object, it will be a no-op.
Donald Curtis0e209b02015-03-24 09:29:54 -0700705 if (bundle_group->HasContentName(iter->first) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 !iter->second->SetupMux(selected_proxy)) {
Donald Curtis0e209b02015-03-24 09:29:54 -0700707 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
708 << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000709 return false;
710 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700711 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000712 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700713
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000714 return true;
715}
716
717void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
718 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
719 // TransportProxy should receive the done signal directly, set its allocated
720 // flag internally, and then reissue the done signal to Session.
721 // Overall we should make TransportProxy receive *all* the signals from
722 // Transport, since this removes the need to manually iterate over all
723 // the transports, as is needed to make sure signals are handled properly
724 // when BUNDLEing.
725 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
726 // that make it prohibitively difficult to run dbg builds. Disabled for now.
727 //ASSERT(!IsCandidateAllocationDone());
728 for (TransportMap::iterator iter = transports_.begin();
729 iter != transports_.end(); ++iter) {
730 if (iter->second->impl() == transport) {
731 iter->second->set_candidates_allocated(true);
732 }
733 }
734 MaybeCandidateAllocationDone();
735}
736
737bool BaseSession::IsCandidateAllocationDone() const {
738 for (TransportMap::const_iterator iter = transports_.begin();
739 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000740 if (!iter->second->candidates_allocated()) {
741 LOG(LS_INFO) << "Candidate allocation not done for "
742 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000743 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000744 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000745 }
746 return true;
747}
748
749void BaseSession::MaybeCandidateAllocationDone() {
750 if (IsCandidateAllocationDone()) {
751 LOG(LS_INFO) << "Candidate gathering is complete.";
752 OnCandidatesAllocationDone();
753 }
754}
755
756void BaseSession::OnRoleConflict() {
757 if (role_switch_) {
758 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
759 return;
760 }
761
762 role_switch_ = true;
763 for (TransportMap::iterator iter = transports_.begin();
764 iter != transports_.end(); ++iter) {
765 // Role will be reverse of initial role setting.
766 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
767 iter->second->SetIceRole(role);
768 }
769}
770
771void BaseSession::LogState(State old_state, State new_state) {
772 LOG(LS_INFO) << "Session:" << id()
773 << " Old state:" << StateToString(old_state)
774 << " New state:" << StateToString(new_state)
Peter Thatcher2159b892015-08-21 20:46:05 -0700775 << " Type:" << content_type();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000776}
777
778// static
779bool BaseSession::GetTransportDescription(const SessionDescription* description,
780 const std::string& content_name,
781 TransportDescription* tdesc) {
782 if (!description || !tdesc) {
783 return false;
784 }
785 const TransportInfo* transport_info =
786 description->GetTransportInfoByName(content_name);
787 if (!transport_info) {
788 return false;
789 }
790 *tdesc = transport_info->description;
791 return true;
792}
793
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000794void BaseSession::OnMessage(rtc::Message *pmsg) {
795 switch (pmsg->message_id) {
796 case MSG_TIMEOUT:
797 // Session timeout has occured.
798 SetError(ERROR_TIME, "Session timeout has occured.");
799 break;
800
801 case MSG_STATE:
802 switch (state_) {
803 case STATE_SENTACCEPT:
804 case STATE_RECEIVEDACCEPT:
805 SetState(STATE_INPROGRESS);
806 break;
807
808 default:
809 // Explicitly ignoring some states here.
810 break;
811 }
812 break;
813 }
814}
815
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000816} // namespace cricket