Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / protocol / jingle_session_manager.cc
blob587cefbfe6b8f77b903bf0ab2024d23f74b2fcfb
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.
5 #include "remoting/protocol/jingle_session_manager.h"
7 #include "base/bind.h"
8 #include "remoting/protocol/authenticator.h"
9 #include "remoting/protocol/content_description.h"
10 #include "remoting/protocol/jingle_messages.h"
11 #include "remoting/protocol/jingle_session.h"
12 #include "remoting/protocol/transport.h"
13 #include "remoting/signaling/iq_sender.h"
14 #include "remoting/signaling/signal_strategy.h"
15 #include "third_party/webrtc/base/socketaddress.h"
16 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
18 using buzz::QName;
20 namespace remoting {
21 namespace protocol {
23 JingleSessionManager::JingleSessionManager(
24 scoped_ptr<TransportFactory> transport_factory)
25 : protocol_config_(CandidateSessionConfig::CreateDefault()),
26 transport_factory_(transport_factory.Pass()),
27 signal_strategy_(nullptr),
28 listener_(nullptr),
29 ready_(false) {}
31 JingleSessionManager::~JingleSessionManager() {
32 Close();
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_));
42 signal_strategy_->AddListener(this);
44 OnSignalStrategyStateChange(signal_strategy_->GetState());
47 void JingleSessionManager::set_protocol_config(
48 scoped_ptr<CandidateSessionConfig> config) {
49 protocol_config_ = config.Pass();
52 scoped_ptr<Session> JingleSessionManager::Connect(
53 const std::string& host_jid,
54 scoped_ptr<Authenticator> authenticator) {
55 // Notify |transport_factory_| that it may be used soon.
56 transport_factory_->PrepareTokens();
58 scoped_ptr<JingleSession> session(new JingleSession(this));
59 session->StartConnection(host_jid, authenticator.Pass());
60 sessions_[session->session_id_] = session.get();
61 return session.Pass();
64 void JingleSessionManager::Close() {
65 DCHECK(CalledOnValidThread());
67 // Close() can be called only after all sessions are destroyed.
68 DCHECK(sessions_.empty());
70 listener_ = nullptr;
72 if (signal_strategy_) {
73 signal_strategy_->RemoveListener(this);
74 signal_strategy_ = nullptr;
78 void JingleSessionManager::set_authenticator_factory(
79 scoped_ptr<AuthenticatorFactory> authenticator_factory) {
80 DCHECK(CalledOnValidThread());
81 authenticator_factory_ = authenticator_factory.Pass();
84 void JingleSessionManager::OnSignalStrategyStateChange(
85 SignalStrategy::State state) {
86 if (state == SignalStrategy::CONNECTED && !ready_) {
87 ready_ = true;
88 listener_->OnSessionManagerReady();
92 bool JingleSessionManager::OnSignalStrategyIncomingStanza(
93 const buzz::XmlElement* stanza) {
94 if (!JingleMessage::IsJingleMessage(stanza))
95 return false;
97 JingleMessage message;
98 std::string error;
99 if (!message.ParseXml(stanza, &error)) {
100 SendReply(stanza, JingleMessageReply::BAD_REQUEST);
101 return true;
104 if (message.action == JingleMessage::SESSION_INITIATE) {
105 // Description must be present in session-initiate messages.
106 DCHECK(message.description.get());
108 SendReply(stanza, JingleMessageReply::NONE);
110 // Notify |transport_factory_| that it may be used soon.
111 transport_factory_->PrepareTokens();
113 scoped_ptr<Authenticator> authenticator =
114 authenticator_factory_->CreateAuthenticator(
115 signal_strategy_->GetLocalJid(), message.from,
116 message.description->authenticator_message());
118 JingleSession* session = new JingleSession(this);
119 session->InitializeIncomingConnection(message, authenticator.Pass());
120 sessions_[session->session_id_] = session;
122 // Destroy the session if it was rejected due to incompatible protocol.
123 if (session->state_ != Session::ACCEPTING) {
124 delete session;
125 DCHECK(sessions_.find(message.sid) == sessions_.end());
126 return true;
129 IncomingSessionResponse response = SessionManager::DECLINE;
130 listener_->OnIncomingSession(session, &response);
132 if (response == SessionManager::ACCEPT) {
133 session->AcceptIncomingConnection(message);
134 } else {
135 ErrorCode error;
136 switch (response) {
137 case OVERLOAD:
138 error = HOST_OVERLOAD;
139 break;
141 case DECLINE:
142 error = SESSION_REJECTED;
143 break;
145 default:
146 NOTREACHED();
147 error = SESSION_REJECTED;
150 session->CloseInternal(error);
151 delete session;
152 DCHECK(sessions_.find(message.sid) == sessions_.end());
155 return true;
158 SessionsMap::iterator it = sessions_.find(message.sid);
159 if (it == sessions_.end()) {
160 SendReply(stanza, JingleMessageReply::INVALID_SID);
161 return true;
164 it->second->OnIncomingMessage(message, base::Bind(
165 &JingleSessionManager::SendReply, base::Unretained(this), stanza));
166 return true;
169 void JingleSessionManager::SendReply(const buzz::XmlElement* original_stanza,
170 JingleMessageReply::ErrorType error) {
171 signal_strategy_->SendStanza(
172 JingleMessageReply(error).ToXml(original_stanza));
175 void JingleSessionManager::SessionDestroyed(JingleSession* session) {
176 sessions_.erase(session->session_id_);
179 } // namespace protocol
180 } // namespace remoting