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
);
72 // StartTls() hasn't been called. |socket_| is not encrypted.
75 // StartTls() has been called. Waiting for |writer_| to finish writing
76 // data before starting TLS.
79 // TLS has been started, waiting for TLS handshake to finish.
86 void OnSocketConnected(int result
);
87 void OnTlsConnected(int result
);
90 void OnReadResult(int result
);
91 void HandleReadResult(int result
);
93 // XmppLoginHandler::Delegate interface.
94 void SendMessage(const std::string
& message
) override
;
95 void StartTls() override
;
96 void OnHandshakeDone(const std::string
& jid
,
97 scoped_ptr
<XmppStreamParser
> parser
) override
;
98 void OnLoginHandlerError(SignalStrategy::Error error
) override
;
100 // Callback for BufferedSocketWriter.
101 void OnMessageSent();
103 // Event handlers for XmppStreamParser.
104 void OnStanza(const scoped_ptr
<buzz::XmlElement
> stanza
);
105 void OnParserError();
107 void OnNetworkError(int error
);
109 void SendKeepAlive();
111 net::ClientSocketFactory
* socket_factory_
;
112 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter_
;
113 XmppServerConfig xmpp_server_config_
;
115 // Used by the |socket_|.
116 scoped_ptr
<net::CertVerifier
> cert_verifier_
;
117 scoped_ptr
<net::TransportSecurityState
> transport_security_state_
;
119 scoped_ptr
<net::StreamSocket
> socket_
;
120 scoped_ptr
<BufferedSocketWriter
> writer_
;
121 int pending_writes_
= 0;
122 scoped_refptr
<net::IOBuffer
> read_buffer_
;
123 bool read_pending_
= false;
125 TlsState tls_state_
= TlsState::NOT_REQUESTED
;
127 scoped_ptr
<XmppLoginHandler
> login_handler_
;
128 scoped_ptr
<XmppStreamParser
> stream_parser_
;
133 base::ObserverList
<Listener
, true> listeners_
;
135 base::Timer keep_alive_timer_
;
137 base::ThreadChecker thread_checker_
;
139 DISALLOW_COPY_AND_ASSIGN(Core
);
142 XmppSignalStrategy::Core::Core(
143 net::ClientSocketFactory
* socket_factory
,
144 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
145 const XmppSignalStrategy::XmppServerConfig
& xmpp_server_config
)
146 : socket_factory_(socket_factory
),
147 request_context_getter_(request_context_getter
),
148 xmpp_server_config_(xmpp_server_config
),
151 base::TimeDelta::FromSeconds(kKeepAliveIntervalSeconds
),
152 base::Bind(&Core::SendKeepAlive
, base::Unretained(this)),
155 // Non-secure connections are allowed only for debugging.
156 CHECK(xmpp_server_config_
.use_tls
);
160 XmppSignalStrategy::Core::~Core() {
164 void XmppSignalStrategy::Core::Connect() {
165 DCHECK(thread_checker_
.CalledOnValidThread());
167 // Disconnect first if we are currently connected.
172 FOR_EACH_OBSERVER(Listener
, listeners_
,
173 OnSignalStrategyStateChange(CONNECTING
));
175 socket_
.reset(new jingle_glue::ProxyResolvingClientSocket(
176 socket_factory_
, request_context_getter_
, net::SSLConfig(),
177 net::HostPortPair(xmpp_server_config_
.host
, xmpp_server_config_
.port
)));
179 int result
= socket_
->Connect(base::Bind(
180 &Core::OnSocketConnected
, base::Unretained(this)));
181 if (result
!= net::ERR_IO_PENDING
)
182 OnSocketConnected(result
);
185 void XmppSignalStrategy::Core::Disconnect() {
186 DCHECK(thread_checker_
.CalledOnValidThread());
189 login_handler_
.reset();
190 stream_parser_
.reset();
193 tls_state_
= TlsState::NOT_REQUESTED
;
194 read_pending_
= false;
196 FOR_EACH_OBSERVER(Listener
, listeners_
,
197 OnSignalStrategyStateChange(DISCONNECTED
));
201 SignalStrategy::State
XmppSignalStrategy::Core::GetState() const {
202 DCHECK(thread_checker_
.CalledOnValidThread());
204 if (stream_parser_
) {
207 } else if (socket_
) {
214 SignalStrategy::Error
XmppSignalStrategy::Core::GetError() const {
215 DCHECK(thread_checker_
.CalledOnValidThread());
219 std::string
XmppSignalStrategy::Core::GetLocalJid() const {
220 DCHECK(thread_checker_
.CalledOnValidThread());
224 void XmppSignalStrategy::Core::AddListener(Listener
* listener
) {
225 DCHECK(thread_checker_
.CalledOnValidThread());
226 listeners_
.AddObserver(listener
);
229 void XmppSignalStrategy::Core::RemoveListener(Listener
* listener
) {
230 DCHECK(thread_checker_
.CalledOnValidThread());
231 listeners_
.RemoveObserver(listener
);
234 bool XmppSignalStrategy::Core::SendStanza(scoped_ptr
<buzz::XmlElement
> stanza
) {
235 DCHECK(thread_checker_
.CalledOnValidThread());
237 if (!stream_parser_
) {
238 VLOG(0) << "Dropping signalling message because XMPP is not connected.";
242 SendMessage(stanza
->Str());
244 // Return false if the SendMessage() call above resulted in the SignalStrategy
245 // being disconnected.
246 return stream_parser_
!= nullptr;
249 void XmppSignalStrategy::Core::SetAuthInfo(const std::string
& username
,
250 const std::string
& auth_token
) {
251 DCHECK(thread_checker_
.CalledOnValidThread());
252 xmpp_server_config_
.username
= username
;
253 xmpp_server_config_
.auth_token
= auth_token
;
256 void XmppSignalStrategy::Core::SendMessage(const std::string
& message
) {
257 DCHECK(thread_checker_
.CalledOnValidThread());
258 DCHECK(tls_state_
== TlsState::NOT_REQUESTED
||
259 tls_state_
== TlsState::CONNECTED
);
261 scoped_refptr
<net::IOBufferWithSize
> buffer
=
262 new net::IOBufferWithSize(message
.size());
263 memcpy(buffer
->data(), message
.data(), message
.size());
264 writer_
->Write(buffer
,
265 base::Bind(&Core::OnMessageSent
, base::Unretained(this)));
268 void XmppSignalStrategy::Core::StartTls() {
269 DCHECK(thread_checker_
.CalledOnValidThread());
270 DCHECK(login_handler_
);
271 DCHECK(tls_state_
== TlsState::NOT_REQUESTED
||
272 tls_state_
== TlsState::WAITING_FOR_FLUSH
);
274 if (writer_
->has_data_pending()) {
275 tls_state_
= TlsState::WAITING_FOR_FLUSH
;
279 tls_state_
= TlsState::CONNECTING
;
281 // Reset the writer so we don't try to write to the raw socket anymore.
284 DCHECK(!read_pending_
);
286 scoped_ptr
<net::ClientSocketHandle
> socket_handle(
287 new net::ClientSocketHandle());
288 socket_handle
->SetSocket(socket_
.Pass());
290 cert_verifier_
= net::CertVerifier::CreateDefault();
291 transport_security_state_
.reset(new net::TransportSecurityState());
292 net::SSLClientSocketContext context
;
293 context
.cert_verifier
= cert_verifier_
.get();
294 context
.transport_security_state
= transport_security_state_
.get();
296 socket_
= socket_factory_
->CreateSSLClientSocket(
297 socket_handle
.Pass(),
298 net::HostPortPair(xmpp_server_config_
.host
, kDefaultHttpsPort
),
299 net::SSLConfig(), context
);
301 int result
= socket_
->Connect(
302 base::Bind(&Core::OnTlsConnected
, base::Unretained(this)));
303 if (result
!= net::ERR_IO_PENDING
)
304 OnTlsConnected(result
);
307 void XmppSignalStrategy::Core::OnHandshakeDone(
308 const std::string
& jid
,
309 scoped_ptr
<XmppStreamParser
> parser
) {
310 DCHECK(thread_checker_
.CalledOnValidThread());
313 stream_parser_
= parser
.Pass();
314 stream_parser_
->SetCallbacks(
315 base::Bind(&Core::OnStanza
, base::Unretained(this)),
316 base::Bind(&Core::OnParserError
, base::Unretained(this)));
318 // Don't need |login_handler_| anymore.
319 login_handler_
.reset();
321 FOR_EACH_OBSERVER(Listener
, listeners_
,
322 OnSignalStrategyStateChange(CONNECTED
));
325 void XmppSignalStrategy::Core::OnLoginHandlerError(
326 SignalStrategy::Error error
) {
327 DCHECK(thread_checker_
.CalledOnValidThread());
333 void XmppSignalStrategy::Core::OnMessageSent() {
334 DCHECK(thread_checker_
.CalledOnValidThread());
336 if (tls_state_
== TlsState::WAITING_FOR_FLUSH
&&
337 !writer_
->has_data_pending()) {
342 void XmppSignalStrategy::Core::OnStanza(
343 const scoped_ptr
<buzz::XmlElement
> stanza
) {
344 DCHECK(thread_checker_
.CalledOnValidThread());
346 base::ObserverListBase
<Listener
>::Iterator
it(&listeners_
);
347 for (Listener
* listener
= it
.GetNext(); listener
; listener
= it
.GetNext()) {
348 if (listener
->OnSignalStrategyIncomingStanza(stanza
.get()))
353 void XmppSignalStrategy::Core::OnParserError() {
354 DCHECK(thread_checker_
.CalledOnValidThread());
356 error_
= NETWORK_ERROR
;
360 void XmppSignalStrategy::Core::OnSocketConnected(int result
) {
361 DCHECK(thread_checker_
.CalledOnValidThread());
363 if (result
!= net::OK
) {
364 OnNetworkError(result
);
368 writer_
= BufferedSocketWriter::CreateForSocket(
369 socket_
.get(), base::Bind(&Core::OnNetworkError
, base::Unretained(this)));
371 XmppLoginHandler::TlsMode tls_mode
;
372 if (xmpp_server_config_
.use_tls
) {
373 tls_mode
= (xmpp_server_config_
.port
== kDefaultXmppPort
)
374 ? XmppLoginHandler::TlsMode::WITH_HANDSHAKE
375 : XmppLoginHandler::TlsMode::WITHOUT_HANDSHAKE
;
377 tls_mode
= XmppLoginHandler::TlsMode::NO_TLS
;
380 // The server name is passed as to attribute in the <stream>. When connecting
381 // to talk.google.com it affects the certificate the server will use for TLS:
382 // talk.google.com uses gmail certificate when specified server is gmail.com
383 // or googlemail.com and google.com cert otherwise. In the same time it
384 // doesn't accept talk.google.com as target server. Here we use google.com
385 // server name when authenticating to talk.google.com. This ensures that the
386 // server will use google.com cert which will be accepted by the TLS
387 // implementation in Chrome (TLS API doesn't allow specifying domain other
388 // than the one that was passed to connect()).
389 std::string server
= xmpp_server_config_
.host
;
390 if (server
== "talk.google.com")
391 server
= "google.com";
393 login_handler_
.reset(
394 new XmppLoginHandler(server
, xmpp_server_config_
.username
,
395 xmpp_server_config_
.auth_token
, tls_mode
, this));
396 login_handler_
->Start();
401 void XmppSignalStrategy::Core::OnTlsConnected(int result
) {
402 DCHECK(thread_checker_
.CalledOnValidThread());
403 DCHECK(tls_state_
== TlsState::CONNECTING
);
404 tls_state_
= TlsState::CONNECTED
;
406 if (result
!= net::OK
) {
407 OnNetworkError(result
);
411 writer_
= BufferedSocketWriter::CreateForSocket(
412 socket_
.get(), base::Bind(&Core::OnNetworkError
, base::Unretained(this)));
414 login_handler_
->OnTlsStarted();
419 void XmppSignalStrategy::Core::ReadSocket() {
420 DCHECK(thread_checker_
.CalledOnValidThread());
422 while (socket_
&& !read_pending_
&& (tls_state_
== TlsState::NOT_REQUESTED
||
423 tls_state_
== TlsState::CONNECTED
)) {
424 read_buffer_
= new net::IOBuffer(kReadBufferSize
);
425 int result
= socket_
->Read(
426 read_buffer_
.get(), kReadBufferSize
,
427 base::Bind(&Core::OnReadResult
, base::Unretained(this)));
428 HandleReadResult(result
);
432 void XmppSignalStrategy::Core::OnReadResult(int result
) {
433 DCHECK(thread_checker_
.CalledOnValidThread());
434 DCHECK(read_pending_
);
435 read_pending_
= false;
436 HandleReadResult(result
);
440 void XmppSignalStrategy::Core::HandleReadResult(int result
) {
441 DCHECK(thread_checker_
.CalledOnValidThread());
443 if (result
== net::ERR_IO_PENDING
) {
444 read_pending_
= true;
449 OnNetworkError(result
);
454 // Connection was closed by the server.
460 if (stream_parser_
) {
461 stream_parser_
->AppendData(std::string(read_buffer_
->data(), result
));
463 login_handler_
->OnDataReceived(std::string(read_buffer_
->data(), result
));
467 void XmppSignalStrategy::Core::OnNetworkError(int error
) {
468 DCHECK(thread_checker_
.CalledOnValidThread());
470 LOG(ERROR
) << "XMPP socket error " << error
;
471 error_
= NETWORK_ERROR
;
475 void XmppSignalStrategy::Core::SendKeepAlive() {
476 DCHECK(thread_checker_
.CalledOnValidThread());
478 if (GetState() == CONNECTED
)
482 XmppSignalStrategy::XmppSignalStrategy(
483 net::ClientSocketFactory
* socket_factory
,
484 const scoped_refptr
<net::URLRequestContextGetter
>& request_context_getter
,
485 const XmppServerConfig
& xmpp_server_config
)
486 : core_(new Core(socket_factory
,
487 request_context_getter
,
488 xmpp_server_config
)) {
491 XmppSignalStrategy::~XmppSignalStrategy() {
492 // All listeners should be removed at this point, so it's safe to detach
494 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, core_
.release());
497 void XmppSignalStrategy::Connect() {
501 void XmppSignalStrategy::Disconnect() {
505 SignalStrategy::State
XmppSignalStrategy::GetState() const {
506 return core_
->GetState();
509 SignalStrategy::Error
XmppSignalStrategy::GetError() const {
510 return core_
->GetError();
513 std::string
XmppSignalStrategy::GetLocalJid() const {
514 return core_
->GetLocalJid();
517 void XmppSignalStrategy::AddListener(Listener
* listener
) {
518 core_
->AddListener(listener
);
521 void XmppSignalStrategy::RemoveListener(Listener
* listener
) {
522 core_
->RemoveListener(listener
);
524 bool XmppSignalStrategy::SendStanza(scoped_ptr
<buzz::XmlElement
> stanza
) {
525 return core_
->SendStanza(stanza
.Pass());
528 std::string
XmppSignalStrategy::GetNextId() {
529 return base::Uint64ToString(base::RandUint64());
532 void XmppSignalStrategy::SetAuthInfo(const std::string
& username
,
533 const std::string
& auth_token
) {
534 core_
->SetAuthInfo(username
, auth_token
);
537 } // namespace remoting