Home | History | Annotate | Download | only in protocol
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "remoting/protocol/jingle_session_manager.h"
      6 
      7 #include "base/bind.h"
      8 #include "remoting/jingle_glue/iq_sender.h"
      9 #include "remoting/jingle_glue/signal_strategy.h"
     10 #include "remoting/protocol/authenticator.h"
     11 #include "remoting/protocol/content_description.h"
     12 #include "remoting/protocol/jingle_messages.h"
     13 #include "remoting/protocol/jingle_session.h"
     14 #include "remoting/protocol/transport.h"
     15 #include "third_party/libjingle/source/talk/base/socketaddress.h"
     16 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
     17 
     18 using buzz::QName;
     19 
     20 namespace remoting {
     21 namespace protocol {
     22 
     23 JingleSessionManager::JingleSessionManager(
     24     scoped_ptr<TransportFactory> transport_factory)
     25     : transport_factory_(transport_factory.Pass()),
     26       signal_strategy_(NULL),
     27       listener_(NULL),
     28       ready_(false) {
     29 }
     30 
     31 JingleSessionManager::~JingleSessionManager() {
     32   Close();
     33 }
     34 
     35 void JingleSessionManager::Init(
     36     SignalStrategy* signal_strategy,
     37     SessionManager::Listener* listener) {
     38   listener_ = listener;
     39   signal_strategy_ = signal_strategy;
     40   iq_sender_.reset(new IqSender(signal_strategy_));
     41 
     42   signal_strategy_->AddListener(this);
     43 
     44   OnSignalStrategyStateChange(signal_strategy_->GetState());
     45 }
     46 
     47 scoped_ptr<Session> JingleSessionManager::Connect(
     48     const std::string& host_jid,
     49     scoped_ptr<Authenticator> authenticator,
     50     scoped_ptr<CandidateSessionConfig> config) {
     51   // Notify |transport_factory_| that it may be used soon.
     52   transport_factory_->PrepareTokens();
     53 
     54   scoped_ptr<JingleSession> session(new JingleSession(this));
     55   session->StartConnection(host_jid, authenticator.Pass(), config.Pass());
     56   sessions_[session->session_id_] = session.get();
     57   return session.PassAs<Session>();
     58 }
     59 
     60 void JingleSessionManager::Close() {
     61   DCHECK(CalledOnValidThread());
     62 
     63   // Close() can be called only after all sessions are destroyed.
     64   DCHECK(sessions_.empty());
     65 
     66   listener_ = NULL;
     67 
     68   if (signal_strategy_) {
     69     signal_strategy_->RemoveListener(this);
     70     signal_strategy_ = NULL;
     71   }
     72 }
     73 
     74 void JingleSessionManager::set_authenticator_factory(
     75     scoped_ptr<AuthenticatorFactory> authenticator_factory) {
     76   DCHECK(CalledOnValidThread());
     77   authenticator_factory_ = authenticator_factory.Pass();
     78 }
     79 
     80 void JingleSessionManager::OnSignalStrategyStateChange(
     81     SignalStrategy::State state) {
     82   if (state == SignalStrategy::CONNECTED && !ready_) {
     83     ready_ = true;
     84     listener_->OnSessionManagerReady();
     85   }
     86 }
     87 
     88 bool JingleSessionManager::OnSignalStrategyIncomingStanza(
     89     const buzz::XmlElement* stanza) {
     90   if (!JingleMessage::IsJingleMessage(stanza))
     91     return false;
     92 
     93   JingleMessage message;
     94   std::string error;
     95   if (!message.ParseXml(stanza, &error)) {
     96     SendReply(stanza, JingleMessageReply::BAD_REQUEST);
     97     return true;
     98   }
     99 
    100   if (message.action == JingleMessage::SESSION_INITIATE) {
    101     // Description must be present in session-initiate messages.
    102     DCHECK(message.description.get());
    103 
    104     SendReply(stanza, JingleMessageReply::NONE);
    105 
    106     // Notify |transport_factory_| that it may be used soon.
    107     transport_factory_->PrepareTokens();
    108 
    109     scoped_ptr<Authenticator> authenticator =
    110         authenticator_factory_->CreateAuthenticator(
    111             signal_strategy_->GetLocalJid(), message.from,
    112             message.description->authenticator_message());
    113 
    114     JingleSession* session = new JingleSession(this);
    115     session->InitializeIncomingConnection(message, authenticator.Pass());
    116     sessions_[session->session_id_] = session;
    117 
    118     IncomingSessionResponse response = SessionManager::DECLINE;
    119     listener_->OnIncomingSession(session, &response);
    120 
    121     if (response == SessionManager::ACCEPT) {
    122       session->AcceptIncomingConnection(message);
    123     } else {
    124       ErrorCode error;
    125       switch (response) {
    126         case INCOMPATIBLE:
    127           error = INCOMPATIBLE_PROTOCOL;
    128           break;
    129 
    130         case OVERLOAD:
    131           error = HOST_OVERLOAD;
    132           break;
    133 
    134         case DECLINE:
    135           error = SESSION_REJECTED;
    136           break;
    137 
    138         default:
    139           NOTREACHED();
    140           error = SESSION_REJECTED;
    141       }
    142 
    143       session->CloseInternal(error);
    144       delete session;
    145       DCHECK(sessions_.find(message.sid) == sessions_.end());
    146     }
    147 
    148     return true;
    149   }
    150 
    151   SessionsMap::iterator it = sessions_.find(message.sid);
    152   if (it == sessions_.end()) {
    153     SendReply(stanza, JingleMessageReply::INVALID_SID);
    154     return true;
    155   }
    156 
    157   it->second->OnIncomingMessage(message, base::Bind(
    158       &JingleSessionManager::SendReply, base::Unretained(this), stanza));
    159   return true;
    160 }
    161 
    162 void JingleSessionManager::SendReply(const buzz::XmlElement* original_stanza,
    163                                      JingleMessageReply::ErrorType error) {
    164   signal_strategy_->SendStanza(
    165       JingleMessageReply(error).ToXml(original_stanza));
    166 }
    167 
    168 void JingleSessionManager::SessionDestroyed(JingleSession* session) {
    169   sessions_.erase(session->session_id_);
    170 }
    171 
    172 }  // namespace protocol
    173 }  // namespace remoting
    174