blob: ece08e8eae76be4b3b1a2272a5c5cb96ffc56447 [file] [log] [blame]
// Copyright 2014 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.
#ifndef EXTENSIONS_BROWSER_API_SOCKET_TCP_SOCKET_H_
#define EXTENSIONS_BROWSER_API_SOCKET_TCP_SOCKET_H_
#include <stdint.h>
#include <memory>
#include <string>
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "extensions/browser/api/socket/socket.h"
#include "extensions/browser/api/socket/tcp_socket.h"
#include "extensions/common/api/socket.h"
#include "net/base/completion_once_callback.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/public/mojom/tls_socket.mojom.h"
namespace content {
class BrowserContext;
class StoragePartition;
}
namespace extensions {
class MojoDataPump;
class TCPSocket : public Socket {
public:
using UpgradeToTLSCallback =
base::OnceCallback<void(int,
network::mojom::TLSClientSocketPtr,
const net::IPEndPoint&,
const net::IPEndPoint&,
mojo::ScopedDataPipeConsumerHandle,
mojo::ScopedDataPipeProducerHandle)>;
// Constuctor for when |socket_mode_| is unknown. The |socket_mode_| will be
// filled in when the consumer calls Listen/Connect.
TCPSocket(content::BrowserContext* browser_context,
const std::string& owner_extension_id);
// Created using TCPServerSocket::Accept().
TCPSocket(network::mojom::TCPConnectedSocketPtr socket,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream,
const base::Optional<net::IPEndPoint>& remote_addr,
const std::string& owner_extension_id);
~TCPSocket() override;
void Connect(const net::AddressList& address,
net::CompletionOnceCallback callback) override;
void Disconnect(bool socket_destroying) override;
void Bind(const std::string& address,
uint16_t port,
const CompletionCallback& callback) override;
void Read(int count, ReadCompletionCallback callback) override;
void RecvFrom(int count, const RecvFromCompletionCallback& callback) override;
void SendTo(scoped_refptr<net::IOBuffer> io_buffer,
int byte_count,
const net::IPEndPoint& address,
const CompletionCallback& callback) override;
void SetKeepAlive(bool enable,
int delay,
SetKeepAliveCallback callback) override;
void SetNoDelay(bool no_delay, SetNoDelayCallback callback) override;
void Listen(const std::string& address,
uint16_t port,
int backlog,
ListenCallback callback) override;
void Accept(AcceptCompletionCallback callback) override;
bool IsConnected() override;
bool GetPeerAddress(net::IPEndPoint* address) override;
bool GetLocalAddress(net::IPEndPoint* address) override;
Socket::SocketType GetSocketType() const override;
void UpgradeToTLS(api::socket::SecureOptions* options,
UpgradeToTLSCallback callback);
void SetStoragePartitionForTest(
content::StoragePartition* storage_partition) {
storage_partition_ = storage_partition;
}
protected:
int WriteImpl(net::IOBuffer* io_buffer,
int io_buffer_size,
const net::CompletionCallback& callback) override;
private:
// Connects a client TCP socket. This is done on the UI thread because
// StoragePartition::GetNetworkContext() needs to happen on the UI thread.
// The completion callback is posted back to the thread on which |this| lives.
static void ConnectOnUIThread(
content::StoragePartition* storage_partition,
content::BrowserContext* browser_context,
const net::AddressList& remote_address_list,
network::mojom::TCPConnectedSocketRequest request,
network::mojom::NetworkContext::CreateTCPConnectedSocketCallback
callback);
static void OnConnectCompleteOnUIThread(
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
network::mojom::NetworkContext::CreateTCPConnectedSocketCallback callback,
int result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
void OnConnectComplete(int result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
// Connects a server TCP socket. This is done on the UI thread because
// StoragePartition::GetNetworkContext() needs to happen on the UI thread.
// The completion callback is posted back to the thread on which |this| lives.
static void ListenOnUIThread(
content::StoragePartition* storage_partition,
content::BrowserContext* browser_context,
const net::IPEndPoint& local_addr,
int backlog,
network::mojom::TCPServerSocketRequest request,
network::mojom::NetworkContext::CreateTCPServerSocketCallback callback);
static void OnListenCompleteOnUIThread(
const scoped_refptr<base::SequencedTaskRunner>& original_task_runner,
network::mojom::NetworkContext::CreateTCPServerSocketCallback callback,
int result,
const base::Optional<net::IPEndPoint>& local_addr);
void OnListenComplete(int result,
const base::Optional<net::IPEndPoint>& local_addr);
void OnAccept(int result,
const base::Optional<net::IPEndPoint>& remote_addr,
network::mojom::TCPConnectedSocketPtr connected_socket,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
void OnWriteComplete(const net::CompletionCallback& callback, int result);
void OnReadComplete(int result, scoped_refptr<net::IOBuffer> io_buffer);
void OnUpgradeToTLSComplete(UpgradeToTLSCallback callback,
network::mojom::TLSClientSocketPtr tls_socket,
const net::IPEndPoint& local_addr,
const net::IPEndPoint& peer_addr,
int result,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream,
const base::Optional<net::SSLInfo>& ssl_info);
content::StoragePartition* GetStoragePartitionHelper();
enum SocketMode {
UNKNOWN = 0,
CLIENT,
SERVER,
};
// |this| doesn't outlive |browser_context_| because |this| is owned by
// ApiResourceManager which is a BrowserContextKeyedAPI.
content::BrowserContext* browser_context_;
SocketMode socket_mode_;
// CLIENT mode.
network::mojom::TCPConnectedSocketPtr client_socket_;
// SERVER mode.
network::mojom::TCPServerSocketPtr server_socket_;
net::CompletionOnceCallback connect_callback_;
ListenCallback listen_callback_;
AcceptCompletionCallback accept_callback_;
ReadCompletionCallback read_callback_;
std::unique_ptr<MojoDataPump> mojo_data_pump_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::Optional<net::IPEndPoint> local_addr_;
base::Optional<net::IPEndPoint> peer_addr_;
// Only used in tests.
content::StoragePartition* storage_partition_ = nullptr;
// WeakPtr is used when posting tasks to |task_runner_| which might outlive
// |this|.
base::WeakPtrFactory<TCPSocket> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TCPSocket);
};
// TCP Socket instances from the "sockets.tcp" namespace. These are regular
// socket objects with additional properties related to the behavior defined in
// the "sockets.tcp" namespace.
class ResumableTCPSocket : public TCPSocket {
public:
ResumableTCPSocket(content::BrowserContext* browser_context,
const std::string& owner_extension_id);
// Created using TCPServerSocket::Accept().
ResumableTCPSocket(network::mojom::TCPConnectedSocketPtr socket,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream,
const base::Optional<net::IPEndPoint>& remote_addr,
const std::string& owner_extension_id);
~ResumableTCPSocket() override;
// Overriden from ApiResource
bool IsPersistent() const override;
const std::string& name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
bool persistent() const { return persistent_; }
void set_persistent(bool persistent) { persistent_ = persistent; }
int buffer_size() const { return buffer_size_; }
void set_buffer_size(int buffer_size) { buffer_size_ = buffer_size; }
bool paused() const { return paused_; }
void set_paused(bool paused) { paused_ = paused; }
private:
friend class ApiResourceManager<ResumableTCPSocket>;
static const char* service_name() { return "ResumableTCPSocketManager"; }
// Application-defined string - see sockets_tcp.idl.
std::string name_;
// Flag indicating whether the socket is left open when the application is
// suspended - see sockets_tcp.idl.
bool persistent_;
// The size of the buffer used to receive data - see sockets_tcp.idl.
int buffer_size_;
// Flag indicating whether a connected socket blocks its peer from sending
// more data - see sockets_tcp.idl.
bool paused_;
};
// TCP Socket instances from the "sockets.tcpServer" namespace. These are
// regular socket objects with additional properties related to the behavior
// defined in the "sockets.tcpServer" namespace.
class ResumableTCPServerSocket : public TCPSocket {
public:
ResumableTCPServerSocket(content::BrowserContext* browser_context,
const std::string& owner_extension_id);
// Overriden from ApiResource
bool IsPersistent() const override;
const std::string& name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
bool persistent() const { return persistent_; }
void set_persistent(bool persistent) { persistent_ = persistent; }
bool paused() const { return paused_; }
void set_paused(bool paused) { paused_ = paused; }
private:
friend class ApiResourceManager<ResumableTCPServerSocket>;
static const char* service_name() {
return "ResumableTCPServerSocketManager";
}
// Application-defined string - see sockets_tcp_server.idl.
std::string name_;
// Flag indicating whether the socket is left open when the application is
// suspended - see sockets_tcp_server.idl.
bool persistent_;
// Flag indicating whether a connected socket blocks its peer from sending
// more data - see sockets_tcp_server.idl.
bool paused_;
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_SOCKET_TCP_SOCKET_H_