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/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"
17
18 using buzz::QName;
19
20 namespace remoting {
21 namespace protocol {
22
JingleSessionManager(scoped_ptr<TransportFactory> transport_factory)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
~JingleSessionManager()31 JingleSessionManager::~JingleSessionManager() {
32 Close();
33 }
34
Init(SignalStrategy * signal_strategy,SessionManager::Listener * listener)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
Connect(const std::string & host_jid,scoped_ptr<Authenticator> authenticator,scoped_ptr<CandidateSessionConfig> config)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
Close()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
set_authenticator_factory(scoped_ptr<AuthenticatorFactory> authenticator_factory)74 void JingleSessionManager::set_authenticator_factory(
75 scoped_ptr<AuthenticatorFactory> authenticator_factory) {
76 DCHECK(CalledOnValidThread());
77 authenticator_factory_ = authenticator_factory.Pass();
78 }
79
OnSignalStrategyStateChange(SignalStrategy::State state)80 void JingleSessionManager::OnSignalStrategyStateChange(
81 SignalStrategy::State state) {
82 if (state == SignalStrategy::CONNECTED && !ready_) {
83 ready_ = true;
84 listener_->OnSessionManagerReady();
85 }
86 }
87
OnSignalStrategyIncomingStanza(const buzz::XmlElement * stanza)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
SendReply(const buzz::XmlElement * original_stanza,JingleMessageReply::ErrorType error)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
SessionDestroyed(JingleSession * session)168 void JingleSessionManager::SessionDestroyed(JingleSession* session) {
169 sessions_.erase(session->session_id_);
170 }
171
172 } // namespace protocol
173 } // namespace remoting
174