// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "remoting/protocol/jingle_session_manager.h" #include "base/bind.h" #include "remoting/jingle_glue/iq_sender.h" #include "remoting/jingle_glue/signal_strategy.h" #include "remoting/protocol/authenticator.h" #include "remoting/protocol/content_description.h" #include "remoting/protocol/jingle_messages.h" #include "remoting/protocol/jingle_session.h" #include "remoting/protocol/transport.h" #include "third_party/libjingle/source/talk/base/socketaddress.h" #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" using buzz::QName; namespace remoting { namespace protocol { JingleSessionManager::JingleSessionManager( scoped_ptr<TransportFactory> transport_factory) : transport_factory_(transport_factory.Pass()), signal_strategy_(NULL), listener_(NULL), ready_(false) { } JingleSessionManager::~JingleSessionManager() { Close(); } void JingleSessionManager::Init( SignalStrategy* signal_strategy, SessionManager::Listener* listener) { listener_ = listener; signal_strategy_ = signal_strategy; iq_sender_.reset(new IqSender(signal_strategy_)); signal_strategy_->AddListener(this); OnSignalStrategyStateChange(signal_strategy_->GetState()); } scoped_ptr<Session> JingleSessionManager::Connect( const std::string& host_jid, scoped_ptr<Authenticator> authenticator, scoped_ptr<CandidateSessionConfig> config) { // Notify |transport_factory_| that it may be used soon. transport_factory_->PrepareTokens(); scoped_ptr<JingleSession> session(new JingleSession(this)); session->StartConnection(host_jid, authenticator.Pass(), config.Pass()); sessions_[session->session_id_] = session.get(); return session.PassAs<Session>(); } void JingleSessionManager::Close() { DCHECK(CalledOnValidThread()); // Close() can be called only after all sessions are destroyed. DCHECK(sessions_.empty()); listener_ = NULL; if (signal_strategy_) { signal_strategy_->RemoveListener(this); signal_strategy_ = NULL; } } void JingleSessionManager::set_authenticator_factory( scoped_ptr<AuthenticatorFactory> authenticator_factory) { DCHECK(CalledOnValidThread()); authenticator_factory_ = authenticator_factory.Pass(); } void JingleSessionManager::OnSignalStrategyStateChange( SignalStrategy::State state) { if (state == SignalStrategy::CONNECTED && !ready_) { ready_ = true; listener_->OnSessionManagerReady(); } } bool JingleSessionManager::OnSignalStrategyIncomingStanza( const buzz::XmlElement* stanza) { if (!JingleMessage::IsJingleMessage(stanza)) return false; JingleMessage message; std::string error; if (!message.ParseXml(stanza, &error)) { SendReply(stanza, JingleMessageReply::BAD_REQUEST); return true; } if (message.action == JingleMessage::SESSION_INITIATE) { // Description must be present in session-initiate messages. DCHECK(message.description.get()); SendReply(stanza, JingleMessageReply::NONE); // Notify |transport_factory_| that it may be used soon. transport_factory_->PrepareTokens(); scoped_ptr<Authenticator> authenticator = authenticator_factory_->CreateAuthenticator( signal_strategy_->GetLocalJid(), message.from, message.description->authenticator_message()); JingleSession* session = new JingleSession(this); session->InitializeIncomingConnection(message, authenticator.Pass()); sessions_[session->session_id_] = session; IncomingSessionResponse response = SessionManager::DECLINE; listener_->OnIncomingSession(session, &response); if (response == SessionManager::ACCEPT) { session->AcceptIncomingConnection(message); } else { ErrorCode error; switch (response) { case INCOMPATIBLE: error = INCOMPATIBLE_PROTOCOL; break; case OVERLOAD: error = HOST_OVERLOAD; break; case DECLINE: error = SESSION_REJECTED; break; default: NOTREACHED(); error = SESSION_REJECTED; } session->CloseInternal(error); delete session; DCHECK(sessions_.find(message.sid) == sessions_.end()); } return true; } SessionsMap::iterator it = sessions_.find(message.sid); if (it == sessions_.end()) { SendReply(stanza, JingleMessageReply::INVALID_SID); return true; } it->second->OnIncomingMessage(message, base::Bind( &JingleSessionManager::SendReply, base::Unretained(this), stanza)); return true; } void JingleSessionManager::SendReply(const buzz::XmlElement* original_stanza, JingleMessageReply::ErrorType error) { signal_strategy_->SendStanza( JingleMessageReply(error).ToXml(original_stanza)); } void JingleSessionManager::SessionDestroyed(JingleSession* session) { sessions_.erase(session->session_id_); } } // namespace protocol } // namespace remoting