Skip to content

Commit

Permalink
NetworkContext: Add API to make bound sockets.
Browse files Browse the repository at this point in the history
Existing methods merged bind+listen and bind+connect, but the Pepper
socket API exposes the ability to separately bind and then either listen
or connect on sockets. Since bind provides a local address, and the bind
call is more likely to fail than the listen call on server sockets,
we can't just make the Pepper API wrap the merged calls without
potentially breaking some embedders.

Bug: 878139
Cq-Include-Trybots: luci.chromium.try:linux_mojo
Change-Id: I639c8ac45477fef8d0dee7c85c21e4123edc3a6a
Reviewed-on: https://chromium-review.googlesource.com/1198314
Commit-Queue: Matt Menke <mmenke@chromium.org>
Reviewed-by: Maks Orlovich <morlovich@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588571}
  • Loading branch information
Matt Menke authored and Commit Bot committed Sep 4, 2018
1 parent a8ff8e9 commit 701f142
Show file tree
Hide file tree
Showing 15 changed files with 773 additions and 25 deletions.
32 changes: 19 additions & 13 deletions net/socket/tcp_server_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,48 @@
namespace net {

TCPServerSocket::TCPServerSocket(NetLog* net_log, const NetLogSource& source)
: socket_(nullptr, net_log, source), pending_accept_(false) {}
: TCPServerSocket(
std::make_unique<TCPSocket>(nullptr /* socket_performance_watcher */,
net_log,
source)) {}

TCPServerSocket::TCPServerSocket(std::unique_ptr<TCPSocket> socket)
: socket_(std::move(socket)), pending_accept_(false) {}

int TCPServerSocket::AdoptSocket(SocketDescriptor socket) {
return socket_.AdoptUnconnectedSocket(socket);
return socket_->AdoptUnconnectedSocket(socket);
}

TCPServerSocket::~TCPServerSocket() = default;

int TCPServerSocket::Listen(const IPEndPoint& address, int backlog) {
int result = socket_.Open(address.GetFamily());
int result = socket_->Open(address.GetFamily());
if (result != OK)
return result;

result = socket_.SetDefaultOptionsForServer();
result = socket_->SetDefaultOptionsForServer();
if (result != OK) {
socket_.Close();
socket_->Close();
return result;
}

result = socket_.Bind(address);
result = socket_->Bind(address);
if (result != OK) {
socket_.Close();
socket_->Close();
return result;
}

result = socket_.Listen(backlog);
result = socket_->Listen(backlog);
if (result != OK) {
socket_.Close();
socket_->Close();
return result;
}

return OK;
}

int TCPServerSocket::GetLocalAddress(IPEndPoint* address) const {
return socket_.GetLocalAddress(address);
return socket_->GetLocalAddress(address);
}

int TCPServerSocket::Accept(std::unique_ptr<StreamSocket>* socket,
Expand All @@ -69,8 +75,8 @@ int TCPServerSocket::Accept(std::unique_ptr<StreamSocket>* socket,
CompletionOnceCallback accept_callback =
base::BindOnce(&TCPServerSocket::OnAcceptCompleted,
base::Unretained(this), socket, std::move(callback));
int result = socket_.Accept(&accepted_socket_, &accepted_address_,
std::move(accept_callback));
int result = socket_->Accept(&accepted_socket_, &accepted_address_,
std::move(accept_callback));
if (result != ERR_IO_PENDING) {
// |accept_callback| won't be called so we need to run
// ConvertAcceptedSocket() ourselves in order to do the conversion from
Expand All @@ -84,7 +90,7 @@ int TCPServerSocket::Accept(std::unique_ptr<StreamSocket>* socket,
}

void TCPServerSocket::DetachFromThread() {
socket_.DetachFromThread();
socket_->DetachFromThread();
}

int TCPServerSocket::ConvertAcceptedSocket(
Expand Down
6 changes: 5 additions & 1 deletion net/socket/tcp_server_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ struct NetLogSource;
class NET_EXPORT TCPServerSocket : public ServerSocket {
public:
TCPServerSocket(NetLog* net_log, const NetLogSource& source);

// Adopts the provided socket, which must not be a connected socket.
explicit TCPServerSocket(std::unique_ptr<TCPSocket> socket);

~TCPServerSocket() override;

// Takes ownership of |socket|, which has been opened, but may or may not be
Expand Down Expand Up @@ -56,7 +60,7 @@ class NET_EXPORT TCPServerSocket : public ServerSocket {
CompletionOnceCallback forward_callback,
int result);

TCPSocket socket_;
std::unique_ptr<TCPSocket> socket_;

std::unique_ptr<TCPSocket> accepted_socket_;
IPEndPoint accepted_address_;
Expand Down
3 changes: 3 additions & 0 deletions services/network/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ component("network_service") {
"ssl_config_service_mojo.h",
"ssl_config_type_converter.cc",
"ssl_config_type_converter.h",
"tcp_bound_socket.cc",
"tcp_bound_socket.h",
"tcp_connected_socket.cc",
"tcp_connected_socket.h",
"tcp_server_socket.cc",
Expand Down Expand Up @@ -261,6 +263,7 @@ source_set("tests") {
"session_cleanup_cookie_store_unittest.cc",
"socket_data_pump_unittest.cc",
"ssl_config_service_mojo_unittest.cc",
"tcp_bound_socket_unittest.cc",
"tcp_socket_unittest.cc",
"test/test_url_loader_factory_unittest.cc",
"test_chunked_data_pipe_getter.cc",
Expand Down
11 changes: 11 additions & 0 deletions services/network/network_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,17 @@ void NetworkContext::CreateTCPConnectedSocket(
std::move(request), std::move(observer), std::move(callback));
}

void NetworkContext::CreateTCPBoundSocket(
const net::IPEndPoint& local_addr,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::TCPBoundSocketRequest request,
CreateTCPBoundSocketCallback callback) {
socket_factory_->CreateTCPBoundSocket(
local_addr,
static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
std::move(request), std::move(callback));
}

void NetworkContext::CreateProxyResolvingSocketFactory(
mojom::ProxyResolvingSocketFactoryRequest request) {
proxy_resolving_socket_factories_.AddBinding(
Expand Down
5 changes: 5 additions & 0 deletions services/network/network_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojom::TCPConnectedSocketRequest request,
mojom::SocketObserverPtr observer,
CreateTCPConnectedSocketCallback callback) override;
void CreateTCPBoundSocket(
const net::IPEndPoint& local_addr,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::TCPBoundSocketRequest request,
CreateTCPBoundSocketCallback callback) override;
void CreateProxyResolvingSocketFactory(
mojom::ProxyResolvingSocketFactoryRequest request) override;
void CreateWebSocket(mojom::WebSocketRequest request,
Expand Down
27 changes: 22 additions & 5 deletions services/network/public/mojom/network_context.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -499,11 +499,28 @@ interface NetworkContext {
MutableNetworkTrafficAnnotationTag traffic_annotation,
TCPConnectedSocket& socket,
SocketObserver? observer)
=> (int32 result,
net.interfaces.IPEndPoint? local_addr,
net.interfaces.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
=> (int32 result,
net.interfaces.IPEndPoint? local_addr,
net.interfaces.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);

// Creates a TCPSocket bound to |local_addr|. The socket created can only be
// used for the purpose specified in |traffic_annotation|, and cannot be
// re-used for other purposes. |local_addr| is treated the same as in
// CreateTCPServerSocket().
//
// On success, the resulting local address will be written to |local_addr_out|
// and |result| is net::OK. On failure, |result| is a network error code.
//
// It's recommended consumers use CreateTCPServerSocket() or
// CreateTCPConnectedSocket(). This method is just provided so legacy
// consumers can mimic Berkeley sockets semantics.
CreateTCPBoundSocket(net.interfaces.IPEndPoint local_addr,
MutableNetworkTrafficAnnotationTag traffic_annotation,
TCPBoundSocket& socket)
=> (int32 result,
net.interfaces.IPEndPoint? local_addr);

// Creates a ProxyResolvingSocketFactory that shares some configuration params
// with this NetworkContext, but uses separate socket pools.
Expand Down
27 changes: 27 additions & 0 deletions services/network/public/mojom/tcp_socket.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,39 @@

module network.mojom;

import "net/interfaces/address_list.mojom";
import "net/interfaces/ip_endpoint.mojom";
import "services/network/public/mojom/ssl_config.mojom";
import "services/network/public/mojom/tls_socket.mojom";
import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";

// Represents a bound TCP socket. Once a call succeeds, cannot be reused.
interface TCPBoundSocket {
// Starts listening on the socket. |net_error| is set to net::OK on success,
// or a network error code on failure. Works just like
// NetworkContext::CreateServerSocket, except it operates on an already bound
// socket. The TCPBoundSocket will be destroyed on completion, whether the
// call succeeds or not.
Listen(uint32 backlog, TCPServerSocket& socket)
=> (int32 net_error);

// Attempts to connect the socket to |remote_addr_list|. |net_error| is set to
// net::OK on success, or a network error code on failure. Works just like
// NetworkContext::CreateTCPConnectedSocket(), except it operates on an
// already bound socket. The TCPBoundSocket will be destroyed on completion,
// whether the call succeeds or not.
Connect(
net.interfaces.IPEndPoint remote_addr,
TCPConnectedSocket& socket,
SocketObserver? observer)
=> (int32 net_error,
net.interfaces.IPEndPoint? local_addr,
net.interfaces.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
};

// Represents a connected TCP socket. Writes and Reads are through the data
// pipes supplied upon construction. Consumer should use
// SocketObserver interface to get notified about any error occurred
Expand Down
41 changes: 40 additions & 1 deletion services/network/socket_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "net/ssl/ssl_config_service.h"
#include "net/url_request/url_request_context.h"
#include "services/network/ssl_config_type_converter.h"
#include "services/network/tcp_connected_socket.h"
#include "services/network/tls_client_socket.h"
#include "services/network/udp_socket.h"

Expand Down Expand Up @@ -110,6 +109,46 @@ void SocketFactory::CreateTCPConnectedSocket(
socket_raw->Connect(local_addr, remote_addr_list, std::move(callback));
}

void SocketFactory::CreateTCPBoundSocket(
const net::IPEndPoint& local_addr,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
mojom::TCPBoundSocketRequest request,
mojom::NetworkContext::CreateTCPBoundSocketCallback callback) {
auto socket =
std::make_unique<TCPBoundSocket>(this, net_log_, traffic_annotation);
net::IPEndPoint local_addr_out;
int result = socket->Bind(local_addr, &local_addr_out);
if (result != net::OK) {
std::move(callback).Run(result, base::nullopt);
return;
}
socket->set_id(tcp_bound_socket_bindings_.AddBinding(std::move(socket),
std::move(request)));
std::move(callback).Run(result, local_addr_out);
}

void SocketFactory::DestroyBoundSocket(mojo::BindingId bound_socket_id) {
tcp_bound_socket_bindings_.RemoveBinding(bound_socket_id);
}

void SocketFactory::OnBoundSocketListening(
mojo::BindingId bound_socket_id,
std::unique_ptr<TCPServerSocket> server_socket,
mojom::TCPServerSocketRequest server_socket_request) {
tcp_server_socket_bindings_.AddBinding(std::move(server_socket),
std::move(server_socket_request));
tcp_bound_socket_bindings_.RemoveBinding(bound_socket_id);
}

void SocketFactory::OnBoundSocketConnected(
mojo::BindingId bound_socket_id,
std::unique_ptr<TCPConnectedSocket> connected_socket,
mojom::TCPConnectedSocketRequest connected_socket_request) {
tcp_connected_socket_bindings_.AddBinding(
std::move(connected_socket), std::move(connected_socket_request));
tcp_bound_socket_bindings_.RemoveBinding(bound_socket_id);
}

void SocketFactory::CreateTLSClientSocket(
const net::HostPortPair& host_port_pair,
mojom::TLSClientSocketOptionsPtr socket_options,
Expand Down
31 changes: 29 additions & 2 deletions services/network/socket_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/public/mojom/tls_socket.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
#include "services/network/tcp_bound_socket.h"
#include "services/network/tcp_connected_socket.h"
#include "services/network/tcp_server_socket.h"

Expand All @@ -33,8 +34,8 @@ namespace network {
// Helper class that handles socket requests. It takes care of destroying
// socket implementation instances when mojo pipes are broken.
class COMPONENT_EXPORT(NETWORK_SERVICE) SocketFactory
: public TCPServerSocket::Delegate,
public TCPConnectedSocket::Delegate {
: public TCPConnectedSocket::Delegate,
public TCPServerSocket::Delegate {
public:
// Constructs a SocketFactory. If |net_log| is non-null, it is used to
// log NetLog events when logging is enabled. |net_log| used to must outlive
Expand All @@ -43,6 +44,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SocketFactory
net::URLRequestContext* url_request_context);
virtual ~SocketFactory();

// These all correspond to the NetworkContext methods of the same name.
void CreateUDPSocket(mojom::UDPSocketRequest request,
mojom::UDPSocketReceiverPtr receiver);
void CreateTCPServerSocket(
Expand All @@ -58,6 +60,30 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SocketFactory
mojom::TCPConnectedSocketRequest request,
mojom::SocketObserverPtr observer,
mojom::NetworkContext::CreateTCPConnectedSocketCallback callback);
void CreateTCPBoundSocket(
const net::IPEndPoint& local_addr,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
mojom::TCPBoundSocketRequest request,
mojom::NetworkContext::CreateTCPBoundSocketCallback callback);

// Destroys the specified BoundSocket object.
void DestroyBoundSocket(mojo::BindingId bound_socket_id);

// Invoked when a BoundSocket successfully starts listening. Destroys the
// BoundSocket object, adding a binding for the provided TCPServerSocket in
// its place.
void OnBoundSocketListening(
mojo::BindingId bound_socket_id,
std::unique_ptr<TCPServerSocket> server_socket,
mojom::TCPServerSocketRequest server_socket_request);

// Invoked when a BoundSocket successfully establishes a connection. Destroys
// the BoundSocket object, adding a binding for the provided
// TCPConnectedSocket in its place.
void OnBoundSocketConnected(
mojo::BindingId bound_socket_id,
std::unique_ptr<TCPConnectedSocket> connected_socket,
mojom::TCPConnectedSocketRequest connected_socket_request);

private:
// TCPServerSocket::Delegate implementation:
Expand Down Expand Up @@ -93,6 +119,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SocketFactory
mojo::StrongBindingSet<mojom::TCPConnectedSocket>
tcp_connected_socket_bindings_;
mojo::StrongBindingSet<mojom::TLSClientSocket> tls_socket_bindings_;
mojo::StrongBindingSet<mojom::TCPBoundSocket> tcp_bound_socket_bindings_;

DISALLOW_COPY_AND_ASSIGN(SocketFactory);
};
Expand Down
Loading

0 comments on commit 701f142

Please sign in to comment.