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/sessionclient.h"
36#include "talk/p2p/base/transport.h"
37#include "talk/p2p/base/transportchannelproxy.h"
38#include "talk/p2p/base/p2ptransport.h"
39#include "talk/p2p/base/p2ptransportchannel.h"
40
41#include "talk/p2p/base/constants.h"
42
43namespace {
44
45const uint32 MSG_TIMEOUT = 1;
46const uint32 MSG_ERROR = 2;
47const uint32 MSG_STATE = 3;
48
49}  // namespace
50
51namespace cricket {
52
53bool 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
61TransportProxy::~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  delete transport_;
68}
69
70std::string TransportProxy::type() const {
71  return transport_->type();
72}
73
74TransportChannel* TransportProxy::GetChannel(const std::string& name) {
75  return GetProxy(name);
76}
77
78TransportChannel* TransportProxy::CreateChannel(
79    const std::string& name, const std::string& content_type) {
80  ASSERT(GetChannel(name) == NULL);
81  ASSERT(!transport_->HasChannel(name));
82
83  // We always create a proxy in case we need to change out the transport later.
84  TransportChannelProxy* channel =
85      new TransportChannelProxy(name, content_type);
86  channels_[name] = channel;
87
88  if (state_ == STATE_NEGOTIATED) {
89    SetProxyImpl(name, channel);
90  } else if (state_ == STATE_CONNECTING) {
91    GetOrCreateImpl(name, content_type);
92  }
93  return channel;
94}
95
96void TransportProxy::DestroyChannel(const std::string& name) {
97  TransportChannel* channel = GetChannel(name);
98  if (channel) {
99    channels_.erase(name);
100    channel->SignalDestroyed(channel);
101    delete channel;
102  }
103}
104
105void TransportProxy::SpeculativelyConnectChannels() {
106  ASSERT(state_ == STATE_INIT || state_ == STATE_CONNECTING);
107  state_ = STATE_CONNECTING;
108  for (ChannelMap::iterator iter = channels_.begin();
109       iter != channels_.end(); ++iter) {
110    GetOrCreateImpl(iter->first, iter->second->content_type());
111  }
112  transport_->ConnectChannels();
113}
114
115void TransportProxy::CompleteNegotiation() {
116  if (state_ != STATE_NEGOTIATED) {
117    state_ = STATE_NEGOTIATED;
118    for (ChannelMap::iterator iter = channels_.begin();
119         iter != channels_.end(); ++iter) {
120      SetProxyImpl(iter->first, iter->second);
121    }
122    transport_->ConnectChannels();
123  }
124}
125
126void TransportProxy::AddSentCandidates(const Candidates& candidates) {
127  for (Candidates::const_iterator cand = candidates.begin();
128       cand != candidates.end(); ++cand) {
129    sent_candidates_.push_back(*cand);
130  }
131}
132
133
134TransportChannelProxy* TransportProxy::GetProxy(const std::string& name) {
135  ChannelMap::iterator iter = channels_.find(name);
136  return (iter != channels_.end()) ? iter->second : NULL;
137}
138
139TransportChannelImpl* TransportProxy::GetOrCreateImpl(
140    const std::string& name, const std::string& content_type) {
141  TransportChannelImpl* impl = transport_->GetChannel(name);
142  if (impl == NULL) {
143    impl = transport_->CreateChannel(name, content_type);
144  }
145  return impl;
146}
147
148void TransportProxy::SetProxyImpl(
149    const std::string& name, TransportChannelProxy* proxy) {
150  TransportChannelImpl* impl = GetOrCreateImpl(name, proxy->content_type());
151  ASSERT(impl != NULL);
152  proxy->SetImplementation(impl);
153}
154
155
156
157
158BaseSession::BaseSession(talk_base::Thread *signaling_thread)
159    : state_(STATE_INIT), error_(ERROR_NONE),
160      local_description_(NULL), remote_description_(NULL),
161      signaling_thread_(signaling_thread) {
162}
163
164BaseSession::~BaseSession() {
165  delete remote_description_;
166  delete local_description_;
167}
168
169void BaseSession::SetState(State state) {
170  ASSERT(signaling_thread_->IsCurrent());
171  if (state != state_) {
172    state_ = state;
173    SignalState(this, state_);
174    signaling_thread_->Post(this, MSG_STATE);
175  }
176}
177
178void BaseSession::SetError(Error error) {
179  ASSERT(signaling_thread_->IsCurrent());
180  if (error != error_) {
181    error_ = error;
182    SignalError(this, error);
183  }
184}
185
186void BaseSession::OnMessage(talk_base::Message *pmsg) {
187  switch (pmsg->message_id) {
188  case MSG_TIMEOUT:
189    // Session timeout has occured.
190    SetError(ERROR_TIME);
191    break;
192
193  case MSG_ERROR:
194    TerminateWithReason(STR_TERMINATE_ERROR);
195    break;
196
197  case MSG_STATE:
198    switch (state_) {
199    case STATE_SENTACCEPT:
200    case STATE_RECEIVEDACCEPT:
201      SetState(STATE_INPROGRESS);
202      break;
203
204    case STATE_SENTREJECT:
205    case STATE_RECEIVEDREJECT:
206      // Assume clean termination.
207      Terminate();
208      break;
209
210    default:
211      // Explicitly ignoring some states here.
212      break;
213    }
214    break;
215  }
216}
217
218
219Session::Session(SessionManager *session_manager,
220                 const std::string& local_name,
221                 const std::string& initiator_name,
222                 const std::string& sid, const std::string& content_type,
223                 SessionClient* client) :
224    BaseSession(session_manager->signaling_thread()) {
225  ASSERT(session_manager->signaling_thread()->IsCurrent());
226  ASSERT(client != NULL);
227  session_manager_ = session_manager;
228  local_name_ = local_name;
229  sid_ = sid;
230  initiator_name_ = initiator_name;
231  content_type_ = content_type;
232  // TODO: Once we support different transport types,
233  // don't hard code this here.
234  transport_type_ = NS_GINGLE_P2P;
235  transport_parser_ = new P2PTransportParser();
236  client_ = client;
237  error_ = ERROR_NONE;
238  state_ = STATE_INIT;
239  initiator_ = false;
240  current_protocol_ = PROTOCOL_HYBRID;
241}
242
243Session::~Session() {
244  ASSERT(signaling_thread_->IsCurrent());
245
246  ASSERT(state_ != STATE_DEINIT);
247  state_ = STATE_DEINIT;
248  SignalState(this, state_);
249
250  for (TransportMap::iterator iter = transports_.begin();
251       iter != transports_.end(); ++iter) {
252    delete iter->second;
253  }
254
255  delete transport_parser_;
256}
257
258Transport* Session::GetTransport(const std::string& content_name) {
259  TransportProxy* transproxy = GetTransportProxy(content_name);
260  if (transproxy == NULL)
261    return NULL;
262  return transproxy->impl();
263}
264
265void Session::set_allow_local_ips(bool allow) {
266  allow_local_ips_ = allow;
267  for (TransportMap::iterator iter = transports_.begin();
268       iter != transports_.end(); ++iter) {
269    iter->second->impl()->set_allow_local_ips(allow);
270  }
271}
272
273bool Session::Initiate(const std::string &to,
274                       const SessionDescription* sdesc) {
275  ASSERT(signaling_thread_->IsCurrent());
276  SessionError error;
277
278  // Only from STATE_INIT
279  if (state_ != STATE_INIT)
280    return false;
281
282  // Setup for signaling.
283  remote_name_ = to;
284  initiator_ = true;
285  set_local_description(sdesc);
286  if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
287                              &error)) {
288    LOG(LS_ERROR) << "Could not create transports: " << error.text;
289    return false;
290  }
291
292  if (!SendInitiateMessage(sdesc, &error)) {
293    LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
294    return false;
295  }
296
297  SetState(Session::STATE_SENTINITIATE);
298
299  SpeculativelyConnectAllTransportChannels();
300  return true;
301}
302
303bool Session::Accept(const SessionDescription* sdesc) {
304  ASSERT(signaling_thread_->IsCurrent());
305
306  // Only if just received initiate
307  if (state_ != STATE_RECEIVEDINITIATE)
308    return false;
309
310  // Setup for signaling.
311  initiator_ = false;
312  set_local_description(sdesc);
313
314  SessionError error;
315  if (!SendAcceptMessage(sdesc, &error)) {
316    LOG(LS_ERROR) << "Could not send accept message: " << error.text;
317    return false;
318  }
319
320  SetState(Session::STATE_SENTACCEPT);
321  return true;
322}
323
324bool Session::Reject(const std::string& reason) {
325  ASSERT(signaling_thread_->IsCurrent());
326
327  // Reject is sent in response to an initiate or modify, to reject the
328  // request
329  if (state_ != STATE_RECEIVEDINITIATE && state_ != STATE_RECEIVEDMODIFY)
330    return false;
331
332  // Setup for signaling.
333  initiator_ = false;
334
335  SessionError error;
336  if (!SendRejectMessage(reason, &error)) {
337    LOG(LS_ERROR) << "Could not send reject message: " << error.text;
338    return false;
339  }
340
341  SetState(STATE_SENTREJECT);
342  return true;
343}
344
345bool Session::TerminateWithReason(const std::string& reason) {
346  ASSERT(signaling_thread_->IsCurrent());
347
348  // Either side can terminate, at any time.
349  switch (state_) {
350    case STATE_SENTTERMINATE:
351    case STATE_RECEIVEDTERMINATE:
352      return false;
353
354    case STATE_SENTREJECT:
355    case STATE_RECEIVEDREJECT:
356      // We don't need to send terminate if we sent or received a reject...
357      // it's implicit.
358      break;
359
360    default:
361      SessionError error;
362      if (!SendTerminateMessage(reason, &error)) {
363        LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
364        return false;
365      }
366      break;
367  }
368
369  SetState(STATE_SENTTERMINATE);
370  return true;
371}
372
373bool Session::SendInfoMessage(const XmlElements& elems) {
374  ASSERT(signaling_thread_->IsCurrent());
375  SessionError error;
376  if (!SendMessage(ACTION_SESSION_INFO, elems, &error)) {
377    LOG(LS_ERROR) << "Could not send info message " << error.text;
378    return false;
379  }
380  return true;
381}
382
383
384TransportProxy* Session::GetTransportProxy(const Transport* transport) {
385  for (TransportMap::iterator iter = transports_.begin();
386       iter != transports_.end(); ++iter) {
387    TransportProxy* transproxy = iter->second;
388    if (transproxy->impl() == transport) {
389      return transproxy;
390    }
391  }
392  return NULL;
393}
394
395TransportProxy* Session::GetTransportProxy(const std::string& content_name) {
396  TransportMap::iterator iter = transports_.find(content_name);
397  return (iter != transports_.end()) ? iter->second : NULL;
398}
399
400TransportProxy* Session::GetFirstTransportProxy() {
401  if (transports_.empty())
402    return NULL;
403  return transports_.begin()->second;
404}
405
406TransportInfos Session::GetEmptyTransportInfos(
407    const ContentInfos& contents) const {
408  TransportInfos tinfos;
409  for (ContentInfos::const_iterator content = contents.begin();
410       content != contents.end(); ++content) {
411    tinfos.push_back(
412        TransportInfo(content->name, transport_type_, Candidates()));
413  }
414  return tinfos;
415}
416
417
418bool Session::OnRemoteCandidates(
419    const TransportInfos& tinfos, ParseError* error) {
420  for (TransportInfos::const_iterator tinfo = tinfos.begin();
421       tinfo != tinfos.end(); ++tinfo) {
422    TransportProxy* transproxy = GetTransportProxy(tinfo->content_name);
423    if (transproxy == NULL) {
424      return BadParse("Unknown content name: " + tinfo->content_name, error);
425    }
426
427    // Must complete negotiation before sending remote candidates, or
428    // there won't be any channel impls.
429    transproxy->CompleteNegotiation();
430    for (Candidates::const_iterator cand = tinfo->candidates.begin();
431         cand != tinfo->candidates.end(); ++cand) {
432      if (!transproxy->impl()->VerifyCandidate(*cand, error))
433        return false;
434
435      if (!transproxy->impl()->HasChannel(cand->name())) {
436        buzz::XmlElement* extra_info =
437            new buzz::XmlElement(QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME);
438        extra_info->AddAttr(buzz::QN_NAME, cand->name());
439        error->extra = extra_info;
440
441        return BadParse("channel named in candidate does not exist: " +
442                        cand->name() + " for content: "+ tinfo->content_name,
443                        error);
444      }
445    }
446    transproxy->impl()->OnRemoteCandidates(tinfo->candidates);
447  }
448
449  return true;
450}
451
452
453TransportProxy* Session::GetOrCreateTransportProxy(
454    const std::string& content_name) {
455  TransportProxy* transproxy = GetTransportProxy(content_name);
456  if (transproxy)
457    return transproxy;
458
459  Transport* transport =
460      new P2PTransport(signaling_thread_,
461                       session_manager_->worker_thread(),
462                       session_manager_->port_allocator());
463  transport->set_allow_local_ips(allow_local_ips_);
464  transport->SignalConnecting.connect(
465      this, &Session::OnTransportConnecting);
466  transport->SignalWritableState.connect(
467      this, &Session::OnTransportWritable);
468  transport->SignalRequestSignaling.connect(
469      this, &Session::OnTransportRequestSignaling);
470  transport->SignalCandidatesReady.connect(
471      this, &Session::OnTransportCandidatesReady);
472  transport->SignalTransportError.connect(
473      this, &Session::OnTransportSendError);
474  transport->SignalChannelGone.connect(
475      this, &Session::OnTransportChannelGone);
476
477  transproxy = new TransportProxy(content_name, transport);
478  transports_[content_name] = transproxy;
479
480  return transproxy;
481}
482
483bool Session::CreateTransportProxies(const TransportInfos& tinfos,
484                                     SessionError* error) {
485  for (TransportInfos::const_iterator tinfo = tinfos.begin();
486       tinfo != tinfos.end(); ++tinfo) {
487    if (tinfo->transport_type != transport_type_) {
488      error->SetText("No supported transport in offer.");
489      return false;
490    }
491
492    GetOrCreateTransportProxy(tinfo->content_name);
493  }
494  return true;
495}
496
497void Session::SpeculativelyConnectAllTransportChannels() {
498  for (TransportMap::iterator iter = transports_.begin();
499       iter != transports_.end(); ++iter) {
500    iter->second->SpeculativelyConnectChannels();
501  }
502}
503
504TransportParserMap Session::GetTransportParsers() {
505  TransportParserMap parsers;
506  parsers[transport_type_] = transport_parser_;
507  return parsers;
508}
509
510ContentParserMap Session::GetContentParsers() {
511  ContentParserMap parsers;
512  parsers[content_type_] = client_;
513  return parsers;
514}
515
516TransportChannel* Session::CreateChannel(const std::string& content_name,
517                                         const std::string& channel_name) {
518  // We create the proxy "on demand" here because we need to support
519  // creating channels at any time, even before we send or receive
520  // initiate messages, which is before we create the transports.
521  TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
522  return transproxy->CreateChannel(channel_name, content_type_);
523}
524
525TransportChannel* Session::GetChannel(const std::string& content_name,
526                                      const std::string& channel_name) {
527  TransportProxy* transproxy = GetTransportProxy(content_name);
528  if (transproxy == NULL)
529    return NULL;
530  else
531    return transproxy->GetChannel(channel_name);
532}
533
534void Session::DestroyChannel(const std::string& content_name,
535                             const std::string& channel_name) {
536  TransportProxy* transproxy = GetTransportProxy(content_name);
537  ASSERT(transproxy != NULL);
538  transproxy->DestroyChannel(channel_name);
539}
540
541void Session::OnSignalingReady() {
542  ASSERT(signaling_thread_->IsCurrent());
543  for (TransportMap::iterator iter = transports_.begin();
544       iter != transports_.end(); ++iter) {
545    iter->second->impl()->OnSignalingReady();
546  }
547}
548
549void Session::OnTransportConnecting(Transport* transport) {
550  // This is an indication that we should begin watching the writability
551  // state of the transport.
552  OnTransportWritable(transport);
553}
554
555void Session::OnTransportWritable(Transport* transport) {
556  ASSERT(signaling_thread_->IsCurrent());
557
558  // If the transport is not writable, start a timer to make sure that it
559  // becomes writable within a reasonable amount of time.  If it does not, we
560  // terminate since we can't actually send data.  If the transport is writable,
561  // cancel the timer.  Note that writability transitions may occur repeatedly
562  // during the lifetime of the session.
563  signaling_thread_->Clear(this, MSG_TIMEOUT);
564  if (transport->HasChannels() && !transport->writable()) {
565    signaling_thread_->PostDelayed(
566        session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
567  }
568}
569
570void Session::OnTransportRequestSignaling(Transport* transport) {
571  ASSERT(signaling_thread_->IsCurrent());
572  SignalRequestSignaling(this);
573}
574
575void Session::OnTransportCandidatesReady(Transport* transport,
576                                         const Candidates& candidates) {
577  ASSERT(signaling_thread_->IsCurrent());
578  TransportProxy* transproxy = GetTransportProxy(transport);
579  if (transproxy != NULL) {
580    if (!transproxy->negotiated()) {
581      transproxy->AddSentCandidates(candidates);
582    }
583    SessionError error;
584    if (!SendTransportInfoMessage(
585            TransportInfo(transproxy->content_name(), transproxy->type(),
586                          candidates),
587            &error)) {
588      LOG(LS_ERROR) << "Could not send transport info message: "
589                    << error.text;
590      return;
591    }
592  }
593}
594
595void Session::OnTransportSendError(Transport* transport,
596                                   const buzz::XmlElement* stanza,
597                                   const buzz::QName& name,
598                                   const std::string& type,
599                                   const std::string& text,
600                                   const buzz::XmlElement* extra_info) {
601  ASSERT(signaling_thread_->IsCurrent());
602  SignalErrorMessage(this, stanza, name, type, text, extra_info);
603}
604
605void Session::OnTransportChannelGone(Transport* transport,
606                                     const std::string& name) {
607  ASSERT(signaling_thread_->IsCurrent());
608  SignalChannelGone(this, name);
609}
610
611void Session::OnIncomingMessage(const SessionMessage& msg) {
612  ASSERT(signaling_thread_->IsCurrent());
613  ASSERT(state_ == STATE_INIT || msg.from == remote_name_);
614
615  if (current_protocol_== PROTOCOL_HYBRID) {
616    if (msg.protocol == PROTOCOL_GINGLE) {
617      current_protocol_ = PROTOCOL_GINGLE;
618    } else {
619      current_protocol_ = PROTOCOL_JINGLE;
620    }
621  }
622
623  bool valid = false;
624  MessageError error;
625  switch (msg.type) {
626    case ACTION_SESSION_INITIATE:
627      valid = OnInitiateMessage(msg, &error);
628      break;
629    case ACTION_SESSION_INFO:
630      valid = OnInfoMessage(msg);
631      break;
632    case ACTION_SESSION_ACCEPT:
633      valid = OnAcceptMessage(msg, &error);
634      break;
635    case ACTION_SESSION_REJECT:
636      valid = OnRejectMessage(msg, &error);
637      break;
638    case ACTION_SESSION_TERMINATE:
639      valid = OnTerminateMessage(msg, &error);
640      break;
641    case ACTION_TRANSPORT_INFO:
642      valid = OnTransportInfoMessage(msg, &error);
643      break;
644    case ACTION_TRANSPORT_ACCEPT:
645      valid = OnTransportAcceptMessage(msg, &error);
646      break;
647    case ACTION_NOTIFY:
648      valid = OnNotifyMessage(msg, &error);
649      break;
650    case ACTION_UPDATE:
651      valid = OnUpdateMessage(msg, &error);
652      break;
653    default:
654      valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
655                         "unknown session message type",
656                         &error);
657  }
658
659  if (valid) {
660    SendAcknowledgementMessage(msg.stanza);
661  } else {
662    SignalErrorMessage(this, msg.stanza, error.type,
663                       "modify", error.text, NULL);
664  }
665}
666
667void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
668                           const buzz::XmlElement* error_stanza) {
669  ASSERT(signaling_thread_->IsCurrent());
670
671  SessionMessage msg;
672  ParseError parse_error;
673  if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
674    LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
675                  << ":" << orig_stanza;
676    return;
677  }
678
679  // If the error is a session redirect, call OnRedirectError, which will
680  // continue the session with a new remote JID.
681  SessionRedirect redirect;
682  if (FindSessionRedirect(error_stanza, &redirect)) {
683    SessionError error;
684    if (!OnRedirectError(redirect, &error)) {
685      // TODO: Should we send a message back?  The standard
686      // says nothing about it.
687      LOG(LS_ERROR) << "Failed to redirect: " << error.text;
688      SetError(ERROR_RESPONSE);
689    }
690    return;
691  }
692
693  std::string error_type = "cancel";
694
695  const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
696  if (error) {
697    ASSERT(error->HasAttr(buzz::QN_TYPE));
698    error_type = error->Attr(buzz::QN_TYPE);
699
700    LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
701                  << "in response to:\n" << orig_stanza->Str();
702  } else {
703    // don't crash if <error> is missing
704    LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
705    return;
706  }
707
708  if (msg.type == ACTION_TRANSPORT_INFO) {
709    // Transport messages frequently generate errors because they are sent right
710    // when we detect a network failure.  For that reason, we ignore such
711    // errors, because if we do not establish writability again, we will
712    // terminate anyway.  The exceptions are transport-specific error tags,
713    // which we pass on to the respective transport.
714
715    // TODO: This is only used for unknown channel name.
716    // For Jingle, find a stanard-compliant way of doing this.  For
717    // Gingle, guess the content name based on the channel name.
718    for (const buzz::XmlElement* elem = error->FirstElement();
719         NULL != elem; elem = elem->NextElement()) {
720      TransportProxy* transproxy = GetFirstTransportProxy();
721      if (transproxy && transproxy->type() == error->Name().Namespace()) {
722        transproxy->impl()->OnTransportError(elem);
723      }
724    }
725  } else if ((error_type != "continue") && (error_type != "wait")) {
726    // We do not set an error if the other side said it is okay to continue
727    // (possibly after waiting).  These errors can be ignored.
728    SetError(ERROR_RESPONSE);
729  }
730}
731
732bool Session::OnInitiateMessage(const SessionMessage& msg,
733                                MessageError* error) {
734  if (!CheckState(STATE_INIT, error))
735    return false;
736
737  SessionInitiate init;
738  if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
739                            GetContentParsers(), GetTransportParsers(),
740                            &init, error))
741    return false;
742
743  SessionError session_error;
744  if (!CreateTransportProxies(init.transports, &session_error)) {
745    return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
746                      session_error.text, error);
747  }
748
749  initiator_ = false;
750  remote_name_ = msg.from;
751  set_remote_description(new SessionDescription(init.ClearContents()));
752  SetState(STATE_RECEIVEDINITIATE);
753
754  // Users of Session may listen to state change and call Reject().
755  if (state_ != STATE_SENTREJECT) {
756    if (!OnRemoteCandidates(init.transports, error))
757      return false;
758  }
759  return true;
760}
761
762bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
763  if (!CheckState(STATE_SENTINITIATE, error))
764    return false;
765
766  SessionAccept accept;
767  if (!ParseSessionAccept(msg.protocol, msg.action_elem,
768                          GetContentParsers(), GetTransportParsers(),
769                          &accept, error))
770    return false;
771
772  set_remote_description(new SessionDescription(accept.ClearContents()));
773  SetState(STATE_RECEIVEDACCEPT);
774
775  // Users of Session may listen to state change and call Reject().
776  if (state_ != STATE_SENTREJECT) {
777    if (!OnRemoteCandidates(accept.transports, error))
778      return false;
779  }
780
781  return true;
782}
783
784bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
785  if (!CheckState(STATE_SENTINITIATE, error))
786    return false;
787
788  SetState(STATE_RECEIVEDREJECT);
789  return true;
790}
791
792// Only used by app/win32/fileshare.cc.
793bool Session::OnInfoMessage(const SessionMessage& msg) {
794  SignalInfoMessage(this, CopyOfXmlChildren(msg.action_elem));
795  return true;
796}
797
798bool Session::OnTerminateMessage(const SessionMessage& msg,
799                                 MessageError* error) {
800  SessionTerminate term;
801  if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
802    return false;
803
804  SignalReceivedTerminateReason(this, term.reason);
805  if (term.debug_reason != buzz::STR_EMPTY) {
806    LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
807  }
808
809  SetState(STATE_RECEIVEDTERMINATE);
810  return true;
811}
812
813bool Session::OnTransportInfoMessage(const SessionMessage& msg,
814                                     MessageError* error) {
815  TransportInfos tinfos;
816  if (!ParseTransportInfos(msg.protocol, msg.action_elem,
817                           initiator_description()->contents(),
818                           GetTransportParsers(), &tinfos, error))
819    return false;
820
821  if (!OnRemoteCandidates(tinfos, error))
822    return false;
823
824  return true;
825}
826
827bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
828                                       MessageError* error) {
829  // TODO: Currently here only for compatibility with
830  // Gingle 1.1 clients (notably, Google Voice).
831  return true;
832}
833
834bool Session::OnNotifyMessage(const SessionMessage& msg,
835                              MessageError* error) {
836  SessionNotify notify;
837  if (!ParseSessionNotify(msg.action_elem, &notify, error)) {
838    return false;
839  }
840
841  SignalMediaSources(notify.nickname_to_sources);
842
843  return true;
844}
845
846bool Session::OnUpdateMessage(const SessionMessage& msg,
847                              MessageError* error) {
848  SessionUpdate update;
849  if (!ParseSessionUpdate(msg.action_elem, &update, error)) {
850    return false;
851  }
852
853  // TODO: Process this message appropriately.
854
855  return true;
856}
857
858bool BareJidsEqual(const std::string& name1,
859                   const std::string& name2) {
860  buzz::Jid jid1(name1);
861  buzz::Jid jid2(name2);
862
863  return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
864}
865
866bool Session::OnRedirectError(const SessionRedirect& redirect,
867                              SessionError* error) {
868  MessageError message_error;
869  if (!CheckState(STATE_SENTINITIATE, &message_error)) {
870    return BadWrite(message_error.text, error);
871  }
872
873  if (!BareJidsEqual(remote_name_, redirect.target))
874    return BadWrite("Redirection not allowed: must be the same bare jid.",
875                    error);
876
877  // When we receive a redirect, we point the session at the new JID
878  // and resend the candidates.
879  remote_name_ = redirect.target;
880  return (SendInitiateMessage(local_description(), error) &&
881          ResendAllTransportInfoMessages(error));
882}
883
884bool Session::CheckState(State state, MessageError* error) {
885  ASSERT(state_ == state);
886  if (state_ != state) {
887    return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
888                      "message not allowed in current state",
889                      error);
890  }
891  return true;
892}
893
894void Session::SetError(Error error) {
895  BaseSession::SetError(error);
896  if (error_ != ERROR_NONE)
897    signaling_thread_->Post(this, MSG_ERROR);
898}
899
900void Session::OnMessage(talk_base::Message *pmsg) {
901  // preserve this because BaseSession::OnMessage may modify it
902  BaseSession::State orig_state = state_;
903
904  BaseSession::OnMessage(pmsg);
905
906  switch (pmsg->message_id) {
907  case MSG_STATE:
908    switch (orig_state) {
909    case STATE_SENTTERMINATE:
910    case STATE_RECEIVEDTERMINATE:
911      session_manager_->DestroySession(this);
912      break;
913
914    default:
915      // Explicitly ignoring some states here.
916      break;
917    }
918    break;
919  }
920}
921
922bool Session::SendInitiateMessage(const SessionDescription* sdesc,
923                                  SessionError* error) {
924  SessionInitiate init;
925  init.contents = sdesc->contents();
926  init.transports = GetEmptyTransportInfos(init.contents);
927  return SendMessage(ACTION_SESSION_INITIATE, init, error);
928}
929
930bool Session::WriteSessionAction(
931    SignalingProtocol protocol, const SessionInitiate& init,
932    XmlElements* elems, WriteError* error) {
933  ContentParserMap content_parsers = GetContentParsers();
934  TransportParserMap trans_parsers = GetTransportParsers();
935
936  return WriteSessionInitiate(protocol, init.contents, init.transports,
937                              content_parsers, trans_parsers,
938                              elems, error);
939}
940
941bool Session::SetVideoView(
942    const std::vector<VideoViewRequest>& view_requests) {
943  SessionView view;
944  SessionError error;
945
946  view.view_requests = view_requests;
947
948  return !SendViewMessage(view, &error);
949}
950
951bool Session::SendAcceptMessage(const SessionDescription* sdesc,
952                                SessionError* error) {
953  XmlElements elems;
954  if (!WriteSessionAccept(current_protocol_,
955                          sdesc->contents(),
956                          GetEmptyTransportInfos(sdesc->contents()),
957                          GetContentParsers(), GetTransportParsers(),
958                          &elems, error)) {
959    return false;
960  }
961  return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
962}
963
964bool Session::SendRejectMessage(const std::string& reason,
965                                SessionError* error) {
966  XmlElements elems;
967  return SendMessage(ACTION_SESSION_REJECT, elems, error);
968}
969
970
971bool Session::SendTerminateMessage(const std::string& reason,
972                                   SessionError* error) {
973  SessionTerminate term(reason);
974  return SendMessage(ACTION_SESSION_TERMINATE, term, error);
975}
976
977bool Session::WriteSessionAction(SignalingProtocol protocol,
978                                 const SessionTerminate& term,
979                                 XmlElements* elems, WriteError* error) {
980  WriteSessionTerminate(protocol, term, elems);
981  return true;
982}
983
984bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
985                                       SessionError* error) {
986  return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
987}
988
989bool Session::WriteSessionAction(SignalingProtocol protocol,
990                                 const TransportInfo& tinfo,
991                                 XmlElements* elems, WriteError* error) {
992  TransportInfos tinfos;
993  tinfos.push_back(tinfo);
994  TransportParserMap parsers = GetTransportParsers();
995
996  return WriteTransportInfos(protocol, tinfos, parsers,
997                             elems, error);
998}
999
1000bool Session::SendViewMessage(const SessionView& view, SessionError* error) {
1001  XmlElements elems;
1002  WriteSessionView(view, &elems);
1003  return SendMessage(ACTION_VIEW, elems, error);
1004}
1005
1006bool Session::ResendAllTransportInfoMessages(SessionError* error) {
1007  for (TransportMap::iterator iter = transports_.begin();
1008       iter != transports_.end(); ++iter) {
1009    TransportProxy* transproxy = iter->second;
1010    if (transproxy->sent_candidates().size() > 0) {
1011      if (!SendTransportInfoMessage(
1012              TransportInfo(
1013                  transproxy->content_name(),
1014                  transproxy->type(),
1015                  transproxy->sent_candidates()),
1016              error)) {
1017        return false;
1018      }
1019      transproxy->ClearSentCandidates();
1020    }
1021  }
1022  return true;
1023}
1024
1025bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
1026                          SessionError* error) {
1027  talk_base::scoped_ptr<buzz::XmlElement> stanza(
1028      new buzz::XmlElement(buzz::QN_IQ));
1029
1030  SessionMessage msg(current_protocol_, type, sid_, initiator_name_);
1031  msg.to = remote_name_;
1032  WriteSessionMessage(msg, action_elems, stanza.get());
1033
1034  SignalOutgoingMessage(this, stanza.get());
1035  return true;
1036}
1037
1038template <typename Action>
1039bool Session::SendMessage(ActionType type, const Action& action,
1040                          SessionError* error) {
1041  talk_base::scoped_ptr<buzz::XmlElement> stanza(
1042      new buzz::XmlElement(buzz::QN_IQ));
1043  if (!WriteActionMessage(type, action, stanza.get(), error))
1044    return false;
1045
1046  SignalOutgoingMessage(this, stanza.get());
1047  return true;
1048}
1049
1050template <typename Action>
1051bool Session::WriteActionMessage(ActionType type, const Action& action,
1052                                 buzz::XmlElement* stanza,
1053                                 WriteError* error) {
1054  if (current_protocol_ == PROTOCOL_HYBRID) {
1055    if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
1056      return false;
1057    if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
1058      return false;
1059  } else {
1060    if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
1061      return false;
1062  }
1063  return true;
1064}
1065
1066template <typename Action>
1067bool Session::WriteActionMessage(SignalingProtocol protocol,
1068                                 ActionType type, const Action& action,
1069                                 buzz::XmlElement* stanza, WriteError* error) {
1070  XmlElements action_elems;
1071  if (!WriteSessionAction(protocol, action, &action_elems, error))
1072    return false;
1073
1074  SessionMessage msg(protocol, type, sid_, initiator_name_);
1075  msg.to = remote_name_;
1076
1077  WriteSessionMessage(msg, action_elems, stanza);
1078  return true;
1079}
1080
1081void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
1082  talk_base::scoped_ptr<buzz::XmlElement> ack(
1083      new buzz::XmlElement(buzz::QN_IQ));
1084  ack->SetAttr(buzz::QN_TO, remote_name_);
1085  ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
1086  ack->SetAttr(buzz::QN_TYPE, "result");
1087
1088  SignalOutgoingMessage(this, ack.get());
1089}
1090
1091}  // namespace cricket
1092