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