Fixing UMA logging for GestureNav
[chromium-blink-merge.git] / remoting / signaling / xmpp_signal_strategy.cc
blobb4612667447e97e762f2e1c0a82cf0e23ad3dbb7
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 void VerifyNoListeners();
72 private:
73 void OnSocketConnected(int result);
74 void OnTlsConnected(int result);
76 void ReadSocket();
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);
89 void OnParserError();
91 void OnNetworkError(int error);
93 void SendKeepAlive();
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_;
106 bool read_pending_;
107 bool tls_pending_;
109 scoped_ptr<XmppLoginHandler> login_handler_;
110 scoped_ptr<XmppStreamParser> stream_parser_;
111 std::string jid_;
113 Error error_;
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),
132 tls_pending_(false),
133 error_(OK),
134 keep_alive_timer_(
135 FROM_HERE,
136 base::TimeDelta::FromSeconds(kKeepAliveIntervalSeconds),
137 base::Bind(&Core::SendKeepAlive, base::Unretained(this)),
138 true) {
139 #if defined(NDEBUG)
140 // Non-secure connections are allowed only for debugging.
141 CHECK(xmpp_server_config_.use_tls);
142 #endif
145 XmppSignalStrategy::Core::~Core() {
146 Disconnect();
149 void XmppSignalStrategy::Core::Connect() {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 // Disconnect first if we are currently connected.
153 Disconnect();
155 error_ = OK;
157 FOR_EACH_OBSERVER(Listener, listeners_,
158 OnSignalStrategyStateChange(CONNECTING));
160 socket_.reset(new jingle_glue::ProxyResolvingClientSocket(
161 socket_factory_, request_context_getter_, net::SSLConfig(),
162 net::HostPortPair(xmpp_server_config_.host, xmpp_server_config_.port)));
164 int result = socket_->Connect(base::Bind(
165 &Core::OnSocketConnected, base::Unretained(this)));
166 if (result != net::ERR_IO_PENDING)
167 OnSocketConnected(result);
170 void XmppSignalStrategy::Core::Disconnect() {
171 DCHECK(thread_checker_.CalledOnValidThread());
173 if (socket_) {
174 login_handler_.reset();
175 stream_parser_.reset();
176 writer_.reset();
177 socket_.reset();
179 FOR_EACH_OBSERVER(Listener, listeners_,
180 OnSignalStrategyStateChange(DISCONNECTED));
184 SignalStrategy::State XmppSignalStrategy::Core::GetState() const {
185 DCHECK(thread_checker_.CalledOnValidThread());
187 if (stream_parser_) {
188 DCHECK(socket_);
189 return CONNECTED;
190 } else if (socket_) {
191 return CONNECTING;
192 } else {
193 return DISCONNECTED;
197 SignalStrategy::Error XmppSignalStrategy::Core::GetError() const {
198 DCHECK(thread_checker_.CalledOnValidThread());
199 return error_;
202 std::string XmppSignalStrategy::Core::GetLocalJid() const {
203 DCHECK(thread_checker_.CalledOnValidThread());
204 return jid_;
207 void XmppSignalStrategy::Core::AddListener(Listener* listener) {
208 DCHECK(thread_checker_.CalledOnValidThread());
209 listeners_.AddObserver(listener);
212 void XmppSignalStrategy::Core::RemoveListener(Listener* listener) {
213 DCHECK(thread_checker_.CalledOnValidThread());
214 listeners_.RemoveObserver(listener);
217 bool XmppSignalStrategy::Core::SendStanza(scoped_ptr<buzz::XmlElement> stanza) {
218 DCHECK(thread_checker_.CalledOnValidThread());
220 if (!stream_parser_) {
221 VLOG(0) << "Dropping signalling message because XMPP "
222 "connection has been terminated.";
223 return false;
226 SendMessage(stanza->Str());
227 return true;
230 void XmppSignalStrategy::Core::SetAuthInfo(const std::string& username,
231 const std::string& auth_token) {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 xmpp_server_config_.username = username;
234 xmpp_server_config_.auth_token = auth_token;
237 void XmppSignalStrategy::Core::SendMessage(const std::string& message) {
238 DCHECK(thread_checker_.CalledOnValidThread());
239 scoped_refptr<net::IOBufferWithSize> buffer =
240 new net::IOBufferWithSize(message.size());
241 memcpy(buffer->data(), message.data(), message.size());
242 writer_->Write(buffer, base::Closure());
245 void XmppSignalStrategy::Core::StartTls() {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 DCHECK(login_handler_);
249 // Reset the writer so we don't try to write to the raw socket anymore.
250 DCHECK_EQ(writer_->GetBufferSize(), 0);
251 writer_.reset();
253 DCHECK(!read_pending_);
255 scoped_ptr<net::ClientSocketHandle> socket_handle(
256 new net::ClientSocketHandle());
257 socket_handle->SetSocket(socket_.Pass());
259 cert_verifier_.reset(net::CertVerifier::CreateDefault());
260 transport_security_state_.reset(new net::TransportSecurityState());
261 net::SSLClientSocketContext context;
262 context.cert_verifier = cert_verifier_.get();
263 context.transport_security_state = transport_security_state_.get();
265 socket_ = socket_factory_->CreateSSLClientSocket(
266 socket_handle.Pass(),
267 net::HostPortPair(xmpp_server_config_.host, kDefaultHttpsPort),
268 net::SSLConfig(), context);
270 tls_pending_ = true;
271 int result = socket_->Connect(
272 base::Bind(&Core::OnTlsConnected, base::Unretained(this)));
273 if (result != net::ERR_IO_PENDING)
274 OnTlsConnected(result);
277 void XmppSignalStrategy::Core::OnHandshakeDone(
278 const std::string& jid,
279 scoped_ptr<XmppStreamParser> parser) {
280 DCHECK(thread_checker_.CalledOnValidThread());
282 jid_ = jid;
283 stream_parser_ = parser.Pass();
284 stream_parser_->SetCallbacks(
285 base::Bind(&Core::OnStanza, base::Unretained(this)),
286 base::Bind(&Core::OnParserError, base::Unretained(this)));
288 // Don't need |login_handler_| anymore.
289 login_handler_.reset();
291 FOR_EACH_OBSERVER(Listener, listeners_,
292 OnSignalStrategyStateChange(CONNECTED));
295 void XmppSignalStrategy::Core::OnLoginHandlerError(
296 SignalStrategy::Error error) {
297 DCHECK(thread_checker_.CalledOnValidThread());
299 error_ = error;
300 Disconnect();
303 void XmppSignalStrategy::Core::OnStanza(
304 const scoped_ptr<buzz::XmlElement> stanza) {
305 DCHECK(thread_checker_.CalledOnValidThread());
307 ObserverListBase<Listener>::Iterator it(&listeners_);
308 for (Listener* listener = it.GetNext(); listener; listener = it.GetNext()) {
309 if (listener->OnSignalStrategyIncomingStanza(stanza.get()))
310 return;
314 void XmppSignalStrategy::Core::OnParserError() {
315 DCHECK(thread_checker_.CalledOnValidThread());
317 error_ = NETWORK_ERROR;
318 Disconnect();
321 void XmppSignalStrategy::Core::OnSocketConnected(int result) {
322 DCHECK(thread_checker_.CalledOnValidThread());
324 if (result != net::OK) {
325 OnNetworkError(result);
326 return;
329 writer_.reset(new BufferedSocketWriter());
330 writer_->Init(socket_.get(), base::Bind(&Core::OnNetworkError,
331 base::Unretained(this)));
333 XmppLoginHandler::TlsMode tls_mode;
334 if (xmpp_server_config_.use_tls) {
335 tls_mode = (xmpp_server_config_.port == kDefaultXmppPort)
336 ? XmppLoginHandler::TlsMode::WITH_HANDSHAKE
337 : XmppLoginHandler::TlsMode::WITHOUT_HANDSHAKE;
338 } else {
339 tls_mode = XmppLoginHandler::TlsMode::NO_TLS;
342 // The server name is passed as to attribute in the <stream>. When connecting
343 // to talk.google.com it affects the certificate the server will use for TLS:
344 // talk.google.com uses gmail certificate when specified server is gmail.com
345 // or googlemail.com and google.com cert otherwise. In the same time it
346 // doesn't accept talk.google.com as target server. Here we use google.com
347 // server name when authenticating to talk.google.com. This ensures that the
348 // server will use google.com cert which will be accepted by the TLS
349 // implementation in Chrome (TLS API doesn't allow specifying domain other
350 // than the one that was passed to connect()).
351 std::string server = xmpp_server_config_.host;
352 if (server == "talk.google.com")
353 server = "google.com";
355 login_handler_.reset(
356 new XmppLoginHandler(server, xmpp_server_config_.username,
357 xmpp_server_config_.auth_token, tls_mode, this));
358 login_handler_->Start();
360 ReadSocket();
363 void XmppSignalStrategy::Core::OnTlsConnected(int result) {
364 DCHECK(thread_checker_.CalledOnValidThread());
365 DCHECK(tls_pending_);
366 tls_pending_ = false;
368 if (result != net::OK) {
369 OnNetworkError(result);
370 return;
373 writer_.reset(new BufferedSocketWriter());
374 writer_->Init(socket_.get(), base::Bind(&Core::OnNetworkError,
375 base::Unretained(this)));
377 login_handler_->OnTlsStarted();
379 ReadSocket();
382 void XmppSignalStrategy::Core::ReadSocket() {
383 DCHECK(thread_checker_.CalledOnValidThread());
385 while (socket_ && !read_pending_ && !tls_pending_) {
386 read_buffer_ = new net::IOBuffer(kReadBufferSize);
387 int result = socket_->Read(
388 read_buffer_.get(), kReadBufferSize,
389 base::Bind(&Core::OnReadResult, base::Unretained(this)));
390 HandleReadResult(result);
394 void XmppSignalStrategy::Core::OnReadResult(int result) {
395 DCHECK(thread_checker_.CalledOnValidThread());
396 DCHECK(read_pending_);
397 read_pending_ = false;
398 HandleReadResult(result);
399 ReadSocket();
402 void XmppSignalStrategy::Core::HandleReadResult(int result) {
403 DCHECK(thread_checker_.CalledOnValidThread());
405 if (result == net::ERR_IO_PENDING) {
406 read_pending_ = true;
407 return;
410 if (result < 0) {
411 OnNetworkError(result);
412 return;
415 if (result == 0) {
416 // Connection was closed by the server.
417 error_ = OK;
418 Disconnect();
419 return;
422 if (stream_parser_) {
423 stream_parser_->AppendData(std::string(read_buffer_->data(), result));
424 } else {
425 login_handler_->OnDataReceived(std::string(read_buffer_->data(), result));
429 void XmppSignalStrategy::Core::OnNetworkError(int error) {
430 DCHECK(thread_checker_.CalledOnValidThread());
432 LOG(ERROR) << "XMPP socket error " << error;
433 error_ = NETWORK_ERROR;
434 Disconnect();
437 void XmppSignalStrategy::Core::SendKeepAlive() {
438 DCHECK(thread_checker_.CalledOnValidThread());
440 if (GetState() == CONNECTED)
441 SendMessage(" ");
444 XmppSignalStrategy::XmppSignalStrategy(
445 net::ClientSocketFactory* socket_factory,
446 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
447 const XmppServerConfig& xmpp_server_config)
448 : core_(new Core(socket_factory,
449 request_context_getter,
450 xmpp_server_config)) {
453 XmppSignalStrategy::~XmppSignalStrategy() {
454 // All listeners should be removed at this point, so it's safe to detach
455 // |core_|.
456 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, core_.release());
459 void XmppSignalStrategy::Connect() {
460 core_->Connect();
463 void XmppSignalStrategy::Disconnect() {
464 core_->Disconnect();
467 SignalStrategy::State XmppSignalStrategy::GetState() const {
468 return core_->GetState();
471 SignalStrategy::Error XmppSignalStrategy::GetError() const {
472 return core_->GetError();
475 std::string XmppSignalStrategy::GetLocalJid() const {
476 return core_->GetLocalJid();
479 void XmppSignalStrategy::AddListener(Listener* listener) {
480 core_->AddListener(listener);
483 void XmppSignalStrategy::RemoveListener(Listener* listener) {
484 core_->RemoveListener(listener);
486 bool XmppSignalStrategy::SendStanza(scoped_ptr<buzz::XmlElement> stanza) {
487 return core_->SendStanza(stanza.Pass());
490 std::string XmppSignalStrategy::GetNextId() {
491 return base::Uint64ToString(base::RandUint64());
494 void XmppSignalStrategy::SetAuthInfo(const std::string& username,
495 const std::string& auth_token) {
496 core_->SetAuthInfo(username, auth_token);
499 } // namespace remoting