blob: 20bd765b1c7a2e607c4d91c9e3f0bc577fe20c3b [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/tcp_client_socket_brokered.h"
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "net/base/address_list.h"
#include "net/base/completion_once_callback.h"
#include "net/socket/tcp_client_socket.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/brokered_client_socket_factory.h"
#include "services/network/public/cpp/transferable_socket.h"
namespace network {
TCPClientSocketBrokered::TCPClientSocketBrokered(
const net::AddressList& addresses,
std::unique_ptr<net::SocketPerformanceWatcher> socket_performance_watcher,
net::NetworkQualityEstimator* network_quality_estimator,
net::NetLog* net_log,
const net::NetLogSource& source,
BrokeredClientSocketFactory* client_socket_factory)
: addresses_(addresses),
socket_performance_watcher_(std::move(socket_performance_watcher)),
network_quality_estimator_(network_quality_estimator),
net_log_(net_log),
source_(source),
client_socket_factory_(client_socket_factory) {}
TCPClientSocketBrokered::~TCPClientSocketBrokered() {
Disconnect();
}
int TCPClientSocketBrokered::Bind(const net::IPEndPoint& address) {
// TODO(liza): Implement this.
NOTREACHED();
return net::OK;
}
bool TCPClientSocketBrokered::SetKeepAlive(bool enable, int delay) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return false;
}
return brokered_socket_->SetKeepAlive(enable, delay);
}
bool TCPClientSocketBrokered::SetNoDelay(bool no_delay) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return false;
}
return brokered_socket_->SetNoDelay(no_delay);
}
void TCPClientSocketBrokered::SetBeforeConnectCallback(
const BeforeConnectCallback& before_connect_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!before_connect_callback_);
DCHECK(!IsConnected());
DCHECK(!is_connect_in_progress_);
before_connect_callback_ = before_connect_callback;
}
int TCPClientSocketBrokered::Connect(net::CompletionOnceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(liza): add support for reconnecting disconnected socket, or look into
// removing support for reconnection from TCPClientSocket if it's not needed.
DCHECK(!callback.is_null());
// If connecting or already connected, then just return OK.
if (IsConnected() || is_connect_in_progress_)
return net::OK;
is_connect_in_progress_ = true;
// TODO(https://crbug.com/1321274): Pass in AddressFamily of single IPEndPoint
client_socket_factory_->BrokerCreateTcpSocket(
addresses_.begin()->GetFamily(),
base::BindOnce(&TCPClientSocketBrokered::DidCompleteCreate,
brokered_weak_ptr_factory_.GetWeakPtr(),
std::move(callback)));
return net::ERR_IO_PENDING;
}
int TCPClientSocketBrokered::OpenSocketForBind(const net::IPEndPoint& address) {
// TODO(liza): Implement this.
NOTREACHED();
return net::OK;
}
void TCPClientSocketBrokered::DidCompleteOpenForBind(
const net::IPEndPoint& address,
std::unique_ptr<net::TCPSocket> new_socket,
net::Error result) {
// TODO(liza): Implement this.
NOTREACHED();
}
void TCPClientSocketBrokered::DidCompleteConnect(
net::CompletionOnceCallback callback,
int result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(result, net::ERR_IO_PENDING);
is_connect_in_progress_ = false;
// The callback may delete {this}.
std::move(callback).Run(result);
}
void TCPClientSocketBrokered ::DidCompleteCreate(
net::CompletionOnceCallback callback,
network::TransferableSocket socket,
int result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (result != net::OK) {
std::move(callback).Run(result);
return;
}
// Create an unconnected TCPSocket with the socket fd that was opened in the
// browser process.
std::unique_ptr<net::TCPSocket> tcp_socket = std::make_unique<net::TCPSocket>(
std::move(socket_performance_watcher_), net_log_, source_);
tcp_socket->AdoptUnconnectedSocket(socket.TakeSocket());
// TODO(liza): Pass through the NetworkHandle.
brokered_socket_ = std::make_unique<net::TCPClientSocket>(
std::move(tcp_socket), addresses_, network_quality_estimator_);
brokered_socket_->ApplySocketTag(tag_);
if (before_connect_callback_) {
int callback_result = before_connect_callback_.Run();
DCHECK_NE(net::ERR_IO_PENDING, callback_result);
if (callback_result != net::OK) {
std::move(callback).Run(callback_result);
return;
}
}
brokered_socket_->Connect(base::BindOnce(
&TCPClientSocketBrokered::DidCompleteConnect,
brokered_weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void TCPClientSocketBrokered::Disconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (brokered_socket_) {
brokered_socket_->Disconnect();
}
is_connect_in_progress_ = false;
}
bool TCPClientSocketBrokered::IsConnected() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return false;
}
return brokered_socket_->IsConnected();
}
bool TCPClientSocketBrokered::IsConnectedAndIdle() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return false;
}
return brokered_socket_->IsConnectedAndIdle();
}
int TCPClientSocketBrokered::GetPeerAddress(net::IPEndPoint* address) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->GetPeerAddress(std::move(address));
}
int TCPClientSocketBrokered::GetLocalAddress(net::IPEndPoint* address) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->GetLocalAddress(std::move(address));
}
const net::NetLogWithSource& TCPClientSocketBrokered::NetLog() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return NetLog();
}
return brokered_socket_->NetLog();
}
bool TCPClientSocketBrokered::WasEverUsed() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return false;
}
return brokered_socket_->WasEverUsed();
}
bool TCPClientSocketBrokered::WasAlpnNegotiated() const {
return false;
}
net::NextProto TCPClientSocketBrokered::GetNegotiatedProtocol() const {
return net::kProtoUnknown;
}
bool TCPClientSocketBrokered::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
int64_t TCPClientSocketBrokered::GetTotalReceivedBytes() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return 0;
}
return brokered_socket_->GetTotalReceivedBytes();
}
void TCPClientSocketBrokered::ApplySocketTag(const net::SocketTag& tag) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
tag_ = tag;
} else {
brokered_socket_->ApplySocketTag(tag);
}
}
int TCPClientSocketBrokered::Read(net::IOBuffer* buf,
int buf_len,
net::CompletionOnceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->Read(buf, buf_len, std::move(callback));
}
int TCPClientSocketBrokered::ReadIfReady(net::IOBuffer* buf,
int buf_len,
net::CompletionOnceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->ReadIfReady(buf, buf_len, std::move(callback));
}
int TCPClientSocketBrokered::CancelReadIfReady() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->CancelReadIfReady();
}
int TCPClientSocketBrokered::Write(
net::IOBuffer* buf,
int buf_len,
net::CompletionOnceCallback callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->Write(std::move(buf), buf_len, std::move(callback),
traffic_annotation);
}
int TCPClientSocketBrokered::SetReceiveBufferSize(int32_t size) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->SetReceiveBufferSize(size);
}
int TCPClientSocketBrokered::SetSendBufferSize(int32_t size) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!brokered_socket_) {
return net::ERR_SOCKET_NOT_CONNECTED;
}
return brokered_socket_->SetSendBufferSize(size);
}
} // namespace network