1 // Copyright 2014 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/signaling/xmpp_signal_strategy.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/observer_list.h"
13 #include "base/rand_util.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/threading/thread_checker.h"
18 #include "base/time/time.h"
19 #include "base/timer/timer.h"
20 #include "jingle/glue/proxy_resolving_client_socket.h"
21 #include "net/cert/cert_verifier.h"
22 #include "net/http/transport_security_state.h"
23 #include "net/socket/client_socket_factory.h"
24 #include "net/socket/client_socket_handle.h"
25 #include "net/socket/ssl_client_socket.h"
26 #include "net/url_request/url_request_context_getter.h"
27 #include "remoting/base/buffered_socket_writer.h"
28 #include "remoting/signaling/xmpp_login_handler.h"
29 #include "remoting/signaling/xmpp_stream_parser.h"
30 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
32 // Use 50 seconds keep-alive interval, in case routers terminate
33 // connections that are idle for more than a minute.
34 const int kKeepAliveIntervalSeconds
= 50;
36 const int kReadBufferSize
= 4096;
38 const int kDefaultXmppPort
= 5222;
39 const int kDefaultHttpsPort
= 443;
43 XmppSignalStrategy::XmppServerConfig::XmppServerConfig()
44 : port(kDefaultXmppPort
), use_tls(true) {
47 XmppSignalStrategy::XmppServerConfig::~XmppServerConfig() {
50 class XmppSignalStrategy::Core
: public XmppLoginHandler::Delegate
{
53 net::ClientSocketFactory
* socket_factory
,
54 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
55 const XmppServerConfig
& xmpp_server_config
);
60 State
GetState() const;
61 Error
GetError() const;
62 std::string
GetLocalJid() const;
63 void AddListener(Listener
* listener
);
64 void RemoveListener(Listener
* listener
);
65 bool SendStanza(scoped_ptr
<buzz::XmlElement
> stanza
);
67 void SetAuthInfo(const std::string
& username
,
68 const std::string
& auth_token
);
70 void VerifyNoListeners();
73 void OnSocketConnected(int result
);
74 void OnTlsConnected(int result
);
77 void OnReadResult(int result
);
78 void HandleReadResult(int result
);
80 // XmppLoginHandler::Delegate interface.
81 void SendMessage(const std::string
& message
) override
;
82 void StartTls() override
;
83 void OnHandshakeDone(const std::string
& jid
,
84 scoped_ptr
<XmppStreamParser
> parser
) override
;
85 void OnLoginHandlerError(SignalStrategy::Error error
) override
;
87 // Event handlers for XmppStreamParser.
88 void OnStanza(const scoped_ptr
<buzz::XmlElement
> stanza
);
91 void OnNetworkError(int error
);
95 net::ClientSocketFactory
* socket_factory_
;
96 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter_
;
97 XmppServerConfig xmpp_server_config_
;
99 // Used by the |socket_|.
100 scoped_ptr
<net::CertVerifier
> cert_verifier_
;
101 scoped_ptr
<net::TransportSecurityState
> transport_security_state_
;
103 scoped_ptr
<net::StreamSocket
> socket_
;
104 scoped_ptr
<BufferedSocketWriter
> writer_
;
105 scoped_refptr
<net::IOBuffer
> read_buffer_
;
109 scoped_ptr
<XmppLoginHandler
> login_handler_
;
110 scoped_ptr
<XmppStreamParser
> stream_parser_
;
115 ObserverList
<Listener
, true> listeners_
;
117 base::Timer keep_alive_timer_
;
119 base::ThreadChecker thread_checker_
;
121 DISALLOW_COPY_AND_ASSIGN(Core
);
124 XmppSignalStrategy::Core::Core(
125 net::ClientSocketFactory
* socket_factory
,
126 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
127 const XmppSignalStrategy::XmppServerConfig
& xmpp_server_config
)
128 : socket_factory_(socket_factory
),
129 request_context_getter_(request_context_getter
),
130 xmpp_server_config_(xmpp_server_config
),
131 read_pending_(false),
136 base::TimeDelta::FromSeconds(kKeepAliveIntervalSeconds
),
137 base::Bind(&Core::SendKeepAlive
, base::Unretained(this)),
140 // Non-secure connections are allowed only for debugging.
141 CHECK(xmpp_server_config_
.use_tls
);
144 // TODO(sergeyu): Support for direct connections without TLS is not
146 if (!xmpp_server_config_
.use_tls
)
149 // Port 5222 may be blocked by firewall. talk.google.com allows connections on
150 // port 443 which can be used instead of 5222. The webapp still requests to
151 // use port 5222 for backwards compatibility with older versions of the host
152 // that do not pass correct |use_fake_ssl_client_socket| value to
153 // XmppClientSocketFactory (and so cannot connect to port 443). In case we are
154 // connecting to talk.google.com try to use port 443 anyway.
156 // TODO(sergeyu): Once all hosts support connections on port 443
157 // the webapp needs to be updated to request port 443 and these 2 lines can be
158 // removed. crbug.com/443384
159 if (xmpp_server_config_
.host
== "talk.google.com" &&
160 xmpp_server_config_
.port
== kDefaultXmppPort
) {
161 xmpp_server_config_
.port
= kDefaultHttpsPort
;
165 XmppSignalStrategy::Core::~Core() {
169 void XmppSignalStrategy::Core::Connect() {
170 DCHECK(thread_checker_
.CalledOnValidThread());
172 // Disconnect first if we are currently connected.
177 FOR_EACH_OBSERVER(Listener
, listeners_
,
178 OnSignalStrategyStateChange(CONNECTING
));
180 socket_
.reset(new jingle_glue::ProxyResolvingClientSocket(
181 socket_factory_
, request_context_getter_
, net::SSLConfig(),
182 net::HostPortPair(xmpp_server_config_
.host
, xmpp_server_config_
.port
)));
184 int result
= socket_
->Connect(base::Bind(
185 &Core::OnSocketConnected
, base::Unretained(this)));
186 if (result
!= net::ERR_IO_PENDING
)
187 OnSocketConnected(result
);
190 void XmppSignalStrategy::Core::Disconnect() {
191 DCHECK(thread_checker_
.CalledOnValidThread());
194 login_handler_
.reset();
195 stream_parser_
.reset();
199 FOR_EACH_OBSERVER(Listener
, listeners_
,
200 OnSignalStrategyStateChange(DISCONNECTED
));
204 SignalStrategy::State
XmppSignalStrategy::Core::GetState() const {
205 DCHECK(thread_checker_
.CalledOnValidThread());
207 if (stream_parser_
) {
210 } else if (socket_
) {
217 SignalStrategy::Error
XmppSignalStrategy::Core::GetError() const {
218 DCHECK(thread_checker_
.CalledOnValidThread());
222 std::string
XmppSignalStrategy::Core::GetLocalJid() const {
223 DCHECK(thread_checker_
.CalledOnValidThread());
227 void XmppSignalStrategy::Core::AddListener(Listener
* listener
) {
228 DCHECK(thread_checker_
.CalledOnValidThread());
229 listeners_
.AddObserver(listener
);
232 void XmppSignalStrategy::Core::RemoveListener(Listener
* listener
) {
233 DCHECK(thread_checker_
.CalledOnValidThread());
234 listeners_
.RemoveObserver(listener
);
237 bool XmppSignalStrategy::Core::SendStanza(scoped_ptr
<buzz::XmlElement
> stanza
) {
238 DCHECK(thread_checker_
.CalledOnValidThread());
240 if (!stream_parser_
) {
241 VLOG(0) << "Dropping signalling message because XMPP "
242 "connection has been terminated.";
246 SendMessage(stanza
->Str());
250 void XmppSignalStrategy::Core::SetAuthInfo(const std::string
& username
,
251 const std::string
& auth_token
) {
252 DCHECK(thread_checker_
.CalledOnValidThread());
253 xmpp_server_config_
.username
= username
;
254 xmpp_server_config_
.auth_token
= auth_token
;
257 void XmppSignalStrategy::Core::SendMessage(const std::string
& message
) {
258 DCHECK(thread_checker_
.CalledOnValidThread());
259 scoped_refptr
<net::IOBufferWithSize
> buffer
=
260 new net::IOBufferWithSize(message
.size());
261 memcpy(buffer
->data(), message
.data(), message
.size());
262 writer_
->Write(buffer
, base::Closure());
265 void XmppSignalStrategy::Core::StartTls() {
266 DCHECK(thread_checker_
.CalledOnValidThread());
267 DCHECK(login_handler_
);
269 // Reset the writer so we don't try to write to the raw socket anymore.
270 DCHECK_EQ(writer_
->GetBufferSize(), 0);
273 DCHECK(!read_pending_
);
275 scoped_ptr
<net::ClientSocketHandle
> socket_handle(
276 new net::ClientSocketHandle());
277 socket_handle
->SetSocket(socket_
.Pass());
279 cert_verifier_
.reset(net::CertVerifier::CreateDefault());
280 transport_security_state_
.reset(new net::TransportSecurityState());
281 net::SSLClientSocketContext context
;
282 context
.cert_verifier
= cert_verifier_
.get();
283 context
.transport_security_state
= transport_security_state_
.get();
285 socket_
= socket_factory_
->CreateSSLClientSocket(
286 socket_handle
.Pass(),
287 net::HostPortPair(xmpp_server_config_
.host
, kDefaultHttpsPort
),
288 net::SSLConfig(), context
);
291 int result
= socket_
->Connect(
292 base::Bind(&Core::OnTlsConnected
, base::Unretained(this)));
293 if (result
!= net::ERR_IO_PENDING
)
294 OnTlsConnected(result
);
297 void XmppSignalStrategy::Core::OnHandshakeDone(
298 const std::string
& jid
,
299 scoped_ptr
<XmppStreamParser
> parser
) {
300 DCHECK(thread_checker_
.CalledOnValidThread());
303 stream_parser_
= parser
.Pass();
304 stream_parser_
->SetCallbacks(
305 base::Bind(&Core::OnStanza
, base::Unretained(this)),
306 base::Bind(&Core::OnParserError
, base::Unretained(this)));
308 // Don't need |login_handler_| anymore.
309 login_handler_
.reset();
311 FOR_EACH_OBSERVER(Listener
, listeners_
,
312 OnSignalStrategyStateChange(CONNECTED
));
315 void XmppSignalStrategy::Core::OnLoginHandlerError(
316 SignalStrategy::Error error
) {
317 DCHECK(thread_checker_
.CalledOnValidThread());
323 void XmppSignalStrategy::Core::OnStanza(
324 const scoped_ptr
<buzz::XmlElement
> stanza
) {
325 DCHECK(thread_checker_
.CalledOnValidThread());
327 ObserverListBase
<Listener
>::Iterator
it(&listeners_
);
328 for (Listener
* listener
= it
.GetNext(); listener
; listener
= it
.GetNext()) {
329 if (listener
->OnSignalStrategyIncomingStanza(stanza
.get()))
334 void XmppSignalStrategy::Core::OnParserError() {
335 DCHECK(thread_checker_
.CalledOnValidThread());
337 error_
= NETWORK_ERROR
;
341 void XmppSignalStrategy::Core::OnSocketConnected(int result
) {
342 DCHECK(thread_checker_
.CalledOnValidThread());
344 if (result
!= net::OK
) {
345 OnNetworkError(result
);
349 writer_
.reset(new BufferedSocketWriter());
350 writer_
->Init(socket_
.get(), base::Bind(&Core::OnNetworkError
,
351 base::Unretained(this)));
353 XmppLoginHandler::TlsMode tls_mode
;
354 if (xmpp_server_config_
.use_tls
) {
355 tls_mode
= (xmpp_server_config_
.port
== kDefaultXmppPort
)
356 ? XmppLoginHandler::TlsMode::WITH_HANDSHAKE
357 : XmppLoginHandler::TlsMode::WITHOUT_HANDSHAKE
;
359 tls_mode
= XmppLoginHandler::TlsMode::NO_TLS
;
362 // The server name is passed as to attribute in the <stream>. When connecting
363 // to talk.google.com it affects the certificate the server will use for TLS:
364 // talk.google.com uses gmail certificate when specified server is gmail.com
365 // or googlemail.com and google.com cert otherwise. In the same time it
366 // doesn't accept talk.google.com as target server. Here we use google.com
367 // server name when authenticating to talk.google.com. This ensures that the
368 // server will use google.com cert which will be accepted by the TLS
369 // implementation in Chrome (TLS API doesn't allow specifying domain other
370 // than the one that was passed to connect()).
371 std::string server
= xmpp_server_config_
.host
;
372 if (server
== "talk.google.com")
373 server
= "google.com";
375 login_handler_
.reset(
376 new XmppLoginHandler(server
, xmpp_server_config_
.username
,
377 xmpp_server_config_
.auth_token
, tls_mode
, this));
378 login_handler_
->Start();
383 void XmppSignalStrategy::Core::OnTlsConnected(int result
) {
384 DCHECK(thread_checker_
.CalledOnValidThread());
385 DCHECK(tls_pending_
);
386 tls_pending_
= false;
388 if (result
!= net::OK
) {
389 OnNetworkError(result
);
393 writer_
.reset(new BufferedSocketWriter());
394 writer_
->Init(socket_
.get(), base::Bind(&Core::OnNetworkError
,
395 base::Unretained(this)));
397 login_handler_
->OnTlsStarted();
402 void XmppSignalStrategy::Core::ReadSocket() {
403 DCHECK(thread_checker_
.CalledOnValidThread());
405 while (socket_
&& !read_pending_
&& !tls_pending_
) {
406 read_buffer_
= new net::IOBuffer(kReadBufferSize
);
407 int result
= socket_
->Read(
408 read_buffer_
.get(), kReadBufferSize
,
409 base::Bind(&Core::OnReadResult
, base::Unretained(this)));
410 HandleReadResult(result
);
414 void XmppSignalStrategy::Core::OnReadResult(int result
) {
415 DCHECK(thread_checker_
.CalledOnValidThread());
416 DCHECK(read_pending_
);
417 read_pending_
= false;
418 HandleReadResult(result
);
422 void XmppSignalStrategy::Core::HandleReadResult(int result
) {
423 DCHECK(thread_checker_
.CalledOnValidThread());
425 if (result
== net::ERR_IO_PENDING
) {
426 read_pending_
= true;
431 OnNetworkError(result
);
436 // Connection was closed by the server.
442 if (stream_parser_
) {
443 stream_parser_
->AppendData(std::string(read_buffer_
->data(), result
));
445 login_handler_
->OnDataReceived(std::string(read_buffer_
->data(), result
));
449 void XmppSignalStrategy::Core::OnNetworkError(int error
) {
450 DCHECK(thread_checker_
.CalledOnValidThread());
452 LOG(ERROR
) << "XMPP socket error " << error
;
453 error_
= NETWORK_ERROR
;
457 void XmppSignalStrategy::Core::SendKeepAlive() {
458 DCHECK(thread_checker_
.CalledOnValidThread());
460 if (GetState() == CONNECTED
)
464 XmppSignalStrategy::XmppSignalStrategy(
465 net::ClientSocketFactory
* socket_factory
,
466 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
467 const XmppServerConfig
& xmpp_server_config
)
468 : core_(new Core(socket_factory
,
469 request_context_getter
,
470 xmpp_server_config
)) {
473 XmppSignalStrategy::~XmppSignalStrategy() {
474 // All listeners should be removed at this point, so it's safe to detach
476 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, core_
.release());
479 void XmppSignalStrategy::Connect() {
483 void XmppSignalStrategy::Disconnect() {
487 SignalStrategy::State
XmppSignalStrategy::GetState() const {
488 return core_
->GetState();
491 SignalStrategy::Error
XmppSignalStrategy::GetError() const {
492 return core_
->GetError();
495 std::string
XmppSignalStrategy::GetLocalJid() const {
496 return core_
->GetLocalJid();
499 void XmppSignalStrategy::AddListener(Listener
* listener
) {
500 core_
->AddListener(listener
);
503 void XmppSignalStrategy::RemoveListener(Listener
* listener
) {
504 core_
->RemoveListener(listener
);
506 bool XmppSignalStrategy::SendStanza(scoped_ptr
<buzz::XmlElement
> stanza
) {
507 return core_
->SendStanza(stanza
.Pass());
510 std::string
XmppSignalStrategy::GetNextId() {
511 return base::Uint64ToString(base::RandUint64());
514 void XmppSignalStrategy::SetAuthInfo(const std::string
& username
,
515 const std::string
& auth_token
) {
516 core_
->SetAuthInfo(username
, auth_token
);
519 } // namespace remoting