Home | History | Annotate | Download | only in base
      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 
     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 
     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 
     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   delete transport_;
     68 }
     69 
     70 std::string TransportProxy::type() const {
     71   return transport_->type();
     72 }
     73 
     74 TransportChannel* TransportProxy::GetChannel(const std::string& name) {
     75   return GetProxy(name);
     76 }
     77 
     78 TransportChannel* 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 
     96 void 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 
    105 void 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 
    115 void 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 
    126 void 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 
    134 TransportChannelProxy* TransportProxy::GetProxy(const std::string& name) {
    135   ChannelMap::iterator iter = channels_.find(name);
    136   return (iter != channels_.end()) ? iter->second : NULL;
    137 }
    138 
    139 TransportChannelImpl* 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 
    148 void 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 
    158 BaseSession::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 
    164 BaseSession::~BaseSession() {
    165   delete remote_description_;
    166   delete local_description_;
    167 }
    168 
    169 void 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 
    178 void BaseSession::SetError(Error error) {
    179   ASSERT(signaling_thread_->IsCurrent());
    180   if (error != error_) {
    181     error_ = error;
    182     SignalError(this, error);
    183   }
    184 }
    185 
    186 void 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 
    219 Session::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 
    243 Session::~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 
    258 Transport* 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 
    265 void 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 
    273 bool 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 
    303 bool 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 
    324 bool 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 
    345 bool 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 
    373 bool 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 
    384 TransportProxy* 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 
    395 TransportProxy* 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 
    400 TransportProxy* Session::GetFirstTransportProxy() {
    401   if (transports_.empty())
    402     return NULL;
    403   return transports_.begin()->second;
    404 }
    405 
    406 TransportInfos 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 
    418 bool 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 
    453 TransportProxy* 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 
    483 bool 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 
    497 void Session::SpeculativelyConnectAllTransportChannels() {
    498   for (TransportMap::iterator iter = transports_.begin();
    499        iter != transports_.end(); ++iter) {
    500     iter->second->SpeculativelyConnectChannels();
    501   }
    502 }
    503 
    504 TransportParserMap Session::GetTransportParsers() {
    505   TransportParserMap parsers;
    506   parsers[transport_type_] = transport_parser_;
    507   return parsers;
    508 }
    509 
    510 ContentParserMap Session::GetContentParsers() {
    511   ContentParserMap parsers;
    512   parsers[content_type_] = client_;
    513   return parsers;
    514 }
    515 
    516 TransportChannel* 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 
    525 TransportChannel* 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 
    534 void 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 
    541 void 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 
    549 void 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 
    555 void 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 
    570 void Session::OnTransportRequestSignaling(Transport* transport) {
    571   ASSERT(signaling_thread_->IsCurrent());
    572   SignalRequestSignaling(this);
    573 }
    574 
    575 void 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 
    595 void 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 
    605 void Session::OnTransportChannelGone(Transport* transport,
    606                                      const std::string& name) {
    607   ASSERT(signaling_thread_->IsCurrent());
    608   SignalChannelGone(this, name);
    609 }
    610 
    611 void 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 
    667 void 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 
    732 bool 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 
    762 bool 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 
    784 bool 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.
    793 bool Session::OnInfoMessage(const SessionMessage& msg) {
    794   SignalInfoMessage(this, CopyOfXmlChildren(msg.action_elem));
    795   return true;
    796 }
    797 
    798 bool 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 
    813 bool 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 
    827 bool 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 
    834 bool 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 
    846 bool 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 
    858 bool 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 
    866 bool 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 
    884 bool 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 
    894 void Session::SetError(Error error) {
    895   BaseSession::SetError(error);
    896   if (error_ != ERROR_NONE)
    897     signaling_thread_->Post(this, MSG_ERROR);
    898 }
    899 
    900 void 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 
    922 bool 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 
    930 bool 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 
    941 bool 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 
    951 bool 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 
    964 bool Session::SendRejectMessage(const std::string& reason,
    965                                 SessionError* error) {
    966   XmlElements elems;
    967   return SendMessage(ACTION_SESSION_REJECT, elems, error);
    968 }
    969 
    970 
    971 bool Session::SendTerminateMessage(const std::string& reason,
    972                                    SessionError* error) {
    973   SessionTerminate term(reason);
    974   return SendMessage(ACTION_SESSION_TERMINATE, term, error);
    975 }
    976 
    977 bool Session::WriteSessionAction(SignalingProtocol protocol,
    978                                  const SessionTerminate& term,
    979                                  XmlElements* elems, WriteError* error) {
    980   WriteSessionTerminate(protocol, term, elems);
    981   return true;
    982 }
    983 
    984 bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
    985                                        SessionError* error) {
    986   return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
    987 }
    988 
    989 bool 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 
   1000 bool Session::SendViewMessage(const SessionView& view, SessionError* error) {
   1001   XmlElements elems;
   1002   WriteSessionView(view, &elems);
   1003   return SendMessage(ACTION_VIEW, elems, error);
   1004 }
   1005 
   1006 bool 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 
   1025 bool 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 
   1038 template <typename Action>
   1039 bool 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 
   1050 template <typename Action>
   1051 bool 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 
   1066 template <typename Action>
   1067 bool 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 
   1081 void 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