blob: 30a9f2b0cf2ce601bf39586a70a54b792c9e5da1 [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"
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +000015#include "webrtc/p2p/base/sessionclient.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000016#include "webrtc/p2p/base/transport.h"
17#include "webrtc/p2p/base/transportchannelproxy.h"
18#include "webrtc/p2p/base/transportinfo.h"
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +000019#include "webrtc/libjingle/xmpp/constants.h"
20#include "webrtc/libjingle/xmpp/jid.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000021#include "webrtc/base/bind.h"
22#include "webrtc/base/common.h"
23#include "webrtc/base/helpers.h"
24#include "webrtc/base/logging.h"
25#include "webrtc/base/scoped_ptr.h"
26#include "webrtc/base/sslstreamadapter.h"
27
28#include "webrtc/p2p/base/constants.h"
29
30namespace cricket {
31
32using rtc::Bind;
33
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +000034bool BadMessage(const buzz::QName type,
35 const std::string& text,
36 MessageError* err) {
37 err->SetType(type);
38 err->SetText(text);
39 return false;
40}
41
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000042TransportProxy::~TransportProxy() {
43 for (ChannelMap::iterator iter = channels_.begin();
44 iter != channels_.end(); ++iter) {
45 iter->second->SignalDestroyed(iter->second);
46 delete iter->second;
47 }
48}
49
50const std::string& TransportProxy::type() const {
51 return transport_->get()->type();
52}
53
54TransportChannel* TransportProxy::GetChannel(int component) {
55 ASSERT(rtc::Thread::Current() == worker_thread_);
56 return GetChannelProxy(component);
57}
58
59TransportChannel* TransportProxy::CreateChannel(
60 const std::string& name, int component) {
61 ASSERT(rtc::Thread::Current() == worker_thread_);
62 ASSERT(GetChannel(component) == NULL);
63 ASSERT(!transport_->get()->HasChannel(component));
64
65 // We always create a proxy in case we need to change out the transport later.
66 TransportChannelProxy* channel =
67 new TransportChannelProxy(content_name(), name, component);
68 channels_[component] = channel;
69
70 // If we're already negotiated, create an impl and hook it up to the proxy
71 // channel. If we're connecting, create an impl but don't hook it up yet.
72 if (negotiated_) {
73 SetupChannelProxy_w(component, channel);
74 } else if (connecting_) {
75 GetOrCreateChannelProxyImpl_w(component);
76 }
77 return channel;
78}
79
80bool TransportProxy::HasChannel(int component) {
81 return transport_->get()->HasChannel(component);
82}
83
84void TransportProxy::DestroyChannel(int component) {
85 ASSERT(rtc::Thread::Current() == worker_thread_);
86 TransportChannel* channel = GetChannel(component);
87 if (channel) {
88 // If the state of TransportProxy is not NEGOTIATED
89 // then TransportChannelProxy and its impl are not
90 // connected. Both must be connected before
91 // deletion.
92 if (!negotiated_) {
93 SetupChannelProxy_w(component, GetChannelProxy(component));
94 }
95
96 channels_.erase(component);
97 channel->SignalDestroyed(channel);
98 delete channel;
99 }
100}
101
102void TransportProxy::ConnectChannels() {
103 if (!connecting_) {
104 if (!negotiated_) {
105 for (ChannelMap::iterator iter = channels_.begin();
106 iter != channels_.end(); ++iter) {
107 GetOrCreateChannelProxyImpl(iter->first);
108 }
109 }
110 connecting_ = true;
111 }
112 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
113 // don't have any channels yet, so we need to allow this method to be called
114 // multiple times. Once we fix Transport, we can move this call inside the
115 // if (!connecting_) block.
116 transport_->get()->ConnectChannels();
117}
118
119void TransportProxy::CompleteNegotiation() {
120 if (!negotiated_) {
121 for (ChannelMap::iterator iter = channels_.begin();
122 iter != channels_.end(); ++iter) {
123 SetupChannelProxy(iter->first, iter->second);
124 }
125 negotiated_ = true;
126 }
127}
128
129void TransportProxy::AddSentCandidates(const Candidates& candidates) {
130 for (Candidates::const_iterator cand = candidates.begin();
131 cand != candidates.end(); ++cand) {
132 sent_candidates_.push_back(*cand);
133 }
134}
135
136void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
137 for (Candidates::const_iterator cand = candidates.begin();
138 cand != candidates.end(); ++cand) {
139 unsent_candidates_.push_back(*cand);
140 }
141}
142
143bool TransportProxy::GetChannelNameFromComponent(
144 int component, std::string* channel_name) const {
145 const TransportChannelProxy* channel = GetChannelProxy(component);
146 if (channel == NULL) {
147 return false;
148 }
149
150 *channel_name = channel->name();
151 return true;
152}
153
154bool TransportProxy::GetComponentFromChannelName(
155 const std::string& channel_name, int* component) const {
156 const TransportChannelProxy* channel = GetChannelProxyByName(channel_name);
157 if (channel == NULL) {
158 return false;
159 }
160
161 *component = channel->component();
162 return true;
163}
164
165TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
166 ChannelMap::const_iterator iter = channels_.find(component);
167 return (iter != channels_.end()) ? iter->second : NULL;
168}
169
170TransportChannelProxy* TransportProxy::GetChannelProxyByName(
171 const std::string& name) const {
172 for (ChannelMap::const_iterator iter = channels_.begin();
173 iter != channels_.end();
174 ++iter) {
175 if (iter->second->name() == name) {
176 return iter->second;
177 }
178 }
179 return NULL;
180}
181
182TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl(
183 int component) {
184 return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
185 &TransportProxy::GetOrCreateChannelProxyImpl_w, this, component));
186}
187
188TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl_w(
189 int component) {
190 ASSERT(rtc::Thread::Current() == worker_thread_);
191 TransportChannelImpl* impl = transport_->get()->GetChannel(component);
192 if (impl == NULL) {
193 impl = transport_->get()->CreateChannel(component);
194 }
195 return impl;
196}
197
198void TransportProxy::SetupChannelProxy(
199 int component, TransportChannelProxy* transproxy) {
200 worker_thread_->Invoke<void>(Bind(
201 &TransportProxy::SetupChannelProxy_w, this, component, transproxy));
202}
203
204void TransportProxy::SetupChannelProxy_w(
205 int component, TransportChannelProxy* transproxy) {
206 ASSERT(rtc::Thread::Current() == worker_thread_);
207 TransportChannelImpl* impl = GetOrCreateChannelProxyImpl(component);
208 ASSERT(impl != NULL);
209 transproxy->SetImplementation(impl);
210}
211
212void TransportProxy::ReplaceChannelProxyImpl(TransportChannelProxy* proxy,
213 TransportChannelImpl* impl) {
214 worker_thread_->Invoke<void>(Bind(
215 &TransportProxy::ReplaceChannelProxyImpl_w, this, proxy, impl));
216}
217
218void TransportProxy::ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy,
219 TransportChannelImpl* impl) {
220 ASSERT(rtc::Thread::Current() == worker_thread_);
221 ASSERT(proxy != NULL);
222 proxy->SetImplementation(impl);
223}
224
225// This function muxes |this| onto |target| by repointing |this| at
226// |target|'s transport and setting our TransportChannelProxies
227// to point to |target|'s underlying implementations.
228bool TransportProxy::SetupMux(TransportProxy* target) {
229 // Bail out if there's nothing to do.
230 if (transport_ == target->transport_) {
231 return true;
232 }
233
234 // Run through all channels and remove any non-rtp transport channels before
235 // setting target transport channels.
236 for (ChannelMap::const_iterator iter = channels_.begin();
237 iter != channels_.end(); ++iter) {
238 if (!target->transport_->get()->HasChannel(iter->first)) {
239 // Remove if channel doesn't exist in |transport_|.
240 ReplaceChannelProxyImpl(iter->second, NULL);
241 } else {
242 // Replace the impl for all the TransportProxyChannels with the channels
243 // from |target|'s transport. Fail if there's not an exact match.
244 ReplaceChannelProxyImpl(
245 iter->second, target->transport_->get()->CreateChannel(iter->first));
246 }
247 }
248
249 // Now replace our transport. Must happen afterwards because
250 // it deletes all impls as a side effect.
251 transport_ = target->transport_;
252 transport_->get()->SignalCandidatesReady.connect(
253 this, &TransportProxy::OnTransportCandidatesReady);
254 set_candidates_allocated(target->candidates_allocated());
255 return true;
256}
257
258void TransportProxy::SetIceRole(IceRole role) {
259 transport_->get()->SetIceRole(role);
260}
261
262bool TransportProxy::SetLocalTransportDescription(
263 const TransportDescription& description,
264 ContentAction action,
265 std::string* error_desc) {
266 // If this is an answer, finalize the negotiation.
267 if (action == CA_ANSWER) {
268 CompleteNegotiation();
269 }
270 bool result = transport_->get()->SetLocalTransportDescription(description,
271 action,
272 error_desc);
273 if (result)
274 local_description_set_ = true;
275 return result;
276}
277
278bool TransportProxy::SetRemoteTransportDescription(
279 const TransportDescription& description,
280 ContentAction action,
281 std::string* error_desc) {
282 // If this is an answer, finalize the negotiation.
283 if (action == CA_ANSWER) {
284 CompleteNegotiation();
285 }
286 bool result = transport_->get()->SetRemoteTransportDescription(description,
287 action,
288 error_desc);
289 if (result)
290 remote_description_set_ = true;
291 return result;
292}
293
294void TransportProxy::OnSignalingReady() {
295 // If we're starting a new allocation sequence, reset our state.
296 set_candidates_allocated(false);
297 transport_->get()->OnSignalingReady();
298}
299
300bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
301 std::string* error) {
302 // Ensure the transport is negotiated before handling candidates.
303 // TODO(juberti): Remove this once everybody calls SetLocalTD.
304 CompleteNegotiation();
305
306 // Verify each candidate before passing down to transport layer.
307 for (Candidates::const_iterator cand = candidates.begin();
308 cand != candidates.end(); ++cand) {
309 if (!transport_->get()->VerifyCandidate(*cand, error))
310 return false;
311 if (!HasChannel(cand->component())) {
312 *error = "Candidate has unknown component: " + cand->ToString() +
313 " for content: " + content_name_;
314 return false;
315 }
316 }
317 transport_->get()->OnRemoteCandidates(candidates);
318 return true;
319}
320
321void TransportProxy::SetIdentity(
322 rtc::SSLIdentity* identity) {
323 transport_->get()->SetIdentity(identity);
324}
325
326std::string BaseSession::StateToString(State state) {
327 switch (state) {
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000328 case Session::STATE_INIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000329 return "STATE_INIT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000330 case Session::STATE_SENTINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000331 return "STATE_SENTINITIATE";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000332 case Session::STATE_RECEIVEDINITIATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000333 return "STATE_RECEIVEDINITIATE";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000334 case Session::STATE_SENTPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 return "STATE_SENTPRACCEPT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000336 case Session::STATE_SENTACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000337 return "STATE_SENTACCEPT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000338 case Session::STATE_RECEIVEDPRACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000339 return "STATE_RECEIVEDPRACCEPT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000340 case Session::STATE_RECEIVEDACCEPT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000341 return "STATE_RECEIVEDACCEPT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000342 case Session::STATE_SENTMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343 return "STATE_SENTMODIFY";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000344 case Session::STATE_RECEIVEDMODIFY:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000345 return "STATE_RECEIVEDMODIFY";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000346 case Session::STATE_SENTREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000347 return "STATE_SENTREJECT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000348 case Session::STATE_RECEIVEDREJECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000349 return "STATE_RECEIVEDREJECT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000350 case Session::STATE_SENTREDIRECT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 return "STATE_SENTREDIRECT";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000352 case Session::STATE_SENTTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 return "STATE_SENTTERMINATE";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000354 case Session::STATE_RECEIVEDTERMINATE:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000355 return "STATE_RECEIVEDTERMINATE";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000356 case Session::STATE_INPROGRESS:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000357 return "STATE_INPROGRESS";
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000358 case Session::STATE_DEINIT:
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 return "STATE_DEINIT";
360 default:
361 break;
362 }
363 return "STATE_" + rtc::ToString(state);
364}
365
366BaseSession::BaseSession(rtc::Thread* signaling_thread,
367 rtc::Thread* worker_thread,
368 PortAllocator* port_allocator,
369 const std::string& sid,
370 const std::string& content_type,
371 bool initiator)
372 : state_(STATE_INIT),
373 error_(ERROR_NONE),
374 signaling_thread_(signaling_thread),
375 worker_thread_(worker_thread),
376 port_allocator_(port_allocator),
377 sid_(sid),
378 content_type_(content_type),
379 transport_type_(NS_GINGLE_P2P),
380 initiator_(initiator),
381 identity_(NULL),
382 ice_tiebreaker_(rtc::CreateRandomId64()),
383 role_switch_(false) {
384 ASSERT(signaling_thread->IsCurrent());
385}
386
387BaseSession::~BaseSession() {
388 ASSERT(signaling_thread()->IsCurrent());
389
390 ASSERT(state_ != STATE_DEINIT);
391 LogState(state_, STATE_DEINIT);
392 state_ = STATE_DEINIT;
393 SignalState(this, state_);
394
395 for (TransportMap::iterator iter = transports_.begin();
396 iter != transports_.end(); ++iter) {
397 delete iter->second;
398 }
399}
400
401const SessionDescription* BaseSession::local_description() const {
402 // TODO(tommi): Assert on thread correctness.
403 return local_description_.get();
404}
405
406const SessionDescription* BaseSession::remote_description() const {
407 // TODO(tommi): Assert on thread correctness.
408 return remote_description_.get();
409}
410
411SessionDescription* BaseSession::remote_description() {
412 // TODO(tommi): Assert on thread correctness.
413 return remote_description_.get();
414}
415
416void BaseSession::set_local_description(const SessionDescription* sdesc) {
417 // TODO(tommi): Assert on thread correctness.
418 if (sdesc != local_description_.get())
419 local_description_.reset(sdesc);
420}
421
422void BaseSession::set_remote_description(SessionDescription* sdesc) {
423 // TODO(tommi): Assert on thread correctness.
424 if (sdesc != remote_description_)
425 remote_description_.reset(sdesc);
426}
427
428const SessionDescription* BaseSession::initiator_description() const {
429 // TODO(tommi): Assert on thread correctness.
430 return initiator_ ? local_description_.get() : remote_description_.get();
431}
432
433bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
434 if (identity_)
435 return false;
436 identity_ = identity;
437 for (TransportMap::iterator iter = transports_.begin();
438 iter != transports_.end(); ++iter) {
439 iter->second->SetIdentity(identity_);
440 }
441 return true;
442}
443
444bool BaseSession::PushdownTransportDescription(ContentSource source,
445 ContentAction action,
446 std::string* error_desc) {
447 if (source == CS_LOCAL) {
448 return PushdownLocalTransportDescription(local_description(),
449 action,
450 error_desc);
451 }
452 return PushdownRemoteTransportDescription(remote_description(),
453 action,
454 error_desc);
455}
456
457bool BaseSession::PushdownLocalTransportDescription(
458 const SessionDescription* sdesc,
459 ContentAction action,
460 std::string* error_desc) {
461 // Update the Transports with the right information, and trigger them to
462 // start connecting.
463 for (TransportMap::iterator iter = transports_.begin();
464 iter != transports_.end(); ++iter) {
465 // If no transport info was in this session description, ret == false
466 // and we just skip this one.
467 TransportDescription tdesc;
468 bool ret = GetTransportDescription(
469 sdesc, iter->second->content_name(), &tdesc);
470 if (ret) {
471 if (!iter->second->SetLocalTransportDescription(tdesc, action,
472 error_desc)) {
473 return false;
474 }
475
476 iter->second->ConnectChannels();
477 }
478 }
479
480 return true;
481}
482
483bool BaseSession::PushdownRemoteTransportDescription(
484 const SessionDescription* sdesc,
485 ContentAction action,
486 std::string* error_desc) {
487 // Update the Transports with the right information.
488 for (TransportMap::iterator iter = transports_.begin();
489 iter != transports_.end(); ++iter) {
490 TransportDescription tdesc;
491
492 // If no transport info was in this session description, ret == false
493 // and we just skip this one.
494 bool ret = GetTransportDescription(
495 sdesc, iter->second->content_name(), &tdesc);
496 if (ret) {
497 if (!iter->second->SetRemoteTransportDescription(tdesc, action,
498 error_desc)) {
499 return false;
500 }
501 }
502 }
503
504 return true;
505}
506
507TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
508 const std::string& channel_name,
509 int component) {
510 // We create the proxy "on demand" here because we need to support
511 // creating channels at any time, even before we send or receive
512 // initiate messages, which is before we create the transports.
513 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
514 return transproxy->CreateChannel(channel_name, component);
515}
516
517TransportChannel* BaseSession::GetChannel(const std::string& content_name,
518 int component) {
519 TransportProxy* transproxy = GetTransportProxy(content_name);
520 if (transproxy == NULL)
521 return NULL;
522
523 return transproxy->GetChannel(component);
524}
525
526void BaseSession::DestroyChannel(const std::string& content_name,
527 int component) {
528 TransportProxy* transproxy = GetTransportProxy(content_name);
529 ASSERT(transproxy != NULL);
530 transproxy->DestroyChannel(component);
531}
532
533TransportProxy* BaseSession::GetOrCreateTransportProxy(
534 const std::string& content_name) {
535 TransportProxy* transproxy = GetTransportProxy(content_name);
536 if (transproxy)
537 return transproxy;
538
539 Transport* transport = CreateTransport(content_name);
540 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
541 transport->SetIceTiebreaker(ice_tiebreaker_);
542 // TODO: Connect all the Transport signals to TransportProxy
543 // then to the BaseSession.
544 transport->SignalConnecting.connect(
545 this, &BaseSession::OnTransportConnecting);
546 transport->SignalWritableState.connect(
547 this, &BaseSession::OnTransportWritable);
548 transport->SignalRequestSignaling.connect(
549 this, &BaseSession::OnTransportRequestSignaling);
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000550 transport->SignalTransportError.connect(
551 this, &BaseSession::OnTransportSendError);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000552 transport->SignalRouteChange.connect(
553 this, &BaseSession::OnTransportRouteChange);
554 transport->SignalCandidatesAllocationDone.connect(
555 this, &BaseSession::OnTransportCandidatesAllocationDone);
556 transport->SignalRoleConflict.connect(
557 this, &BaseSession::OnRoleConflict);
558 transport->SignalCompleted.connect(
559 this, &BaseSession::OnTransportCompleted);
560 transport->SignalFailed.connect(
561 this, &BaseSession::OnTransportFailed);
562
563 transproxy = new TransportProxy(worker_thread_, sid_, content_name,
564 new TransportWrapper(transport));
565 transproxy->SignalCandidatesReady.connect(
566 this, &BaseSession::OnTransportProxyCandidatesReady);
567 if (identity_)
568 transproxy->SetIdentity(identity_);
569 transports_[content_name] = transproxy;
570
571 return transproxy;
572}
573
574Transport* BaseSession::GetTransport(const std::string& content_name) {
575 TransportProxy* transproxy = GetTransportProxy(content_name);
576 if (transproxy == NULL)
577 return NULL;
578 return transproxy->impl();
579}
580
581TransportProxy* BaseSession::GetTransportProxy(
582 const std::string& content_name) {
583 TransportMap::iterator iter = transports_.find(content_name);
584 return (iter != transports_.end()) ? iter->second : NULL;
585}
586
587TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
588 for (TransportMap::iterator iter = transports_.begin();
589 iter != transports_.end(); ++iter) {
590 TransportProxy* transproxy = iter->second;
591 if (transproxy->impl() == transport) {
592 return transproxy;
593 }
594 }
595 return NULL;
596}
597
598TransportProxy* BaseSession::GetFirstTransportProxy() {
599 if (transports_.empty())
600 return NULL;
601 return transports_.begin()->second;
602}
603
604void BaseSession::DestroyTransportProxy(
605 const std::string& content_name) {
606 TransportMap::iterator iter = transports_.find(content_name);
607 if (iter != transports_.end()) {
608 delete iter->second;
609 transports_.erase(content_name);
610 }
611}
612
613cricket::Transport* BaseSession::CreateTransport(
614 const std::string& content_name) {
615 ASSERT(transport_type_ == NS_GINGLE_P2P);
616 return new cricket::DtlsTransport<P2PTransport>(
617 signaling_thread(), worker_thread(), content_name,
618 port_allocator(), identity_);
619}
620
621bool BaseSession::GetStats(SessionStats* stats) {
622 for (TransportMap::iterator iter = transports_.begin();
623 iter != transports_.end(); ++iter) {
624 std::string proxy_id = iter->second->content_name();
625 // We are ignoring not-yet-instantiated transports.
626 if (iter->second->impl()) {
627 std::string transport_id = iter->second->impl()->content_name();
628 stats->proxy_to_transport[proxy_id] = transport_id;
629 if (stats->transport_stats.find(transport_id)
630 == stats->transport_stats.end()) {
631 TransportStats subinfos;
632 if (!iter->second->impl()->GetStats(&subinfos)) {
633 return false;
634 }
635 stats->transport_stats[transport_id] = subinfos;
636 }
637 }
638 }
639 return true;
640}
641
642void BaseSession::SetState(State state) {
643 ASSERT(signaling_thread_->IsCurrent());
644 if (state != state_) {
645 LogState(state_, state);
646 state_ = state;
647 SignalState(this, state_);
648 signaling_thread_->Post(this, MSG_STATE);
649 }
650 SignalNewDescription();
651}
652
653void BaseSession::SetError(Error error, const std::string& error_desc) {
654 ASSERT(signaling_thread_->IsCurrent());
655 if (error != error_) {
656 error_ = error;
657 error_desc_ = error_desc;
658 SignalError(this, error);
659 }
660}
661
662void BaseSession::OnSignalingReady() {
663 ASSERT(signaling_thread()->IsCurrent());
664 for (TransportMap::iterator iter = transports_.begin();
665 iter != transports_.end(); ++iter) {
666 iter->second->OnSignalingReady();
667 }
668}
669
670// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
671// start, remove this method once everyone calls PushdownLocalTD.
672void BaseSession::SpeculativelyConnectAllTransportChannels() {
673 // Put all transports into the connecting state.
674 for (TransportMap::iterator iter = transports_.begin();
675 iter != transports_.end(); ++iter) {
676 iter->second->ConnectChannels();
677 }
678}
679
680bool BaseSession::OnRemoteCandidates(const std::string& content_name,
681 const Candidates& candidates,
682 std::string* error) {
683 // Give candidates to the appropriate transport, and tell that transport
684 // to start connecting, if it's not already doing so.
685 TransportProxy* transproxy = GetTransportProxy(content_name);
686 if (!transproxy) {
687 *error = "Unknown content name " + content_name;
688 return false;
689 }
690 if (!transproxy->OnRemoteCandidates(candidates, error)) {
691 return false;
692 }
693 // TODO(juberti): Remove this call once we can be sure that we always have
694 // a local transport description (which will trigger the connection).
695 transproxy->ConnectChannels();
696 return true;
697}
698
699bool BaseSession::MaybeEnableMuxingSupport() {
700 // We need both a local and remote description to decide if we should mux.
701 if ((state_ == STATE_SENTINITIATE ||
702 state_ == STATE_RECEIVEDINITIATE) &&
703 ((local_description_ == NULL) ||
704 (remote_description_ == NULL))) {
705 return false;
706 }
707
708 // In order to perform the multiplexing, we need all proxies to be in the
709 // negotiated state, i.e. to have implementations underneath.
710 // Ensure that this is the case, regardless of whether we are going to mux.
711 for (TransportMap::iterator iter = transports_.begin();
712 iter != transports_.end(); ++iter) {
713 ASSERT(iter->second->negotiated());
714 if (!iter->second->negotiated())
715 return false;
716 }
717
718 // If both sides agree to BUNDLE, mux all the specified contents onto the
719 // transport belonging to the first content name in the BUNDLE group.
720 // If the contents are already muxed, this will be a no-op.
721 // TODO(juberti): Should this check that local and remote have configured
722 // BUNDLE the same way?
723 bool candidates_allocated = IsCandidateAllocationDone();
724 const ContentGroup* local_bundle_group =
725 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
726 const ContentGroup* remote_bundle_group =
727 remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
728 if (local_bundle_group && remote_bundle_group &&
729 local_bundle_group->FirstContentName()) {
730 const std::string* content_name = local_bundle_group->FirstContentName();
731 const ContentInfo* content =
732 local_description_->GetContentByName(*content_name);
braveyao@webrtc.org38881be2014-12-17 05:59:41 +0000733 if (!content) {
734 LOG(LS_WARNING) << "Content \"" << *content_name
735 << "\" referenced in BUNDLE group is not present";
736 return false;
737 }
738
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000739 if (!SetSelectedProxy(content->name, local_bundle_group)) {
740 LOG(LS_WARNING) << "Failed to set up BUNDLE";
741 return false;
742 }
743
744 // If we weren't done gathering before, we might be done now, as a result
745 // of enabling mux.
746 LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
747 << *content_name;
748 if (!candidates_allocated) {
749 MaybeCandidateAllocationDone();
750 }
751 } else {
752 LOG(LS_INFO) << "No BUNDLE information, not bundling.";
753 }
754 return true;
755}
756
757bool BaseSession::SetSelectedProxy(const std::string& content_name,
758 const ContentGroup* muxed_group) {
759 TransportProxy* selected_proxy = GetTransportProxy(content_name);
760 if (!selected_proxy) {
761 return false;
762 }
763
764 ASSERT(selected_proxy->negotiated());
765 for (TransportMap::iterator iter = transports_.begin();
766 iter != transports_.end(); ++iter) {
767 // If content is part of the mux group, then repoint its proxy at the
768 // transport object that we have chosen to mux onto. If the proxy
769 // is already pointing at the right object, it will be a no-op.
770 if (muxed_group->HasContentName(iter->first) &&
771 !iter->second->SetupMux(selected_proxy)) {
772 return false;
773 }
774 }
775 return true;
776}
777
778void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
779 // TODO(juberti): This is a clunky way of processing the done signal. Instead,
780 // TransportProxy should receive the done signal directly, set its allocated
781 // flag internally, and then reissue the done signal to Session.
782 // Overall we should make TransportProxy receive *all* the signals from
783 // Transport, since this removes the need to manually iterate over all
784 // the transports, as is needed to make sure signals are handled properly
785 // when BUNDLEing.
786 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
787 // that make it prohibitively difficult to run dbg builds. Disabled for now.
788 //ASSERT(!IsCandidateAllocationDone());
789 for (TransportMap::iterator iter = transports_.begin();
790 iter != transports_.end(); ++iter) {
791 if (iter->second->impl() == transport) {
792 iter->second->set_candidates_allocated(true);
793 }
794 }
795 MaybeCandidateAllocationDone();
796}
797
798bool BaseSession::IsCandidateAllocationDone() const {
799 for (TransportMap::const_iterator iter = transports_.begin();
800 iter != transports_.end(); ++iter) {
801 if (!iter->second->candidates_allocated())
802 return false;
803 }
804 return true;
805}
806
807void BaseSession::MaybeCandidateAllocationDone() {
808 if (IsCandidateAllocationDone()) {
809 LOG(LS_INFO) << "Candidate gathering is complete.";
810 OnCandidatesAllocationDone();
811 }
812}
813
814void BaseSession::OnRoleConflict() {
815 if (role_switch_) {
816 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
817 return;
818 }
819
820 role_switch_ = true;
821 for (TransportMap::iterator iter = transports_.begin();
822 iter != transports_.end(); ++iter) {
823 // Role will be reverse of initial role setting.
824 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
825 iter->second->SetIceRole(role);
826 }
827}
828
829void BaseSession::LogState(State old_state, State new_state) {
830 LOG(LS_INFO) << "Session:" << id()
831 << " Old state:" << StateToString(old_state)
832 << " New state:" << StateToString(new_state)
833 << " Type:" << content_type()
834 << " Transport:" << transport_type();
835}
836
837// static
838bool BaseSession::GetTransportDescription(const SessionDescription* description,
839 const std::string& content_name,
840 TransportDescription* tdesc) {
841 if (!description || !tdesc) {
842 return false;
843 }
844 const TransportInfo* transport_info =
845 description->GetTransportInfoByName(content_name);
846 if (!transport_info) {
847 return false;
848 }
849 *tdesc = transport_info->description;
850 return true;
851}
852
853void BaseSession::SignalNewDescription() {
854 ContentAction action;
855 ContentSource source;
856 if (!GetContentAction(&action, &source)) {
857 return;
858 }
859 if (source == CS_LOCAL) {
860 SignalNewLocalDescription(this, action);
861 } else {
862 SignalNewRemoteDescription(this, action);
863 }
864}
865
866bool BaseSession::GetContentAction(ContentAction* action,
867 ContentSource* source) {
868 switch (state_) {
869 // new local description
870 case STATE_SENTINITIATE:
871 *action = CA_OFFER;
872 *source = CS_LOCAL;
873 break;
874 case STATE_SENTPRACCEPT:
875 *action = CA_PRANSWER;
876 *source = CS_LOCAL;
877 break;
878 case STATE_SENTACCEPT:
879 *action = CA_ANSWER;
880 *source = CS_LOCAL;
881 break;
882 // new remote description
883 case STATE_RECEIVEDINITIATE:
884 *action = CA_OFFER;
885 *source = CS_REMOTE;
886 break;
887 case STATE_RECEIVEDPRACCEPT:
888 *action = CA_PRANSWER;
889 *source = CS_REMOTE;
890 break;
891 case STATE_RECEIVEDACCEPT:
892 *action = CA_ANSWER;
893 *source = CS_REMOTE;
894 break;
895 default:
896 return false;
897 }
898 return true;
899}
900
901void BaseSession::OnMessage(rtc::Message *pmsg) {
902 switch (pmsg->message_id) {
903 case MSG_TIMEOUT:
904 // Session timeout has occured.
905 SetError(ERROR_TIME, "Session timeout has occured.");
906 break;
907
908 case MSG_STATE:
909 switch (state_) {
910 case STATE_SENTACCEPT:
911 case STATE_RECEIVEDACCEPT:
912 SetState(STATE_INPROGRESS);
913 break;
914
915 default:
916 // Explicitly ignoring some states here.
917 break;
918 }
919 break;
920 }
921}
922
pthatcher@webrtc.org4cb38562014-12-18 02:28:25 +0000923Session::Session(SessionManager* session_manager,
924 const std::string& local_name,
925 const std::string& initiator_name,
926 const std::string& sid,
927 const std::string& content_type,
928 SessionClient* client)
929 : BaseSession(session_manager->signaling_thread(),
930 session_manager->worker_thread(),
931 session_manager->port_allocator(),
932 sid, content_type, initiator_name == local_name) {
933 ASSERT(client != NULL);
934 session_manager_ = session_manager;
935 local_name_ = local_name;
936 initiator_name_ = initiator_name;
937 transport_parser_ = new P2PTransportParser();
938 client_ = client;
939 initiate_acked_ = false;
940 current_protocol_ = PROTOCOL_HYBRID;
941}
942
943Session::~Session() {
944 delete transport_parser_;
945}
946
947bool Session::Initiate(const std::string& to,
948 const SessionDescription* sdesc) {
949 ASSERT(signaling_thread()->IsCurrent());
950 SessionError error;
951
952 // Only from STATE_INIT
953 if (state() != STATE_INIT)
954 return false;
955
956 // Setup for signaling.
957 set_remote_name(to);
958 set_local_description(sdesc);
959 if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
960 &error)) {
961 LOG(LS_ERROR) << "Could not create transports: " << error.text;
962 return false;
963 }
964
965 if (!SendInitiateMessage(sdesc, &error)) {
966 LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
967 return false;
968 }
969
970 // We need to connect transport proxy and impl here so that we can process
971 // the TransportDescriptions.
972 SpeculativelyConnectAllTransportChannels();
973
974 PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
975 SetState(Session::STATE_SENTINITIATE);
976 return true;
977}
978
979bool Session::Accept(const SessionDescription* sdesc) {
980 ASSERT(signaling_thread()->IsCurrent());
981
982 // Only if just received initiate
983 if (state() != STATE_RECEIVEDINITIATE)
984 return false;
985
986 // Setup for signaling.
987 set_local_description(sdesc);
988
989 SessionError error;
990 if (!SendAcceptMessage(sdesc, &error)) {
991 LOG(LS_ERROR) << "Could not send accept message: " << error.text;
992 return false;
993 }
994 // TODO(juberti): Add BUNDLE support to transport-info messages.
995 PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
996 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
997 SetState(Session::STATE_SENTACCEPT);
998 return true;
999}
1000
1001bool Session::Reject(const std::string& reason) {
1002 ASSERT(signaling_thread()->IsCurrent());
1003
1004 // Reject is sent in response to an initiate or modify, to reject the
1005 // request
1006 if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY)
1007 return false;
1008
1009 SessionError error;
1010 if (!SendRejectMessage(reason, &error)) {
1011 LOG(LS_ERROR) << "Could not send reject message: " << error.text;
1012 return false;
1013 }
1014
1015 SetState(STATE_SENTREJECT);
1016 return true;
1017}
1018
1019bool Session::TerminateWithReason(const std::string& reason) {
1020 ASSERT(signaling_thread()->IsCurrent());
1021
1022 // Either side can terminate, at any time.
1023 switch (state()) {
1024 case STATE_SENTTERMINATE:
1025 case STATE_RECEIVEDTERMINATE:
1026 return false;
1027
1028 case STATE_SENTREJECT:
1029 case STATE_RECEIVEDREJECT:
1030 // We don't need to send terminate if we sent or received a reject...
1031 // it's implicit.
1032 break;
1033
1034 default:
1035 SessionError error;
1036 if (!SendTerminateMessage(reason, &error)) {
1037 LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
1038 return false;
1039 }
1040 break;
1041 }
1042
1043 SetState(STATE_SENTTERMINATE);
1044 return true;
1045}
1046
1047bool Session::SendInfoMessage(const XmlElements& elems,
1048 const std::string& remote_name) {
1049 ASSERT(signaling_thread()->IsCurrent());
1050 SessionError error;
1051 if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
1052 LOG(LS_ERROR) << "Could not send info message " << error.text;
1053 return false;
1054 }
1055 return true;
1056}
1057
1058bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) {
1059 XmlElements elems;
1060 WriteError write_error;
1061 if (!WriteDescriptionInfo(current_protocol_,
1062 contents,
1063 GetContentParsers(),
1064 &elems, &write_error)) {
1065 LOG(LS_ERROR) << "Could not write description info message: "
1066 << write_error.text;
1067 return false;
1068 }
1069 SessionError error;
1070 if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) {
1071 LOG(LS_ERROR) << "Could not send description info message: "
1072 << error.text;
1073 return false;
1074 }
1075 return true;
1076}
1077
1078TransportInfos Session::GetEmptyTransportInfos(
1079 const ContentInfos& contents) const {
1080 TransportInfos tinfos;
1081 for (ContentInfos::const_iterator content = contents.begin();
1082 content != contents.end(); ++content) {
1083 tinfos.push_back(TransportInfo(content->name,
1084 TransportDescription(transport_type(),
1085 std::string(),
1086 std::string())));
1087 }
1088 return tinfos;
1089}
1090
1091bool Session::OnRemoteCandidates(
1092 const TransportInfos& tinfos, ParseError* error) {
1093 for (TransportInfos::const_iterator tinfo = tinfos.begin();
1094 tinfo != tinfos.end(); ++tinfo) {
1095 std::string str_error;
1096 if (!BaseSession::OnRemoteCandidates(
1097 tinfo->content_name, tinfo->description.candidates, &str_error)) {
1098 return BadParse(str_error, error);
1099 }
1100 }
1101 return true;
1102}
1103
1104bool Session::CreateTransportProxies(const TransportInfos& tinfos,
1105 SessionError* error) {
1106 for (TransportInfos::const_iterator tinfo = tinfos.begin();
1107 tinfo != tinfos.end(); ++tinfo) {
1108 if (tinfo->description.transport_type != transport_type()) {
1109 error->SetText("No supported transport in offer.");
1110 return false;
1111 }
1112
1113 GetOrCreateTransportProxy(tinfo->content_name);
1114 }
1115 return true;
1116}
1117
1118TransportParserMap Session::GetTransportParsers() {
1119 TransportParserMap parsers;
1120 parsers[transport_type()] = transport_parser_;
1121 return parsers;
1122}
1123
1124CandidateTranslatorMap Session::GetCandidateTranslators() {
1125 CandidateTranslatorMap translators;
1126 // NOTE: This technique makes it impossible to parse G-ICE
1127 // candidates in session-initiate messages because the channels
1128 // aren't yet created at that point. Since we don't use candidates
1129 // in session-initiate messages, we should be OK. Once we switch to
1130 // ICE, this translation shouldn't be necessary.
1131 for (TransportMap::const_iterator iter = transport_proxies().begin();
1132 iter != transport_proxies().end(); ++iter) {
1133 translators[iter->first] = iter->second;
1134 }
1135 return translators;
1136}
1137
1138ContentParserMap Session::GetContentParsers() {
1139 ContentParserMap parsers;
1140 parsers[content_type()] = client_;
1141 // We need to be able parse both RTP-based and SCTP-based Jingle
1142 // with the same client.
1143 if (content_type() == NS_JINGLE_RTP) {
1144 parsers[NS_JINGLE_DRAFT_SCTP] = client_;
1145 }
1146 return parsers;
1147}
1148
1149void Session::OnTransportRequestSignaling(Transport* transport) {
1150 ASSERT(signaling_thread()->IsCurrent());
1151 TransportProxy* transproxy = GetTransportProxy(transport);
1152 ASSERT(transproxy != NULL);
1153 if (transproxy) {
1154 // Reset candidate allocation status for the transport proxy.
1155 transproxy->set_candidates_allocated(false);
1156 }
1157 SignalRequestSignaling(this);
1158}
1159
1160void Session::OnTransportConnecting(Transport* transport) {
1161 // This is an indication that we should begin watching the writability
1162 // state of the transport.
1163 OnTransportWritable(transport);
1164}
1165
1166void Session::OnTransportWritable(Transport* transport) {
1167 ASSERT(signaling_thread()->IsCurrent());
1168
1169 // If the transport is not writable, start a timer to make sure that it
1170 // becomes writable within a reasonable amount of time. If it does not, we
1171 // terminate since we can't actually send data. If the transport is writable,
1172 // cancel the timer. Note that writability transitions may occur repeatedly
1173 // during the lifetime of the session.
1174 signaling_thread()->Clear(this, MSG_TIMEOUT);
1175 if (transport->HasChannels() && !transport->writable()) {
1176 signaling_thread()->PostDelayed(
1177 session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
1178 }
1179}
1180
1181void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy,
1182 const Candidates& candidates) {
1183 ASSERT(signaling_thread()->IsCurrent());
1184 if (transproxy != NULL) {
1185 if (initiator() && !initiate_acked_) {
1186 // TODO: This is to work around server re-ordering
1187 // messages. We send the candidates once the session-initiate
1188 // is acked. Once we have fixed the server to guarantee message
1189 // order, we can remove this case.
1190 transproxy->AddUnsentCandidates(candidates);
1191 } else {
1192 if (!transproxy->negotiated()) {
1193 transproxy->AddSentCandidates(candidates);
1194 }
1195 SessionError error;
1196 if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
1197 LOG(LS_ERROR) << "Could not send transport info message: "
1198 << error.text;
1199 return;
1200 }
1201 }
1202 }
1203}
1204
1205void Session::OnTransportSendError(Transport* transport,
1206 const buzz::XmlElement* stanza,
1207 const buzz::QName& name,
1208 const std::string& type,
1209 const std::string& text,
1210 const buzz::XmlElement* extra_info) {
1211 ASSERT(signaling_thread()->IsCurrent());
1212 SignalErrorMessage(this, stanza, name, type, text, extra_info);
1213}
1214
1215void Session::OnIncomingMessage(const SessionMessage& msg) {
1216 ASSERT(signaling_thread()->IsCurrent());
1217 ASSERT(state() == STATE_INIT || msg.from == remote_name());
1218
1219 if (current_protocol_== PROTOCOL_HYBRID) {
1220 if (msg.protocol == PROTOCOL_GINGLE) {
1221 current_protocol_ = PROTOCOL_GINGLE;
1222 } else {
1223 current_protocol_ = PROTOCOL_JINGLE;
1224 }
1225 }
1226
1227 bool valid = false;
1228 MessageError error;
1229 switch (msg.type) {
1230 case ACTION_SESSION_INITIATE:
1231 valid = OnInitiateMessage(msg, &error);
1232 break;
1233 case ACTION_SESSION_INFO:
1234 valid = OnInfoMessage(msg);
1235 break;
1236 case ACTION_SESSION_ACCEPT:
1237 valid = OnAcceptMessage(msg, &error);
1238 break;
1239 case ACTION_SESSION_REJECT:
1240 valid = OnRejectMessage(msg, &error);
1241 break;
1242 case ACTION_SESSION_TERMINATE:
1243 valid = OnTerminateMessage(msg, &error);
1244 break;
1245 case ACTION_TRANSPORT_INFO:
1246 valid = OnTransportInfoMessage(msg, &error);
1247 break;
1248 case ACTION_TRANSPORT_ACCEPT:
1249 valid = OnTransportAcceptMessage(msg, &error);
1250 break;
1251 case ACTION_DESCRIPTION_INFO:
1252 valid = OnDescriptionInfoMessage(msg, &error);
1253 break;
1254 default:
1255 valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
1256 "unknown session message type",
1257 &error);
1258 }
1259
1260 if (valid) {
1261 SendAcknowledgementMessage(msg.stanza);
1262 } else {
1263 SignalErrorMessage(this, msg.stanza, error.type,
1264 "modify", error.text, NULL);
1265 }
1266}
1267
1268void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
1269 const buzz::XmlElement* response_stanza,
1270 const SessionMessage& msg) {
1271 ASSERT(signaling_thread()->IsCurrent());
1272
1273 if (msg.type == ACTION_SESSION_INITIATE) {
1274 OnInitiateAcked();
1275 }
1276}
1277
1278void Session::OnInitiateAcked() {
1279 // TODO: This is to work around server re-ordering
1280 // messages. We send the candidates once the session-initiate
1281 // is acked. Once we have fixed the server to guarantee message
1282 // order, we can remove this case.
1283 if (!initiate_acked_) {
1284 initiate_acked_ = true;
1285 SessionError error;
1286 SendAllUnsentTransportInfoMessages(&error);
1287 }
1288}
1289
1290void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
1291 const buzz::XmlElement* error_stanza) {
1292 ASSERT(signaling_thread()->IsCurrent());
1293
1294 SessionMessage msg;
1295 ParseError parse_error;
1296 if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
1297 LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
1298 << ":" << orig_stanza;
1299 return;
1300 }
1301
1302 // If the error is a session redirect, call OnRedirectError, which will
1303 // continue the session with a new remote JID.
1304 SessionRedirect redirect;
1305 if (FindSessionRedirect(error_stanza, &redirect)) {
1306 SessionError error;
1307 if (!OnRedirectError(redirect, &error)) {
1308 // TODO: Should we send a message back? The standard
1309 // says nothing about it.
1310 std::ostringstream desc;
1311 desc << "Failed to redirect: " << error.text;
1312 LOG(LS_ERROR) << desc.str();
1313 SetError(ERROR_RESPONSE, desc.str());
1314 }
1315 return;
1316 }
1317
1318 std::string error_type = "cancel";
1319
1320 const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
1321 if (error) {
1322 error_type = error->Attr(buzz::QN_TYPE);
1323
1324 LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
1325 << "in response to:\n" << orig_stanza->Str();
1326 } else {
1327 // don't crash if <error> is missing
1328 LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
1329 return;
1330 }
1331
1332 if (msg.type == ACTION_TRANSPORT_INFO) {
1333 // Transport messages frequently generate errors because they are sent right
1334 // when we detect a network failure. For that reason, we ignore such
1335 // errors, because if we do not establish writability again, we will
1336 // terminate anyway. The exceptions are transport-specific error tags,
1337 // which we pass on to the respective transport.
1338 } else if ((error_type != "continue") && (error_type != "wait")) {
1339 // We do not set an error if the other side said it is okay to continue
1340 // (possibly after waiting). These errors can be ignored.
1341 SetError(ERROR_RESPONSE, "");
1342 }
1343}
1344
1345bool Session::OnInitiateMessage(const SessionMessage& msg,
1346 MessageError* error) {
1347 if (!CheckState(STATE_INIT, error))
1348 return false;
1349
1350 SessionInitiate init;
1351 if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
1352 GetContentParsers(), GetTransportParsers(),
1353 GetCandidateTranslators(),
1354 &init, error))
1355 return false;
1356
1357 SessionError session_error;
1358 if (!CreateTransportProxies(init.transports, &session_error)) {
1359 return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
1360 session_error.text, error);
1361 }
1362
1363 set_remote_name(msg.from);
1364 set_initiator_name(msg.initiator);
1365 set_remote_description(new SessionDescription(init.ClearContents(),
1366 init.transports,
1367 init.groups));
1368 // Updating transport with TransportDescription.
1369 PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
1370 SetState(STATE_RECEIVEDINITIATE);
1371
1372 // Users of Session may listen to state change and call Reject().
1373 if (state() != STATE_SENTREJECT) {
1374 if (!OnRemoteCandidates(init.transports, error))
1375 return false;
1376
1377 // TODO(juberti): Auto-generate and push down the local transport answer.
1378 // This is necessary for trickling to work with RFC 5245 ICE.
1379 }
1380 return true;
1381}
1382
1383bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
1384 if (!CheckState(STATE_SENTINITIATE, error))
1385 return false;
1386
1387 SessionAccept accept;
1388 if (!ParseSessionAccept(msg.protocol, msg.action_elem,
1389 GetContentParsers(), GetTransportParsers(),
1390 GetCandidateTranslators(),
1391 &accept, error)) {
1392 return false;
1393 }
1394
1395 // If we get an accept, we can assume the initiate has been
1396 // received, even if we haven't gotten an IQ response.
1397 OnInitiateAcked();
1398
1399 set_remote_description(new SessionDescription(accept.ClearContents(),
1400 accept.transports,
1401 accept.groups));
1402 // Updating transport with TransportDescription.
1403 PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
1404 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
1405 SetState(STATE_RECEIVEDACCEPT);
1406
1407 if (!OnRemoteCandidates(accept.transports, error))
1408 return false;
1409
1410 return true;
1411}
1412
1413bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
1414 if (!CheckState(STATE_SENTINITIATE, error))
1415 return false;
1416
1417 SetState(STATE_RECEIVEDREJECT);
1418 return true;
1419}
1420
1421bool Session::OnInfoMessage(const SessionMessage& msg) {
1422 SignalInfoMessage(this, msg.action_elem);
1423 return true;
1424}
1425
1426bool Session::OnTerminateMessage(const SessionMessage& msg,
1427 MessageError* error) {
1428 SessionTerminate term;
1429 if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
1430 return false;
1431
1432 SignalReceivedTerminateReason(this, term.reason);
1433 if (term.debug_reason != buzz::STR_EMPTY) {
1434 LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
1435 }
1436
1437 SetState(STATE_RECEIVEDTERMINATE);
1438 return true;
1439}
1440
1441bool Session::OnTransportInfoMessage(const SessionMessage& msg,
1442 MessageError* error) {
1443 TransportInfos tinfos;
1444 if (!ParseTransportInfos(msg.protocol, msg.action_elem,
1445 initiator_description()->contents(),
1446 GetTransportParsers(), GetCandidateTranslators(),
1447 &tinfos, error))
1448 return false;
1449
1450 if (!OnRemoteCandidates(tinfos, error))
1451 return false;
1452
1453 return true;
1454}
1455
1456bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
1457 MessageError* error) {
1458 // TODO: Currently here only for compatibility with
1459 // Gingle 1.1 clients (notably, Google Voice).
1460 return true;
1461}
1462
1463bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
1464 MessageError* error) {
1465 if (!CheckState(STATE_INPROGRESS, error))
1466 return false;
1467
1468 DescriptionInfo description_info;
1469 if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
1470 GetContentParsers(), GetTransportParsers(),
1471 GetCandidateTranslators(),
1472 &description_info, error)) {
1473 return false;
1474 }
1475
1476 ContentInfos& updated_contents = description_info.contents;
1477
1478 // TODO: Currently, reflector sends back
1479 // video stream updates even for an audio-only call, which causes
1480 // this to fail. Put this back once reflector is fixed.
1481 //
1482 // ContentInfos::iterator it;
1483 // First, ensure all updates are valid before modifying remote_description_.
1484 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
1485 // if (remote_description()->GetContentByName(it->name) == NULL) {
1486 // return false;
1487 // }
1488 // }
1489
1490 // TODO: We used to replace contents from an update, but
1491 // that no longer works with partial updates. We need to figure out
1492 // a way to merge patial updates into contents. For now, users of
1493 // Session should listen to SignalRemoteDescriptionUpdate and handle
1494 // updates. They should not expect remote_description to be the
1495 // latest value.
1496 //
1497 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
1498 // remote_description()->RemoveContentByName(it->name);
1499 // remote_description()->AddContent(it->name, it->type, it->description);
1500 // }
1501 // }
1502
1503 SignalRemoteDescriptionUpdate(this, updated_contents);
1504 return true;
1505}
1506
1507bool BareJidsEqual(const std::string& name1,
1508 const std::string& name2) {
1509 buzz::Jid jid1(name1);
1510 buzz::Jid jid2(name2);
1511
1512 return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
1513}
1514
1515bool Session::OnRedirectError(const SessionRedirect& redirect,
1516 SessionError* error) {
1517 MessageError message_error;
1518 if (!CheckState(STATE_SENTINITIATE, &message_error)) {
1519 return BadWrite(message_error.text, error);
1520 }
1521
1522 if (!BareJidsEqual(remote_name(), redirect.target))
1523 return BadWrite("Redirection not allowed: must be the same bare jid.",
1524 error);
1525
1526 // When we receive a redirect, we point the session at the new JID
1527 // and resend the candidates.
1528 set_remote_name(redirect.target);
1529 return (SendInitiateMessage(local_description(), error) &&
1530 ResendAllTransportInfoMessages(error));
1531}
1532
1533bool Session::CheckState(State expected, MessageError* error) {
1534 if (state() != expected) {
1535 // The server can deliver messages out of order/repeated for various
1536 // reasons. For example, if the server does not recive our iq response,
1537 // it could assume that the iq it sent was lost, and will then send
1538 // it again. Ideally, we should implement reliable messaging with
1539 // duplicate elimination.
1540 return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
1541 "message not allowed in current state",
1542 error);
1543 }
1544 return true;
1545}
1546
1547void Session::SetError(Error error, const std::string& error_desc) {
1548 BaseSession::SetError(error, error_desc);
1549 if (error != ERROR_NONE)
1550 signaling_thread()->Post(this, MSG_ERROR);
1551}
1552
1553void Session::OnMessage(rtc::Message* pmsg) {
1554 // preserve this because BaseSession::OnMessage may modify it
1555 State orig_state = state();
1556
1557 BaseSession::OnMessage(pmsg);
1558
1559 switch (pmsg->message_id) {
1560 case MSG_ERROR:
1561 TerminateWithReason(STR_TERMINATE_ERROR);
1562 break;
1563
1564 case MSG_STATE:
1565 switch (orig_state) {
1566 case STATE_SENTREJECT:
1567 case STATE_RECEIVEDREJECT:
1568 // Assume clean termination.
1569 Terminate();
1570 break;
1571
1572 case STATE_SENTTERMINATE:
1573 case STATE_RECEIVEDTERMINATE:
1574 session_manager_->DestroySession(this);
1575 break;
1576
1577 default:
1578 // Explicitly ignoring some states here.
1579 break;
1580 }
1581 break;
1582 }
1583}
1584
1585bool Session::SendInitiateMessage(const SessionDescription* sdesc,
1586 SessionError* error) {
1587 SessionInitiate init;
1588 init.contents = sdesc->contents();
1589 init.transports = GetEmptyTransportInfos(init.contents);
1590 init.groups = sdesc->groups();
1591 return SendMessage(ACTION_SESSION_INITIATE, init, error);
1592}
1593
1594bool Session::WriteSessionAction(
1595 SignalingProtocol protocol, const SessionInitiate& init,
1596 XmlElements* elems, WriteError* error) {
1597 return WriteSessionInitiate(protocol, init.contents, init.transports,
1598 GetContentParsers(), GetTransportParsers(),
1599 GetCandidateTranslators(), init.groups,
1600 elems, error);
1601}
1602
1603bool Session::SendAcceptMessage(const SessionDescription* sdesc,
1604 SessionError* error) {
1605 XmlElements elems;
1606 if (!WriteSessionAccept(current_protocol_,
1607 sdesc->contents(),
1608 GetEmptyTransportInfos(sdesc->contents()),
1609 GetContentParsers(), GetTransportParsers(),
1610 GetCandidateTranslators(), sdesc->groups(),
1611 &elems, error)) {
1612 return false;
1613 }
1614 return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
1615}
1616
1617bool Session::SendRejectMessage(const std::string& reason,
1618 SessionError* error) {
1619 SessionTerminate term(reason);
1620 return SendMessage(ACTION_SESSION_REJECT, term, error);
1621}
1622
1623bool Session::SendTerminateMessage(const std::string& reason,
1624 SessionError* error) {
1625 SessionTerminate term(reason);
1626 return SendMessage(ACTION_SESSION_TERMINATE, term, error);
1627}
1628
1629bool Session::WriteSessionAction(SignalingProtocol protocol,
1630 const SessionTerminate& term,
1631 XmlElements* elems, WriteError* error) {
1632 WriteSessionTerminate(protocol, term, elems);
1633 return true;
1634}
1635
1636bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
1637 SessionError* error) {
1638 return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
1639}
1640
1641bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
1642 const Candidates& candidates,
1643 SessionError* error) {
1644 return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
1645 TransportDescription(transproxy->type(), std::vector<std::string>(),
1646 std::string(), std::string(), ICEMODE_FULL,
1647 CONNECTIONROLE_NONE, NULL, candidates)), error);
1648}
1649
1650bool Session::WriteSessionAction(SignalingProtocol protocol,
1651 const TransportInfo& tinfo,
1652 XmlElements* elems, WriteError* error) {
1653 TransportInfos tinfos;
1654 tinfos.push_back(tinfo);
1655 return WriteTransportInfos(protocol, tinfos,
1656 GetTransportParsers(), GetCandidateTranslators(),
1657 elems, error);
1658}
1659
1660bool Session::ResendAllTransportInfoMessages(SessionError* error) {
1661 for (TransportMap::const_iterator iter = transport_proxies().begin();
1662 iter != transport_proxies().end(); ++iter) {
1663 TransportProxy* transproxy = iter->second;
1664 if (transproxy->sent_candidates().size() > 0) {
1665 if (!SendTransportInfoMessage(
1666 transproxy, transproxy->sent_candidates(), error)) {
1667 LOG(LS_ERROR) << "Could not resend transport info messages: "
1668 << error->text;
1669 return false;
1670 }
1671 transproxy->ClearSentCandidates();
1672 }
1673 }
1674 return true;
1675}
1676
1677bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
1678 for (TransportMap::const_iterator iter = transport_proxies().begin();
1679 iter != transport_proxies().end(); ++iter) {
1680 TransportProxy* transproxy = iter->second;
1681 if (transproxy->unsent_candidates().size() > 0) {
1682 if (!SendTransportInfoMessage(
1683 transproxy, transproxy->unsent_candidates(), error)) {
1684 LOG(LS_ERROR) << "Could not send unsent transport info messages: "
1685 << error->text;
1686 return false;
1687 }
1688 transproxy->ClearUnsentCandidates();
1689 }
1690 }
1691 return true;
1692}
1693
1694bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
1695 SessionError* error) {
1696 return SendMessage(type, action_elems, remote_name(), error);
1697}
1698
1699bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
1700 const std::string& remote_name, SessionError* error) {
1701 rtc::scoped_ptr<buzz::XmlElement> stanza(
1702 new buzz::XmlElement(buzz::QN_IQ));
1703
1704 SessionMessage msg(current_protocol_, type, id(), initiator_name());
1705 msg.to = remote_name;
1706 WriteSessionMessage(msg, action_elems, stanza.get());
1707
1708 SignalOutgoingMessage(this, stanza.get());
1709 return true;
1710}
1711
1712template <typename Action>
1713bool Session::SendMessage(ActionType type, const Action& action,
1714 SessionError* error) {
1715 rtc::scoped_ptr<buzz::XmlElement> stanza(
1716 new buzz::XmlElement(buzz::QN_IQ));
1717 if (!WriteActionMessage(type, action, stanza.get(), error))
1718 return false;
1719
1720 SignalOutgoingMessage(this, stanza.get());
1721 return true;
1722}
1723
1724template <typename Action>
1725bool Session::WriteActionMessage(ActionType type, const Action& action,
1726 buzz::XmlElement* stanza,
1727 WriteError* error) {
1728 if (current_protocol_ == PROTOCOL_HYBRID) {
1729 if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
1730 return false;
1731 if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
1732 return false;
1733 } else {
1734 if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
1735 return false;
1736 }
1737 return true;
1738}
1739
1740template <typename Action>
1741bool Session::WriteActionMessage(SignalingProtocol protocol,
1742 ActionType type, const Action& action,
1743 buzz::XmlElement* stanza, WriteError* error) {
1744 XmlElements action_elems;
1745 if (!WriteSessionAction(protocol, action, &action_elems, error))
1746 return false;
1747
1748 SessionMessage msg(protocol, type, id(), initiator_name());
1749 msg.to = remote_name();
1750
1751 WriteSessionMessage(msg, action_elems, stanza);
1752 return true;
1753}
1754
1755void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
1756 rtc::scoped_ptr<buzz::XmlElement> ack(
1757 new buzz::XmlElement(buzz::QN_IQ));
1758 ack->SetAttr(buzz::QN_TO, remote_name());
1759 ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
1760 ack->SetAttr(buzz::QN_TYPE, "result");
1761
1762 SignalOutgoingMessage(this, ack.get());
1763}
1764
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001765} // namespace cricket