blob: 3eb105476fb13cc1e364ec8ce83a384e50eeade5 [file] [log] [blame]
// Copyright 2018 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 "services/network/tcp_bound_socket.h"
#include <utility>
#include "base/bind.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket/tcp_server_socket.h"
#include "net/socket/tcp_socket.h"
#include "services/network/socket_factory.h"
#include "services/network/tcp_connected_socket.h"
namespace network {
TCPBoundSocket::TCPBoundSocket(
SocketFactory* socket_factory,
net::NetLog* net_log,
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: socket_factory_(socket_factory),
socket_(std::make_unique<net::TCPSocket>(
nullptr /*socket_performance_watcher*/,
net_log,
net::NetLogSource())),
traffic_annotation_(traffic_annotation),
weak_factory_(this) {}
TCPBoundSocket::~TCPBoundSocket() = default;
int TCPBoundSocket::Bind(const net::IPEndPoint& local_addr,
net::IPEndPoint* local_addr_out) {
int result = socket_->Open(local_addr.GetFamily());
if (result != net::OK)
return result;
// This is primarily intended for use with server sockets.
result = socket_->SetDefaultOptionsForServer();
if (result != net::OK)
return result;
result = socket_->Bind(local_addr);
if (result != net::OK)
return result;
return socket_->GetLocalAddress(local_addr_out);
}
void TCPBoundSocket::Listen(uint32_t backlog,
mojom::TCPServerSocketRequest request,
ListenCallback callback) {
DCHECK(socket_->IsValid());
if (connect_callback_) {
// Drop unexpected calls on the floor. Could destroy |this|, but as this is
// currently only reachable from more trusted processes, doesn't seem too
// useful.
NOTREACHED();
return;
}
int result = socket_->Listen(backlog);
// Succeed or fail, pass the result back to the caller.
std::move(callback).Run(result);
// Tear down everything on error.
if (result != net::OK) {
socket_factory_->DestroyBoundSocket(binding_id_);
return;
}
// On success, also set up the TCPServerSocket.
std::unique_ptr<TCPServerSocket> server_socket =
std::make_unique<TCPServerSocket>(
std::make_unique<net::TCPServerSocket>(std::move(socket_)), backlog,
socket_factory_, traffic_annotation_);
socket_factory_->OnBoundSocketListening(binding_id_, std::move(server_socket),
std::move(request));
// The above call will have destroyed |this|.
}
void TCPBoundSocket::Connect(const net::IPEndPoint& remote_addr,
mojom::TCPConnectedSocketRequest request,
mojom::SocketObserverPtr observer,
ConnectCallback callback) {
DCHECK(socket_->IsValid());
if (connect_callback_) {
// Drop unexpected calls on the floor. Could destroy |this|, but as this is
// currently only reachable from more trusted processes, doesn't seem too
// useful.
NOTREACHED();
return;
}
connected_socket_request_ = std::move(request);
socket_observer_ = std::move(observer);
connect_callback_ = std::move(callback);
int result = socket_->Connect(
remote_addr, base::BindOnce(&TCPBoundSocket::OnConnectComplete,
base::Unretained(this)));
if (result == net::ERR_IO_PENDING)
return;
OnConnectComplete(result);
}
void TCPBoundSocket::OnConnectComplete(int result) {
DCHECK(connect_callback_);
net::IPEndPoint peer_addr;
net::IPEndPoint local_addr;
if (result == net::OK)
result = socket_->GetLocalAddress(&local_addr);
if (result == net::OK)
result = socket_->GetPeerAddress(&peer_addr);
if (result != net::OK) {
std::move(connect_callback_)
.Run(result, base::nullopt /* local_addr */,
base::nullopt /* peer_addr */,
mojo::ScopedDataPipeConsumerHandle(),
mojo::ScopedDataPipeProducerHandle());
socket_factory_->DestroyBoundSocket(binding_id_);
return;
}
mojo::DataPipe send_pipe;
mojo::DataPipe receive_pipe;
std::unique_ptr<TCPConnectedSocket> connected_socket =
std::make_unique<TCPConnectedSocket>(
std::move(socket_observer_),
std::make_unique<net::TCPClientSocket>(std::move(socket_), peer_addr),
std::move(receive_pipe.producer_handle),
std::move(send_pipe.consumer_handle), traffic_annotation_);
std::move(connect_callback_)
.Run(result, local_addr, peer_addr,
std::move(receive_pipe.consumer_handle),
std::move(send_pipe.producer_handle));
socket_factory_->OnBoundSocketConnected(binding_id_,
std::move(connected_socket),
std::move(connected_socket_request_));
// The above call will have destroyed |this|.
}
} // namespace network