0

Revert "Make PepperUdpSocketMessageFilter use NetworkService UDP API."

This reverts commit cc2b634dbe.

Reason for revert: Multiple PPAPI tests have begun failing on different OSes after this patch lands. See crbug.com/876824

Original change's description:
> Make PepperUdpSocketMessageFilter use NetworkService UDP API.
> 
> This CL moves all of the logic over to the UI thread, to keep things
> relatively simple and minimize thread hops, since that's where core
> network service objects live.
> 
> It also fixes a pre-existing bug in the PPAPI UDP code, where read
> errors that occur when there's no pending read are converted into
> 0-byte read successes.
> 
> Bug: 848078
> Cq-Include-Trybots: luci.chromium.try:linux_mojo
> Change-Id: Id6d23c26c1ac085211dfcfe23502a307fc29a284
> Reviewed-on: https://chromium-review.googlesource.com/1171568
> Commit-Queue: Matt Menke <mmenke@chromium.org>
> Reviewed-by: John Abd-El-Malek <jam@chromium.org>
> Reviewed-by: Ramin Halavati <rhalavati@chromium.org>
> Reviewed-by: Helen Li <xunjieli@chromium.org>
> Reviewed-by: Bill Budge <bbudge@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#585057}

TBR=bbudge@chromium.org,jam@chromium.org,mmenke@chromium.org,xunjieli@chromium.org,rhalavati@chromium.org

Change-Id: I68b625673615275c102a95aac7df7583a2f7c97d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 848078
Cq-Include-Trybots: luci.chromium.try:linux_mojo
Reviewed-on: https://chromium-review.googlesource.com/1185682
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Commit-Queue: Jonathan Ross <jonross@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585196}
This commit is contained in:
Jonathan Ross
2018-08-22 19:22:39 +00:00
parent e2fd13720c
commit 3ea4abbfde
11 changed files with 331 additions and 851 deletions

@ -4,7 +4,6 @@
#include <stddef.h>
#include "base/callback.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/test/test_timeouts.h"
@ -33,19 +32,13 @@
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/javascript_test_observer.h"
#include "content/public/test/ppapi_test_utils.h"
#include "content/public/test/test_renderer_host.h"
#include "extensions/common/constants.h"
#include "extensions/test/extension_test_message_listener.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/base/net_errors.h"
#include "ppapi/shared_impl/test_utils.h"
#include "rlz/buildflags/buildflags.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#if defined(OS_MACOSX)
@ -388,228 +381,6 @@ TEST_PPAPI_NACL(UDPSocketPrivate_ConnectFailure)
TEST_PPAPI_NACL(UDPSocketPrivate_Broadcast)
TEST_PPAPI_NACL(UDPSocketPrivate_SetSocketFeatureErrors)
namespace {
// UDPSocket subclass that wraps a real network::mojom::UDPSocket, and can
// simulate certain failures. Owns itself, and destroys itself when one of
// its Mojo pipes is closed.
class WrappedUDPSocket : public network::mojom::UDPSocket {
public:
// Type of failure to simulate. "DropPipe" failures correspond to dropping a
// Mojo pipe (Which typically happens if the network service crashes, or the
// parent NetworkContext is torn down). "Error" failures correspond to
// returning net::ERR_FAILED.
enum class FailureType {
kBindError,
kBindDropPipe,
kBroadcastError,
kBroadcastDropPipe,
kSendToDropPipe,
kSendToError,
kDropReceiverPipeOnConstruction,
kDropReceiverPipeOnReceiveMore,
kReadError,
};
WrappedUDPSocket(FailureType failure_type,
network::mojom::NetworkContext* network_context,
network::mojom::UDPSocketRequest socket_request,
network::mojom::UDPSocketReceiverPtr socket_receiver)
: failure_type_(failure_type), binding_(this, std::move(socket_request)) {
if (failure_type == FailureType::kDropReceiverPipeOnConstruction)
socket_receiver.reset();
socket_receiver_ = std::move(socket_receiver);
network_context->CreateUDPSocket(mojo::MakeRequest(&wrapped_socket_),
nullptr);
binding_.set_connection_error_handler(
base::BindOnce(&WrappedUDPSocket::Close, base::Unretained(this)));
wrapped_socket_.set_connection_error_handler(
base::BindOnce(&WrappedUDPSocket::Close, base::Unretained(this)));
}
// network::mojom::UDPSocket implementation.
void Connect(const net::IPEndPoint& remote_addr,
network::mojom::UDPSocketOptionsPtr options,
ConnectCallback callback) override {
NOTREACHED();
}
void Bind(const net::IPEndPoint& local_addr,
network::mojom::UDPSocketOptionsPtr options,
BindCallback callback) override {
if (failure_type_ == FailureType::kBindError) {
std::move(callback).Run(net::ERR_FAILED, base::nullopt);
return;
}
if (failure_type_ == FailureType::kBindDropPipe) {
Close();
return;
}
wrapped_socket_->Bind(local_addr, std::move(options), std::move(callback));
}
void SetBroadcast(bool broadcast, SetBroadcastCallback callback) override {
if (failure_type_ == FailureType::kBroadcastError) {
std::move(callback).Run(net::ERR_FAILED);
return;
}
if (failure_type_ == FailureType::kBroadcastDropPipe) {
Close();
return;
}
wrapped_socket_->SetBroadcast(broadcast, std::move(callback));
}
void SetSendBufferSize(int32_t send_buffer_size,
SetSendBufferSizeCallback callback) override {
wrapped_socket_->SetSendBufferSize(send_buffer_size, std::move(callback));
}
void SetReceiveBufferSize(int32_t receive_buffer_size,
SetReceiveBufferSizeCallback callback) override {
wrapped_socket_->SetReceiveBufferSize(receive_buffer_size,
std::move(callback));
}
void JoinGroup(const net::IPAddress& group_address,
JoinGroupCallback callback) override {
wrapped_socket_->JoinGroup(group_address, std::move(callback));
}
void LeaveGroup(const net::IPAddress& group_address,
LeaveGroupCallback callback) override {
wrapped_socket_->LeaveGroup(group_address, std::move(callback));
}
void ReceiveMore(uint32_t num_additional_datagrams) override {
if (failure_type_ == FailureType::kDropReceiverPipeOnReceiveMore) {
socket_receiver_.reset();
return;
}
if (failure_type_ == FailureType::kReadError) {
for (uint32_t i = 0; i < num_additional_datagrams; ++i) {
socket_receiver_->OnReceived(net::ERR_FAILED, base::nullopt,
base::nullopt);
}
return;
}
// None of the tests using this fixture expect to read anything
// successfully, so just ignore this call if it isn't supposed to result in
// an error of some sort.
}
void ReceiveMoreWithBufferSize(uint32_t num_additional_datagrams,
uint32_t buffer_size) override {
NOTREACHED();
}
void SendTo(const net::IPEndPoint& dest_addr,
base::span<const uint8_t> data,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
SendToCallback callback) override {
if (failure_type_ == FailureType::kSendToError) {
std::move(callback).Run(net::ERR_FAILED);
return;
}
if (failure_type_ == FailureType::kSendToDropPipe) {
Close();
return;
}
wrapped_socket_->SendTo(dest_addr, data, traffic_annotation,
std::move(callback));
}
void Send(base::span<const uint8_t> data,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
SendCallback callback) override {
NOTREACHED();
}
void Close() override {
// Deleting |this| before closing the bindings can cause Mojo to DCHECK if
// there's a pending callback.
binding_.Close();
socket_receiver_.reset();
delete this;
}
private:
const FailureType failure_type_;
mojo::Binding<network::mojom::UDPSocket> binding_;
network::mojom::UDPSocketPtr wrapped_socket_;
// Only populated on certain read FailureTypes.
network::mojom::UDPSocketReceiverPtr socket_receiver_;
DISALLOW_COPY_AND_ASSIGN(WrappedUDPSocket);
};
void TestCreateUDPSocketCallback(
WrappedUDPSocket::FailureType failure_type,
network::mojom::NetworkContext* network_context,
network::mojom::UDPSocketRequest socket_request,
network::mojom::UDPSocketReceiverPtr socket_receiver) {
// This will delete itself when one of its Mojo pipes is closed.
new WrappedUDPSocket(failure_type, network_context, std::move(socket_request),
std::move(socket_receiver));
}
#define RUN_UDP_FAILURE_TEST(test_name, failure_type) \
do { \
auto callback = \
base::BindRepeating(&TestCreateUDPSocketCallback, failure_type); \
ppapi::SetPepperUDPSocketCallackForTesting(&callback); \
RunTestViaHTTP(LIST_TEST(test_name)); \
ppapi::SetPepperUDPSocketCallackForTesting(nullptr); \
} while (false)
} // namespace
// Macro for tests that use |WrappedUDPSocket| to simulate errors. |test_name|
// and |_test| are separate values because there are often multiple ways to get
// the same error pattern (Dropped mojo pipe and failed call, generally).
#define UDPSOCKET_FAILURE_TEST(test_name, _test, failure_type) \
IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, test_name) { \
RUN_UDP_FAILURE_TEST(_test, failure_type); \
} \
IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, MAYBE_PPAPI_NACL(test_name)) { \
RUN_UDP_FAILURE_TEST(_test, failure_type); \
} \
IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(test_name)) { \
RUN_UDP_FAILURE_TEST(_test, failure_type); \
} \
IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
RUN_UDP_FAILURE_TEST(_test, failure_type); \
} \
IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, \
MAYBE_PNACL_NONSFI(test_name)) { \
RUN_UDP_FAILURE_TEST(_test, failure_type); \
}
UDPSOCKET_FAILURE_TEST(UDPSocket_BindError,
UDPSocket_BindFails,
WrappedUDPSocket::FailureType::kBindError);
UDPSOCKET_FAILURE_TEST(UDPSocket_BindDropPipe,
UDPSocket_BindFails,
WrappedUDPSocket::FailureType::kBindDropPipe);
UDPSOCKET_FAILURE_TEST(UDPSocket_BroadcastBeforeBindError,
UDPSocket_BroadcastBeforeBindFails,
WrappedUDPSocket::FailureType::kBroadcastError);
UDPSOCKET_FAILURE_TEST(UDPSocket_BroadcastBeforeBindDropPipe,
UDPSocket_BroadcastBeforeBindFails,
WrappedUDPSocket::FailureType::kBroadcastDropPipe);
UDPSOCKET_FAILURE_TEST(UDPSocket_BroadcastAfterBindError,
UDPSocket_BroadcastAfterBindFails,
WrappedUDPSocket::FailureType::kBroadcastError);
UDPSOCKET_FAILURE_TEST(UDPSocket_BroadcastAfterBindDropPipe,
UDPSocket_BroadcastAfterBindFails,
WrappedUDPSocket::FailureType::kBroadcastDropPipe);
UDPSOCKET_FAILURE_TEST(UDPSocket_SendToBeforeDropPipeFails,
UDPSocket_SendToFails,
WrappedUDPSocket::FailureType::kSendToDropPipe);
UDPSOCKET_FAILURE_TEST(UDPSocket_DropPipeAfterBindSendToFails,
UDPSocket_SendToFails,
WrappedUDPSocket::FailureType::kSendToError);
UDPSOCKET_FAILURE_TEST(UDPSocket_ReadError,
UDPSocket_ReadFails,
WrappedUDPSocket::FailureType::kReadError);
UDPSOCKET_FAILURE_TEST(
UDPSocket_DropReceiverPipeOnConstruction,
UDPSocket_ReadFails,
WrappedUDPSocket::FailureType::kDropReceiverPipeOnConstruction);
UDPSOCKET_FAILURE_TEST(
UDPSocket_DropReceiverPipeOnReceiveMore,
UDPSocket_ReadFails,
WrappedUDPSocket::FailureType::kDropReceiverPipeOnReceiveMore);
// Disallowed socket tests.
TEST_PPAPI_NACL_DISALLOWED_SOCKETS(HostResolverPrivateDisallowed)
TEST_PPAPI_NACL_DISALLOWED_SOCKETS(TCPServerSocketPrivateDisallowed)

@ -13,20 +13,15 @@
#include "build/build_config.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/process_type.h"
#include "content/public/common/socket_permission_request.h"
#include "ipc/ipc_message_macros.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_source.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/socket/udp_socket.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
@ -38,7 +33,6 @@
#include "ppapi/proxy/udp_socket_resource_constants.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
#include "ppapi/shared_impl/socket_option_data.h"
#include "services/network/public/mojom/network_context.mojom.h"
#if defined(OS_CHROMEOS)
#include "chromeos/network/firewall_hole.h"
@ -48,23 +42,20 @@ using ppapi::NetAddressPrivateImpl;
using ppapi::host::NetErrorToPepperError;
using ppapi::proxy::UDPSocketResourceConstants;
namespace content {
namespace {
const PepperUDPSocketMessageFilter::CreateUDPSocketCallback*
g_create_udp_socket_callback_for_testing = nullptr;
size_t g_num_udp_filter_instances = 0;
} // namespace
namespace content {
PepperUDPSocketMessageFilter::PendingSend::PendingSend(
const net::IPAddress& address,
int port,
std::vector<uint8_t> data,
const scoped_refptr<net::IOBufferWithSize>& buffer,
const ppapi::host::ReplyMessageContext& context)
: address(address), port(port), data(std::move(data)), context(context) {}
: address(address), port(port), buffer(buffer), context(context) {}
PepperUDPSocketMessageFilter::PendingSend::PendingSend(
const PendingSend& other) = default;
@ -89,13 +80,7 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
render_process_id_(0),
render_frame_id_(0),
is_potentially_secure_plugin_context_(
host->IsPotentiallySecurePluginContext(instance)),
binding_(this)
#if defined(OS_CHROMEOS)
,
firewall_hole_weak_ptr_factory_(this)
#endif // defined(OS_CHROMEOS)
{
host->IsPotentiallySecurePluginContext(instance)) {
++g_num_udp_filter_instances;
DCHECK(host);
@ -106,35 +91,15 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
}
PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
DCHECK(closed_);
DCHECK(!socket_);
DCHECK(!binding_);
Close();
--g_num_udp_filter_instances;
}
void PepperUDPSocketMessageFilter::SetCreateUDPSocketCallbackForTesting(
const CreateUDPSocketCallback* create_udp_socket_callback) {
DCHECK(!create_udp_socket_callback ||
!g_create_udp_socket_callback_for_testing);
g_create_udp_socket_callback_for_testing = create_udp_socket_callback;
}
// static
size_t PepperUDPSocketMessageFilter::GetNumInstances() {
return g_num_udp_filter_instances;
}
void PepperUDPSocketMessageFilter::OnFilterDestroyed() {
ResourceMessageFilter::OnFilterDestroyed();
// Need to close the socket on the UI thread. Calling Close() also ensures
// that future messages will be ignored, so the mojo pipes won't be
// re-created, so after Close() runs, |this| can be safely deleted on the IO
// thread.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&PepperUDPSocketMessageFilter::Close, this));
}
scoped_refptr<base::TaskRunner>
PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
@ -142,6 +107,7 @@ PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
case PpapiHostMsg_UDPSocket_SetOption::ID:
case PpapiHostMsg_UDPSocket_Close::ID:
case PpapiHostMsg_UDPSocket_RecvSlotAvailable::ID:
return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
case PpapiHostMsg_UDPSocket_Bind::ID:
case PpapiHostMsg_UDPSocket_SendTo::ID:
case PpapiHostMsg_UDPSocket_JoinGroup::ID:
@ -176,14 +142,14 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
const ppapi::host::HostMessageContext* context,
PP_UDPSocket_Option name,
const ppapi::SocketOptionData& value) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (closed_)
return PP_ERROR_FAILED;
switch (name) {
case PP_UDPSOCKET_OPTION_ADDRESS_REUSE: {
if (socket_) {
if (socket_.get()) {
// AllowReuseAddress is only effective before Bind().
// Note that this limitation originally comes from Windows, but
// PPAPI tries to provide platform independent APIs.
@ -206,19 +172,16 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
// If the socket is already bound, proxy the value to UDPSocket.
if (socket_.get())
return NetErrorToPepperError(socket_->SetBroadcast(boolean_value));
// UDPSocket instance is not yet created, so remember the value here.
if (boolean_value) {
socket_options_ |= SOCKET_OPTION_BROADCAST;
} else {
socket_options_ &= ~SOCKET_OPTION_BROADCAST;
}
if (socket_) {
socket_->SetBroadcast(
boolean_value,
CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
context));
return PP_OK_COMPLETIONPENDING;
}
return PP_OK;
}
case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE: {
@ -227,18 +190,15 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value > UDPSocketResourceConstants::kMaxSendBufferSize)
return PP_ERROR_BADARGUMENT;
socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
sndbuf_size_ = integer_value;
// If the socket is already initialized, proxy the value to UDPSocket.
if (socket_) {
socket_->SetSendBufferSize(
integer_value,
CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
context));
return PP_OK_COMPLETIONPENDING;
// If the socket is already bound, proxy the value to UDPSocket.
if (socket_.get()) {
return NetErrorToPepperError(
socket_->SetSendBufferSize(integer_value));
}
// UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
sndbuf_size_ = integer_value;
return PP_OK;
}
case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
@ -247,18 +207,15 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value > UDPSocketResourceConstants::kMaxReceiveBufferSize)
return PP_ERROR_BADARGUMENT;
socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
rcvbuf_size_ = integer_value;
// If the socket is already initialized, proxy the value to UDPSocket.
if (socket_) {
socket_->SetReceiveBufferSize(
integer_value,
CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
context));
return PP_OK_COMPLETIONPENDING;
// If the socket is already bound, proxy the value to UDPSocket.
if (socket_.get()) {
return NetErrorToPepperError(
socket_->SetReceiveBufferSize(integer_value));
}
// UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
rcvbuf_size_ = integer_value;
return PP_OK;
}
case PP_UDPSOCKET_OPTION_MULTICAST_LOOP: {
@ -266,22 +223,21 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
// If the socket is already bound, proxy the value to UDPSocket.
if (socket_) {
if (can_use_multicast_ != PP_OK)
return can_use_multicast_;
return NetErrorToPepperError(
socket_->SetMulticastLoopbackMode(boolean_value));
}
// UDPSocket instance is not yet created, so remember the value here.
if (boolean_value) {
socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
} else {
socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
}
// If the socket is already initialized, either fail if permissions
// disallow multicast, or lie and claim it succeeded, to maintain previous
// behavior.
if (socket_) {
if (can_use_multicast_ != PP_OK)
return can_use_multicast_;
return PP_OK;
}
return PP_OK;
}
case PP_UDPSOCKET_OPTION_MULTICAST_TTL: {
@ -290,20 +246,18 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value < 0 || integer_value > 255)
return PP_ERROR_BADARGUMENT;
// UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
multicast_ttl_ = integer_value;
// If the socket is already initialized, either fail if permissions
// disallow multicast, or lie and claim it succeeded, to maintain previous
// behavior.
// If the socket is already bound, proxy the value to UDPSocket.
if (socket_) {
if (can_use_multicast_ != PP_OK)
return can_use_multicast_;
return PP_OK;
return NetErrorToPepperError(
socket_->SetMulticastTimeToLive(integer_value));
}
// UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
multicast_ttl_ = integer_value;
return PP_OK;
}
default: {
@ -319,9 +273,6 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
if (closed_ || socket_)
return PP_ERROR_FAILED;
// Check for permissions to use multicast APIS. This check must be done while
// on the UI thread, so we cache the value here to be used later on.
PP_NetAddress_Private any_addr;
@ -339,81 +290,10 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
return PP_ERROR_NOACCESS;
}
net::IPAddressBytes address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port))
return PP_ERROR_ADDRESS_INVALID;
net::IPEndPoint end_point(net::IPAddress(address), port);
network::mojom::UDPSocketOptionsPtr udp_socket_options =
network::mojom::UDPSocketOptions::New();
udp_socket_options->allow_address_reuse =
!!(socket_options_ & SOCKET_OPTION_ADDRESS_REUSE);
if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE)
udp_socket_options->send_buffer_size = sndbuf_size_;
if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE)
udp_socket_options->receive_buffer_size = rcvbuf_size_;
if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
if (can_use_multicast_ != PP_OK) {
// TODO(mmenke): The above line implies |can_use_multicast_| is a PP
// error code, but the next line implies it is a net error code. Fix that.
return NetErrorToPepperError(can_use_multicast_);
}
// TODO(mmenke): This doesn't seem to be doing anything - this is the
// default behavior.
udp_socket_options->multicast_loopback_mode = true;
}
if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
if (can_use_multicast_ != PP_OK) {
// TODO(mmenke): The above line implies |can_use_multicast_| is a PP
// error code, but the next line implies it is a net error code. Fix that.
return NetErrorToPepperError(can_use_multicast_);
}
udp_socket_options->multicast_time_to_live = multicast_ttl_;
}
RenderFrameHost* render_frame_host =
RenderFrameHost::FromID(render_process_id_, render_frame_id_);
// If the RenderFrameHost has been closed, just fail the request.
if (!render_frame_host)
return PP_ERROR_NOACCESS;
network::mojom::UDPSocketReceiverPtr udp_socket_receiver;
// Avoid binding the receiver until the socket has been successfully Bound (in
// a socket sense), to avoid providing read data to the caller until it has
// been told that the socket was bound.
network::mojom::UDPSocketReceiverRequest receiver_request =
mojo::MakeRequest(&udp_socket_receiver);
SiteInstance* site_instance = render_frame_host->GetSiteInstance();
network::mojom::NetworkContext* network_context =
BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
site_instance)
->GetNetworkContext();
if (g_create_udp_socket_callback_for_testing) {
g_create_udp_socket_callback_for_testing->Run(
network_context, mojo::MakeRequest(&socket_),
std::move(udp_socket_receiver));
} else {
network_context->CreateUDPSocket(mojo::MakeRequest(&socket_),
std::move(udp_socket_receiver));
}
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
// Watch the socket for errors during the the Bind call.
socket_.set_connection_error_handler(
base::BindOnce(&PepperUDPSocketMessageFilter::SendBindError,
base::Unretained(this), reply_context, PP_ERROR_FAILED));
// This is the actual socket Bind call (i.e., not a Mojo Bind call).
socket_->Bind(end_point, std::move(udp_socket_options),
base::BindOnce(&PepperUDPSocketMessageFilter::DoBindCallback,
base::Unretained(this),
std::move(receiver_request), reply_context));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&PepperUDPSocketMessageFilter::DoBind, this,
context->MakeReplyMessageContext(), addr));
return PP_OK_COMPLETIONPENDING;
}
@ -424,11 +304,6 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
// Check |binding_| instead of |socket_| because |binding_| is only set
// after the Bind() call completes.
if (closed_ || !binding_)
return PP_ERROR_FAILED;
SocketPermissionRequest request =
pepper_socket_utils::CreateSocketPermissionRequest(
SocketPermissionRequest::UDP_SEND_TO, addr);
@ -440,61 +315,32 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
return PP_ERROR_NOACCESS;
}
// Make sure a malicious plugin can't queue up an unlimited number of buffers.
size_t num_pending_sends = pending_sends_.size();
if (num_pending_sends == UDPSocketResourceConstants::kPluginSendBufferSlots) {
return PP_ERROR_FAILED;
}
size_t num_bytes = data.size();
if (num_bytes == 0 ||
num_bytes >
static_cast<size_t>(UDPSocketResourceConstants::kMaxWriteSize)) {
// Size of |data| is checked on the plugin side.
NOTREACHED();
return PP_ERROR_BADARGUMENT;
}
net::IPAddressBytes address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
return PP_ERROR_ADDRESS_INVALID;
}
const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(data.data());
std::vector<uint8_t> data_vector(data_ptr, data_ptr + num_bytes);
pending_sends_.push(PendingSend(net::IPAddress(address), port,
std::move(data_vector),
context->MakeReplyMessageContext()));
// Can only start the send if there isn't another send pending.
if (num_pending_sends == 0)
StartPendingSend();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&PepperUDPSocketMessageFilter::DoSendTo, this,
context->MakeReplyMessageContext(), data, addr));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperUDPSocketMessageFilter::OnMsgClose(
const ppapi::host::HostMessageContext* context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
Close();
return PP_OK;
}
int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
const ppapi::host::HostMessageContext* context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (remaining_recv_slots_ <
UDPSocketResourceConstants::kPluginReceiveBufferSlots) {
// If the pipe was closed, but the consumer has not yet closed the UDP
// socket, keep the read buffer filled with errors.
if (!binding_) {
PepperUDPSocketMessageFilter::SendRecvFromError(PP_ERROR_FAILED);
return PP_OK;
}
remaining_recv_slots_++;
socket_->ReceiveMore(1);
}
if (!recvfrom_buffer_.get() && !closed_ && socket_.get()) {
DCHECK_EQ(1u, remaining_recv_slots_);
DoRecvFrom();
}
return PP_OK;
@ -518,11 +364,7 @@ int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
socket_->JoinGroup(
net::IPAddress(group),
CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
context));
return PP_OK_COMPLETIONPENDING;
return NetErrorToPepperError(socket_->JoinGroup(net::IPAddress(group)));
}
int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
@ -543,205 +385,308 @@ int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
socket_->LeaveGroup(
net::IPAddress(group),
CreateCompletionCallback<PpapiPluginMsg_UDPSocket_LeaveGroupReply>(
context));
return PP_OK_COMPLETIONPENDING;
return NetErrorToPepperError(socket_->LeaveGroup(net::IPAddress(group)));
}
void PepperUDPSocketMessageFilter::DoBindCallback(
network::mojom::UDPSocketReceiverRequest receiver_request,
void PepperUDPSocketMessageFilter::DoBind(
const ppapi::host::ReplyMessageContext& context,
int result,
const base::Optional<net::IPEndPoint>& local_addr_out) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const PP_NetAddress_Private& addr) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != net::OK) {
SendBindError(context, NetErrorToPepperError(result));
if (closed_ || socket_.get()) {
SendBindError(context, PP_ERROR_FAILED);
return;
}
auto socket = std::make_unique<net::UDPSocket>(
net::DatagramSocket::DEFAULT_BIND, nullptr, net::NetLogSource());
net::IPAddressBytes address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
net::IPEndPoint end_point(net::IPAddress(address), port);
{
int net_result = socket->Open(end_point.GetFamily());
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_ADDRESS_REUSE) {
int net_result = socket->AllowAddressReuse();
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_BROADCAST) {
int net_result = socket->SetBroadcast(true);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) {
int net_result = socket->SetSendBufferSize(sndbuf_size_);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) {
int net_result = socket->SetReceiveBufferSize(rcvbuf_size_);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
if (can_use_multicast_ != PP_OK) {
SendBindError(context, NetErrorToPepperError(can_use_multicast_));
return;
}
int net_result = socket->SetMulticastLoopbackMode(true);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
if (can_use_multicast_ != PP_OK) {
SendBindError(context, NetErrorToPepperError(can_use_multicast_));
return;
}
int net_result = socket->SetMulticastTimeToLive(multicast_ttl_);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
{
int net_result = socket->Bind(end_point);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
net::IPEndPoint bound_address;
{
int net_result = socket->GetLocalAddress(&bound_address);
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
}
PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
if (!local_addr_out || !NetAddressPrivateImpl::IPEndPointToNetAddress(
local_addr_out->address().bytes(),
local_addr_out->port(), &net_address)) {
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
bound_address.address().bytes(), bound_address.port(),
&net_address)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
if (socket_options_ & SOCKET_OPTION_BROADCAST) {
socket_->SetBroadcast(
true, base::BindOnce(
&PepperUDPSocketMessageFilter::OnBroadcastConfiguredAfterBind,
base::Unretained(this), std::move(receiver_request), context,
*local_addr_out, net_address));
return;
}
// The default value of disabled is fine, if SOCKET_OPTION_BROADCAST is not
// set.
OnBroadcastConfiguredAfterBind(std::move(receiver_request), context,
*local_addr_out, net_address, net::OK);
}
void PepperUDPSocketMessageFilter::OnBroadcastConfiguredAfterBind(
network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const net::IPEndPoint& ip_endpoint,
const PP_NetAddress_Private& net_address,
int net_result) {
if (net_result != net::OK) {
SendBindError(context, NetErrorToPepperError(net_result));
return;
}
#if defined(OS_CHROMEOS)
pepper_socket_utils::OpenUDPFirewallHole(
ip_endpoint,
base::BindRepeating(&PepperUDPSocketMessageFilter::OnFirewallHoleOpened,
firewall_hole_weak_ptr_factory_.GetWeakPtr(),
base::Passed(std::move(receiver_request)), context,
net_address));
#else // !defined(OS_CHROMEOS)
OnBindComplete(std::move(receiver_request), context, net_address);
#endif // !defined(OS_CHROMEOS)
OpenFirewallHole(
bound_address,
base::Bind(&PepperUDPSocketMessageFilter::OnBindComplete, this,
base::Passed(&socket), context, net_address));
#else
OnBindComplete(std::move(socket), context, net_address);
#endif
}
void PepperUDPSocketMessageFilter::OnBindComplete(
network::mojom::UDPSocketReceiverRequest receiver_request,
std::unique_ptr<net::UDPSocket> socket,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(socket_);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
socket_.swap(socket);
SendBindReply(context, PP_OK, net_address);
binding_.Bind(std::move(receiver_request));
binding_.set_connection_error_handler(base::BindOnce(
&PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
socket_.set_connection_error_handler(base::BindOnce(
&PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
socket_->ReceiveMore(UDPSocketResourceConstants::kPluginReceiveBufferSlots);
DoRecvFrom();
}
#if defined(OS_CHROMEOS)
void PepperUDPSocketMessageFilter::OpenFirewallHole(
const net::IPEndPoint& local_address,
base::Closure bind_complete) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
pepper_socket_utils::FirewallHoleOpenCallback callback = base::Bind(
&PepperUDPSocketMessageFilter::OnFirewallHoleOpened, this, bind_complete);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&pepper_socket_utils::OpenUDPFirewallHole, local_address,
callback));
}
void PepperUDPSocketMessageFilter::OnFirewallHoleOpened(
network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address,
base::Closure bind_complete,
std::unique_ptr<chromeos::FirewallHole> hole) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
firewall_hole_.reset(hole.release());
OnBindComplete(std::move(receiver_request), context, net_address);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, bind_complete);
}
#endif // defined(OS_CHROMEOS)
void PepperUDPSocketMessageFilter::StartPendingSend() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
void PepperUDPSocketMessageFilter::DoRecvFrom() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!closed_);
DCHECK(socket_.get());
DCHECK(!recvfrom_buffer_.get());
DCHECK_GT(remaining_recv_slots_, 0u);
recvfrom_buffer_ =
new net::IOBuffer(UDPSocketResourceConstants::kMaxReadSize);
// Use base::Unretained(this), so that the lifespan of this object doesn't
// have to last until the callback is called.
// It is safe to do so because |socket_| is owned by this object. If this
// object gets destroyed (and so does |socket_|), the callback won't be
// called.
int net_result = socket_->RecvFrom(
recvfrom_buffer_.get(), UDPSocketResourceConstants::kMaxReadSize,
&recvfrom_address_,
base::BindOnce(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
base::Unretained(this)));
if (net_result != net::ERR_IO_PENDING)
OnRecvFromCompleted(net_result);
}
void PepperUDPSocketMessageFilter::DoSendTo(
const ppapi::host::ReplyMessageContext& context,
const std::string& data,
const PP_NetAddress_Private& addr) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(socket_.get());
if (closed_ || !socket_.get()) {
SendSendToError(context, PP_ERROR_FAILED);
return;
}
size_t num_bytes = data.size();
if (num_bytes == 0 ||
num_bytes >
static_cast<size_t>(UDPSocketResourceConstants::kMaxWriteSize)) {
// Size of |data| is checked on the plugin side.
NOTREACHED();
SendSendToError(context, PP_ERROR_BADARGUMENT);
return;
}
net::IPAddressBytes address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
scoped_refptr<net::IOBufferWithSize> buffer(
new net::IOBufferWithSize(num_bytes));
memcpy(buffer->data(), data.data(), num_bytes);
// Make sure a malicious plugin can't queue up an unlimited number of buffers.
size_t num_pending_sends = pending_sends_.size();
if (num_pending_sends == UDPSocketResourceConstants::kPluginSendBufferSlots) {
SendSendToError(context, PP_ERROR_FAILED);
return;
}
pending_sends_.push(
PendingSend(net::IPAddress(address), port, buffer, context));
// If there are other sends pending, we can't start yet.
if (num_pending_sends)
return;
int net_result = StartPendingSend();
if (net_result != net::ERR_IO_PENDING)
FinishPendingSend(net_result);
}
int PepperUDPSocketMessageFilter::StartPendingSend() {
DCHECK(!pending_sends_.empty());
DCHECK(socket_);
net::NetworkTrafficAnnotationTag annotation =
net::DefineNetworkTrafficAnnotation("pepper_udp_socket_message_filter",
R"(
semantics {
sender: "Chrome Plugin UDP Socket API"
description:
"Chrome plugins can use this API to send and receive data over the "
"network using UDP connections."
trigger: "A request from a plugin."
data: "Any data that the plugin sends."
destination: OTHER
destination_other:
"Data can be sent to any destination."
}
policy {
cookies_allowed: NO
setting:
"The only remaining plugin is Flash, so disabling it in Content "
"settings will prevent all use of UDP sockets by plugins."
policy_exception_justification:
"There is no single policy related to plugin use of UDP sockets, "
"but there are a number of policies that allow disabling plugins."
})");
const PendingSend& pending_send = pending_sends_.front();
// See OnMsgRecvFrom() for the reason why we use base::Unretained(this)
// when calling |socket_| methods.
socket_->SendTo(
int net_result = socket_->SendTo(
pending_send.buffer.get(), pending_send.buffer->size(),
net::IPEndPoint(pending_send.address, pending_send.port),
pending_send.data, net::MutableNetworkTrafficAnnotationTag(annotation),
base::BindOnce(&PepperUDPSocketMessageFilter::OnSendToCompleted,
base::Unretained(this)));
return net_result;
}
void PepperUDPSocketMessageFilter::Close() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
socket_.reset();
binding_.Close();
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (socket_.get() && !closed_)
socket_->Close();
closed_ = true;
}
void PepperUDPSocketMessageFilter::OnReceived(
int result,
const base::Optional<net::IPEndPoint>& src_addr,
base::Optional<base::span<const uint8_t>> data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!closed_);
void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(recvfrom_buffer_.get());
int32_t pp_result = NetErrorToPepperError(result);
int32_t pp_result = NetErrorToPepperError(net_result);
// Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
// to send back.
PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
if (pp_result == PP_OK &&
(!src_addr ||
!NetAddressPrivateImpl::IPEndPointToNetAddress(
src_addr->address().bytes(), src_addr->port(), &addr))) {
if (pp_result >= 0 &&
!NetAddressPrivateImpl::IPEndPointToNetAddress(
recvfrom_address_.address().bytes(), recvfrom_address_.port(),
&addr)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
}
if (pp_result == PP_OK) {
std::string data_string;
if (data) {
data_string = std::string(reinterpret_cast<const char*>(data->data()),
data->size());
}
SendRecvFromResult(PP_OK, data_string, addr);
if (pp_result >= 0) {
SendRecvFromResult(PP_OK, std::string(recvfrom_buffer_->data(), pp_result),
addr);
} else {
SendRecvFromError(pp_result);
}
// This should always be the case, but best to protect against a broken /
// taken over network service.
if (remaining_recv_slots_ > 0)
remaining_recv_slots_--;
recvfrom_buffer_ = nullptr;
DCHECK_GT(remaining_recv_slots_, 0u);
remaining_recv_slots_--;
if (remaining_recv_slots_ > 0 && !closed_ && socket_.get())
DoRecvFrom();
}
void PepperUDPSocketMessageFilter::OnSendToCompleted(int net_result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
FinishPendingSend(net_result);
if (!pending_sends_.empty())
StartPendingSend();
// Start pending sends until none are left or a send doesn't complete.
while (!pending_sends_.empty()) {
net_result = StartPendingSend();
if (net_result == net::ERR_IO_PENDING)
break;
FinishPendingSend(net_result);
}
}
void PepperUDPSocketMessageFilter::FinishPendingSend(int net_result) {
DCHECK(!pending_sends_.empty());
const PendingSend& pending_send = pending_sends_.front();
int32_t pp_result = NetErrorToPepperError(net_result);
if (pp_result < 0) {
if (pp_result < 0)
SendSendToError(pending_send.context, pp_result);
} else {
// The cast should be safe because of the
// UDPSocketResourceConstants::kMaxSendBufferSize before enqueuing the send.
SendSendToReply(pending_send.context, PP_OK,
static_cast<int>(pending_send.data.size()));
}
else
SendSendToReply(pending_send.context, PP_OK, pp_result);
pending_sends_.pop();
}
@ -762,19 +707,6 @@ void PepperUDPSocketMessageFilter::SendRecvFromResult(
int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr) {
// Unlike SendReply, which is safe to call on any thread, SendUnsolicitedReply
// calls are only safe to make on the IO thread.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
&PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread, this,
result, data, addr));
}
void PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread(
int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr) {
if (resource_host()) {
resource_host()->host()->SendUnsolicitedReply(
resource_host()->pp_resource(),
@ -794,12 +726,6 @@ void PepperUDPSocketMessageFilter::SendSendToReply(
void PepperUDPSocketMessageFilter::SendBindError(
const ppapi::host::ReplyMessageContext& context,
int32_t result) {
socket_.reset();
#if defined(OS_CHROMEOS)
// In the unlikely case that this is due to a Mojo error while trying to open
// a hole in the firewall on ChromeOS, abandon opening a hole in the firewall.
firewall_hole_weak_ptr_factory_.InvalidateWeakPtrs();
#endif // !defined(OS_CHROMEOS)
SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
}
@ -815,19 +741,6 @@ void PepperUDPSocketMessageFilter::SendSendToError(
SendSendToReply(context, result, 0);
}
void PepperUDPSocketMessageFilter::PipeClosed() {
Close();
while (!pending_sends_.empty())
FinishPendingSend(PP_ERROR_FAILED);
// Any reads should fail, after a pipe error.
while (remaining_recv_slots_ > 0) {
--remaining_recv_slots_;
SendRecvFromError(PP_ERROR_FAILED);
}
}
int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
const PP_NetAddress_Private& addr) {
// Check for plugin permissions.
@ -845,29 +758,4 @@ int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
return PP_OK;
}
template <class ReturnMessage>
base::OnceCallback<void(int result)>
PepperUDPSocketMessageFilter::CreateCompletionCallback(
const ppapi::host::HostMessageContext* context) {
std::unique_ptr<int> result = std::make_unique<int>(net::ERR_FAILED);
int* result_ptr = result.get();
base::ScopedClosureRunner closure_runner(
base::BindOnce(&PepperUDPSocketMessageFilter::ReturnResult<ReturnMessage>,
base::Unretained(this), context->MakeReplyMessageContext(),
base::Passed(std::move(result))));
return base::BindOnce(
[](base::ScopedClosureRunner closure_runner, int* result_ptr,
int net_result) { *result_ptr = net_result; },
std::move(closure_runner), result_ptr);
}
template <class ReturnMessage>
void PepperUDPSocketMessageFilter::ReturnResult(
const ppapi::host::ReplyMessageContext& context,
std::unique_ptr<int> result) {
ppapi::host::ReplyMessageContext reply_context(context);
reply_context.params.set_result(NetErrorToPepperError(*result));
SendReply(reply_context, ReturnMessage());
}
} // namespace content

@ -6,29 +6,26 @@
#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_UDP_SOCKET_MESSAGE_FILTER_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/common/process_type.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/completion_callback.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/socket/udp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/ppb_udp_socket.h"
#include "ppapi/host/resource_message_filter.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
struct PP_NetAddress_Private;
@ -37,6 +34,11 @@ struct PP_NetAddress_Private;
#include "content/public/browser/browser_thread.h"
#endif // defined(OS_CHROMEOS)
namespace net {
class IOBuffer;
class IOBufferWithSize;
}
namespace ppapi {
class SocketOptionData;
@ -46,32 +48,17 @@ struct ReplyMessageContext;
}
}
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
namespace content {
class BrowserPpapiHostImpl;
class CONTENT_EXPORT PepperUDPSocketMessageFilter
: public ppapi::host::ResourceMessageFilter,
public network::mojom::UDPSocketReceiver {
: public ppapi::host::ResourceMessageFilter {
public:
PepperUDPSocketMessageFilter(BrowserPpapiHostImpl* host,
PP_Instance instance,
bool private_api);
using CreateUDPSocketCallback = base::RepeatingCallback<void(
network::mojom::NetworkContext* network_context,
network::mojom::UDPSocketRequest socket_request,
network::mojom::UDPSocketReceiverPtr socket_receiver)>;
static void SetCreateUDPSocketCallbackForTesting(
const CreateUDPSocketCallback* create_udp_socket_callback);
static size_t GetNumInstances();
protected:
@ -90,19 +77,18 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
struct PendingSend {
PendingSend(const net::IPAddress& address,
int port,
std::vector<uint8_t> data,
const scoped_refptr<net::IOBufferWithSize>& buffer,
const ppapi::host::ReplyMessageContext& context);
PendingSend(const PendingSend& other);
~PendingSend();
net::IPAddress address;
int port;
std::vector<uint8_t> data;
scoped_refptr<net::IOBufferWithSize> buffer;
ppapi::host::ReplyMessageContext context;
};
// ppapi::host::ResourceMessageFilter overrides.
void OnFilterDestroyed() override;
scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
const IPC::Message& message) override;
int32_t OnResourceMessageReceived(
@ -125,34 +111,25 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
int32_t OnMsgLeaveGroup(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& addr);
void DoBindCallback(network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
int result,
const base::Optional<net::IPEndPoint>& local_addr_out);
void OnBroadcastConfiguredAfterBind(
network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const net::IPEndPoint& ip_endpoint,
const PP_NetAddress_Private& net_address,
int net_result);
void OnBindComplete(network::mojom::UDPSocketReceiverRequest receiver_request,
void DoBind(const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr);
void OnBindComplete(std::unique_ptr<net::UDPSocket> socket,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address);
#if defined(OS_CHROMEOS)
void OnFirewallHoleOpened(
network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address,
std::unique_ptr<chromeos::FirewallHole> hole);
void OpenFirewallHole(const net::IPEndPoint& local_address,
base::Closure bind_complete);
void OnFirewallHoleOpened(base::Closure bind_complete,
std::unique_ptr<chromeos::FirewallHole> hole);
#endif // defined(OS_CHROMEOS)
void StartPendingSend();
void DoRecvFrom();
void DoSendTo(const ppapi::host::ReplyMessageContext& context,
const std::string& data,
const PP_NetAddress_Private& addr);
int StartPendingSend();
void Close();
// network::mojom::UDPSocketReceiver override:
void OnReceived(int result,
const base::Optional<net::IPEndPoint>& src_addr,
base::Optional<base::span<const uint8_t>> data) override;
void OnRecvFromCompleted(int net_result);
void OnSendToCompleted(int net_result);
void FinishPendingSend(int net_result);
@ -162,9 +139,6 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void SendRecvFromResult(int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr);
void SendRecvFromResultOnIOThread(int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr);
void SendSendToReply(const ppapi::host::ReplyMessageContext& context,
int32_t result,
int32_t bytes_written);
@ -174,18 +148,9 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void SendRecvFromError(int32_t result);
void SendSendToError(const ppapi::host::ReplyMessageContext& context,
int32_t result);
void PipeClosed();
int32_t CanUseMulticastAPI(const PP_NetAddress_Private& addr);
template <class ReturnMessage>
base::OnceCallback<void(int result)> CreateCompletionCallback(
const ppapi::host::HostMessageContext* context);
template <class ReturnMessage>
void ReturnResult(const ppapi::host::ReplyMessageContext& context,
std::unique_ptr<int> result);
// Bitwise-or of SocketOption flags. This stores the state about whether
// each option is set before Bind() is called.
int socket_options_;
@ -198,10 +163,20 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
int multicast_ttl_;
int32_t can_use_multicast_;
std::unique_ptr<net::UDPSocket> socket_;
bool closed_;
#if defined(OS_CHROMEOS)
std::unique_ptr<chromeos::FirewallHole,
content::BrowserThread::DeleteOnUIThread>
firewall_hole_;
#endif // defined(OS_CHROMEOS)
scoped_refptr<net::IOBuffer> recvfrom_buffer_;
base::queue<PendingSend> pending_sends_;
net::IPEndPoint recvfrom_address_;
size_t remaining_recv_slots_;
bool external_plugin_;
@ -212,27 +187,6 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
const bool is_potentially_secure_plugin_context_;
// Bound (in a Mojo sense) when binding (in a network sense) starts. Closed in
// Close() and on Mojo pipe errors. Must only be accessed (and destroyed) on
// UI thread.
network::mojom::UDPSocketPtr socket_;
// Bound (in a Mojo sense) when binding (in a network sense) completes.
// Binding late avoids receiving data when still setting up the socket. Closed
// in Close() and on Mojo pipe errors. Must only be accessed (and destroyed)
// on UI thread.
mojo::Binding<network::mojom::UDPSocketReceiver> binding_;
#if defined(OS_CHROMEOS)
std::unique_ptr<chromeos::FirewallHole,
content::BrowserThread::DeleteOnUIThread>
firewall_hole_;
// Allows for cancellation of opening a hole in the firewall in the case the
// network service crashes.
base::WeakPtrFactory<PepperUDPSocketMessageFilter>
firewall_hole_weak_ptr_factory_;
#endif // defined(OS_CHROMEOS)
DISALLOW_COPY_AND_ASSIGN(PepperUDPSocketMessageFilter);
};

@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/path_service.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "ppapi/shared_impl/ppapi_constants.h"
@ -145,10 +144,4 @@ bool RegisterBlinkTestPlugin(base::CommandLine* command_line) {
return RegisterPlugins(command_line, plugins);
}
void SetPepperUDPSocketCallackForTesting(
const CreateUDPSocketCallback* create_udp_socket_callback) {
content::PepperUDPSocketMessageFilter::SetCreateUDPSocketCallbackForTesting(
create_udp_socket_callback);
}
} // namespace ppapi

@ -5,21 +5,13 @@
#ifndef CONTENT_PUBLIC_TEST_PPAPI_TEST_UTILS_H_
#define CONTENT_PUBLIC_TEST_PPAPI_TEST_UTILS_H_
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
namespace base {
class CommandLine;
}
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
// This file specifies utility functions used in Pepper testing in
// browser_tests and content_browsertests.
namespace ppapi {
@ -43,17 +35,6 @@ bool RegisterFlashTestPlugin(base::CommandLine* command_line)
bool RegisterBlinkTestPlugin(base::CommandLine* command_line)
WARN_UNUSED_RESULT;
using CreateUDPSocketCallback = base::RepeatingCallback<void(
network::mojom::NetworkContext* network_context,
network::mojom::UDPSocketRequest socket_request,
network::mojom::UDPSocketReceiverPtr socket_receiver)>;
// Sets callback to be invoked when creating a UDPSocket for use by pepper.
// Passed in callback must remain valid until the method is called again with
// a nullptr, to clear the callback.
void SetPepperUDPSocketCallackForTesting(
const CreateUDPSocketCallback* create_udp_socket_callback);
} // namespace ppapi
#endif // CONTENT_PUBLIC_TEST_PPAPI_TEST_UTILS_H_

@ -54,7 +54,7 @@ void ResourceMessageFilter::OnFilterAdded(ResourceHost* resource_host) {
}
void ResourceMessageFilter::OnFilterDestroyed() {
resource_host_ = nullptr;
resource_host_ = NULL;
}
bool ResourceMessageFilter::HandleMessage(const IPC::Message& msg,

@ -92,7 +92,7 @@ class PPAPI_HOST_EXPORT ResourceMessageFilter
// Called when a filter is added to a ResourceHost.
void OnFilterAdded(ResourceHost* resource_host);
// Called when a filter is removed from a ResourceHost.
virtual void OnFilterDestroyed();
void OnFilterDestroyed();
// This will dispatch the message handler on the target thread. It returns
// true if the message was handled by this filter and false otherwise.

@ -226,11 +226,11 @@ int32_t UDPSocketFilter::RecvQueue::RequestData(
if (static_cast<size_t>(num_bytes) < front.data.size())
return PP_ERROR_MESSAGE_TOO_BIG;
int32_t result = static_cast<int32_t>(front.data.size());
std::unique_ptr<std::string> data_to_pass(new std::string);
data_to_pass->swap(front.data);
int32_t result =
SetRecvFromOutput(pp_instance_, std::move(data_to_pass), front.addr,
buffer_out, num_bytes, addr_out, front.result);
SetRecvFromOutput(pp_instance_, std::move(data_to_pass), front.addr,
buffer_out, num_bytes, addr_out, PP_OK);
last_recvfrom_addr_ = front.addr;
recv_buffers_.pop();
slot_available_callback_.Run();

@ -104,14 +104,6 @@ void TestUDPSocket::RunTests(const std::string& filter) {
RUN_CALLBACK_TEST(TestUDPSocket, SetOption, filter);
RUN_CALLBACK_TEST(TestUDPSocket, ParallelSend, filter);
RUN_CALLBACK_TEST(TestUDPSocket, Multicast, filter);
// Failure tests. Generally can only be run individually, since they require
// specific socket failures to be injected into the UDP code.
RUN_CALLBACK_TEST(TestUDPSocket, BindFails, filter);
RUN_CALLBACK_TEST(TestUDPSocket, BroadcastBeforeBindFails, filter);
RUN_CALLBACK_TEST(TestUDPSocket, BroadcastAfterBindFails, filter);
RUN_CALLBACK_TEST(TestUDPSocket, SendToFails, filter);
RUN_CALLBACK_TEST(TestUDPSocket, ReadFails, filter);
}
std::string TestUDPSocket::GetLocalAddress(pp::NetAddress* address) {
@ -524,93 +516,3 @@ std::string TestUDPSocket::TestMulticast() {
PASS();
}
std::string TestUDPSocket::TestBindFails() {
pp::UDPSocket socket(instance_);
PP_NetAddress_IPv4 any_ipv4_address = {0, {0, 0, 0, 0}};
pp::NetAddress any_address(instance_, any_ipv4_address);
TestCompletionCallback callback(instance_->pp_instance(), callback_type());
callback.WaitForResult(socket.Bind(any_address, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_ERROR_FAILED, callback.result());
PASS();
}
std::string TestUDPSocket::TestBroadcastBeforeBindFails() {
pp::UDPSocket socket(instance_);
ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&socket));
PP_NetAddress_IPv4 any_ipv4_address = {0, {0, 0, 0, 0}};
pp::NetAddress any_address(instance_, any_ipv4_address);
TestCompletionCallback callback(instance_->pp_instance(), callback_type());
callback.WaitForResult(socket.Bind(any_address, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_ERROR_FAILED, callback.result());
PASS();
}
std::string TestUDPSocket::TestBroadcastAfterBindFails() {
pp::UDPSocket socket(instance_);
PP_NetAddress_IPv4 any_ipv4_address = {0, {0, 0, 0, 0}};
pp::NetAddress any_address(instance_, any_ipv4_address);
ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&socket, any_address));
TestCompletionCallback callback(instance_->pp_instance(), callback_type());
callback.WaitForResult(socket.SetOption(
PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(true), callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_ERROR_FAILED, callback.result());
// Setting broadcast again should also fail.
TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
callback_2.WaitForResult(socket.SetOption(
PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(true), callback_2.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback_2);
ASSERT_EQ(PP_ERROR_FAILED, callback_2.result());
PASS();
}
std::string TestUDPSocket::TestSendToFails() {
pp::UDPSocket socket(instance_);
PP_NetAddress_IPv4 any_ipv4_address = {0, {0, 0, 0, 0}};
pp::NetAddress any_address(instance_, any_ipv4_address);
ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&socket, any_address));
std::vector<char> buffer(1);
buffer[0] = 1;
PP_NetAddress_IPv4 target_ipv4_address = {1024, {127, 0, 0, 1}};
pp::NetAddress target_address(instance_, target_ipv4_address);
// All writes should fail.
for (int i = 0; i < 10; ++i) {
TestCompletionCallbackWithOutput<pp::NetAddress> callback(
instance_->pp_instance(), callback_type());
callback.WaitForResult(
socket.SendTo(buffer.data(), static_cast<int32_t>(buffer.size()),
target_address, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_ERROR_FAILED, callback.result());
}
PASS();
}
std::string TestUDPSocket::TestReadFails() {
pp::UDPSocket socket(instance_);
PP_NetAddress_IPv4 any_ipv4_address = {0, {0, 0, 0, 0}};
pp::NetAddress any_address(instance_, any_ipv4_address);
ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&socket, any_address));
std::vector<char> buffer(1);
// All reads should fail. Larger number of reads increases the chance that at
// least one read will be synchronous.
for (int i = 0; i < 200; ++i) {
TestCompletionCallbackWithOutput<pp::NetAddress> callback(
instance_->pp_instance(), callback_type());
callback.WaitForResult(socket.RecvFrom(&buffer[0],
static_cast<int32_t>(buffer.size()),
callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_ERROR_FAILED, callback.result());
}
PASS();
}

@ -63,14 +63,6 @@ class TestUDPSocket: public TestCase {
std::string TestParallelSend();
std::string TestMulticast();
// Error cases. It's up to the parent test fixture to ensure that these events
// result in errors.
std::string TestBindFails();
std::string TestBroadcastBeforeBindFails();
std::string TestBroadcastAfterBindFails();
std::string TestSendToFails();
std::string TestReadFails();
pp::NetAddress address_;
const PPB_UDPSocket_1_0* socket_interface_1_0_;

@ -176,7 +176,6 @@ Refer to README.md for content description and update process.
<item id="payments_sync_cards" hash_code="95588446" type="0" content_hash_code="56526513" os_list="linux,windows" file_path="components/autofill/core/browser/payments/payments_client.cc"/>
<item id="pdf_plugin_placeholder" hash_code="56866367" type="0" content_hash_code="16907221" os_list="linux,windows" file_path="chrome/browser/plugins/pdf_plugin_placeholder_observer.cc"/>
<item id="pepper_tcp_socket" hash_code="120623198" type="0" content_hash_code="55474823" os_list="linux,windows" file_path="content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc"/>
<item id="pepper_udp_socket_message_filter" hash_code="19997224" type="0" content_hash_code="62688533" os_list="linux,mac,windows" file_path="content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc"/>
<item id="per_user_topic_registration_request" hash_code="10498172" type="0" content_hash_code="32495619" os_list="linux,windows" file_path="components/invalidation/impl/per_user_topic_registration_request.cc"/>
<item id="permission_reporting" hash_code="131741641" type="0" deprecated="2018-03-06" content_hash_code="7213535" file_path=""/>
<item id="permission_request_creator" hash_code="43206794" type="0" content_hash_code="73571699" os_list="linux,windows" file_path="chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc"/>