blob: 55b1d90c1a811563a69f9793ae04fff1f6886054 [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);
Peter Thatcher54360512015-07-08 11:08:35 -0700521 transport->SignalReceivingState.connect(
522 this, &BaseSession::OnTransportReceiving);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000523 transport->SignalRequestSignaling.connect(
524 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525 transport->SignalRouteChange.connect(
526 this, &BaseSession::OnTransportRouteChange);
527 transport->SignalCandidatesAllocationDone.connect(
528 this, &BaseSession::OnTransportCandidatesAllocationDone);
529 transport->SignalRoleConflict.connect(
530 this, &BaseSession::OnRoleConflict);
531 transport->SignalCompleted.connect(
532 this, &BaseSession::OnTransportCompleted);
533 transport->SignalFailed.connect(
534 this, &BaseSession::OnTransportFailed);
535
536 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
537 new TransportWrapper(transport));
538 transproxy->SignalCandidatesReady.connect(
539 this, &BaseSession::OnTransportProxyCandidatesReady);
540 if (identity_)
541 transproxy->SetIdentity(identity_);
542 transports_[content_name] = transproxy;
543
544 return transproxy;
545}
546
547Transport* BaseSession::GetTransport(const std::string& content_name) {
548 TransportProxy* transproxy = GetTransportProxy(content_name);
549 if (transproxy == NULL)
550 return NULL;
551 return transproxy->impl();
552}
553
554TransportProxy* BaseSession::GetTransportProxy(
555 const std::string& content_name) {
556 TransportMap::iterator iter = transports_.find(content_name);
557 return (iter != transports_.end()) ? iter->second : NULL;
558}
559
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000560void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000561 const std::string& content_name) {
562 TransportMap::iterator iter = transports_.find(content_name);
563 if (iter != transports_.end()) {
564 delete iter->second;
565 transports_.erase(content_name);
566 }
567}
568
569cricket::Transport* BaseSession::CreateTransport(
570 const std::string& content_name) {
571 ASSERT(transport_type_ == NS_GINGLE_P2P);
572 return new cricket::DtlsTransport<P2PTransport>(
573 signaling_thread(), worker_thread(), content_name,
574 port_allocator(), identity_);
575}
576
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000577void BaseSession::SetState(State state) {
578 ASSERT(signaling_thread_->IsCurrent());
579 if (state != state_) {
580 LogState(state_, state);
581 state_ = state;
582 SignalState(this, state_);
583 signaling_thread_->Post(this, MSG_STATE);
584 }
585 SignalNewDescription();
586}
587
588void BaseSession::SetError(Error error, const std::string& error_desc) {
589 ASSERT(signaling_thread_->IsCurrent());
590 if (error != error_) {
591 error_ = error;
592 error_desc_ = error_desc;
593 SignalError(this, error);
594 }
595}
596
597void BaseSession::OnSignalingReady() {
598 ASSERT(signaling_thread()->IsCurrent());
599 for (TransportMap::iterator iter = transports_.begin();
600 iter != transports_.end(); ++iter) {
601 iter->second->OnSignalingReady();
602 }
603}
604
605// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
606// start, remove this method once everyone calls PushdownLocalTD.
607void BaseSession::SpeculativelyConnectAllTransportChannels() {
608 // Put all transports into the connecting state.
609 for (TransportMap::iterator iter = transports_.begin();
610 iter != transports_.end(); ++iter) {
611 iter->second->ConnectChannels();
612 }
613}
614
615bool BaseSession::OnRemoteCandidates(const std::string& content_name,
616 const Candidates& candidates,
617 std::string* error) {
618 // Give candidates to the appropriate transport, and tell that transport
619 // to start connecting, if it's not already doing so.
620 TransportProxy* transproxy = GetTransportProxy(content_name);
621 if (!transproxy) {
622 *error = "Unknown content name " + content_name;
623 return false;
624 }
625 if (!transproxy->OnRemoteCandidates(candidates, error)) {
626 return false;
627 }
628 // TODO(juberti): Remove this call once we can be sure that we always have
629 // a local transport description (which will trigger the connection).
630 transproxy->ConnectChannels();
631 return true;
632}
633
634bool BaseSession::MaybeEnableMuxingSupport() {
635 // We need both a local and remote description to decide if we should mux.
636 if ((state_ == STATE_SENTINITIATE ||
637 state_ == STATE_RECEIVEDINITIATE) &&
638 ((local_description_ == NULL) ||
639 (remote_description_ == NULL))) {
640 return false;
641 }
642
643 // In order to perform the multiplexing, we need all proxies to be in the
644 // negotiated state, i.e. to have implementations underneath.
645 // Ensure that this is the case, regardless of whether we are going to mux.
646 for (TransportMap::iterator iter = transports_.begin();
647 iter != transports_.end(); ++iter) {
648 ASSERT(iter->second->negotiated());
Donald Curtis0e209b02015-03-24 09:29:54 -0700649 if (!iter->second->negotiated()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000650 return false;
Donald Curtis0e209b02015-03-24 09:29:54 -0700651 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000652 }
653
654 // If both sides agree to BUNDLE, mux all the specified contents onto the
655 // transport belonging to the first content name in the BUNDLE group.
656 // If the contents are already muxed, this will be a no-op.
657 // TODO(juberti): Should this check that local and remote have configured
658 // BUNDLE the same way?
659 bool candidates_allocated = IsCandidateAllocationDone();
660 const ContentGroup* local_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700661 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000662 const ContentGroup* remote_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700663 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
664 if (local_bundle_group && remote_bundle_group) {
665 if (!BundleContentGroup(local_bundle_group)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666 LOG(LS_WARNING) << "Failed to set up BUNDLE";
667 return false;
668 }
669
670 // If we weren't done gathering before, we might be done now, as a result
671 // of enabling mux.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000672 if (!candidates_allocated) {
673 MaybeCandidateAllocationDone();
674 }
675 } else {
Donald Curtis0e209b02015-03-24 09:29:54 -0700676 LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677 }
678 return true;
679}
680
Donald Curtis0e209b02015-03-24 09:29:54 -0700681bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
682 const std::string* content_name = bundle_group->FirstContentName();
683 if (!content_name) {
684 LOG(LS_INFO) << "No content names specified in BUNDLE group.";
685 return true;
686 }
687
Donald Curtis0e209b02015-03-24 09:29:54 -0700688 TransportProxy* selected_proxy = GetTransportProxy(*content_name);
689 if (!selected_proxy) {
690 LOG(LS_WARNING) << "No transport found for content \""
691 << *content_name << "\".";
692 return false;
693 }
694
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000695 for (TransportMap::iterator iter = transports_.begin();
696 iter != transports_.end(); ++iter) {
697 // If content is part of the mux group, then repoint its proxy at the
698 // transport object that we have chosen to mux onto. If the proxy
699 // is already pointing at the right object, it will be a no-op.
Donald Curtis0e209b02015-03-24 09:29:54 -0700700 if (bundle_group->HasContentName(iter->first) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000701 !iter->second->SetupMux(selected_proxy)) {
Donald Curtis0e209b02015-03-24 09:29:54 -0700702 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
703 << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704 return false;
705 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700706 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000707 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700708
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000709 return true;
710}
711
712void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
713 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
714 // TransportProxy should receive the done signal directly, set its allocated
715 // flag internally, and then reissue the done signal to Session.
716 // Overall we should make TransportProxy receive *all* the signals from
717 // Transport, since this removes the need to manually iterate over all
718 // the transports, as is needed to make sure signals are handled properly
719 // when BUNDLEing.
720 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
721 // that make it prohibitively difficult to run dbg builds. Disabled for now.
722 //ASSERT(!IsCandidateAllocationDone());
723 for (TransportMap::iterator iter = transports_.begin();
724 iter != transports_.end(); ++iter) {
725 if (iter->second->impl() == transport) {
726 iter->second->set_candidates_allocated(true);
727 }
728 }
729 MaybeCandidateAllocationDone();
730}
731
732bool BaseSession::IsCandidateAllocationDone() const {
733 for (TransportMap::const_iterator iter = transports_.begin();
734 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000735 if (!iter->second->candidates_allocated()) {
736 LOG(LS_INFO) << "Candidate allocation not done for "
737 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000738 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000739 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 }
741 return true;
742}
743
744void BaseSession::MaybeCandidateAllocationDone() {
745 if (IsCandidateAllocationDone()) {
746 LOG(LS_INFO) << "Candidate gathering is complete.";
747 OnCandidatesAllocationDone();
748 }
749}
750
751void BaseSession::OnRoleConflict() {
752 if (role_switch_) {
753 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
754 return;
755 }
756
757 role_switch_ = true;
758 for (TransportMap::iterator iter = transports_.begin();
759 iter != transports_.end(); ++iter) {
760 // Role will be reverse of initial role setting.
761 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
762 iter->second->SetIceRole(role);
763 }
764}
765
766void BaseSession::LogState(State old_state, State new_state) {
767 LOG(LS_INFO) << "Session:" << id()
768 << " Old state:" << StateToString(old_state)
769 << " New state:" << StateToString(new_state)
770 << " Type:" << content_type()
771 << " Transport:" << transport_type();
772}
773
774// static
775bool BaseSession::GetTransportDescription(const SessionDescription* description,
776 const std::string& content_name,
777 TransportDescription* tdesc) {
778 if (!description || !tdesc) {
779 return false;
780 }
781 const TransportInfo* transport_info =
782 description->GetTransportInfoByName(content_name);
783 if (!transport_info) {
784 return false;
785 }
786 *tdesc = transport_info->description;
787 return true;
788}
789
790void BaseSession::SignalNewDescription() {
791 ContentAction action;
792 ContentSource source;
793 if (!GetContentAction(&action, &source)) {
794 return;
795 }
796 if (source == CS_LOCAL) {
797 SignalNewLocalDescription(this, action);
798 } else {
799 SignalNewRemoteDescription(this, action);
800 }
801}
802
803bool BaseSession::GetContentAction(ContentAction* action,
804 ContentSource* source) {
805 switch (state_) {
806 // new local description
807 case STATE_SENTINITIATE:
808 *action = CA_OFFER;
809 *source = CS_LOCAL;
810 break;
811 case STATE_SENTPRACCEPT:
812 *action = CA_PRANSWER;
813 *source = CS_LOCAL;
814 break;
815 case STATE_SENTACCEPT:
816 *action = CA_ANSWER;
817 *source = CS_LOCAL;
818 break;
819 // new remote description
820 case STATE_RECEIVEDINITIATE:
821 *action = CA_OFFER;
822 *source = CS_REMOTE;
823 break;
824 case STATE_RECEIVEDPRACCEPT:
825 *action = CA_PRANSWER;
826 *source = CS_REMOTE;
827 break;
828 case STATE_RECEIVEDACCEPT:
829 *action = CA_ANSWER;
830 *source = CS_REMOTE;
831 break;
832 default:
833 return false;
834 }
835 return true;
836}
837
838void BaseSession::OnMessage(rtc::Message *pmsg) {
839 switch (pmsg->message_id) {
840 case MSG_TIMEOUT:
841 // Session timeout has occured.
842 SetError(ERROR_TIME, "Session timeout has occured.");
843 break;
844
845 case MSG_STATE:
846 switch (state_) {
847 case STATE_SENTACCEPT:
848 case STATE_RECEIVEDACCEPT:
849 SetState(STATE_INPROGRESS);
850 break;
851
852 default:
853 // Explicitly ignoring some states here.
854 break;
855 }
856 break;
857 }
858}
859
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000860} // namespace cricket