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