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"
8 #include "remoting/jingle_glue/iq_sender.h"
9 #include "remoting/jingle_glue/jingle_info_request.h"
10 #include "remoting/jingle_glue/signal_strategy.h"
11 #include "remoting/protocol/authenticator.h"
12 #include "remoting/protocol/content_description.h"
13 #include "remoting/protocol/jingle_messages.h"
14 #include "remoting/protocol/jingle_session.h"
15 #include "remoting/protocol/transport.h"
16 #include "remoting/protocol/transport_config.h"
17 #include "third_party/libjingle/source/talk/base/socketaddress.h"
18 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
25 JingleSessionManager::JingleSessionManager(
26 scoped_ptr
<TransportFactory
> transport_factory
,
27 bool fetch_stun_relay_config
)
28 : transport_factory_(transport_factory
.Pass()),
29 fetch_stun_relay_config_(fetch_stun_relay_config
),
30 signal_strategy_(NULL
),
35 JingleSessionManager::~JingleSessionManager() {
39 void JingleSessionManager::Init(
40 SignalStrategy
* signal_strategy
,
41 SessionManager::Listener
* listener
) {
43 signal_strategy_
= signal_strategy
;
44 iq_sender_
.reset(new IqSender(signal_strategy_
));
46 signal_strategy_
->AddListener(this);
48 OnSignalStrategyStateChange(signal_strategy_
->GetState());
51 void JingleSessionManager::OnJingleInfo(
52 const std::string
& relay_token
,
53 const std::vector
<std::string
>& relay_hosts
,
54 const std::vector
<talk_base::SocketAddress
>& stun_hosts
) {
55 DCHECK(CalledOnValidThread());
57 // TODO(sergeyu): Add support for multiple STUN/relay servers when
58 // it's implemented in libjingle and P2P Transport API.
59 TransportConfig config
;
60 config
.stun_server
= stun_hosts
[0].ToString();
61 config
.relay_server
= relay_hosts
[0];
62 config
.relay_token
= relay_token
;
63 transport_factory_
->SetTransportConfig(config
);
65 VLOG(1) << "STUN server: " << config
.stun_server
66 << " Relay server: " << config
.relay_server
67 << " Relay token: " << config
.relay_token
;
72 listener_
->OnSessionManagerReady();
76 scoped_ptr
<Session
> JingleSessionManager::Connect(
77 const std::string
& host_jid
,
78 scoped_ptr
<Authenticator
> authenticator
,
79 scoped_ptr
<CandidateSessionConfig
> config
) {
80 scoped_ptr
<JingleSession
> session(new JingleSession(this));
81 session
->StartConnection(host_jid
, authenticator
.Pass(), config
.Pass());
82 sessions_
[session
->session_id_
] = session
.get();
83 return session
.PassAs
<Session
>();
86 void JingleSessionManager::Close() {
87 DCHECK(CalledOnValidThread());
89 // Close() can be called only after all sessions are destroyed.
90 DCHECK(sessions_
.empty());
93 jingle_info_request_
.reset();
95 if (signal_strategy_
) {
96 signal_strategy_
->RemoveListener(this);
97 signal_strategy_
= NULL
;
101 void JingleSessionManager::set_authenticator_factory(
102 scoped_ptr
<AuthenticatorFactory
> authenticator_factory
) {
103 DCHECK(CalledOnValidThread());
104 authenticator_factory_
= authenticator_factory
.Pass();
107 void JingleSessionManager::OnSignalStrategyStateChange(
108 SignalStrategy::State state
) {
109 if (state
== SignalStrategy::CONNECTED
) {
110 // Request STUN/Relay info if necessary.
111 if (fetch_stun_relay_config_
) {
112 jingle_info_request_
.reset(new JingleInfoRequest(signal_strategy_
));
113 jingle_info_request_
->Send(base::Bind(&JingleSessionManager::OnJingleInfo
,
114 base::Unretained(this)));
115 } else if (!ready_
) {
117 listener_
->OnSessionManagerReady();
122 bool JingleSessionManager::OnSignalStrategyIncomingStanza(
123 const buzz::XmlElement
* stanza
) {
124 if (!JingleMessage::IsJingleMessage(stanza
))
127 JingleMessage message
;
129 if (!message
.ParseXml(stanza
, &error
)) {
130 SendReply(stanza
, JingleMessageReply::BAD_REQUEST
);
134 if (message
.action
== JingleMessage::SESSION_INITIATE
) {
135 // Description must be present in session-initiate messages.
136 DCHECK(message
.description
.get());
138 SendReply(stanza
, JingleMessageReply::NONE
);
140 scoped_ptr
<Authenticator
> authenticator
=
141 authenticator_factory_
->CreateAuthenticator(
142 signal_strategy_
->GetLocalJid(), message
.from
,
143 message
.description
->authenticator_message());
145 JingleSession
* session
= new JingleSession(this);
146 session
->InitializeIncomingConnection(message
, authenticator
.Pass());
147 sessions_
[session
->session_id_
] = session
;
149 IncomingSessionResponse response
= SessionManager::DECLINE
;
150 listener_
->OnIncomingSession(session
, &response
);
152 if (response
== SessionManager::ACCEPT
) {
153 session
->AcceptIncomingConnection(message
);
158 error
= INCOMPATIBLE_PROTOCOL
;
162 error
= HOST_OVERLOAD
;
166 error
= SESSION_REJECTED
;
171 error
= SESSION_REJECTED
;
174 session
->CloseInternal(error
);
176 DCHECK(sessions_
.find(message
.sid
) == sessions_
.end());
182 SessionsMap::iterator it
= sessions_
.find(message
.sid
);
183 if (it
== sessions_
.end()) {
184 SendReply(stanza
, JingleMessageReply::INVALID_SID
);
188 it
->second
->OnIncomingMessage(message
, base::Bind(
189 &JingleSessionManager::SendReply
, base::Unretained(this), stanza
));
193 void JingleSessionManager::SendReply(const buzz::XmlElement
* original_stanza
,
194 JingleMessageReply::ErrorType error
) {
195 signal_strategy_
->SendStanza(
196 JingleMessageReply(error
).ToXml(original_stanza
));
199 void JingleSessionManager::SessionDestroyed(JingleSession
* session
) {
200 sessions_
.erase(session
->session_id_
);
203 } // namespace protocol
204 } // namespace remoting