blob: 5be8fd9c35983225b4fe1c32a1a08a74ab65f4bb [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
guoweisd12140a2015-09-10 13:32:11 -070040const std::string& TransportProxy::type() const {
41 return transport_->get()->type();
42}
43
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000044TransportChannel* 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
Henrik Boströmd8281982015-08-27 10:12:24 +0200284void TransportProxy::SetCertificate(
285 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
286 transport_->get()->SetCertificate(certificate);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000287}
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),
guoweisd12140a2015-09-10 13:32:11 -0700342 transport_type_(NS_GINGLE_P2P),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343 initiator_(initiator),
Joachim Bauch04e5b492015-05-29 09:40:39 +0200344 ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000345 ice_tiebreaker_(rtc::CreateRandomId64()),
honghaiz90099622015-07-13 12:19:33 -0700346 role_switch_(false),
347 ice_receiving_timeout_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000348 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
Henrik Boströmd8281982015-08-27 10:12:24 +0200397bool BaseSession::SetCertificate(
398 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
399 if (certificate_)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000400 return false;
Henrik Boströmd8281982015-08-27 10:12:24 +0200401 if (!certificate)
402 return false;
403 certificate_ = certificate;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000404 for (TransportMap::iterator iter = transports_.begin();
405 iter != transports_.end(); ++iter) {
Henrik Boströmd8281982015-08-27 10:12:24 +0200406 iter->second->SetCertificate(certificate_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 }
408 return true;
409}
410
Joachim Bauch04e5b492015-05-29 09:40:39 +0200411bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
412 if (state_ != STATE_INIT) {
413 return false;
414 }
415
416 ssl_max_version_ = version;
417 return true;
418}
419
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420bool BaseSession::PushdownTransportDescription(ContentSource source,
421 ContentAction action,
422 std::string* error_desc) {
423 if (source == CS_LOCAL) {
424 return PushdownLocalTransportDescription(local_description(),
425 action,
426 error_desc);
427 }
428 return PushdownRemoteTransportDescription(remote_description(),
429 action,
430 error_desc);
431}
432
433bool BaseSession::PushdownLocalTransportDescription(
434 const SessionDescription* sdesc,
435 ContentAction action,
436 std::string* error_desc) {
437 // Update the Transports with the right information, and trigger them to
438 // start connecting.
439 for (TransportMap::iterator iter = transports_.begin();
440 iter != transports_.end(); ++iter) {
441 // If no transport info was in this session description, ret == false
442 // and we just skip this one.
443 TransportDescription tdesc;
444 bool ret = GetTransportDescription(
445 sdesc, iter->second->content_name(), &tdesc);
446 if (ret) {
447 if (!iter->second->SetLocalTransportDescription(tdesc, action,
448 error_desc)) {
449 return false;
450 }
451
452 iter->second->ConnectChannels();
453 }
454 }
455
456 return true;
457}
458
459bool BaseSession::PushdownRemoteTransportDescription(
460 const SessionDescription* sdesc,
461 ContentAction action,
462 std::string* error_desc) {
463 // Update the Transports with the right information.
464 for (TransportMap::iterator iter = transports_.begin();
465 iter != transports_.end(); ++iter) {
466 TransportDescription tdesc;
467
468 // If no transport info was in this session description, ret == false
469 // and we just skip this one.
470 bool ret = GetTransportDescription(
471 sdesc, iter->second->content_name(), &tdesc);
472 if (ret) {
473 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
474 error_desc)) {
475 return false;
476 }
477 }
478 }
479
480 return true;
481}
482
honghaiz90099622015-07-13 12:19:33 -0700483void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) {
484 ice_receiving_timeout_ = timeout_ms;
485 for (const auto& kv : transport_proxies()) {
486 Transport* transport = kv.second->impl();
487 if (transport) {
488 transport->SetChannelReceivingTimeout(timeout_ms);
489 }
490 }
491}
492
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494 int component) {
495 // We create the proxy "on demand" here because we need to support
496 // creating channels at any time, even before we send or receive
497 // initiate messages, which is before we create the transports.
498 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000499 return transproxy->CreateChannel(component);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000500}
501
502TransportChannel* BaseSession::GetChannel(const std::string& content_name,
503 int component) {
504 TransportProxy* transproxy = GetTransportProxy(content_name);
505 if (transproxy == NULL)
506 return NULL;
507
508 return transproxy->GetChannel(component);
509}
510
511void BaseSession::DestroyChannel(const std::string& content_name,
512 int component) {
513 TransportProxy* transproxy = GetTransportProxy(content_name);
514 ASSERT(transproxy != NULL);
515 transproxy->DestroyChannel(component);
516}
517
518TransportProxy* BaseSession::GetOrCreateTransportProxy(
519 const std::string& content_name) {
520 TransportProxy* transproxy = GetTransportProxy(content_name);
521 if (transproxy)
522 return transproxy;
523
524 Transport* transport = CreateTransport(content_name);
525 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
526 transport->SetIceTiebreaker(ice_tiebreaker_);
Joachim Bauch04e5b492015-05-29 09:40:39 +0200527 transport->SetSslMaxProtocolVersion(ssl_max_version_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000528 // TODO: Connect all the Transport signals to TransportProxy
529 // then to the BaseSession.
530 transport->SignalConnecting.connect(
531 this, &BaseSession::OnTransportConnecting);
532 transport->SignalWritableState.connect(
533 this, &BaseSession::OnTransportWritable);
Peter Thatcher54360512015-07-08 11:08:35 -0700534 transport->SignalReceivingState.connect(
535 this, &BaseSession::OnTransportReceiving);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000536 transport->SignalRequestSignaling.connect(
537 this, &BaseSession::OnTransportRequestSignaling);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000538 transport->SignalRouteChange.connect(
539 this, &BaseSession::OnTransportRouteChange);
540 transport->SignalCandidatesAllocationDone.connect(
541 this, &BaseSession::OnTransportCandidatesAllocationDone);
542 transport->SignalRoleConflict.connect(
543 this, &BaseSession::OnRoleConflict);
544 transport->SignalCompleted.connect(
545 this, &BaseSession::OnTransportCompleted);
546 transport->SignalFailed.connect(
547 this, &BaseSession::OnTransportFailed);
548
549 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
550 new TransportWrapper(transport));
551 transproxy->SignalCandidatesReady.connect(
552 this, &BaseSession::OnTransportProxyCandidatesReady);
Henrik Boströmd8281982015-08-27 10:12:24 +0200553 if (certificate_)
554 transproxy->SetCertificate(certificate_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000555 transports_[content_name] = transproxy;
556
557 return transproxy;
558}
559
560Transport* BaseSession::GetTransport(const std::string& content_name) {
561 TransportProxy* transproxy = GetTransportProxy(content_name);
562 if (transproxy == NULL)
563 return NULL;
564 return transproxy->impl();
565}
566
567TransportProxy* BaseSession::GetTransportProxy(
568 const std::string& content_name) {
569 TransportMap::iterator iter = transports_.find(content_name);
570 return (iter != transports_.end()) ? iter->second : NULL;
571}
572
bjornv@webrtc.org520a69e2015-02-04 12:45:44 +0000573void BaseSession::DestroyTransportProxy(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 const std::string& content_name) {
575 TransportMap::iterator iter = transports_.find(content_name);
576 if (iter != transports_.end()) {
577 delete iter->second;
578 transports_.erase(content_name);
579 }
580}
581
honghaiz90099622015-07-13 12:19:33 -0700582Transport* BaseSession::CreateTransport(const std::string& content_name) {
guoweisd12140a2015-09-10 13:32:11 -0700583 ASSERT(transport_type_ == NS_GINGLE_P2P);
honghaiz90099622015-07-13 12:19:33 -0700584 Transport* transport = new DtlsTransport<P2PTransport>(
585 signaling_thread(), worker_thread(), content_name, port_allocator(),
Henrik Boströmd8281982015-08-27 10:12:24 +0200586 certificate_);
honghaiz90099622015-07-13 12:19:33 -0700587 transport->SetChannelReceivingTimeout(ice_receiving_timeout_);
588 return transport;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000589}
590
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591void BaseSession::SetState(State state) {
592 ASSERT(signaling_thread_->IsCurrent());
593 if (state != state_) {
594 LogState(state_, state);
595 state_ = state;
596 SignalState(this, state_);
597 signaling_thread_->Post(this, MSG_STATE);
598 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599}
600
601void BaseSession::SetError(Error error, const std::string& error_desc) {
602 ASSERT(signaling_thread_->IsCurrent());
603 if (error != error_) {
604 error_ = error;
605 error_desc_ = error_desc;
606 SignalError(this, error);
607 }
608}
609
610void BaseSession::OnSignalingReady() {
611 ASSERT(signaling_thread()->IsCurrent());
612 for (TransportMap::iterator iter = transports_.begin();
613 iter != transports_.end(); ++iter) {
614 iter->second->OnSignalingReady();
615 }
616}
617
618// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
619// start, remove this method once everyone calls PushdownLocalTD.
620void BaseSession::SpeculativelyConnectAllTransportChannels() {
621 // Put all transports into the connecting state.
622 for (TransportMap::iterator iter = transports_.begin();
623 iter != transports_.end(); ++iter) {
624 iter->second->ConnectChannels();
625 }
626}
627
628bool BaseSession::OnRemoteCandidates(const std::string& content_name,
629 const Candidates& candidates,
630 std::string* error) {
631 // Give candidates to the appropriate transport, and tell that transport
632 // to start connecting, if it's not already doing so.
633 TransportProxy* transproxy = GetTransportProxy(content_name);
634 if (!transproxy) {
635 *error = "Unknown content name " + content_name;
636 return false;
637 }
638 if (!transproxy->OnRemoteCandidates(candidates, error)) {
639 return false;
640 }
641 // TODO(juberti): Remove this call once we can be sure that we always have
642 // a local transport description (which will trigger the connection).
643 transproxy->ConnectChannels();
644 return true;
645}
646
647bool BaseSession::MaybeEnableMuxingSupport() {
648 // We need both a local and remote description to decide if we should mux.
649 if ((state_ == STATE_SENTINITIATE ||
650 state_ == STATE_RECEIVEDINITIATE) &&
651 ((local_description_ == NULL) ||
652 (remote_description_ == NULL))) {
653 return false;
654 }
655
656 // In order to perform the multiplexing, we need all proxies to be in the
657 // negotiated state, i.e. to have implementations underneath.
658 // Ensure that this is the case, regardless of whether we are going to mux.
659 for (TransportMap::iterator iter = transports_.begin();
660 iter != transports_.end(); ++iter) {
661 ASSERT(iter->second->negotiated());
Donald Curtis0e209b02015-03-24 09:29:54 -0700662 if (!iter->second->negotiated()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000663 return false;
Donald Curtis0e209b02015-03-24 09:29:54 -0700664 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000665 }
666
667 // If both sides agree to BUNDLE, mux all the specified contents onto the
668 // transport belonging to the first content name in the BUNDLE group.
669 // If the contents are already muxed, this will be a no-op.
670 // TODO(juberti): Should this check that local and remote have configured
671 // BUNDLE the same way?
672 bool candidates_allocated = IsCandidateAllocationDone();
673 const ContentGroup* local_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700674 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675 const ContentGroup* remote_bundle_group =
Donald Curtis0e209b02015-03-24 09:29:54 -0700676 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
677 if (local_bundle_group && remote_bundle_group) {
678 if (!BundleContentGroup(local_bundle_group)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000679 LOG(LS_WARNING) << "Failed to set up BUNDLE";
680 return false;
681 }
682
683 // If we weren't done gathering before, we might be done now, as a result
684 // of enabling mux.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000685 if (!candidates_allocated) {
686 MaybeCandidateAllocationDone();
687 }
688 } else {
Donald Curtis0e209b02015-03-24 09:29:54 -0700689 LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000690 }
691 return true;
692}
693
Donald Curtis0e209b02015-03-24 09:29:54 -0700694bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
695 const std::string* content_name = bundle_group->FirstContentName();
696 if (!content_name) {
697 LOG(LS_INFO) << "No content names specified in BUNDLE group.";
698 return true;
699 }
700
Donald Curtis0e209b02015-03-24 09:29:54 -0700701 TransportProxy* selected_proxy = GetTransportProxy(*content_name);
702 if (!selected_proxy) {
703 LOG(LS_WARNING) << "No transport found for content \""
704 << *content_name << "\".";
705 return false;
706 }
707
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000708 for (TransportMap::iterator iter = transports_.begin();
709 iter != transports_.end(); ++iter) {
710 // If content is part of the mux group, then repoint its proxy at the
711 // transport object that we have chosen to mux onto. If the proxy
712 // is already pointing at the right object, it will be a no-op.
Donald Curtis0e209b02015-03-24 09:29:54 -0700713 if (bundle_group->HasContentName(iter->first) &&
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000714 !iter->second->SetupMux(selected_proxy)) {
Donald Curtis0e209b02015-03-24 09:29:54 -0700715 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
716 << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000717 return false;
718 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700719 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000720 }
Donald Curtis0e209b02015-03-24 09:29:54 -0700721
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000722 return true;
723}
724
725void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
726 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
727 // TransportProxy should receive the done signal directly, set its allocated
728 // flag internally, and then reissue the done signal to Session.
729 // Overall we should make TransportProxy receive *all* the signals from
730 // Transport, since this removes the need to manually iterate over all
731 // the transports, as is needed to make sure signals are handled properly
732 // when BUNDLEing.
733 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
734 // that make it prohibitively difficult to run dbg builds. Disabled for now.
735 //ASSERT(!IsCandidateAllocationDone());
736 for (TransportMap::iterator iter = transports_.begin();
737 iter != transports_.end(); ++iter) {
738 if (iter->second->impl() == transport) {
739 iter->second->set_candidates_allocated(true);
740 }
741 }
742 MaybeCandidateAllocationDone();
743}
744
745bool BaseSession::IsCandidateAllocationDone() const {
746 for (TransportMap::const_iterator iter = transports_.begin();
747 iter != transports_.end(); ++iter) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000748 if (!iter->second->candidates_allocated()) {
749 LOG(LS_INFO) << "Candidate allocation not done for "
750 << iter->second->content_name();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000751 return false;
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000752 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 }
754 return true;
755}
756
757void BaseSession::MaybeCandidateAllocationDone() {
758 if (IsCandidateAllocationDone()) {
759 LOG(LS_INFO) << "Candidate gathering is complete.";
760 OnCandidatesAllocationDone();
761 }
762}
763
764void BaseSession::OnRoleConflict() {
765 if (role_switch_) {
766 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
767 return;
768 }
769
770 role_switch_ = true;
771 for (TransportMap::iterator iter = transports_.begin();
772 iter != transports_.end(); ++iter) {
773 // Role will be reverse of initial role setting.
774 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
775 iter->second->SetIceRole(role);
776 }
777}
778
779void BaseSession::LogState(State old_state, State new_state) {
780 LOG(LS_INFO) << "Session:" << id()
781 << " Old state:" << StateToString(old_state)
782 << " New state:" << StateToString(new_state)
guoweisd12140a2015-09-10 13:32:11 -0700783 << " Type:" << content_type()
784 << " Transport:" << transport_type();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000785}
786
787// static
788bool BaseSession::GetTransportDescription(const SessionDescription* description,
789 const std::string& content_name,
790 TransportDescription* tdesc) {
791 if (!description || !tdesc) {
792 return false;
793 }
794 const TransportInfo* transport_info =
795 description->GetTransportInfoByName(content_name);
796 if (!transport_info) {
797 return false;
798 }
799 *tdesc = transport_info->description;
800 return true;
801}
802
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000803void BaseSession::OnMessage(rtc::Message *pmsg) {
804 switch (pmsg->message_id) {
805 case MSG_TIMEOUT:
806 // Session timeout has occured.
807 SetError(ERROR_TIME, "Session timeout has occured.");
808 break;
809
810 case MSG_STATE:
811 switch (state_) {
812 case STATE_SENTACCEPT:
813 case STATE_RECEIVEDACCEPT:
814 SetState(STATE_INPROGRESS);
815 break;
816
817 default:
818 // Explicitly ignoring some states here.
819 break;
820 }
821 break;
822 }
823}
824
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000825} // namespace cricket