blob: 4a1e41f1f9487907a403f94009ee4e814500b7ed [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "jingle/notifier/base/xmpp_connection.h"
#include <stddef.h>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "base/threading/thread_task_runner_handle.h"
#include "jingle/glue/network_service_async_socket.h"
#include "jingle/glue/task_pump.h"
#include "jingle/notifier/base/weak_xmpp_client.h"
#include "net/socket/client_socket_factory.h"
#include "net/ssl/ssl_config_service.h"
#include "services/network/public/mojom/tls_socket.mojom.h"
#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
namespace notifier {
XmppConnection::Delegate::~Delegate() {}
namespace {
jingle_xmpp::AsyncSocket* CreateSocket(
const jingle_xmpp::XmppClientSettings& xmpp_client_settings,
jingle_glue::GetProxyResolvingSocketFactoryCallback
get_socket_factory_callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation) {
bool use_fake_ssl_client_socket =
(xmpp_client_settings.protocol() == jingle_xmpp::PROTO_SSLTCP);
// The default SSLConfig is good enough for us for now.
const net::SSLConfig ssl_config;
// These numbers were taken from similar numbers in
// XmppSocketAdapter.
const size_t kReadBufSize = 64U * 1024U;
const size_t kWriteBufSize = 64U * 1024U;
return new jingle_glue::NetworkServiceAsyncSocket(
get_socket_factory_callback, use_fake_ssl_client_socket, kReadBufSize,
kWriteBufSize, traffic_annotation);
}
} // namespace
XmppConnection::XmppConnection(
const jingle_xmpp::XmppClientSettings& xmpp_client_settings,
jingle_glue::GetProxyResolvingSocketFactoryCallback
get_socket_factory_callback,
Delegate* delegate,
jingle_xmpp::PreXmppAuth* pre_xmpp_auth,
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: task_pump_(new jingle_glue::TaskPump()),
on_connect_called_(false),
delegate_(delegate) {
DCHECK(delegate_);
// Owned by |task_pump_|, but is guaranteed to live at least as long
// as this function.
WeakXmppClient* weak_xmpp_client = new WeakXmppClient(task_pump_.get());
weak_xmpp_client->SignalStateChange.connect(
this, &XmppConnection::OnStateChange);
weak_xmpp_client->SignalLogInput.connect(
this, &XmppConnection::OnInputLog);
weak_xmpp_client->SignalLogOutput.connect(
this, &XmppConnection::OnOutputLog);
const char kLanguage[] = "en";
jingle_xmpp::XmppReturnStatus connect_status = weak_xmpp_client->Connect(
xmpp_client_settings, kLanguage,
CreateSocket(xmpp_client_settings, get_socket_factory_callback,
traffic_annotation),
pre_xmpp_auth);
// jingle_xmpp::XmppClient::Connect() should never fail.
DCHECK_EQ(connect_status, jingle_xmpp::XMPP_RETURN_OK);
weak_xmpp_client->Start();
weak_xmpp_client_ = weak_xmpp_client->AsWeakPtr();
}
XmppConnection::~XmppConnection() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ClearClient();
task_pump_->Stop();
// We do this because XmppConnection may get destroyed as a result
// of a signal from XmppClient. If we delete |task_pump_| here, bad
// things happen when the stack pops back up to the XmppClient's
// (which is deleted by |task_pump_|) function.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
std::move(task_pump_));
}
void XmppConnection::OnStateChange(jingle_xmpp::XmppEngine::State state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << "XmppClient state changed to " << state;
if (!weak_xmpp_client_.get()) {
LOG(DFATAL) << "weak_xmpp_client_ unexpectedly NULL";
return;
}
if (!delegate_) {
LOG(DFATAL) << "delegate_ unexpectedly NULL";
return;
}
switch (state) {
case jingle_xmpp::XmppEngine::STATE_OPEN:
if (on_connect_called_) {
LOG(DFATAL) << "State changed to STATE_OPEN more than once";
} else {
delegate_->OnConnect(weak_xmpp_client_);
on_connect_called_ = true;
}
break;
case jingle_xmpp::XmppEngine::STATE_CLOSED: {
int subcode = 0;
jingle_xmpp::XmppEngine::Error error =
weak_xmpp_client_->GetError(&subcode);
const jingle_xmpp::XmlElement* stream_error =
weak_xmpp_client_->GetStreamError();
ClearClient();
Delegate* delegate = delegate_;
delegate_ = NULL;
delegate->OnError(error, subcode, stream_error);
break;
}
default:
// Do nothing.
break;
}
}
void XmppConnection::OnInputLog(const char* data, int len) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << "XMPP Input: " << base::StringPiece(data, len);
}
void XmppConnection::OnOutputLog(const char* data, int len) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << "XMPP Output: " << base::StringPiece(data, len);
}
void XmppConnection::ClearClient() {
if (weak_xmpp_client_.get()) {
weak_xmpp_client_->Invalidate();
DCHECK(!weak_xmpp_client_.get());
}
}
} // namespace notifier