1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/p2p/base/session.h"
29 #include "talk/base/common.h"
30 #include "talk/base/logging.h"
31 #include "talk/base/helpers.h"
32 #include "talk/base/scoped_ptr.h"
33 #include "talk/xmpp/constants.h"
34 #include "talk/xmpp/jid.h"
35 #include "talk/p2p/base/p2ptransport.h"
36 #include "talk/p2p/base/p2ptransportchannel.h"
37 #include "talk/p2p/base/sessionclient.h"
38 #include "talk/p2p/base/transport.h"
39 #include "talk/p2p/base/transportchannelproxy.h"
40
41 #include "talk/p2p/base/constants.h"
42
43 namespace {
44
45 const uint32 MSG_TIMEOUT = 1;
46 const uint32 MSG_ERROR = 2;
47 const uint32 MSG_STATE = 3;
48
49 } // namespace
50
51 namespace cricket {
52
BadMessage(const buzz::QName type,const std::string & text,MessageError * err)53 bool BadMessage(const buzz::QName type,
54 const std::string& text,
55 MessageError* err) {
56 err->SetType(type);
57 err->SetText(text);
58 return false;
59 }
60
~TransportProxy()61 TransportProxy::~TransportProxy() {
62 for (ChannelMap::iterator iter = channels_.begin();
63 iter != channels_.end(); ++iter) {
64 iter->second->SignalDestroyed(iter->second);
65 delete iter->second;
66 }
67 }
68
type() const69 std::string TransportProxy::type() const {
70 return transport_->get()->type();
71 }
72
SetImplementation(TransportWrapper * impl)73 void TransportProxy::SetImplementation(TransportWrapper *impl) {
74 transport_ = impl;
75 }
76
GetChannel(const std::string & name)77 TransportChannel* TransportProxy::GetChannel(const std::string& name) {
78 return GetProxy(name);
79 }
80
CreateChannel(const std::string & name,const std::string & content_type)81 TransportChannel* TransportProxy::CreateChannel(
82 const std::string& name, const std::string& content_type) {
83 ASSERT(GetChannel(name) == NULL);
84 ASSERT(!transport_->get()->HasChannel(name));
85
86 // We always create a proxy in case we need to change out the transport later.
87 TransportChannelProxy* channel =
88 new TransportChannelProxy(name, content_type);
89 channels_[name] = channel;
90
91 if (state_ == STATE_NEGOTIATED) {
92 SetProxyImpl(name, channel);
93 } else if (state_ == STATE_CONNECTING) {
94 GetOrCreateImpl(name, content_type);
95 }
96 return channel;
97 }
98
DestroyChannel(const std::string & name)99 void TransportProxy::DestroyChannel(const std::string& name) {
100 TransportChannel* channel = GetChannel(name);
101 if (channel) {
102 channels_.erase(name);
103 channel->SignalDestroyed(channel);
104 delete channel;
105 }
106 }
107
SpeculativelyConnectChannels()108 void TransportProxy::SpeculativelyConnectChannels() {
109 ASSERT(state_ == STATE_INIT || state_ == STATE_CONNECTING);
110 state_ = STATE_CONNECTING;
111 for (ChannelMap::iterator iter = channels_.begin();
112 iter != channels_.end(); ++iter) {
113 GetOrCreateImpl(iter->first, iter->second->content_type());
114 }
115 transport_->get()->ConnectChannels();
116 }
117
CompleteNegotiation()118 void TransportProxy::CompleteNegotiation() {
119 if (state_ != STATE_NEGOTIATED) {
120 state_ = STATE_NEGOTIATED;
121 for (ChannelMap::iterator iter = channels_.begin();
122 iter != channels_.end(); ++iter) {
123 SetProxyImpl(iter->first, iter->second);
124 }
125 transport_->get()->ConnectChannels();
126 }
127 }
128
AddSentCandidates(const Candidates & candidates)129 void 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
AddUnsentCandidates(const Candidates & candidates)136 void 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
GetProxy(const std::string & name)143 TransportChannelProxy* TransportProxy::GetProxy(const std::string& name) {
144 ChannelMap::iterator iter = channels_.find(name);
145 return (iter != channels_.end()) ? iter->second : NULL;
146 }
147
GetOrCreateImpl(const std::string & name,const std::string & content_type)148 TransportChannelImpl* TransportProxy::GetOrCreateImpl(
149 const std::string& name, const std::string& content_type) {
150 TransportChannelImpl* impl = transport_->get()->GetChannel(name);
151 if (impl == NULL) {
152 impl = transport_->get()->CreateChannel(name, content_type);
153 impl->set_session_id(sid_);
154 }
155 return impl;
156 }
157
SetProxyImpl(const std::string & name,TransportChannelProxy * proxy)158 void TransportProxy::SetProxyImpl(
159 const std::string& name, TransportChannelProxy* proxy) {
160 TransportChannelImpl* impl = GetOrCreateImpl(name, proxy->content_type());
161 ASSERT(impl != NULL);
162 proxy->SetImplementation(impl);
163 }
164
165 // This function muxes |this| onto proxy by making a copy
166 // of |proxy|'s transport and setting our TransportChannelProxies
167 // to point to |proxy|'s underlying implementations.
SetupMux(TransportProxy * proxy)168 void TransportProxy::SetupMux(TransportProxy* proxy) {
169 size_t index = 0;
170 // Copy the channels from proxy 1:1 onto us.
171 for (ChannelMap::const_iterator iter = proxy->channels().begin();
172 iter != proxy->channels().end(); ++iter, ++index) {
173 ReplaceImpl(iter->second, index);
174 }
175 // Now replace our transport. Must happen afterwards because
176 // it deletes all impls as a side effect.
177 transport_ = proxy->transport_;
178 }
179
180 // Mux the channel at |this->channels_[index]| (also known as
181 // |target_channel| onto |channel|. The new implementation (actually
182 // a ref-count-increased version of what's in |channel->impl| is
183 // obtained by calling CreateChannel on |channel|'s Transport object.
ReplaceImpl(TransportChannelProxy * channel,size_t index)184 void TransportProxy::ReplaceImpl(TransportChannelProxy* channel,
185 size_t index) {
186 if (index < channels().size()) {
187 ChannelMap::const_iterator iter = channels().begin();
188 // map::iterator does not allow random access
189 for (size_t i = 0; i < index; ++i, ++iter);
190
191 TransportChannelProxy* target_channel = iter->second;
192 if (target_channel) {
193 // Reset the implementation on the target_channel
194 target_channel->SetImplementation(
195 // Increments ref count
196 channel->impl()->GetTransport()->CreateChannel(channel->name(),
197 channel->content_type()));
198 }
199 } else {
200 LOG(LS_WARNING) << "invalid TransportChannelProxy index to replace";
201 }
202 }
203
StateToString(State state)204 std::string BaseSession::StateToString(State state) {
205 switch (state) {
206 case Session::STATE_INIT:
207 return "STATE_INIT";
208 case Session::STATE_SENTINITIATE:
209 return "STATE_SENTINITIATE";
210 case Session::STATE_RECEIVEDINITIATE:
211 return "STATE_RECEIVEDINITIATE";
212 case Session::STATE_SENTACCEPT:
213 return "STATE_SENTACCEPT";
214 case Session::STATE_RECEIVEDACCEPT:
215 return "STATE_RECEIVEDACCEPT";
216 case Session::STATE_SENTMODIFY:
217 return "STATE_SENTMODIFY";
218 case Session::STATE_RECEIVEDMODIFY:
219 return "STATE_RECEIVEDMODIFY";
220 case Session::STATE_SENTREJECT:
221 return "STATE_SENTREJECT";
222 case Session::STATE_RECEIVEDREJECT:
223 return "STATE_RECEIVEDREJECT";
224 case Session::STATE_SENTREDIRECT:
225 return "STATE_SENTREDIRECT";
226 case Session::STATE_SENTTERMINATE:
227 return "STATE_SENTTERMINATE";
228 case Session::STATE_RECEIVEDTERMINATE:
229 return "STATE_RECEIVEDTERMINATE";
230 case Session::STATE_INPROGRESS:
231 return "STATE_INPROGRESS";
232 case Session::STATE_DEINIT:
233 return "STATE_DEINIT";
234 default:
235 break;
236 }
237 return "STATE_" + talk_base::ToString(state);
238 }
239
BaseSession(talk_base::Thread * signaling_thread,talk_base::Thread * worker_thread,PortAllocator * port_allocator,const std::string & sid,const std::string & content_type,bool initiator)240 BaseSession::BaseSession(talk_base::Thread* signaling_thread,
241 talk_base::Thread* worker_thread,
242 PortAllocator* port_allocator,
243 const std::string& sid,
244 const std::string& content_type,
245 bool initiator)
246 : state_(STATE_INIT),
247 error_(ERROR_NONE),
248 signaling_thread_(signaling_thread),
249 worker_thread_(worker_thread),
250 port_allocator_(port_allocator),
251 sid_(sid),
252 content_type_(content_type),
253 transport_type_(NS_GINGLE_P2P),
254 initiator_(initiator),
255 local_description_(NULL),
256 remote_description_(NULL) {
257 ASSERT(signaling_thread->IsCurrent());
258 }
259
~BaseSession()260 BaseSession::~BaseSession() {
261 ASSERT(signaling_thread()->IsCurrent());
262
263 ASSERT(state_ != STATE_DEINIT);
264 LogState(state_, STATE_DEINIT);
265 state_ = STATE_DEINIT;
266 SignalState(this, state_);
267
268 for (TransportMap::iterator iter = transports_.begin();
269 iter != transports_.end(); ++iter) {
270 delete iter->second;
271 }
272
273 delete remote_description_;
274 delete local_description_;
275 }
276
set_allow_local_ips(bool allow)277 void BaseSession::set_allow_local_ips(bool allow) {
278 allow_local_ips_ = allow;
279 for (TransportMap::iterator iter = transports_.begin();
280 iter != transports_.end(); ++iter) {
281 iter->second->impl()->set_allow_local_ips(allow);
282 }
283 }
284
CreateChannel(const std::string & content_name,const std::string & channel_name)285 TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
286 const std::string& channel_name) {
287 // We create the proxy "on demand" here because we need to support
288 // creating channels at any time, even before we send or receive
289 // initiate messages, which is before we create the transports.
290 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
291 return transproxy->CreateChannel(channel_name, content_type_);
292 }
293
GetChannel(const std::string & content_name,const std::string & channel_name)294 TransportChannel* BaseSession::GetChannel(const std::string& content_name,
295 const std::string& channel_name) {
296 TransportProxy* transproxy = GetTransportProxy(content_name);
297 if (transproxy == NULL)
298 return NULL;
299 else
300 return transproxy->GetChannel(channel_name);
301 }
302
DestroyChannel(const std::string & content_name,const std::string & channel_name)303 void BaseSession::DestroyChannel(const std::string& content_name,
304 const std::string& channel_name) {
305 TransportProxy* transproxy = GetTransportProxy(content_name);
306 ASSERT(transproxy != NULL);
307 transproxy->DestroyChannel(channel_name);
308 }
309
GetOrCreateTransportProxy(const std::string & content_name)310 TransportProxy* BaseSession::GetOrCreateTransportProxy(
311 const std::string& content_name) {
312 TransportProxy* transproxy = GetTransportProxy(content_name);
313 if (transproxy)
314 return transproxy;
315
316 Transport* transport = CreateTransport();
317 transport->set_allow_local_ips(allow_local_ips_);
318 transport->SignalConnecting.connect(
319 this, &BaseSession::OnTransportConnecting);
320 transport->SignalWritableState.connect(
321 this, &BaseSession::OnTransportWritable);
322 transport->SignalRequestSignaling.connect(
323 this, &BaseSession::OnTransportRequestSignaling);
324 transport->SignalCandidatesReady.connect(
325 this, &BaseSession::OnTransportCandidatesReady);
326 transport->SignalTransportError.connect(
327 this, &BaseSession::OnTransportSendError);
328 transport->SignalChannelGone.connect(
329 this, &BaseSession::OnTransportChannelGone);
330 transport->SignalRouteChange.connect(
331 this, &BaseSession::OnTransportRouteChange);
332 transport->SignalCandidatesAllocationDone.connect(
333 this, &BaseSession::OnTransportCandidatesAllocationDone);
334
335 transproxy = new TransportProxy(sid_, content_name,
336 new TransportWrapper(transport));
337 transports_[content_name] = transproxy;
338
339 return transproxy;
340 }
341
GetTransport(const std::string & content_name)342 Transport* BaseSession::GetTransport(const std::string& content_name) {
343 TransportProxy* transproxy = GetTransportProxy(content_name);
344 if (transproxy == NULL)
345 return NULL;
346 return transproxy->impl();
347 }
348
GetTransportProxy(const std::string & content_name)349 TransportProxy* BaseSession::GetTransportProxy(
350 const std::string& content_name) {
351 TransportMap::iterator iter = transports_.find(content_name);
352 return (iter != transports_.end()) ? iter->second : NULL;
353 }
354
GetTransportProxy(const Transport * transport)355 TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
356 for (TransportMap::iterator iter = transports_.begin();
357 iter != transports_.end(); ++iter) {
358 TransportProxy* transproxy = iter->second;
359 if (transproxy->impl() == transport) {
360 return transproxy;
361 }
362 }
363 return NULL;
364 }
365
GetFirstTransportProxy()366 TransportProxy* BaseSession::GetFirstTransportProxy() {
367 if (transports_.empty())
368 return NULL;
369 return transports_.begin()->second;
370 }
371
DestroyTransportProxy(const std::string & content_name)372 void BaseSession::DestroyTransportProxy(
373 const std::string& content_name) {
374 TransportMap::iterator iter = transports_.find(content_name);
375 if (iter != transports_.end()) {
376 delete iter->second;
377 transports_.erase(content_name);
378 }
379 }
380
CreateTransport()381 cricket::Transport* BaseSession::CreateTransport() {
382 ASSERT(transport_type_ == NS_GINGLE_P2P);
383 return new cricket::P2PTransport(
384 signaling_thread(), worker_thread(), port_allocator());
385 }
386
SetState(State state)387 void BaseSession::SetState(State state) {
388 ASSERT(signaling_thread_->IsCurrent());
389 if (state != state_) {
390 LogState(state_, state);
391 state_ = state;
392 SignalState(this, state_);
393 signaling_thread_->Post(this, MSG_STATE);
394 }
395 }
396
SetError(Error error)397 void BaseSession::SetError(Error error) {
398 ASSERT(signaling_thread_->IsCurrent());
399 if (error != error_) {
400 error_ = error;
401 SignalError(this, error);
402 }
403 }
404
OnSignalingReady()405 void BaseSession::OnSignalingReady() {
406 ASSERT(signaling_thread()->IsCurrent());
407 for (TransportMap::iterator iter = transports_.begin();
408 iter != transports_.end(); ++iter) {
409 iter->second->impl()->OnSignalingReady();
410 }
411 }
412
SpeculativelyConnectAllTransportChannels()413 void BaseSession::SpeculativelyConnectAllTransportChannels() {
414 for (TransportMap::iterator iter = transports_.begin();
415 iter != transports_.end(); ++iter) {
416 iter->second->SpeculativelyConnectChannels();
417 }
418 }
419
ContentsGrouped()420 bool BaseSession::ContentsGrouped() {
421 // TODO - present implementation checks for groups present
422 // in SDP. It may be necessary to check content_names in groups of both
423 // local and remote descriptions. Assumption here is that when this method
424 // returns true, media contents can be muxed.
425 if (local_description()->HasGroup(GROUP_TYPE_BUNDLE) &&
426 remote_description()->HasGroup(GROUP_TYPE_BUNDLE)) {
427 return true;
428 }
429 return false;
430 }
431
MaybeEnableMuxingSupport()432 bool BaseSession::MaybeEnableMuxingSupport() {
433 bool ret = true;
434 if (!ContentsGrouped()) {
435 LOG(LS_INFO) << "Contents are not grouped together cannot be muxed";
436 } else {
437 // Always use first content name from the group for muxing. Hence ordering
438 // of content names in SDP should match to the order in group.
439 const ContentGroup* muxed_content_group =
440 local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
441 const std::string* content_name =
442 muxed_content_group->FirstContentName();
443 if (content_name) {
444 const ContentInfo* content =
445 local_description_->GetContentByName(*content_name);
446 ASSERT(content != NULL);
447 SetSelectedProxy(content->name, muxed_content_group);
448 }
449 }
450 return ret;
451 }
452
SetSelectedProxy(const std::string & content_name,const ContentGroup * muxed_group)453 void BaseSession::SetSelectedProxy(const std::string& content_name,
454 const ContentGroup* muxed_group) {
455 TransportProxy* selected_proxy = GetTransportProxy(content_name);
456 if (selected_proxy) {
457 ASSERT(selected_proxy->negotiated());
458 for (TransportMap::iterator iter = transports_.begin();
459 iter != transports_.end(); ++iter) {
460 // If content is part of group, then try to replace the Proxy with
461 // the selected.
462 if (iter->first != content_name &&
463 muxed_group->HasContentName(iter->first)) {
464 TransportProxy* proxy = iter->second;
465 proxy->SetupMux(selected_proxy);
466 }
467 }
468 }
469 }
470
OnTransportCandidatesAllocationDone(Transport * transport)471 void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
472 TransportProxy* transport_proxy = GetTransportProxy(transport);
473 if (transport_proxy) {
474 transport_proxy->set_candidates_allocated(true);
475 }
476
477 // Check all other TransportProxies got this signal.
478 for (TransportMap::iterator iter = transports_.begin();
479 iter != transports_.end(); ++iter) {
480 if (iter->second->impl() == transport) {
481 if (!iter->second->candidates_allocated())
482 return;
483 }
484 }
485 OnCandidatesAllocationDone();
486 }
487
LogState(State old_state,State new_state)488 void BaseSession::LogState(State old_state, State new_state) {
489 LOG(LS_INFO) << "Session:" << id()
490 << " Old state:" << StateToString(old_state)
491 << " New state:" << StateToString(new_state)
492 << " Type:" << content_type()
493 << " Transport:" << transport_type();
494 }
495
OnMessage(talk_base::Message * pmsg)496 void BaseSession::OnMessage(talk_base::Message *pmsg) {
497 switch (pmsg->message_id) {
498 case MSG_TIMEOUT:
499 // Session timeout has occurred.
500 SetError(ERROR_TIME);
501 break;
502
503 case MSG_STATE:
504 switch (state_) {
505 case STATE_SENTACCEPT:
506 case STATE_RECEIVEDACCEPT:
507 SetState(STATE_INPROGRESS);
508 break;
509
510 default:
511 // Explicitly ignoring some states here.
512 break;
513 }
514 break;
515 }
516 }
517
Session(SessionManager * session_manager,const std::string & local_name,const std::string & initiator_name,const std::string & sid,const std::string & content_type,SessionClient * client)518 Session::Session(SessionManager* session_manager,
519 const std::string& local_name,
520 const std::string& initiator_name,
521 const std::string& sid,
522 const std::string& content_type,
523 SessionClient* client)
524 : BaseSession(session_manager->signaling_thread(),
525 session_manager->worker_thread(),
526 session_manager->port_allocator(),
527 sid, content_type, initiator_name == local_name) {
528 ASSERT(client != NULL);
529 session_manager_ = session_manager;
530 local_name_ = local_name;
531 initiator_name_ = initiator_name;
532 transport_parser_ = new P2PTransportParser();
533 client_ = client;
534 initiate_acked_ = false;
535 current_protocol_ = PROTOCOL_HYBRID;
536 }
537
~Session()538 Session::~Session() {
539 delete transport_parser_;
540 }
541
Initiate(const std::string & to,const SessionDescription * sdesc)542 bool Session::Initiate(const std::string &to,
543 const SessionDescription* sdesc) {
544 ASSERT(signaling_thread()->IsCurrent());
545 SessionError error;
546
547 // Only from STATE_INIT
548 if (state() != STATE_INIT)
549 return false;
550
551 // Setup for signaling.
552 set_remote_name(to);
553 set_local_description(sdesc);
554 if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
555 &error)) {
556 LOG(LS_ERROR) << "Could not create transports: " << error.text;
557 return false;
558 }
559
560 if (!SendInitiateMessage(sdesc, &error)) {
561 LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
562 return false;
563 }
564
565 SetState(Session::STATE_SENTINITIATE);
566
567 SpeculativelyConnectAllTransportChannels();
568 return true;
569 }
570
Accept(const SessionDescription * sdesc)571 bool Session::Accept(const SessionDescription* sdesc) {
572 ASSERT(signaling_thread()->IsCurrent());
573
574 // Only if just received initiate
575 if (state() != STATE_RECEIVEDINITIATE)
576 return false;
577
578 // Setup for signaling.
579 set_local_description(sdesc);
580
581 SessionError error;
582 if (!SendAcceptMessage(sdesc, &error)) {
583 LOG(LS_ERROR) << "Could not send accept message: " << error.text;
584 return false;
585 }
586 // TODO - Add BUNDLE support to transport-info messages.
587 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
588 SetState(Session::STATE_SENTACCEPT);
589 return true;
590 }
591
Reject(const std::string & reason)592 bool Session::Reject(const std::string& reason) {
593 ASSERT(signaling_thread()->IsCurrent());
594
595 // Reject is sent in response to an initiate or modify, to reject the
596 // request
597 if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY)
598 return false;
599
600 SessionError error;
601 if (!SendRejectMessage(reason, &error)) {
602 LOG(LS_ERROR) << "Could not send reject message: " << error.text;
603 return false;
604 }
605
606 SetState(STATE_SENTREJECT);
607 return true;
608 }
609
TerminateWithReason(const std::string & reason)610 bool Session::TerminateWithReason(const std::string& reason) {
611 ASSERT(signaling_thread()->IsCurrent());
612
613 // Either side can terminate, at any time.
614 switch (state()) {
615 case STATE_SENTTERMINATE:
616 case STATE_RECEIVEDTERMINATE:
617 return false;
618
619 case STATE_SENTREJECT:
620 case STATE_RECEIVEDREJECT:
621 // We don't need to send terminate if we sent or received a reject...
622 // it's implicit.
623 break;
624
625 default:
626 SessionError error;
627 if (!SendTerminateMessage(reason, &error)) {
628 LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
629 return false;
630 }
631 break;
632 }
633
634 SetState(STATE_SENTTERMINATE);
635 return true;
636 }
637
SendInfoMessage(const XmlElements & elems)638 bool Session::SendInfoMessage(const XmlElements& elems) {
639 ASSERT(signaling_thread()->IsCurrent());
640 SessionError error;
641 if (!SendMessage(ACTION_SESSION_INFO, elems, &error)) {
642 LOG(LS_ERROR) << "Could not send info message " << error.text;
643 return false;
644 }
645 return true;
646 }
647
GetEmptyTransportInfos(const ContentInfos & contents) const648 TransportInfos Session::GetEmptyTransportInfos(
649 const ContentInfos& contents) const {
650 TransportInfos tinfos;
651 for (ContentInfos::const_iterator content = contents.begin();
652 content != contents.end(); ++content) {
653 tinfos.push_back(
654 TransportInfo(content->name, transport_type(), Candidates()));
655 }
656 return tinfos;
657 }
658
OnRemoteCandidates(const TransportInfos & tinfos,ParseError * error)659 bool Session::OnRemoteCandidates(
660 const TransportInfos& tinfos, ParseError* error) {
661 for (TransportInfos::const_iterator tinfo = tinfos.begin();
662 tinfo != tinfos.end(); ++tinfo) {
663 TransportProxy* transproxy = GetTransportProxy(tinfo->content_name);
664 if (transproxy == NULL) {
665 return BadParse("Unknown content name: " + tinfo->content_name, error);
666 }
667
668 // Must complete negotiation before sending remote candidates, or
669 // there won't be any channel impls.
670 transproxy->CompleteNegotiation();
671 for (Candidates::const_iterator cand = tinfo->candidates.begin();
672 cand != tinfo->candidates.end(); ++cand) {
673 if (!transproxy->impl()->VerifyCandidate(*cand, error))
674 return false;
675
676 if (!transproxy->impl()->HasChannel(cand->name())) {
677 buzz::XmlElement* extra_info =
678 new buzz::XmlElement(QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME);
679 extra_info->AddAttr(buzz::QN_NAME, cand->name());
680 error->extra = extra_info;
681
682 return BadParse("channel named in candidate does not exist: " +
683 cand->name() + " for content: "+ tinfo->content_name,
684 error);
685 }
686 }
687 transproxy->impl()->OnRemoteCandidates(tinfo->candidates);
688 }
689
690 return true;
691 }
692
CreateTransportProxies(const TransportInfos & tinfos,SessionError * error)693 bool Session::CreateTransportProxies(const TransportInfos& tinfos,
694 SessionError* error) {
695 for (TransportInfos::const_iterator tinfo = tinfos.begin();
696 tinfo != tinfos.end(); ++tinfo) {
697 if (tinfo->transport_type != transport_type()) {
698 error->SetText("No supported transport in offer.");
699 return false;
700 }
701
702 GetOrCreateTransportProxy(tinfo->content_name);
703 }
704 return true;
705 }
706
GetTransportParsers()707 TransportParserMap Session::GetTransportParsers() {
708 TransportParserMap parsers;
709 parsers[transport_type()] = transport_parser_;
710 return parsers;
711 }
712
GetContentParsers()713 ContentParserMap Session::GetContentParsers() {
714 ContentParserMap parsers;
715 parsers[content_type()] = client_;
716 return parsers;
717 }
718
OnTransportRequestSignaling(Transport * transport)719 void Session::OnTransportRequestSignaling(Transport* transport) {
720 ASSERT(signaling_thread()->IsCurrent());
721 TransportProxy* transport_proxy = GetTransportProxy(transport);
722 ASSERT(transport_proxy != NULL);
723 if (transport_proxy) {
724 // Reset candidate allocation status for the transport proxy.
725 transport_proxy->set_candidates_allocated(false);
726 }
727 SignalRequestSignaling(this);
728 }
729
OnTransportConnecting(Transport * transport)730 void Session::OnTransportConnecting(Transport* transport) {
731 // This is an indication that we should begin watching the writability
732 // state of the transport.
733 OnTransportWritable(transport);
734 }
735
OnTransportWritable(Transport * transport)736 void Session::OnTransportWritable(Transport* transport) {
737 ASSERT(signaling_thread()->IsCurrent());
738
739 // If the transport is not writable, start a timer to make sure that it
740 // becomes writable within a reasonable amount of time. If it does not, we
741 // terminate since we can't actually send data. If the transport is writable,
742 // cancel the timer. Note that writability transitions may occur repeatedly
743 // during the lifetime of the session.
744 signaling_thread()->Clear(this, MSG_TIMEOUT);
745 if (transport->HasChannels() && !transport->writable()) {
746 signaling_thread()->PostDelayed(
747 session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
748 }
749 }
750
OnTransportCandidatesReady(Transport * transport,const Candidates & candidates)751 void Session::OnTransportCandidatesReady(Transport* transport,
752 const Candidates& candidates) {
753 ASSERT(signaling_thread()->IsCurrent());
754 TransportProxy* transproxy = GetTransportProxy(transport);
755 if (transproxy != NULL) {
756 if (initiator() && !initiate_acked_) {
757 // TODO: This is to work around server re-ordering
758 // messages. We send the candidates once the session-initiate
759 // is acked. Once we have fixed the server to guarantee message
760 // order, we can remove this case.
761 transproxy->AddUnsentCandidates(candidates);
762 } else {
763 if (!transproxy->negotiated()) {
764 transproxy->AddSentCandidates(candidates);
765 }
766 SessionError error;
767 if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
768 LOG(LS_ERROR) << "Could not send transport info message: "
769 << error.text;
770 return;
771 }
772 }
773 }
774 }
775
OnTransportSendError(Transport * transport,const buzz::XmlElement * stanza,const buzz::QName & name,const std::string & type,const std::string & text,const buzz::XmlElement * extra_info)776 void Session::OnTransportSendError(Transport* transport,
777 const buzz::XmlElement* stanza,
778 const buzz::QName& name,
779 const std::string& type,
780 const std::string& text,
781 const buzz::XmlElement* extra_info) {
782 ASSERT(signaling_thread()->IsCurrent());
783 SignalErrorMessage(this, stanza, name, type, text, extra_info);
784 }
785
OnTransportChannelGone(Transport * transport,const std::string & name)786 void Session::OnTransportChannelGone(Transport* transport,
787 const std::string& name) {
788 ASSERT(signaling_thread()->IsCurrent());
789 SignalChannelGone(this, name);
790 }
791
OnIncomingMessage(const SessionMessage & msg)792 void Session::OnIncomingMessage(const SessionMessage& msg) {
793 ASSERT(signaling_thread()->IsCurrent());
794 ASSERT(state() == STATE_INIT || msg.from == remote_name());
795
796 if (current_protocol_== PROTOCOL_HYBRID) {
797 if (msg.protocol == PROTOCOL_GINGLE) {
798 current_protocol_ = PROTOCOL_GINGLE;
799 } else {
800 current_protocol_ = PROTOCOL_JINGLE;
801 }
802 }
803
804 bool valid = false;
805 MessageError error;
806 switch (msg.type) {
807 case ACTION_SESSION_INITIATE:
808 valid = OnInitiateMessage(msg, &error);
809 break;
810 case ACTION_SESSION_INFO:
811 valid = OnInfoMessage(msg);
812 break;
813 case ACTION_SESSION_ACCEPT:
814 valid = OnAcceptMessage(msg, &error);
815 break;
816 case ACTION_SESSION_REJECT:
817 valid = OnRejectMessage(msg, &error);
818 break;
819 case ACTION_SESSION_TERMINATE:
820 valid = OnTerminateMessage(msg, &error);
821 break;
822 case ACTION_TRANSPORT_INFO:
823 valid = OnTransportInfoMessage(msg, &error);
824 break;
825 case ACTION_TRANSPORT_ACCEPT:
826 valid = OnTransportAcceptMessage(msg, &error);
827 break;
828 case ACTION_DESCRIPTION_INFO:
829 valid = OnDescriptionInfoMessage(msg, &error);
830 break;
831 default:
832 valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
833 "unknown session message type",
834 &error);
835 }
836
837 if (valid) {
838 SendAcknowledgementMessage(msg.stanza);
839 } else {
840 SignalErrorMessage(this, msg.stanza, error.type,
841 "modify", error.text, NULL);
842 }
843 }
844
OnIncomingResponse(const buzz::XmlElement * orig_stanza,const buzz::XmlElement * response_stanza,const SessionMessage & msg)845 void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
846 const buzz::XmlElement* response_stanza,
847 const SessionMessage& msg) {
848 ASSERT(signaling_thread()->IsCurrent());
849
850 if (msg.type == ACTION_SESSION_INITIATE) {
851 OnInitiateAcked();
852 }
853 }
854
OnInitiateAcked()855 void Session::OnInitiateAcked() {
856 // TODO: This is to work around server re-ordering
857 // messages. We send the candidates once the session-initiate
858 // is acked. Once we have fixed the server to guarantee message
859 // order, we can remove this case.
860 if (!initiate_acked_) {
861 initiate_acked_ = true;
862 SessionError error;
863 SendAllUnsentTransportInfoMessages(&error);
864 }
865 }
866
OnFailedSend(const buzz::XmlElement * orig_stanza,const buzz::XmlElement * error_stanza)867 void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
868 const buzz::XmlElement* error_stanza) {
869 ASSERT(signaling_thread()->IsCurrent());
870
871 SessionMessage msg;
872 ParseError parse_error;
873 if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
874 LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
875 << ":" << orig_stanza;
876 return;
877 }
878
879 // If the error is a session redirect, call OnRedirectError, which will
880 // continue the session with a new remote JID.
881 SessionRedirect redirect;
882 if (FindSessionRedirect(error_stanza, &redirect)) {
883 SessionError error;
884 if (!OnRedirectError(redirect, &error)) {
885 // TODO: Should we send a message back? The standard
886 // says nothing about it.
887 LOG(LS_ERROR) << "Failed to redirect: " << error.text;
888 SetError(ERROR_RESPONSE);
889 }
890 return;
891 }
892
893 std::string error_type = "cancel";
894
895 const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
896 if (error) {
897 error_type = error->Attr(buzz::QN_TYPE);
898
899 LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
900 << "in response to:\n" << orig_stanza->Str();
901 } else {
902 // don't crash if <error> is missing
903 LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
904 return;
905 }
906
907 if (msg.type == ACTION_TRANSPORT_INFO) {
908 // Transport messages frequently generate errors because they are sent right
909 // when we detect a network failure. For that reason, we ignore such
910 // errors, because if we do not establish writability again, we will
911 // terminate anyway. The exceptions are transport-specific error tags,
912 // which we pass on to the respective transport.
913
914 // TODO: This is only used for unknown channel name.
915 // For Jingle, find a standard-compliant way of doing this. For
916 // Gingle, guess the content name based on the channel name.
917 for (const buzz::XmlElement* elem = error->FirstElement();
918 NULL != elem; elem = elem->NextElement()) {
919 TransportProxy* transproxy = GetFirstTransportProxy();
920 if (transproxy && transproxy->type() == error->Name().Namespace()) {
921 transproxy->impl()->OnTransportError(elem);
922 }
923 }
924 } else if ((error_type != "continue") && (error_type != "wait")) {
925 // We do not set an error if the other side said it is okay to continue
926 // (possibly after waiting). These errors can be ignored.
927 SetError(ERROR_RESPONSE);
928 }
929 }
930
OnInitiateMessage(const SessionMessage & msg,MessageError * error)931 bool Session::OnInitiateMessage(const SessionMessage& msg,
932 MessageError* error) {
933 if (!CheckState(STATE_INIT, error))
934 return false;
935
936 SessionInitiate init;
937 if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
938 GetContentParsers(), GetTransportParsers(),
939 &init, error))
940 return false;
941
942 SessionError session_error;
943 if (!CreateTransportProxies(init.transports, &session_error)) {
944 return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
945 session_error.text, error);
946 }
947
948 set_remote_name(msg.from);
949 set_remote_description(new SessionDescription(init.ClearContents(),
950 init.groups));
951 SetState(STATE_RECEIVEDINITIATE);
952
953 // Users of Session may listen to state change and call Reject().
954 if (state() != STATE_SENTREJECT) {
955 if (!OnRemoteCandidates(init.transports, error))
956 return false;
957 }
958 return true;
959 }
960
OnAcceptMessage(const SessionMessage & msg,MessageError * error)961 bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
962 if (!CheckState(STATE_SENTINITIATE, error))
963 return false;
964
965 SessionAccept accept;
966 if (!ParseSessionAccept(msg.protocol, msg.action_elem,
967 GetContentParsers(), GetTransportParsers(),
968 &accept, error)) {
969 return false;
970 }
971
972 // If we get an accept, we can assume the initiate has been
973 // received, even if we haven't gotten an IQ response.
974 OnInitiateAcked();
975
976 set_remote_description(new SessionDescription(accept.ClearContents(),
977 accept.groups));
978 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
979 SetState(STATE_RECEIVEDACCEPT);
980
981 // Users of Session may listen to state change and call Reject().
982 if (state() != STATE_SENTREJECT) {
983 if (!OnRemoteCandidates(accept.transports, error))
984 return false;
985 }
986
987 return true;
988 }
989
OnRejectMessage(const SessionMessage & msg,MessageError * error)990 bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
991 if (!CheckState(STATE_SENTINITIATE, error))
992 return false;
993
994 SetState(STATE_RECEIVEDREJECT);
995 return true;
996 }
997
OnInfoMessage(const SessionMessage & msg)998 bool Session::OnInfoMessage(const SessionMessage& msg) {
999 SignalInfoMessage(this, msg.action_elem);
1000 return true;
1001 }
1002
OnTerminateMessage(const SessionMessage & msg,MessageError * error)1003 bool Session::OnTerminateMessage(const SessionMessage& msg,
1004 MessageError* error) {
1005 SessionTerminate term;
1006 if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
1007 return false;
1008
1009 SignalReceivedTerminateReason(this, term.reason);
1010 if (term.debug_reason != buzz::STR_EMPTY) {
1011 LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
1012 }
1013
1014 SetState(STATE_RECEIVEDTERMINATE);
1015 return true;
1016 }
1017
OnTransportInfoMessage(const SessionMessage & msg,MessageError * error)1018 bool Session::OnTransportInfoMessage(const SessionMessage& msg,
1019 MessageError* error) {
1020 TransportInfos tinfos;
1021 if (!ParseTransportInfos(msg.protocol, msg.action_elem,
1022 initiator_description()->contents(),
1023 GetTransportParsers(), &tinfos, error))
1024 return false;
1025
1026 if (!OnRemoteCandidates(tinfos, error))
1027 return false;
1028
1029 return true;
1030 }
1031
OnTransportAcceptMessage(const SessionMessage & msg,MessageError * error)1032 bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
1033 MessageError* error) {
1034 // TODO: Currently here only for compatibility with
1035 // Gingle 1.1 clients (notably, Google Voice).
1036 return true;
1037 }
1038
OnDescriptionInfoMessage(const SessionMessage & msg,MessageError * error)1039 bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
1040 MessageError* error) {
1041 if (!CheckState(STATE_INPROGRESS, error))
1042 return false;
1043
1044 DescriptionInfo description_info;
1045 if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
1046 GetContentParsers(), GetTransportParsers(),
1047 &description_info, error)) {
1048 return false;
1049 }
1050
1051 ContentInfos updated_contents = description_info.ClearContents();
1052
1053 // TODO: Currently, reflector sends back
1054 // video stream updates even for an audio-only call, which causes
1055 // this to fail. Put this back once reflector is fixed.
1056 //
1057 // ContentInfos::iterator it;
1058 // First, ensure all updates are valid before modifying remote_description_.
1059 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
1060 // if (remote_description()->GetContentByName(it->name) == NULL) {
1061 // return false;
1062 // }
1063 // }
1064
1065 // TODO: We used to replace contents from an update, but
1066 // that no longer works with partial updates. We need to figure out
1067 // a way to merge patial updates into contents. For now, users of
1068 // Session should listen to SignalRemoteDescriptionUpdate and handle
1069 // updates. They should not expect remote_description to be the
1070 // latest value.
1071 //
1072 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
1073 // remote_description()->RemoveContentByName(it->name);
1074 // remote_description()->AddContent(it->name, it->type, it->description);
1075 // }
1076 // }
1077
1078 SignalRemoteDescriptionUpdate(this, updated_contents);
1079 return true;
1080 }
1081
BareJidsEqual(const std::string & name1,const std::string & name2)1082 bool BareJidsEqual(const std::string& name1,
1083 const std::string& name2) {
1084 buzz::Jid jid1(name1);
1085 buzz::Jid jid2(name2);
1086
1087 return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
1088 }
1089
OnRedirectError(const SessionRedirect & redirect,SessionError * error)1090 bool Session::OnRedirectError(const SessionRedirect& redirect,
1091 SessionError* error) {
1092 MessageError message_error;
1093 if (!CheckState(STATE_SENTINITIATE, &message_error)) {
1094 return BadWrite(message_error.text, error);
1095 }
1096
1097 if (!BareJidsEqual(remote_name(), redirect.target))
1098 return BadWrite("Redirection not allowed: must be the same bare jid.",
1099 error);
1100
1101 // When we receive a redirect, we point the session at the new JID
1102 // and resend the candidates.
1103 set_remote_name(redirect.target);
1104 return (SendInitiateMessage(local_description(), error) &&
1105 ResendAllTransportInfoMessages(error));
1106 }
1107
CheckState(State expected,MessageError * error)1108 bool Session::CheckState(State expected, MessageError* error) {
1109 ASSERT(state() == expected);
1110 if (state() != expected) {
1111 return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
1112 "message not allowed in current state",
1113 error);
1114 }
1115 return true;
1116 }
1117
SetError(Error error)1118 void Session::SetError(Error error) {
1119 BaseSession::SetError(error);
1120 if (error != ERROR_NONE)
1121 signaling_thread()->Post(this, MSG_ERROR);
1122 }
1123
OnMessage(talk_base::Message * pmsg)1124 void Session::OnMessage(talk_base::Message *pmsg) {
1125 // preserve this because BaseSession::OnMessage may modify it
1126 State orig_state = state();
1127
1128 BaseSession::OnMessage(pmsg);
1129
1130 switch (pmsg->message_id) {
1131 case MSG_ERROR:
1132 TerminateWithReason(STR_TERMINATE_ERROR);
1133 break;
1134
1135 case MSG_STATE:
1136 switch (orig_state) {
1137 case STATE_SENTREJECT:
1138 case STATE_RECEIVEDREJECT:
1139 // Assume clean termination.
1140 Terminate();
1141 break;
1142
1143 case STATE_SENTTERMINATE:
1144 case STATE_RECEIVEDTERMINATE:
1145 session_manager_->DestroySession(this);
1146 break;
1147
1148 default:
1149 // Explicitly ignoring some states here.
1150 break;
1151 }
1152 break;
1153 }
1154 }
1155
SendInitiateMessage(const SessionDescription * sdesc,SessionError * error)1156 bool Session::SendInitiateMessage(const SessionDescription* sdesc,
1157 SessionError* error) {
1158 SessionInitiate init;
1159 init.contents = sdesc->contents();
1160 init.transports = GetEmptyTransportInfos(init.contents);
1161 init.groups = sdesc->groups();
1162 return SendMessage(ACTION_SESSION_INITIATE, init, error);
1163 }
1164
WriteSessionAction(SignalingProtocol protocol,const SessionInitiate & init,XmlElements * elems,WriteError * error)1165 bool Session::WriteSessionAction(
1166 SignalingProtocol protocol, const SessionInitiate& init,
1167 XmlElements* elems, WriteError* error) {
1168 ContentParserMap content_parsers = GetContentParsers();
1169 TransportParserMap trans_parsers = GetTransportParsers();
1170
1171 return WriteSessionInitiate(protocol, init.contents, init.transports,
1172 content_parsers, trans_parsers, init.groups,
1173 elems, error);
1174 }
1175
SendAcceptMessage(const SessionDescription * sdesc,SessionError * error)1176 bool Session::SendAcceptMessage(const SessionDescription* sdesc,
1177 SessionError* error) {
1178 XmlElements elems;
1179 if (!WriteSessionAccept(current_protocol_,
1180 sdesc->contents(),
1181 GetEmptyTransportInfos(sdesc->contents()),
1182 GetContentParsers(), GetTransportParsers(),
1183 sdesc->groups(), &elems, error)) {
1184 return false;
1185 }
1186 return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
1187 }
1188
SendRejectMessage(const std::string & reason,SessionError * error)1189 bool Session::SendRejectMessage(const std::string& reason,
1190 SessionError* error) {
1191 SessionTerminate term(reason);
1192 return SendMessage(ACTION_SESSION_REJECT, term, error);
1193 }
1194
SendTerminateMessage(const std::string & reason,SessionError * error)1195 bool Session::SendTerminateMessage(const std::string& reason,
1196 SessionError* error) {
1197 SessionTerminate term(reason);
1198 return SendMessage(ACTION_SESSION_TERMINATE, term, error);
1199 }
1200
WriteSessionAction(SignalingProtocol protocol,const SessionTerminate & term,XmlElements * elems,WriteError * error)1201 bool Session::WriteSessionAction(SignalingProtocol protocol,
1202 const SessionTerminate& term,
1203 XmlElements* elems, WriteError* error) {
1204 WriteSessionTerminate(protocol, term, elems);
1205 return true;
1206 }
1207
SendTransportInfoMessage(const TransportInfo & tinfo,SessionError * error)1208 bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
1209 SessionError* error) {
1210 return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
1211 }
1212
SendTransportInfoMessage(const TransportProxy * transproxy,const Candidates & candidates,SessionError * error)1213 bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
1214 const Candidates& candidates,
1215 SessionError* error) {
1216 return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
1217 transproxy->type(),
1218 candidates),
1219 error);
1220 }
1221
WriteSessionAction(SignalingProtocol protocol,const TransportInfo & tinfo,XmlElements * elems,WriteError * error)1222 bool Session::WriteSessionAction(SignalingProtocol protocol,
1223 const TransportInfo& tinfo,
1224 XmlElements* elems, WriteError* error) {
1225 TransportInfos tinfos;
1226 tinfos.push_back(tinfo);
1227 TransportParserMap parsers = GetTransportParsers();
1228
1229 return WriteTransportInfos(protocol, tinfos, parsers,
1230 elems, error);
1231 }
1232
ResendAllTransportInfoMessages(SessionError * error)1233 bool Session::ResendAllTransportInfoMessages(SessionError* error) {
1234 for (TransportMap::const_iterator iter = transport_proxies().begin();
1235 iter != transport_proxies().end(); ++iter) {
1236 TransportProxy* transproxy = iter->second;
1237 if (transproxy->sent_candidates().size() > 0) {
1238 if (!SendTransportInfoMessage(
1239 transproxy, transproxy->sent_candidates(), error)) {
1240 LOG(LS_ERROR) << "Could not resend transport info messages: "
1241 << error->text;
1242 return false;
1243 }
1244 transproxy->ClearSentCandidates();
1245 }
1246 }
1247 return true;
1248 }
1249
SendAllUnsentTransportInfoMessages(SessionError * error)1250 bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
1251 for (TransportMap::const_iterator iter = transport_proxies().begin();
1252 iter != transport_proxies().end(); ++iter) {
1253 TransportProxy* transproxy = iter->second;
1254 if (transproxy->unsent_candidates().size() > 0) {
1255 if (!SendTransportInfoMessage(
1256 transproxy, transproxy->unsent_candidates(), error)) {
1257 LOG(LS_ERROR) << "Could not send unsent transport info messages: "
1258 << error->text;
1259 return false;
1260 }
1261 transproxy->ClearUnsentCandidates();
1262 }
1263 }
1264 return true;
1265 }
1266
SendMessage(ActionType type,const XmlElements & action_elems,SessionError * error)1267 bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
1268 SessionError* error) {
1269 talk_base::scoped_ptr<buzz::XmlElement> stanza(
1270 new buzz::XmlElement(buzz::QN_IQ));
1271
1272 SessionMessage msg(current_protocol_, type, id(), initiator_name());
1273 msg.to = remote_name();
1274 WriteSessionMessage(msg, action_elems, stanza.get());
1275
1276 SignalOutgoingMessage(this, stanza.get());
1277 return true;
1278 }
1279
1280 template <typename Action>
SendMessage(ActionType type,const Action & action,SessionError * error)1281 bool Session::SendMessage(ActionType type, const Action& action,
1282 SessionError* error) {
1283 talk_base::scoped_ptr<buzz::XmlElement> stanza(
1284 new buzz::XmlElement(buzz::QN_IQ));
1285 if (!WriteActionMessage(type, action, stanza.get(), error))
1286 return false;
1287
1288 SignalOutgoingMessage(this, stanza.get());
1289 return true;
1290 }
1291
1292 template <typename Action>
WriteActionMessage(ActionType type,const Action & action,buzz::XmlElement * stanza,WriteError * error)1293 bool Session::WriteActionMessage(ActionType type, const Action& action,
1294 buzz::XmlElement* stanza,
1295 WriteError* error) {
1296 if (current_protocol_ == PROTOCOL_HYBRID) {
1297 if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
1298 return false;
1299 if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
1300 return false;
1301 } else {
1302 if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
1303 return false;
1304 }
1305 return true;
1306 }
1307
1308 template <typename Action>
WriteActionMessage(SignalingProtocol protocol,ActionType type,const Action & action,buzz::XmlElement * stanza,WriteError * error)1309 bool Session::WriteActionMessage(SignalingProtocol protocol,
1310 ActionType type, const Action& action,
1311 buzz::XmlElement* stanza, WriteError* error) {
1312 XmlElements action_elems;
1313 if (!WriteSessionAction(protocol, action, &action_elems, error))
1314 return false;
1315
1316 SessionMessage msg(protocol, type, id(), initiator_name());
1317 msg.to = remote_name();
1318
1319 WriteSessionMessage(msg, action_elems, stanza);
1320 return true;
1321 }
1322
SendAcknowledgementMessage(const buzz::XmlElement * stanza)1323 void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
1324 talk_base::scoped_ptr<buzz::XmlElement> ack(
1325 new buzz::XmlElement(buzz::QN_IQ));
1326 ack->SetAttr(buzz::QN_TO, remote_name());
1327 ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
1328 ack->SetAttr(buzz::QN_TYPE, "result");
1329
1330 SignalOutgoingMessage(this, ack.get());
1331 }
1332
1333 } // namespace cricket
1334