Roll src/third_party/WebKit 787a07c:716df21 (svn 201034:201036)
[chromium-blink-merge.git] / remoting / signaling / xmpp_signal_strategy.cc
blob5edbb377f5b69a30ac947e436623f1971152dad8
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"
7 #include <vector>
9 #include "base/bind.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;
41 namespace remoting {
43 XmppSignalStrategy::XmppServerConfig::XmppServerConfig()
44 : port(kDefaultXmppPort), use_tls(true) {
47 XmppSignalStrategy::XmppServerConfig::~XmppServerConfig() {
50 class XmppSignalStrategy::Core : public XmppLoginHandler::Delegate {
51 public:
52 Core(
53 net::ClientSocketFactory* socket_factory,
54 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
55 const XmppServerConfig& xmpp_server_config);
56 ~Core() override;
58 void Connect();
59 void Disconnect();
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 private:
71 enum class TlsState {
72 // StartTls() hasn't been called. |socket_| is not encrypted.
73 NOT_REQUESTED,
75 // StartTls() has been called. Waiting for |writer_| to finish writing
76 // data before starting TLS.
77 WAITING_FOR_FLUSH,
79 // TLS has been started, waiting for TLS handshake to finish.
80 CONNECTING,
82 // TLS is connected.
83 CONNECTED,
86 void OnSocketConnected(int result);
87 void OnTlsConnected(int result);
89 void ReadSocket();
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_;
129 std::string jid_;
131 Error error_ = OK;
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),
149 keep_alive_timer_(
150 FROM_HERE,
151 base::TimeDelta::FromSeconds(kKeepAliveIntervalSeconds),
152 base::Bind(&Core::SendKeepAlive, base::Unretained(this)),
153 true) {
154 #if defined(NDEBUG)
155 // Non-secure connections are allowed only for debugging.
156 CHECK(xmpp_server_config_.use_tls);
157 #endif
160 XmppSignalStrategy::Core::~Core() {
161 Disconnect();
164 void XmppSignalStrategy::Core::Connect() {
165 DCHECK(thread_checker_.CalledOnValidThread());
167 // Disconnect first if we are currently connected.
168 Disconnect();
170 error_ = OK;
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());
188 if (socket_) {
189 login_handler_.reset();
190 stream_parser_.reset();
191 writer_.reset();
192 socket_.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_) {
205 DCHECK(socket_);
206 return CONNECTED;
207 } else if (socket_) {
208 return CONNECTING;
209 } else {
210 return DISCONNECTED;
214 SignalStrategy::Error XmppSignalStrategy::Core::GetError() const {
215 DCHECK(thread_checker_.CalledOnValidThread());
216 return error_;
219 std::string XmppSignalStrategy::Core::GetLocalJid() const {
220 DCHECK(thread_checker_.CalledOnValidThread());
221 return jid_;
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.";
239 return false;
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;
276 return;
279 tls_state_ = TlsState::CONNECTING;
281 // Reset the writer so we don't try to write to the raw socket anymore.
282 writer_.reset();
284 DCHECK(!read_pending_);
286 scoped_ptr<net::ClientSocketHandle> socket_handle(
287 new net::ClientSocketHandle());
288 socket_handle->SetSocket(socket_.Pass());
290 cert_verifier_.reset(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());
312 jid_ = jid;
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());
329 error_ = error;
330 Disconnect();
333 void XmppSignalStrategy::Core::OnMessageSent() {
334 DCHECK(thread_checker_.CalledOnValidThread());
336 if (tls_state_ == TlsState::WAITING_FOR_FLUSH &&
337 !writer_->has_data_pending()) {
338 StartTls();
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()))
349 return;
353 void XmppSignalStrategy::Core::OnParserError() {
354 DCHECK(thread_checker_.CalledOnValidThread());
356 error_ = NETWORK_ERROR;
357 Disconnect();
360 void XmppSignalStrategy::Core::OnSocketConnected(int result) {
361 DCHECK(thread_checker_.CalledOnValidThread());
363 if (result != net::OK) {
364 OnNetworkError(result);
365 return;
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;
376 } else {
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();
398 ReadSocket();
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);
408 return;
411 writer_ = BufferedSocketWriter::CreateForSocket(
412 socket_.get(), base::Bind(&Core::OnNetworkError, base::Unretained(this)));
414 login_handler_->OnTlsStarted();
416 ReadSocket();
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);
437 ReadSocket();
440 void XmppSignalStrategy::Core::HandleReadResult(int result) {
441 DCHECK(thread_checker_.CalledOnValidThread());
443 if (result == net::ERR_IO_PENDING) {
444 read_pending_ = true;
445 return;
448 if (result < 0) {
449 OnNetworkError(result);
450 return;
453 if (result == 0) {
454 // Connection was closed by the server.
455 error_ = OK;
456 Disconnect();
457 return;
460 if (stream_parser_) {
461 stream_parser_->AppendData(std::string(read_buffer_->data(), result));
462 } else {
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;
472 Disconnect();
475 void XmppSignalStrategy::Core::SendKeepAlive() {
476 DCHECK(thread_checker_.CalledOnValidThread());
478 if (GetState() == CONNECTED)
479 SendMessage(" ");
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
493 // |core_|.
494 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, core_.release());
497 void XmppSignalStrategy::Connect() {
498 core_->Connect();
501 void XmppSignalStrategy::Disconnect() {
502 core_->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