blob: d1f6e54a0abc8f25c4e5546a4ba91c0d27d90edf [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),
Joachim Bauch04e5b492015-05-29 09:40:39 +0200345 ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 ice_tiebreaker_(rtc::CreateRandomId64()),
347 role_switch_(false) {
348 ASSERT(signaling_thread->IsCurrent());
349}
350
351BaseSession::~BaseSession() {
352 ASSERT(signaling_thread()->IsCurrent());
353
354 ASSERT(state_ != STATE_DEINIT);
355 LogState(state_, STATE_DEINIT);
356 state_ = STATE_DEINIT;
357 SignalState(this, state_);
358
359 for (TransportMap::iterator iter = transports_.begin();
360 iter != transports_.end(); ++iter) {
361 delete iter->second;
362 }
363}
364
365const SessionDescription* BaseSession::local_description() const {
366 // TODO(tommi): Assert on thread correctness.
367 return local_description_.get();
368}
369
370const SessionDescription* BaseSession::remote_description() const {
371 // TODO(tommi): Assert on thread correctness.
372 return remote_description_.get();
373}
374
375SessionDescription* BaseSession::remote_description() {
376 // TODO(tommi): Assert on thread correctness.
377 return remote_description_.get();
378}
379
380void BaseSession::set_local_description(const SessionDescription* sdesc) {
381 // TODO(tommi): Assert on thread correctness.
382 if (sdesc != local_description_.get())
383 local_description_.reset(sdesc);
384}
385
386void BaseSession::set_remote_description(SessionDescription* sdesc) {
387 // TODO(tommi): Assert on thread correctness.
388 if (sdesc != remote_description_)
389 remote_description_.reset(sdesc);
390}
391
392const SessionDescription* BaseSession::initiator_description() const {
393 // TODO(tommi): Assert on thread correctness.
394 return initiator_ ? local_description_.get() : remote_description_.get();
395}
396
397bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
398 if (identity_)
399 return false;
400 identity_ = identity;
401 for (TransportMap::iterator iter = transports_.begin();
402 iter != transports_.end(); ++iter) {
403 iter->second->SetIdentity(identity_);
404 }
405 return true;
406}
407
Joachim Bauch04e5b492015-05-29 09:40:39 +0200408bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
409 if (state_ != STATE_INIT) {
410 return false;
411 }
412
413 ssl_max_version_ = version;
414 return true;
415}
416
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000417bool BaseSession::PushdownTransportDescription(ContentSource source,
418 ContentAction action,
419 std::string* error_desc) {
420 if (source == CS_LOCAL) {
421 return PushdownLocalTransportDescription(local_description(),
422 action,
423 error_desc);
424 }
425 return PushdownRemoteTransportDescription(remote_description(),
426 action,
427 error_desc);
428}
429
430bool BaseSession::PushdownLocalTransportDescription(
431 const SessionDescription* sdesc,
432 ContentAction action,
433 std::string* error_desc) {
434 // Update the Transports with the right information, and trigger them to
435 // start connecting.
436 for (TransportMap::iterator iter = transports_.begin();
437 iter != transports_.end(); ++iter) {
438 // If no transport info was in this session description, ret == false
439 // and we just skip this one.
440 TransportDescription tdesc;
441 bool ret = GetTransportDescription(
442 sdesc, iter->second->content_name(), &tdesc);
443 if (ret) {
444 if (!iter->second->SetLocalTransportDescription(tdesc, action,
445 error_desc)) {
446 return false;
447 }
448
449 iter->second->ConnectChannels();
450 }
451 }
452
453 return true;
454}
455
456bool BaseSession::PushdownRemoteTransportDescription(
457 const SessionDescription* sdesc,
458 ContentAction action,
459 std::string* error_desc) {
460 // Update the Transports with the right information.
461 for (TransportMap::iterator iter = transports_.begin();
462 iter != transports_.end(); ++iter) {
463 TransportDescription tdesc;
464
465 // If no transport info was in this session description, ret == false
466 // and we just skip this one.
467 bool ret = GetTransportDescription(
468 sdesc, iter->second->content_name(), &tdesc);
469 if (ret) {
470 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
471 error_desc)) {
472 return false;
473 }
474 }
475 }
476
477 return true;
478}
479
480TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000481 int component) {
482 // We create the proxy "on demand" here because we need to support
483 // creating channels at any time, even before we send or receive
484 // initiate messages, which is before we create the transports.
485 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000486 return transproxy->CreateChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487}
488
489TransportChannel* BaseSession::GetChannel(const std::string& content_name,
490 int component) {
491 TransportProxy* transproxy = GetTransportProxy(content_name);
492 if (transproxy == NULL)
493 return NULL;
494
495 return transproxy->GetChannel(component);
496}
497
498void BaseSession::DestroyChannel(const std::string& content_name,
499 int component) {
500 TransportProxy* transproxy = GetTransportProxy(content_name);
501 ASSERT(transproxy != NULL);
502 transproxy->DestroyChannel(component);
503}
504
505TransportProxy* BaseSession::GetOrCreateTransportProxy(
506 const std::string& content_name) {
507 TransportProxy* transproxy = GetTransportProxy(content_name);
508 if (transproxy)
509 return transproxy;
510
511 Transport* transport = CreateTransport(content_name);
512 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
513 transport->SetIceTiebreaker(ice_tiebreaker_);
Joachim Bauch04e5b492015-05-29 09:40:39 +0200514 transport->SetSslMaxProtocolVersion(ssl_max_version_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515 // TODO: Connect all the Transport signals to TransportProxy
516 // then to the BaseSession.
517 transport->SignalConnecting.connect(
518 this, &BaseSession::OnTransportConnecting);
519 transport->SignalWritableState.connect(
520 this, &BaseSession::OnTransportWritable);
521 transport->SignalRequestSignaling.connect(
522 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000523 transport->SignalRouteChange.connect(
524 this, &BaseSession::OnTransportRouteChange);
525 transport->SignalCandidatesAllocationDone.connect(
526 this, &BaseSession::OnTransportCandidatesAllocationDone);
527 transport->SignalRoleConflict.connect(
528 this, &BaseSession::OnRoleConflict);
529 transport->SignalCompleted.connect(
530 this, &BaseSession::OnTransportCompleted);
531 transport->SignalFailed.connect(
532 this, &BaseSession::OnTransportFailed);
533
534 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
535 new TransportWrapper(transport));
536 transproxy->SignalCandidatesReady.connect(
537 this, &BaseSession::OnTransportProxyCandidatesReady);
538 if (identity_)
539 transproxy->SetIdentity(identity_);
540 transports_[content_name] = transproxy;
541
542 return transproxy;
543}
544
545Transport* BaseSession::GetTransport(const std::string& content_name) {
546 TransportProxy* transproxy = GetTransportProxy(content_name);
547 if (transproxy == NULL)
548 return NULL;
549 return transproxy->impl();
550}
551
552TransportProxy* BaseSession::GetTransportProxy(
553 const std::string& content_name) {
554 TransportMap::iterator iter = transports_.find(content_name);
555 return (iter != transports_.end()) ? iter->second : NULL;
556}
557
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000558void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000559 const std::string& content_name) {
560 TransportMap::iterator iter = transports_.find(content_name);
561 if (iter != transports_.end()) {
562 delete iter->second;
563 transports_.erase(content_name);
564 }
565}
566
567cricket::Transport* BaseSession::CreateTransport(
568 const std::string& content_name) {
569 ASSERT(transport_type_ == NS_GINGLE_P2P);
570 return new cricket::DtlsTransport<P2PTransport>(
571 signaling_thread(), worker_thread(), content_name,
572 port_allocator(), identity_);
573}
574
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000575void BaseSession::SetState(State state) {
576 ASSERT(signaling_thread_->IsCurrent());
577 if (state != state_) {
578 LogState(state_, state);
579 state_ = state;
580 SignalState(this, state_);
581 signaling_thread_->Post(this, MSG_STATE);
582 }
583 SignalNewDescription();
584}
585
586void BaseSession::SetError(Error error, const std::string& error_desc) {
587 ASSERT(signaling_thread_->IsCurrent());
588 if (error != error_) {
589 error_ = error;
590 error_desc_ = error_desc;
591 SignalError(this, error);
592 }
593}
594
595void BaseSession::OnSignalingReady() {
596 ASSERT(signaling_thread()->IsCurrent());
597 for (TransportMap::iterator iter = transports_.begin();
598 iter != transports_.end(); ++iter) {
599 iter->second->OnSignalingReady();
600 }
601}
602
603// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
604// start, remove this method once everyone calls PushdownLocalTD.
605void BaseSession::SpeculativelyConnectAllTransportChannels() {
606 // Put all transports into the connecting state.
607 for (TransportMap::iterator iter = transports_.begin();
608 iter != transports_.end(); ++iter) {
609 iter->second->ConnectChannels();
610 }
611}
612
613bool BaseSession::OnRemoteCandidates(const std::string& content_name,
614 const Candidates& candidates,
615 std::string* error) {
616 // Give candidates to the appropriate transport, and tell that transport
617 // to start connecting, if it's not already doing so.
618 TransportProxy* transproxy = GetTransportProxy(content_name);
619 if (!transproxy) {
620 *error = "Unknown content name " + content_name;
621 return false;
622 }
623 if (!transproxy->OnRemoteCandidates(candidates, error)) {
624 return false;
625 }
626 // TODO(juberti): Remove this call once we can be sure that we always have
627 // a local transport description (which will trigger the connection).
628 transproxy->ConnectChannels();
629 return true;
630}
631
632bool BaseSession::MaybeEnableMuxingSupport() {
633 // We need both a local and remote description to decide if we should mux.
634 if ((state_ == STATE_SENTINITIATE ||
635 state_ == STATE_RECEIVEDINITIATE) &&
636 ((local_description_ == NULL) ||
637 (remote_description_ == NULL))) {
638 return false;
639 }
640
641 // In order to perform the multiplexing, we need all proxies to be in the
642 // negotiated state, i.e. to have implementations underneath.
643 // Ensure that this is the case, regardless of whether we are going to mux.
644 for (TransportMap::iterator iter = transports_.begin();
645 iter != transports_.end(); ++iter) {
646 ASSERT(iter->second->negotiated());
Donald Curtis0e209b02015-03-24 09:29:54 -0700647 if (!iter->second->negotiated()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000648 return false;
Donald Curtis0e209b02015-03-24 09:29:54 -0700649 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000650 }
651
652 // If both sides agree to BUNDLE, mux all the specified contents onto the
653 // transport belonging to the first content name in the BUNDLE group.
654 // If the contents are already muxed, this will be a no-op.
655 // TODO(juberti): Should this check that local and remote have configured
656 // BUNDLE the same way?
657 bool candidates_allocated = IsCandidateAllocationDone();
658 const ContentGroup* local_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700659 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000660 const ContentGroup* remote_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700661 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
662 if (local_bundle_group && remote_bundle_group) {
663 if (!BundleContentGroup(local_bundle_group)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 LOG(LS_WARNING) << "Failed to set up BUNDLE";
665 return false;
666 }
667
668 // If we weren't done gathering before, we might be done now, as a result
669 // of enabling mux.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000670 if (!candidates_allocated) {
671 MaybeCandidateAllocationDone();
672 }
673 } else {
Donald Curtis0e209b02015-03-24 09:29:54 -0700674 LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675 }
676 return true;
677}
678
Donald Curtis0e209b02015-03-24 09:29:54 -0700679bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
680 const std::string* content_name = bundle_group->FirstContentName();
681 if (!content_name) {
682 LOG(LS_INFO) << "No content names specified in BUNDLE group.";
683 return true;
684 }
685
Donald Curtis0e209b02015-03-24 09:29:54 -0700686 TransportProxy* selected_proxy = GetTransportProxy(*content_name);
687 if (!selected_proxy) {
688 LOG(LS_WARNING) << "No transport found for content \""
689 << *content_name << "\".";
690 return false;
691 }
692
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693 for (TransportMap::iterator iter = transports_.begin();
694 iter != transports_.end(); ++iter) {
695 // If content is part of the mux group, then repoint its proxy at the
696 // transport object that we have chosen to mux onto. If the proxy
697 // is already pointing at the right object, it will be a no-op.
Donald Curtis0e209b02015-03-24 09:29:54 -0700698 if (bundle_group->HasContentName(iter->first) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000699 !iter->second->SetupMux(selected_proxy)) {
Donald Curtis0e209b02015-03-24 09:29:54 -0700700 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
701 << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000702 return false;
703 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700704 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000705 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700706
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000707 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